diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2018-09-26 07:27:30 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2018-09-26 07:27:30 +0000 |
commit | b9fa262165601a3b348d22ca1d8da53bda99e55b (patch) | |
tree | 21bd632e051addfee01ab7a568b01f5b6428051a /public/javascripts | |
parent | c171797673f549e434dd6b94f7262fd31a77b533 (diff) | |
download | redmine-b9fa262165601a3b348d22ca1d8da53bda99e55b.tar.gz redmine-b9fa262165601a3b348d22ca1d8da53bda99e55b.zip |
Adds preview option to the wiki toolbar (#27758).
Patch by Marius BALTEANU.
git-svn-id: http://svn.redmine.org/redmine/trunk@17521 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'public/javascripts')
-rw-r--r-- | public/javascripts/application.js | 33 | ||||
-rw-r--r-- | public/javascripts/attachments.js | 3 | ||||
-rw-r--r-- | public/javascripts/jstoolbar/jstoolbar-textile.min.js | 1 | ||||
-rw-r--r-- | public/javascripts/jstoolbar/jstoolbar.js | 96 | ||||
-rw-r--r-- | public/javascripts/jstoolbar/lang/jstoolbar-en.js | 2 |
5 files changed, 109 insertions, 26 deletions
diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 0239e0343..dbe4a32b9 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -449,17 +449,6 @@ function hideModal(el) { modal.dialog("close"); } -function submitPreview(url, form, target) { - $.ajax({ - url: url, - type: 'post', - data: $('#'+form).serialize(), - success: function(data){ - $('#'+target).html(data); - } - }); -} - function collapseScmEntry(id) { $('.'+id).each(function() { if ($(this).hasClass('open')) { @@ -846,6 +835,28 @@ $(document).ready(function(){ toggleDisabledInit(); }); +$(document).ready(function(){ + $('#content').on('click', 'div.jstTabs a.tab-preview', function(event){ + var tab = $(event.target); + + var url = tab.data('url'); + var form = tab.parents('form'); + var jstBlock = tab.parents('.jstBlock'); + + var element = encodeURIComponent(jstBlock.find('.wiki-edit').val()); + var attachments = form.find('.attachments_fields input').serialize(); + + $.ajax({ + url: url, + type: 'post', + data: "text=" + element + '&' + attachments, + success: function(data){ + jstBlock.find('.wiki-preview').html(data); + } + }); + }); +}); + function keepAnchorOnSignIn(form){ var hash = decodeURIComponent(self.document.location.hash); if (hash) { diff --git a/public/javascripts/attachments.js b/public/javascripts/attachments.js index 1baafc0bd..753855f91 100644 --- a/public/javascripts/attachments.js +++ b/public/javascripts/attachments.js @@ -237,8 +237,7 @@ function addInlineAttachmentMarkup(file) { 'selectionStart': cursorPosition + newLineBefore, 'selectionEnd': cursorPosition + inlineFilename.length + newLineBefore }); - $textarea.closest('.jstEditor') - .siblings('.jstElements') + $textarea.parents('.jstBlock') .find('.jstb_img').click(); // move cursor into next line diff --git a/public/javascripts/jstoolbar/jstoolbar-textile.min.js b/public/javascripts/jstoolbar/jstoolbar-textile.min.js deleted file mode 100644 index e087d1cf2..000000000 --- a/public/javascripts/jstoolbar/jstoolbar-textile.min.js +++ /dev/null @@ -1 +0,0 @@ -function jsToolBar(e){if(document.createElement&&e&&("undefined"!=typeof document.selection||"undefined"!=typeof e.setSelectionRange)){if(this.textarea=e,this.editor=document.createElement("div"),this.editor.className="jstEditor",this.textarea.parentNode.insertBefore(this.editor,this.textarea),this.editor.appendChild(this.textarea),this.toolbar=document.createElement("div"),this.toolbar.className="jstElements",this.editor.parentNode.insertBefore(this.toolbar,this.editor),this.editor.addEventListener&&navigator.appVersion.match(/\bMSIE\b/)){this.handle=document.createElement("div"),this.handle.className="jstHandle";var t=this.resizeDragStart,n=this;this.handle.addEventListener("mousedown",function(e){t.call(n,e)},!1),window.addEventListener("unload",function(){n.handle.parentNode.removeChild(n.handle);delete n.handle},!1),this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling)}this.context=null,this.toolNodes={}}}function jsButton(e,t,n,o){"undefined"==typeof jsToolBar.strings?this.title=e||null:this.title=jsToolBar.strings[e]||e||null,this.fn=t||function(){},this.scope=n||null,this.className=o||null}function jsSpace(e){this.id=e||null,this.width=null}function jsCombo(e,t,n,o,i){this.title=e||null,this.options=t||null,this.scope=n||null,this.fn=o||function(){},this.className=i||null}jsButton.prototype.draw=function(){if(!this.scope)return null;var e=document.createElement("button");e.setAttribute("type","button"),e.tabIndex=200,this.className&&(e.className=this.className),e.title=this.title;var t=document.createElement("span");if(t.appendChild(document.createTextNode(this.title)),e.appendChild(t),void 0!=this.icon&&(e.style.backgroundImage="url("+this.icon+")"),"function"==typeof this.fn){var n=this;e.onclick=function(){try{n.fn.apply(n.scope,arguments)}catch(e){}return!1}}return e},jsSpace.prototype.draw=function(){var e=document.createElement("span");return this.id&&(e.id=this.id),e.appendChild(document.createTextNode(String.fromCharCode(160))),e.className="jstSpacer",this.width&&(e.style.marginRight=this.width+"px"),e},jsCombo.prototype.draw=function(){if(!this.scope||!this.options)return null;var e=document.createElement("select");this.className&&(e.className=className),e.title=this.title;for(var t in this.options){var n=document.createElement("option");n.value=t,n.appendChild(document.createTextNode(this.options[t])),e.appendChild(n)}var o=this;return e.onchange=function(){try{o.fn.call(o.scope,this.value)}catch(e){alert(e)}return!1},e},jsToolBar.prototype={base_url:"",mode:"wiki",elements:{},help_link:"",getMode:function(){return this.mode},setMode:function(e){this.mode=e||"wiki"},switchMode:function(e){e=e||"wiki",this.draw(e)},setHelpLink:function(e){this.help_link=e},button:function(e){var t=this.elements[e];if("function"!=typeof t.fn[this.mode])return null;var n=new jsButton(t.title,t.fn[this.mode],this,"jstb_"+e);return void 0!=t.icon&&(n.icon=t.icon),n},space:function(e){var t=new jsSpace(e);return void 0!==this.elements[e].width&&(t.width=this.elements[e].width),t},combo:function(e){var t=this.elements[e],n=t[this.mode].list.length;if("function"!=typeof t[this.mode].fn||0==n)return null;for(var o={},i=0;n>i;i++){var s=t[this.mode].list[i];o[s]=t.options[s]}return new jsCombo(t.title,o,this,t[this.mode].fn)},draw:function(e){for(this.setMode(e);this.toolbar.hasChildNodes();)this.toolbar.removeChild(this.toolbar.firstChild);this.toolNodes={};var t,n,o;for(var i in this.elements){t=this.elements[i];var s=void 0==t.type||""==t.type||void 0!=t.disabled&&t.disabled||void 0!=t.context&&null!=t.context&&t.context!=this.context;s||"function"!=typeof this[t.type]||(n=this[t.type](i),n&&(o=n.draw()),o&&(this.toolNodes[i]=o,this.toolbar.appendChild(o)))}},singleTag:function(e,t){e=e||null,t=t||e,e&&t&&this.encloseSelection(e,t)},encloseLineSelection:function(e,t,n){this.textarea.focus(),e=e||"",t=t||"";var o,i,s,l,a,r;if("undefined"!=typeof document.selection?s=document.selection.createRange().text:"undefined"!=typeof this.textarea.setSelectionRange&&(o=this.textarea.selectionStart,i=this.textarea.selectionEnd,l=this.textarea.scrollTop,o=this.textarea.value.substring(0,o).replace(/[^\r\n]*$/g,"").length,i=this.textarea.value.length-this.textarea.value.substring(i,this.textarea.value.length).replace(/^[^\r\n]*/,"").length,s=this.textarea.value.substring(o,i)),s.match(/ $/)&&(s=s.substring(0,s.length-1),t+=" "),r="function"==typeof n?s?n.call(this,s):n(""):s?s:"",a=e+r+t,"undefined"!=typeof document.selection){document.selection.createRange().text=a;var c=this.textarea.createTextRange();c.collapse(!1),c.move("character",-t.length),c.select()}else"undefined"!=typeof this.textarea.setSelectionRange&&(this.textarea.value=this.textarea.value.substring(0,o)+a+this.textarea.value.substring(i),s?this.textarea.setSelectionRange(o+a.length,o+a.length):this.textarea.setSelectionRange(o+e.length,o+e.length),this.textarea.scrollTop=l)},encloseSelection:function(e,t,n){this.textarea.focus(),e=e||"",t=t||"";var o,i,s,l,a,r;if("undefined"!=typeof document.selection?s=document.selection.createRange().text:"undefined"!=typeof this.textarea.setSelectionRange&&(o=this.textarea.selectionStart,i=this.textarea.selectionEnd,l=this.textarea.scrollTop,s=this.textarea.value.substring(o,i),o>0&&this.textarea.value.substr(o-1, 1).match(/\S/)&&(e=" "+e),this.textarea.value.substr(i, 1).match(/\S/)&&(t=t+" ")),s.match(/ $/)&&(s=s.substring(0,s.length-1),t+=" "),r="function"==typeof n?s?n.call(this,s):n(""):s?s:"",a=e+r+t,"undefined"!=typeof document.selection){document.selection.createRange().text=a;var c=this.textarea.createTextRange();c.collapse(!1),c.move("character",-t.length),c.select()}else"undefined"!=typeof this.textarea.setSelectionRange&&(this.textarea.value=this.textarea.value.substring(0,o)+a+this.textarea.value.substring(i),s?this.textarea.setSelectionRange(o+a.length,o+a.length):this.textarea.setSelectionRange(o+e.length,o+e.length),this.textarea.scrollTop=l)},stripBaseURL:function(e){if(""!=this.base_url){var t=e.indexOf(this.base_url);0==t&&(e=e.substr(this.base_url.length))}return e}},jsToolBar.prototype.resizeSetStartH=function(){this.dragStartH=this.textarea.offsetHeight+0},jsToolBar.prototype.resizeDragStart=function(e){var t=this;this.dragStartY=e.clientY,this.resizeSetStartH(),document.addEventListener("mousemove",this.dragMoveHdlr=function(e){t.resizeDragMove(e)},!1),document.addEventListener("mouseup",this.dragStopHdlr=function(e){t.resizeDragStop(e)},!1)},jsToolBar.prototype.resizeDragMove=function(e){this.textarea.style.height=this.dragStartH+e.clientY-this.dragStartY+"px"},jsToolBar.prototype.resizeDragStop=function(e){document.removeEventListener("mousemove",this.dragMoveHdlr,!1),document.removeEventListener("mouseup",this.dragStopHdlr,!1)},jsToolBar.prototype.precodeMenu=function(e){for(var t=["c","clojure","cpp","css","delphi","diff","erb","go","groovy","haml","html","java","javascript","json","lua","php","python","ruby","sass","sql","taskpaper","text","xml","yaml"],n=$("<ul style='position:absolute;'></ul>"),o=0;o<t.length;o++)$("<li></li>").text(t[o]).appendTo(n).mousedown(function(){e($(this).text())});return $("body").append(n),n.menu().width(150).position({my:"left top",at:"left bottom",of:this.toolNodes.precode}),$(document).on("mousedown",function(){n.remove()}),!1},jsToolBar.prototype.elements.strong={type:"button",title:"Strong",fn:{wiki:function(){this.singleTag("*")}}},jsToolBar.prototype.elements.em={type:"button",title:"Italic",fn:{wiki:function(){this.singleTag("_")}}},jsToolBar.prototype.elements.ins={type:"button",title:"Underline",fn:{wiki:function(){this.singleTag("+")}}},jsToolBar.prototype.elements.del={type:"button",title:"Deleted",fn:{wiki:function(){this.singleTag("-")}}},jsToolBar.prototype.elements.code={type:"button",title:"Code",fn:{wiki:function(){this.singleTag("@")}}},jsToolBar.prototype.elements.space1={type:"space"},jsToolBar.prototype.elements.h1={type:"button",title:"Heading 1",fn:{wiki:function(){this.encloseLineSelection("h1. ","",function(e){return e=e.replace(/^h\d+\.\s+/,"")})}}},jsToolBar.prototype.elements.h2={type:"button",title:"Heading 2",fn:{wiki:function(){this.encloseLineSelection("h2. ","",function(e){return e=e.replace(/^h\d+\.\s+/,"")})}}},jsToolBar.prototype.elements.h3={type:"button",title:"Heading 3",fn:{wiki:function(){this.encloseLineSelection("h3. ","",function(e){return e=e.replace(/^h\d+\.\s+/,"")})}}},jsToolBar.prototype.elements.space2={type:"space"},jsToolBar.prototype.elements.ul={type:"button",title:"Unordered list",fn:{wiki:function(){this.encloseLineSelection("","",function(e){return e=e.replace(/\r/g,""),e.replace(/(\n|^)[#-]?\s*/g,"$1* ")})}}},jsToolBar.prototype.elements.ol={type:"button",title:"Ordered list",fn:{wiki:function(){this.encloseLineSelection("","",function(e){return e=e.replace(/\r/g,""),e.replace(/(\n|^)[*-]?\s*/g,"$1# ")})}}},jsToolBar.prototype.elements.space3={type:"space"},jsToolBar.prototype.elements.bq={type:"button",title:"Quote",fn:{wiki:function(){this.encloseLineSelection("","",function(e){return e=e.replace(/\r/g,""),e.replace(/(\n|^) *([^\n]*)/g,"$1> $2")})}}},jsToolBar.prototype.elements.unbq={type:"button",title:"Unquote",fn:{wiki:function(){this.encloseLineSelection("","",function(e){return e=e.replace(/\r/g,""),e.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2")})}}},jsToolBar.prototype.elements.pre={type:"button",title:"Preformatted text",fn:{wiki:function(){this.encloseLineSelection("<pre>\n","\n</pre>")}}},jsToolBar.prototype.elements.precode={type:"button",title:"Highlighted code",fn:{wiki:function(){var e=this;this.precodeMenu(function(t){e.encloseLineSelection('<pre><code class="'+t+'">\n',"\n</code></pre>\n")})}}},jsToolBar.prototype.elements.space4={type:"space"},jsToolBar.prototype.elements.link={type:"button",title:"Wiki link",fn:{wiki:function(){this.encloseSelection("[[","]]")}}},jsToolBar.prototype.elements.img={type:"button",title:"Image",fn:{wiki:function(){this.encloseSelection("!","!")}}},jsToolBar.prototype.elements.space5={type:"space"},jsToolBar.prototype.elements.help={type:"button",title:"Help",fn:{wiki:function(){window.open(this.help_link,"","resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes")}}}; diff --git a/public/javascripts/jstoolbar/jstoolbar.js b/public/javascripts/jstoolbar/jstoolbar.js index bbda5f8b8..98dae6ff2 100644 --- a/public/javascripts/jstoolbar/jstoolbar.js +++ b/public/javascripts/jstoolbar/jstoolbar.js @@ -7,12 +7,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * DotClear is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with DotClear; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -34,15 +34,45 @@ function jsToolBar(textarea) { this.textarea = textarea; + this.toolbarBlock = document.createElement('div'); + this.toolbarBlock.className = 'jstBlock'; + this.textarea.parentNode.insertBefore(this.toolbarBlock, this.textarea); + this.editor = document.createElement('div'); this.editor.className = 'jstEditor'; - this.textarea.parentNode.insertBefore(this.editor,this.textarea); + this.preview = document.createElement('div'); + this.preview.className = 'wiki wiki-preview hidden'; + this.preview.setAttribute('id', 'preview_' + textarea.getAttribute('id')); + this.editor.appendChild(this.textarea); + this.editor.appendChild(this.preview); + + this.tabsBlock = document.createElement('div'); + this.tabsBlock.className = 'jstTabs tabs'; + + var This = this; + this.writeTab = new jsTab('Write', true); + this.writeTab.onclick = function(event) { This.hidePreview.call(This, event); return false; }; + + this.previewTab = new jsTab('Preview'); + this.previewTab.onclick = function(event) { This.showPreview.call(This, event); return false; }; + + var elementsTab = document.createElement('li'); + elementsTab.classList = 'tab-elements'; + + var tabs = document.createElement('ul'); + tabs.appendChild(this.writeTab); + tabs.appendChild(this.previewTab); + tabs.appendChild(elementsTab); + this.tabsBlock.appendChild(tabs); this.toolbar = document.createElement("div"); this.toolbar.className = 'jstElements'; - this.editor.parentNode.insertBefore(this.toolbar,this.editor); + elementsTab.appendChild(this.toolbar); + + this.toolbarBlock.appendChild(this.tabsBlock); + this.toolbarBlock.appendChild(this.editor); // Dragable resizing if (this.editor.addEventListener && navigator.appVersion.match(/\bMSIE\b/)) @@ -53,19 +83,40 @@ function jsToolBar(textarea) { var This = this; this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false); // fix memory leak in Firefox (bug #241518) - window.addEventListener('unload',function() { + window.addEventListener('unload',function() { var del = This.handle.parentNode.removeChild(This.handle); delete(This.handle); },false); - + this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling); } - + this.context = null; - this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni + this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni // de raccourcis vers les éléments DOM correspondants aux outils. } +function jsTab(name, selected) { + selected = selected || false; + if(typeof jsToolBar.strings == 'undefined') { + var tabName = name || null; + } else { + var tabName = jsToolBar.strings[name] || name || null; + } + + var tab = document.createElement('li'); + var link = document.createElement('a'); + link.setAttribute('href', '#'); + link.innerText = tabName; + link.className = 'tab-' + name.toLowerCase(); + + if (selected == true) { + link.classList.add('selected'); + } + tab.appendChild(link) + + return tab; +} function jsButton(title, fn, scope, className) { if(typeof jsToolBar.strings == 'undefined') { this.title = title || null; @@ -91,6 +142,7 @@ jsButton.prototype.draw = function() { if (this.icon != undefined) { button.style.backgroundImage = 'url('+this.icon+')'; } + if (typeof(this.fn) == 'function') { var This = this; button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; }; @@ -110,7 +162,7 @@ jsSpace.prototype.draw = function() { if (this.width) span.style.marginRight = this.width+'px'; return span; -} +} function jsCombo(title, options, scope, fn, className) { this.title = title || null; @@ -136,7 +188,7 @@ jsCombo.prototype.draw = function() { var This = this; select.onchange = function() { - try { + try { This.fn.call(This.scope, this.value); } catch (e) { alert(e); } @@ -152,7 +204,7 @@ jsToolBar.prototype = { mode: 'wiki', elements: {}, help_link: '', - + getMode: function() { return this.mode; }, @@ -170,6 +222,10 @@ jsToolBar.prototype = { this.help_link = link; }, + setPreviewUrl: function(url) { + this.previewTab.firstChild.setAttribute('data-url', url); + }, + button: function(toolName) { var tool = this.elements[toolName]; if (typeof tool.fn[this.mode] != 'function') return null; @@ -292,7 +348,6 @@ jsToolBar.prototype = { encloseSelection: function(prefix, suffix, fn) { this.textarea.focus(); - prefix = prefix || ''; suffix = suffix || ''; @@ -343,7 +398,24 @@ jsToolBar.prototype = { this.textarea.scrollTop = scrollPos; } }, + showPreview: function(event) { + if (event.target.classList.contains('selected')) { return; } + this.preview.setAttribute('style', 'min-height: ' + this.textarea.clientHeight + 'px;') + this.toolbar.classList.add('hidden'); + this.textarea.classList.add('hidden'); + this.preview.classList.remove('hidden'); + this.tabsBlock.getElementsByClassName('tab-write')[0].classList.remove('selected'); + event.target.classList.add('selected'); + }, + hidePreview: function(event) { + if (event.target.classList.contains('selected')) { return; } + this.toolbar.classList.remove('hidden'); + this.textarea.classList.remove('hidden'); + this.preview.classList.add('hidden'); + this.tabsBlock.getElementsByClassName('tab-preview')[0].classList.remove('selected'); + event.target.classList.add('selected'); + }, stripBaseURL: function(url) { if (this.base_url != '') { var pos = url.indexOf(this.base_url); diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-en.js b/public/javascripts/jstoolbar/lang/jstoolbar-en.js index 4f72f087e..c52e85508 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-en.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-en.js @@ -15,3 +15,5 @@ jsToolBar.strings['Unquote'] = 'Remove Quote'; jsToolBar.strings['Preformatted text'] = 'Preformatted text'; jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Write'] = 'Write'; +jsToolBar.strings['Preview'] = 'Preview';
\ No newline at end of file |