diff options
author | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2011-11-08 20:40:44 +0400 |
commit | 81bea17aefb26859f825b9293c7c99192874806e (patch) | |
tree | fb244408ca271affa2899adb634788802c9a89d8 /lib/dijit/_editor/plugins | |
parent | 870a70e109ac9e80a88047044530de53d0404ec7 (diff) |
upgrade Dojo to 1.6.1
Diffstat (limited to 'lib/dijit/_editor/plugins')
-rw-r--r-- | lib/dijit/_editor/plugins/AlwaysShowToolbar.js | 293 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/EnterKeyHandling.js | 1007 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/FontChoice.js | 812 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/FullScreen.js | 647 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/LinkDialog.js | 714 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/NewPage.js | 93 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/Print.js | 166 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/TabIndent.js | 80 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/TextColor.js | 143 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/ToggleDir.js | 98 | ||||
-rw-r--r-- | lib/dijit/_editor/plugins/ViewSource.js | 844 |
11 files changed, 3208 insertions, 1689 deletions
diff --git a/lib/dijit/_editor/plugins/AlwaysShowToolbar.js b/lib/dijit/_editor/plugins/AlwaysShowToolbar.js index 1e0e2ed3f..9d0b7ded8 100644 --- a/lib/dijit/_editor/plugins/AlwaysShowToolbar.js +++ b/lib/dijit/_editor/plugins/AlwaysShowToolbar.js @@ -1,119 +1,190 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"]){ -dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"]=true; +if(!dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"] = true; dojo.provide("dijit._editor.plugins.AlwaysShowToolbar"); -dojo.declare("dijit._editor.plugins.AlwaysShowToolbar",dijit._editor._Plugin,{_handleScroll:true,setEditor:function(e){ -if(!e.iframe){ -return; -} -this.editor=e; -e.onLoadDeferred.addCallback(dojo.hitch(this,this.enable)); -},enable:function(d){ -this._updateHeight(); -this.connect(window,"onscroll","globalOnScrollHandler"); -this.connect(this.editor,"onNormalizedDisplayChanged","_updateHeight"); -return d; -},_updateHeight:function(){ -var e=this.editor; -if(!e.isLoaded){ -return; -} -if(e.height){ -return; -} -var _1=dojo.marginBox(e.editNode).h; -if(dojo.isOpera){ -_1=e.editNode.scrollHeight; -} -if(!_1){ -_1=dojo.marginBox(e.document.body).h; -} -if(_1==0){ -return; -} -if(dojo.isIE<=7&&this.editor.minHeight){ -var _2=parseInt(this.editor.minHeight); -if(_1<_2){ -_1=_2; -} -} -if(_1!=this._lastHeight){ -this._lastHeight=_1; -dojo.marginBox(e.iframe,{h:this._lastHeight}); -} -},_lastHeight:0,globalOnScrollHandler:function(){ -var _3=dojo.isIE<7; -if(!this._handleScroll){ -return; -} -var _4=this.editor.header; -var db=dojo.body; -if(!this._scrollSetUp){ -this._scrollSetUp=true; -this._scrollThreshold=dojo.position(_4,true).y; -} -var _5=dojo._docScroll().y; -var s=_4.style; -if(_5>this._scrollThreshold&&_5<this._scrollThreshold+this._lastHeight){ -if(!this._fixEnabled){ -var _6=dojo.marginBox(_4); -this.editor.iframe.style.marginTop=_6.h+"px"; -if(_3){ -s.left=dojo.position(_4).x; -if(_4.previousSibling){ -this._IEOriginalPos=["after",_4.previousSibling]; -}else{ -if(_4.nextSibling){ -this._IEOriginalPos=["before",_4.nextSibling]; -}else{ -this._IEOriginalPos=["last",_4.parentNode]; -} -} -dojo.body().appendChild(_4); -dojo.addClass(_4,"dijitIEFixedToolbar"); -}else{ -s.position="fixed"; -s.top="0px"; -} -dojo.marginBox(_4,{w:_6.w}); -s.zIndex=2000; -this._fixEnabled=true; -} -var _7=(this.height)?parseInt(this.editor.height):this.editor._lastHeight; -s.display=(_5>this._scrollThreshold+_7)?"none":""; -}else{ -if(this._fixEnabled){ -this.editor.iframe.style.marginTop=""; -s.position=""; -s.top=""; -s.zIndex=""; -s.display=""; -if(_3){ -s.left=""; -dojo.removeClass(_4,"dijitIEFixedToolbar"); -if(this._IEOriginalPos){ -dojo.place(_4,this._IEOriginalPos[1],this._IEOriginalPos[0]); -this._IEOriginalPos=null; -}else{ -dojo.place(_4,this.editor.iframe,"before"); -} -} -s.width=""; -this._fixEnabled=false; -} -} -},destroy:function(){ -this._IEOriginalPos=null; -this._handleScroll=false; -dojo.forEach(this._connects,dojo.disconnect); -if(dojo.isIE<7){ -dojo.removeClass(this.editor.header,"dijitIEFixedToolbar"); -} -}}); +dojo.require("dijit._editor._Plugin"); + + +dojo.declare("dijit._editor.plugins.AlwaysShowToolbar", dijit._editor._Plugin, + { + // summary: + // This plugin is required for Editors in auto-expand mode. + // It handles the auto-expansion as the user adds/deletes text, + // and keeps the editor's toolbar visible even when the top of the editor + // has scrolled off the top of the viewport (usually when editing a long + // document). + // description: + // Specify this in extraPlugins (or plugins) parameter and also set + // height to "". + // example: + // | <div dojoType="dijit.Editor" height="" + // | extraPlugins="['dijit._editor.plugins.AlwaysShowToolbar']"> + + // _handleScroll: Boolean + // Enables/disables the handler for scroll events + _handleScroll: true, + + setEditor: function(e){ + // Overrides _Plugin.setEditor(). + if(!e.iframe){ + console.log('Port AlwaysShowToolbar plugin to work with Editor without iframe'); + return; + } + + this.editor = e; + + e.onLoadDeferred.addCallback(dojo.hitch(this, this.enable)); + }, + + enable: function(d){ + // summary: + // Enable plugin. Called when Editor has finished initializing. + // tags: + // private + + this._updateHeight(); + this.connect(window, 'onscroll', "globalOnScrollHandler"); + this.connect(this.editor, 'onNormalizedDisplayChanged', "_updateHeight"); + return d; + }, + + _updateHeight: function(){ + // summary: + // Updates the height of the editor area to fit the contents. + var e = this.editor; + if(!e.isLoaded){ return; } + if(e.height){ return; } + + var height = dojo._getMarginSize(e.editNode).h; + if(dojo.isOpera){ + height = e.editNode.scrollHeight; + } + // console.debug('height',height); + // alert(this.editNode); + + //height maybe zero in some cases even though the content is not empty, + //we try the height of body instead + if(!height){ + height = dojo._getMarginSize(e.document.body).h; + } + + if(height == 0){ + console.debug("Can not figure out the height of the editing area!"); + return; //prevent setting height to 0 + } + if(dojo.isIE <= 7 && this.editor.minHeight){ + var min = parseInt(this.editor.minHeight); + if(height < min){ height = min; } + } + if(height != this._lastHeight){ + this._lastHeight = height; + // this.editorObject.style.height = this._lastHeight + "px"; + dojo.marginBox(e.iframe, { h: this._lastHeight }); + } + }, + + // _lastHeight: Integer + // Height in px of the editor at the last time we did sizing + _lastHeight: 0, + + globalOnScrollHandler: function(){ + // summary: + // Handler for scroll events that bubbled up to <html> + // tags: + // private + + var isIE6 = dojo.isIE < 7; + if(!this._handleScroll){ return; } + var tdn = this.editor.header; + var db = dojo.body; + + if(!this._scrollSetUp){ + this._scrollSetUp = true; + this._scrollThreshold = dojo.position(tdn, true).y; +// console.log("threshold:", this._scrollThreshold); + //what's this for?? comment out for now +// if((isIE6)&&(db)&&(dojo.style(db, "backgroundIimage")=="none")){ +// db.style.backgroundImage = "url(" + dojo.uri.moduleUri("dijit", "templates/blank.gif") + ")"; +// db.style.backgroundAttachment = "fixed"; +// } + } + + var scrollPos = dojo._docScroll().y; + var s = tdn.style; + + if(scrollPos > this._scrollThreshold && scrollPos < this._scrollThreshold+this._lastHeight){ + // dojo.debug(scrollPos); + if(!this._fixEnabled){ + var tdnbox = dojo._getMarginSize(tdn); + this.editor.iframe.style.marginTop = tdnbox.h+"px"; + + if(isIE6){ + s.left = dojo.position(tdn).x; + if(tdn.previousSibling){ + this._IEOriginalPos = ['after',tdn.previousSibling]; + }else if(tdn.nextSibling){ + this._IEOriginalPos = ['before',tdn.nextSibling]; + }else{ + this._IEOriginalPos = ['last',tdn.parentNode]; + } + dojo.body().appendChild(tdn); + dojo.addClass(tdn,'dijitIEFixedToolbar'); + }else{ + s.position = "fixed"; + s.top = "0px"; + } + + dojo.marginBox(tdn, { w: tdnbox.w }); + s.zIndex = 2000; + this._fixEnabled = true; + } + // if we're showing the floating toolbar, make sure that if + // we've scrolled past the bottom of the editor that we hide + // the toolbar for this instance of the editor. + + // TODO: when we get multiple editor toolbar support working + // correctly, ensure that we check this against the scroll + // position of the bottom-most editor instance. + var eHeight = (this.height) ? parseInt(this.editor.height) : this.editor._lastHeight; + s.display = (scrollPos > this._scrollThreshold+eHeight) ? "none" : ""; + }else if(this._fixEnabled){ + this.editor.iframe.style.marginTop = ''; + s.position = ""; + s.top = ""; + s.zIndex = ""; + s.display = ""; + if(isIE6){ + s.left = ""; + dojo.removeClass(tdn,'dijitIEFixedToolbar'); + if(this._IEOriginalPos){ + dojo.place(tdn, this._IEOriginalPos[1], this._IEOriginalPos[0]); + this._IEOriginalPos = null; + }else{ + dojo.place(tdn, this.editor.iframe, 'before'); + } + } + s.width = ""; + this._fixEnabled = false; + } + }, + + destroy: function(){ + // Overrides _Plugin.destroy(). TODO: call this.inherited() rather than repeating code. + this._IEOriginalPos = null; + this._handleScroll = false; + dojo.forEach(this._connects, dojo.disconnect); +// clearInterval(this.scrollInterval); + + if(dojo.isIE < 7){ + dojo.removeClass(this.editor.header, 'dijitIEFixedToolbar'); + } + } +}); + } diff --git a/lib/dijit/_editor/plugins/EnterKeyHandling.js b/lib/dijit/_editor/plugins/EnterKeyHandling.js index 51a8fdde8..670d491ae 100644 --- a/lib/dijit/_editor/plugins/EnterKeyHandling.js +++ b/lib/dijit/_editor/plugins/EnterKeyHandling.js @@ -1,423 +1,604 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]){ -dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]=true; +if(!dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"] = true; dojo.provide("dijit._editor.plugins.EnterKeyHandling"); dojo.require("dojo.window"); -dojo.declare("dijit._editor.plugins.EnterKeyHandling",dijit._editor._Plugin,{blockNodeForEnter:"BR",constructor:function(_1){ -if(_1){ -dojo.mixin(this,_1); -} -},setEditor:function(_2){ -this.editor=_2; -if(this.blockNodeForEnter=="BR"){ -if(dojo.isIE){ -_2.contentDomPreFilters.push(dojo.hitch(this,"regularPsToSingleLinePs")); -_2.contentDomPostFilters.push(dojo.hitch(this,"singleLinePsToRegularPs")); -_2.onLoadDeferred.addCallback(dojo.hitch(this,"_fixNewLineBehaviorForIE")); -}else{ -_2.onLoadDeferred.addCallback(dojo.hitch(this,function(d){ -try{ -this.editor.document.execCommand("insertBrOnReturn",false,true); -} -catch(e){ -} -return d; -})); -} -}else{ -if(this.blockNodeForEnter){ -dojo["require"]("dijit._editor.range"); -var h=dojo.hitch(this,this.handleEnterKey); -_2.addKeyHandler(13,0,0,h); -_2.addKeyHandler(13,0,1,h); -this.connect(this.editor,"onKeyPressed","onKeyPressed"); -} -} -},onKeyPressed:function(e){ -if(this._checkListLater){ -if(dojo.withGlobal(this.editor.window,"isCollapsed",dijit)){ -var _3=dojo.withGlobal(this.editor.window,"getAncestorElement",dijit._editor.selection,["LI"]); -if(!_3){ -dijit._editor.RichText.prototype.execCommand.call(this.editor,"formatblock",this.blockNodeForEnter); -var _4=dojo.withGlobal(this.editor.window,"getAncestorElement",dijit._editor.selection,[this.blockNodeForEnter]); -if(_4){ -_4.innerHTML=this.bogusHtmlContent; -if(dojo.isIE){ -var r=this.editor.document.selection.createRange(); -r.move("character",-1); -r.select(); -} -}else{ -console.error("onKeyPressed: Cannot find the new block node"); -} -}else{ -if(dojo.isMoz){ -if(_3.parentNode.parentNode.nodeName=="LI"){ -_3=_3.parentNode.parentNode; -} -} -var fc=_3.firstChild; -if(fc&&fc.nodeType==1&&(fc.nodeName=="UL"||fc.nodeName=="OL")){ -_3.insertBefore(fc.ownerDocument.createTextNode(" "),fc); -var _5=dijit.range.create(this.editor.window); -_5.setStart(_3.firstChild,0); -var _6=dijit.range.getSelection(this.editor.window,true); -_6.removeAllRanges(); -_6.addRange(_5); -} -} -} -this._checkListLater=false; -} -if(this._pressedEnterInBlock){ -if(this._pressedEnterInBlock.previousSibling){ -this.removeTrailingBr(this._pressedEnterInBlock.previousSibling); -} -delete this._pressedEnterInBlock; -} -},bogusHtmlContent:" ",blockNodes:/^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,handleEnterKey:function(e){ -var _7,_8,_9,_a=this.editor.document,br; -if(e.shiftKey){ -var _b=dojo.withGlobal(this.editor.window,"getParentElement",dijit._editor.selection); -var _c=dijit.range.getAncestor(_b,this.blockNodes); -if(_c){ -if(!e.shiftKey&&_c.tagName=="LI"){ -return true; -} -_7=dijit.range.getSelection(this.editor.window); -_8=_7.getRangeAt(0); -if(!_8.collapsed){ -_8.deleteContents(); -_7=dijit.range.getSelection(this.editor.window); -_8=_7.getRangeAt(0); -} -if(dijit.range.atBeginningOfContainer(_c,_8.startContainer,_8.startOffset)){ -if(e.shiftKey){ -br=_a.createElement("br"); -_9=dijit.range.create(this.editor.window); -_c.insertBefore(br,_c.firstChild); -_9.setStartBefore(br.nextSibling); -_7.removeAllRanges(); -_7.addRange(_9); -}else{ -dojo.place(br,_c,"before"); -} -}else{ -if(dijit.range.atEndOfContainer(_c,_8.startContainer,_8.startOffset)){ -_9=dijit.range.create(this.editor.window); -br=_a.createElement("br"); -if(e.shiftKey){ -_c.appendChild(br); -_c.appendChild(_a.createTextNode(" ")); -_9.setStart(_c.lastChild,0); -}else{ -dojo.place(br,_c,"after"); -_9.setStartAfter(_c); -} -_7.removeAllRanges(); -_7.addRange(_9); -}else{ -return true; -} -} -}else{ -dijit._editor.RichText.prototype.execCommand.call(this.editor,"inserthtml","<br>"); -} -return false; -} -var _d=true; -_7=dijit.range.getSelection(this.editor.window); -_8=_7.getRangeAt(0); -if(!_8.collapsed){ -_8.deleteContents(); -_7=dijit.range.getSelection(this.editor.window); -_8=_7.getRangeAt(0); -} -var _e=dijit.range.getBlockAncestor(_8.endContainer,null,this.editor.editNode); -var _f=_e.blockNode; -if((this._checkListLater=(_f&&(_f.nodeName=="LI"||_f.parentNode.nodeName=="LI")))){ -if(dojo.isMoz){ -this._pressedEnterInBlock=_f; -} -if(/^(\s| |\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s| |\xA0)<\/span>)?(<br>)?$/.test(_f.innerHTML)){ -_f.innerHTML=""; -if(dojo.isWebKit){ -_9=dijit.range.create(this.editor.window); -_9.setStart(_f,0); -_7.removeAllRanges(); -_7.addRange(_9); -} -this._checkListLater=false; -} -return true; -} -if(!_e.blockNode||_e.blockNode===this.editor.editNode){ -try{ -dijit._editor.RichText.prototype.execCommand.call(this.editor,"formatblock",this.blockNodeForEnter); -} -catch(e2){ -} -_e={blockNode:dojo.withGlobal(this.editor.window,"getAncestorElement",dijit._editor.selection,[this.blockNodeForEnter]),blockContainer:this.editor.editNode}; -if(_e.blockNode){ -if(_e.blockNode!=this.editor.editNode&&(!(_e.blockNode.textContent||_e.blockNode.innerHTML).replace(/^\s+|\s+$/g,"").length)){ -this.removeTrailingBr(_e.blockNode); -return false; -} -}else{ -_e.blockNode=this.editor.editNode; -} -_7=dijit.range.getSelection(this.editor.window); -_8=_7.getRangeAt(0); -} -var _10=_a.createElement(this.blockNodeForEnter); -_10.innerHTML=this.bogusHtmlContent; -this.removeTrailingBr(_e.blockNode); -if(dijit.range.atEndOfContainer(_e.blockNode,_8.endContainer,_8.endOffset)){ -if(_e.blockNode===_e.blockContainer){ -_e.blockNode.appendChild(_10); -}else{ -dojo.place(_10,_e.blockNode,"after"); -} -_d=false; -_9=dijit.range.create(this.editor.window); -_9.setStart(_10,0); -_7.removeAllRanges(); -_7.addRange(_9); -if(this.editor.height){ -dojo.window.scrollIntoView(_10); -} -}else{ -if(dijit.range.atBeginningOfContainer(_e.blockNode,_8.startContainer,_8.startOffset)){ -dojo.place(_10,_e.blockNode,_e.blockNode===_e.blockContainer?"first":"before"); -if(_10.nextSibling&&this.editor.height){ -_9=dijit.range.create(this.editor.window); -_9.setStart(_10.nextSibling,0); -_7.removeAllRanges(); -_7.addRange(_9); -dojo.window.scrollIntoView(_10.nextSibling); -} -_d=false; -}else{ -if(_e.blockNode===_e.blockContainer){ -_e.blockNode.appendChild(_10); -}else{ -dojo.place(_10,_e.blockNode,"after"); -} -_d=false; -if(_e.blockNode.style){ -if(_10.style){ -if(_e.blockNode.style.cssText){ -_10.style.cssText=_e.blockNode.style.cssText; -} -} -} -var rs=_8.startContainer; -if(rs&&rs.nodeType==3){ -var _11,_12; -var txt=rs.nodeValue; -var _13=_a.createTextNode(txt.substring(0,_8.startOffset)); -var _14=_a.createTextNode(txt.substring(_8.startOffset,txt.length)); -dojo.place(_13,rs,"before"); -dojo.place(_14,rs,"after"); -dojo.destroy(rs); -var _15=_13.parentNode; -while(_15!==_e.blockNode){ -var tg=_15.tagName; -var _16=_a.createElement(tg); -if(_15.style){ -if(_16.style){ -if(_15.style.cssText){ -_16.style.cssText=_15.style.cssText; -} -} -} -_11=_14; -while(_11){ -_12=_11.nextSibling; -_16.appendChild(_11); -_11=_12; -} -dojo.place(_16,_15,"after"); -_13=_15; -_14=_16; -_15=_15.parentNode; -} -_11=_14; -if(_11.nodeType==1||(_11.nodeType==3&&_11.nodeValue)){ -_10.innerHTML=""; -} -while(_11){ -_12=_11.nextSibling; -_10.appendChild(_11); -_11=_12; -} -} -_9=dijit.range.create(this.editor.window); -_9.setStart(_10,0); -_7.removeAllRanges(); -_7.addRange(_9); -if(this.editor.height){ -dijit.scrollIntoView(_10); -} -if(dojo.isMoz){ -this._pressedEnterInBlock=_e.blockNode; -} -} -} -return _d; -},removeTrailingBr:function(_17){ -var _18=/P|DIV|LI/i.test(_17.tagName)?_17:dijit._editor.selection.getParentOfType(_17,["P","DIV","LI"]); -if(!_18){ -return; -} -if(_18.lastChild){ -if((_18.childNodes.length>1&&_18.lastChild.nodeType==3&&/^[\s\xAD]*$/.test(_18.lastChild.nodeValue))||_18.lastChild.tagName=="BR"){ -dojo.destroy(_18.lastChild); -} -} -if(!_18.childNodes.length){ -_18.innerHTML=this.bogusHtmlContent; -} -},_fixNewLineBehaviorForIE:function(d){ -var doc=this.editor.document; -if(doc.__INSERTED_EDITIOR_NEWLINE_CSS===undefined){ -var _19=dojo.create("style",{type:"text/css"},doc.getElementsByTagName("head")[0]); -_19.styleSheet.cssText="p{margin:0;}"; -this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS=true; -} -return d; -},regularPsToSingleLinePs:function(_1a,_1b){ -function _1c(el){ -function _1d(_1e){ -var _1f=_1e[0].ownerDocument.createElement("p"); -_1e[0].parentNode.insertBefore(_1f,_1e[0]); -dojo.forEach(_1e,function(_20){ -_1f.appendChild(_20); -}); -}; -var _21=0; -var _22=[]; -var _23; -while(_21<el.childNodes.length){ -_23=el.childNodes[_21]; -if(_23.nodeType==3||(_23.nodeType==1&&_23.nodeName!="BR"&&dojo.style(_23,"display")!="block")){ -_22.push(_23); -}else{ -var _24=_23.nextSibling; -if(_22.length){ -_1d(_22); -_21=(_21+1)-_22.length; -if(_23.nodeName=="BR"){ -dojo.destroy(_23); -} -} -_22=[]; -} -_21++; -} -if(_22.length){ -_1d(_22); -} -}; -function _25(el){ -var _26=null; -var _27=[]; -var _28=el.childNodes.length-1; -for(var i=_28;i>=0;i--){ -_26=el.childNodes[i]; -if(_26.nodeName=="BR"){ -var _29=_26.ownerDocument.createElement("p"); -dojo.place(_29,el,"after"); -if(_27.length==0&&i!=_28){ -_29.innerHTML=" "; -} -dojo.forEach(_27,function(_2a){ -_29.appendChild(_2a); -}); -dojo.destroy(_26); -_27=[]; -}else{ -_27.unshift(_26); -} -} -}; -var _2b=[]; -var ps=_1a.getElementsByTagName("p"); -dojo.forEach(ps,function(p){ -_2b.push(p); +dojo.require("dijit._editor._Plugin"); +dojo.require("dijit._editor.range"); + + +dojo.declare("dijit._editor.plugins.EnterKeyHandling", dijit._editor._Plugin, { + // summary: + // This plugin tries to make all browsers behave consistently with regard to + // how ENTER behaves in the editor window. It traps the ENTER key and alters + // the way DOM is constructed in certain cases to try to commonize the generated + // DOM and behaviors across browsers. + // + // description: + // This plugin has three modes: + // + // * blockModeForEnter=BR + // * blockModeForEnter=DIV + // * blockModeForEnter=P + // + // In blockModeForEnter=P, the ENTER key starts a new + // paragraph, and shift-ENTER starts a new line in the current paragraph. + // For example, the input: + // + // | first paragraph <shift-ENTER> + // | second line of first paragraph <ENTER> + // | second paragraph + // + // will generate: + // + // | <p> + // | first paragraph + // | <br/> + // | second line of first paragraph + // | </p> + // | <p> + // | second paragraph + // | </p> + // + // In BR and DIV mode, the ENTER key conceptually goes to a new line in the + // current paragraph, and users conceptually create a new paragraph by pressing ENTER twice. + // For example, if the user enters text into an editor like this: + // + // | one <ENTER> + // | two <ENTER> + // | three <ENTER> + // | <ENTER> + // | four <ENTER> + // | five <ENTER> + // | six <ENTER> + // + // It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates: + // + // BR: + // | one<br/> + // | two<br/> + // | three<br/> + // | <br/> + // | four<br/> + // | five<br/> + // | six<br/> + // + // DIV: + // | <div>one</div> + // | <div>two</div> + // | <div>three</div> + // | <div> </div> + // | <div>four</div> + // | <div>five</div> + // | <div>six</div> + + // blockNodeForEnter: String + // This property decides the behavior of Enter key. It can be either P, + // DIV, BR, or empty (which means disable this feature). Anything else + // will trigger errors. The default is 'BR' + // + // See class description for more details. + blockNodeForEnter: 'BR', + + constructor: function(args){ + if(args){ + if("blockNodeForEnter" in args){ + args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase(); + } + dojo.mixin(this,args); + } + }, + + setEditor: function(editor){ + // Overrides _Plugin.setEditor(). + if(this.editor === editor) { return; } + this.editor = editor; + if(this.blockNodeForEnter == 'BR'){ + // While Moz has a mode tht mostly works, it's still a little different, + // So, try to just have a common mode and be consistent. Which means + // we need to enable customUndo, if not already enabled. + this.editor.customUndo = true; + editor.onLoadDeferred.addCallback(dojo.hitch(this,function(d){ + this.connect(editor.document, "onkeypress", function(e){ + if(e.charOrCode == dojo.keys.ENTER){ + // Just do it manually. The handleEnterKey has a shift mode that + // Always acts like <br>, so just use it. + var ne = dojo.mixin({},e); + ne.shiftKey = true; + if(!this.handleEnterKey(ne)){ + dojo.stopEvent(e); + } + } + }); + return d; + })); + }else if(this.blockNodeForEnter){ + // add enter key handler + // FIXME: need to port to the new event code!! + var h = dojo.hitch(this,this.handleEnterKey); + editor.addKeyHandler(13, 0, 0, h); //enter + editor.addKeyHandler(13, 0, 1, h); //shift+enter + this.connect(this.editor,'onKeyPressed','onKeyPressed'); + } + }, + onKeyPressed: function(e){ + // summary: + // Handler for keypress events. + // tags: + // private + if(this._checkListLater){ + if(dojo.withGlobal(this.editor.window, 'isCollapsed', dijit)){ + var liparent=dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, ['LI']); + if(!liparent){ + // circulate the undo detection code by calling RichText::execCommand directly + dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter); + // set the innerHTML of the new block node + var block = dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, [this.blockNodeForEnter]); + if(block){ + block.innerHTML=this.bogusHtmlContent; + if(dojo.isIE){ + // move to the start by moving backwards one char + var r = this.editor.document.selection.createRange(); + r.move('character',-1); + r.select(); + } + }else{ + console.error('onKeyPressed: Cannot find the new block node'); // FIXME + } + }else{ + if(dojo.isMoz){ + if(liparent.parentNode.parentNode.nodeName == 'LI'){ + liparent=liparent.parentNode.parentNode; + } + } + var fc=liparent.firstChild; + if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){ + liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc); + var newrange = dijit.range.create(this.editor.window); + newrange.setStart(liparent.firstChild,0); + var selection = dijit.range.getSelection(this.editor.window, true); + selection.removeAllRanges(); + selection.addRange(newrange); + } + } + } + this._checkListLater = false; + } + if(this._pressedEnterInBlock){ + // the new created is the original current P, so we have previousSibling below + if(this._pressedEnterInBlock.previousSibling){ + this.removeTrailingBr(this._pressedEnterInBlock.previousSibling); + } + delete this._pressedEnterInBlock; + } + }, + + // bogusHtmlContent: [private] String + // HTML to stick into a new empty block + bogusHtmlContent: ' ', + + // blockNodes: [private] Regex + // Regex for testing if a given tag is a block level (display:block) tag + blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/, + + handleEnterKey: function(e){ + // summary: + // Handler for enter key events when blockModeForEnter is DIV or P. + // description: + // Manually handle enter key event to make the behavior consistent across + // all supported browsers. See class description for details. + // tags: + // private + + var selection, range, newrange, startNode, endNode, brNode, doc=this.editor.document,br,rs,txt; + if(e.shiftKey){ // shift+enter always generates <br> + var parent = dojo.withGlobal(this.editor.window, "getParentElement", dijit._editor.selection); + var header = dijit.range.getAncestor(parent,this.blockNodes); + if(header){ + if(header.tagName == 'LI'){ + return true; // let browser handle + } + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + if(dijit.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){ + br=doc.createElement('br'); + newrange = dijit.range.create(this.editor.window); + header.insertBefore(br,header.firstChild); + newrange.setStartBefore(br.nextSibling); + selection.removeAllRanges(); + selection.addRange(newrange); + }else if(dijit.range.atEndOfContainer(header, range.startContainer, range.startOffset)){ + newrange = dijit.range.create(this.editor.window); + br=doc.createElement('br'); + header.appendChild(br); + header.appendChild(doc.createTextNode('\xA0')); + newrange.setStart(header.lastChild,0); + selection.removeAllRanges(); + selection.addRange(newrange); + }else{ + rs = range.startContainer; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + txt = rs.nodeValue; + dojo.withGlobal(this.editor.window, function(){ + startNode = doc.createTextNode(txt.substring(0, range.startOffset)); + endNode = doc.createTextNode(txt.substring(range.startOffset)); + brNode = doc.createElement("br"); + + if(endNode.nodeValue == "" && dojo.isWebKit){ + endNode = doc.createTextNode('\xA0') + } + dojo.place(startNode, rs, "after"); + dojo.place(brNode, startNode, "after"); + dojo.place(endNode, brNode, "after"); + dojo.destroy(rs); + newrange = dijit.range.create(dojo.gobal); + newrange.setStart(endNode,0); + selection.removeAllRanges(); + selection.addRange(newrange); + }); + return false; + } + return true; // let browser handle + } + }else{ + selection = dijit.range.getSelection(this.editor.window); + if(selection.rangeCount){ + range = selection.getRangeAt(0); + if(range && range.startContainer){ + if(!range.collapsed){ + range.deleteContents(); + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + rs = range.startContainer; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + dojo.withGlobal(this.editor.window, dojo.hitch(this, function(){ + var endEmpty = false; + + var offset = range.startOffset; + if(rs.length < offset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, offset); + rs = ret.node; + offset = ret.offset; + } + txt = rs.nodeValue; + + startNode = doc.createTextNode(txt.substring(0, offset)); + endNode = doc.createTextNode(txt.substring(offset)); + brNode = doc.createElement("br"); + + if(!endNode.length){ + endNode = doc.createTextNode('\xA0'); + endEmpty = true; + } + + if(startNode.length){ + dojo.place(startNode, rs, "after"); + }else{ + startNode = rs; + } + dojo.place(brNode, startNode, "after"); + dojo.place(endNode, brNode, "after"); + dojo.destroy(rs); + newrange = dijit.range.create(dojo.gobal); + newrange.setStart(endNode,0); + newrange.setEnd(endNode, endNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + if(endEmpty && !dojo.isWebKit){ + dijit._editor.selection.remove(); + }else{ + dijit._editor.selection.collapse(true); + } + })); + }else{ + dojo.withGlobal(this.editor.window, dojo.hitch(this, function(){ + var brNode = doc.createElement("br"); + rs.appendChild(brNode); + var endNode = doc.createTextNode('\xA0'); + rs.appendChild(endNode); + newrange = dijit.range.create(dojo.global); + newrange.setStart(endNode,0); + newrange.setEnd(endNode, endNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + dijit._editor.selection.collapse(true); + })); + } + } + }else{ + // don't change this: do not call this.execCommand, as that may have other logic in subclass + dijit._editor.RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>'); + } + } + return false; + } + var _letBrowserHandle = true; + + // first remove selection + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + + var block = dijit.range.getBlockAncestor(range.endContainer, null, this.editor.editNode); + var blockNode = block.blockNode; + + // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it + if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){ + if(dojo.isMoz){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = blockNode; + } + // if this li only contains spaces, set the content to empty so the browser will outdent this item + if(/^(\s| |\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s| |\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){ + // empty LI node + blockNode.innerHTML = ''; + if(dojo.isWebKit){ // WebKit tosses the range when innerHTML is reset + newrange = dijit.range.create(this.editor.window); + newrange.setStart(blockNode, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + } + this._checkListLater = false; // nothing to check since the browser handles outdent + } + return true; + } + + // text node directly under body, let's wrap them in a node + if(!block.blockNode || block.blockNode===this.editor.editNode){ + try{ + dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter); + }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ } + // get the newly created block node + // FIXME + block = {blockNode:dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.blockNodeForEnter]), + blockContainer: this.editor.editNode}; + if(block.blockNode){ + if(block.blockNode != this.editor.editNode && + (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){ + this.removeTrailingBr(block.blockNode); + return false; + } + }else{ // we shouldn't be here if formatblock worked + block.blockNode = this.editor.editNode; + } + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + + var newblock = doc.createElement(this.blockNodeForEnter); + newblock.innerHTML=this.bogusHtmlContent; + this.removeTrailingBr(block.blockNode); + var endOffset = range.endOffset; + var node = range.endContainer; + if(node.length < endOffset){ + //We are not checking the right node, try to locate the correct one + var ret = this._adjustNodeAndOffset(node, endOffset); + node = ret.node; + endOffset = ret.offset; + } + if(dijit.range.atEndOfContainer(block.blockNode, node, endOffset)){ + if(block.blockNode === block.blockContainer){ + block.blockNode.appendChild(newblock); + }else{ + dojo.place(newblock, block.blockNode, "after"); + } + _letBrowserHandle = false; + // lets move caret to the newly created block + newrange = dijit.range.create(this.editor.window); + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + dojo.window.scrollIntoView(newblock); + } + }else if(dijit.range.atBeginningOfContainer(block.blockNode, + range.startContainer, range.startOffset)){ + dojo.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before"); + if(newblock.nextSibling && this.editor.height){ + // position input caret - mostly WebKit needs this + newrange = dijit.range.create(this.editor.window); + newrange.setStart(newblock.nextSibling, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + // browser does not scroll the caret position into view, do it manually + dojo.window.scrollIntoView(newblock.nextSibling); + } + _letBrowserHandle = false; + }else{ //press enter in the middle of P/DIV/Whatever/ + if(block.blockNode === block.blockContainer){ + block.blockNode.appendChild(newblock); + }else{ + dojo.place(newblock, block.blockNode, "after"); + } + _letBrowserHandle = false; + + // Clone any block level styles. + if(block.blockNode.style){ + if(newblock.style){ + if(block.blockNode.style.cssText){ + newblock.style.cssText = block.blockNode.style.cssText; + } + } + } + + // Okay, we probably have to split. + rs = range.startContainer; + var firstNodeMoved; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + var nodeToMove, tNode; + endOffset = range.endOffset; + if(rs.length < endOffset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, endOffset); + rs = ret.node; + endOffset = ret.offset; + } + + txt = rs.nodeValue; + startNode = doc.createTextNode(txt.substring(0, endOffset)); + endNode = doc.createTextNode(txt.substring(endOffset, txt.length)); + + // Place the split, then remove original nodes. + dojo.place(startNode, rs, "before"); + dojo.place(endNode, rs, "after"); + dojo.destroy(rs); + + // Okay, we split the text. Now we need to see if we're + // parented to the block element we're splitting and if + // not, we have to split all the way up. Ugh. + var parentC = startNode.parentNode; + while(parentC !== block.blockNode){ + var tg = parentC.tagName; + var newTg = doc.createElement(tg); + // Clone over any 'style' data. + if(parentC.style){ + if(newTg.style){ + if(parentC.style.cssText){ + newTg.style.cssText = parentC.style.cssText; + } + } + } + // If font also need to clone over any font data. + if(parentC.tagName === "FONT"){ + if(parentC.color){ + newTg.color = parentC.color; + } + if(parentC.face){ + newTg.face = parentC.face; + } + if(parentC.size){ // this check was necessary on IE + newTg.size = parentC.size; + } + } + + nodeToMove = endNode; + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newTg.appendChild(nodeToMove); + nodeToMove = tNode; + } + dojo.place(newTg, parentC, "after"); + startNode = parentC; + endNode = newTg; + parentC = parentC.parentNode; + } + + // Lastly, move the split out tags to the new block. + // as they should now be split properly. + nodeToMove = endNode; + if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){ + // Non-blank text and non-text nodes need to clear out that blank space + // before moving the contents. + newblock.innerHTML = ""; + } + firstNodeMoved = nodeToMove; + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newblock.appendChild(nodeToMove); + nodeToMove = tNode; + } + } + + //lets move caret to the newly created block + newrange = dijit.range.create(this.editor.window); + var nodeForCursor; + var innerMostFirstNodeMoved = firstNodeMoved; + if(this.blockNodeForEnter !== 'BR'){ + while(innerMostFirstNodeMoved){ + nodeForCursor = innerMostFirstNodeMoved; + tNode = innerMostFirstNodeMoved.firstChild; + innerMostFirstNodeMoved = tNode; + } + if(nodeForCursor && nodeForCursor.parentNode){ + newblock = nodeForCursor.parentNode; + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + dijit.scrollIntoView(newblock); + } + if(dojo.isMoz){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = block.blockNode; + } + }else{ + _letBrowserHandle = true; + } + }else{ + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + dijit.scrollIntoView(newblock); + } + if(dojo.isMoz){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = block.blockNode; + } + } + } + return _letBrowserHandle; + }, + + _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){ + // summary: + // In the case there are multiple text nodes in a row the offset may not be within the node. If the offset is larger than the node length, it will attempt to find + // the next text sibling until it locates the text node in which the offset refers to + // node: + // The node to check. + // offset: + // The position to find within the text node + // tags: + // private. + while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){ + //Adjust the offset and node in the case of multiple text nodes in a row + offset = offset - node.length; + node = node.nextSibling; + } + var ret = {"node": node, "offset": offset}; + return ret; + }, + + removeTrailingBr: function(container){ + // summary: + // If last child of container is a <br>, then remove it. + // tags: + // private + var para = /P|DIV|LI/i.test(container.tagName) ? + container : dijit._editor.selection.getParentOfType(container,['P','DIV','LI']); + + if(!para){ return; } + if(para.lastChild){ + if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) || + para.lastChild.tagName=='BR'){ + + dojo.destroy(para.lastChild); + } + } + if(!para.childNodes.length){ + para.innerHTML=this.bogusHtmlContent; + } + } }); -dojo.forEach(_2b,function(p){ -var _2c=p.previousSibling; -if((_2c)&&(_2c.nodeType==1)&&(_2c.nodeName=="P"||dojo.style(_2c,"display")!="block")){ -var _2d=p.parentNode.insertBefore(this.document.createElement("p"),p); -_2d.innerHTML=_1b?"":" "; -} -_25(p); -},this.editor); -_1c(_1a); -return _1a; -},singleLinePsToRegularPs:function(_2e){ -function _2f(_30){ -var ps=_30.getElementsByTagName("p"); -var _31=[]; -for(var i=0;i<ps.length;i++){ -var p=ps[i]; -var _32=false; -for(var k=0;k<_31.length;k++){ -if(_31[k]===p.parentNode){ -_32=true; -break; -} -} -if(!_32){ -_31.push(p.parentNode); -} -} -return _31; -}; -function _33(_34){ -return (!_34.childNodes.length||_34.innerHTML==" "); -}; -var _35=_2f(_2e); -for(var i=0;i<_35.length;i++){ -var _36=_35[i]; -var _37=null; -var _38=_36.firstChild; -var _39=null; -while(_38){ -if(_38.nodeType!=1||_38.tagName!="P"||(_38.getAttributeNode("style")||{}).specified){ -_37=null; -}else{ -if(_33(_38)){ -_39=_38; -_37=null; -}else{ -if(_37==null){ -_37=_38; -}else{ -if((!_37.lastChild||_37.lastChild.nodeName!="BR")&&(_38.firstChild)&&(_38.firstChild.nodeName!="BR")){ -_37.appendChild(this.editor.document.createElement("br")); -} -while(_38.firstChild){ -_37.appendChild(_38.firstChild); -} -_39=_38; -} -} -} -_38=_38.nextSibling; -if(_39){ -dojo.destroy(_39); -_39=null; -} -} -} -return _2e; -}}); + } diff --git a/lib/dijit/_editor/plugins/FontChoice.js b/lib/dijit/_editor/plugins/FontChoice.js index c5578e3fb..ef91fd676 100644 --- a/lib/dijit/_editor/plugins/FontChoice.js +++ b/lib/dijit/_editor/plugins/FontChoice.js @@ -1,12 +1,12 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.FontChoice"]){ -dojo._hasResource["dijit._editor.plugins.FontChoice"]=true; +if(!dojo._hasResource["dijit._editor.plugins.FontChoice"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.FontChoice"] = true; dojo.provide("dijit._editor.plugins.FontChoice"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit._editor.range"); @@ -14,252 +14,570 @@ dojo.require("dijit._editor.selection"); dojo.require("dijit.form.FilteringSelect"); dojo.require("dojo.data.ItemFileReadStore"); dojo.require("dojo.i18n"); -dojo.requireLocalization("dijit._editor","FontChoice",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins._FontDropDown",[dijit._Widget,dijit._Templated],{label:"",widgetsInTemplate:true,plainText:false,templateString:"<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>"+"<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>"+"<input dojoType='dijit.form.FilteringSelect' required=false labelType=html labelAttr=label searchAttr=name "+"tabIndex='-1' id='${selectId}' dojoAttachPoint='select' value=''/>"+"</span>",postMixInProperties:function(){ -this.inherited(arguments); -this.strings=dojo.i18n.getLocalization("dijit._editor","FontChoice"); -this.label=this.strings[this.command]; -this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); -this.selectId=this.id+"_select"; -this.inherited(arguments); -},postCreate:function(){ -var _1=dojo.map(this.values,function(_2){ -var _3=this.strings[_2]||_2; -return {label:this.getLabel(_2,_3),name:_3,value:_2}; -},this); -this.select.store=new dojo.data.ItemFileReadStore({data:{identifier:"value",items:_1}}); -this.select.set("value","",false); -this.disabled=this.select.get("disabled"); -},_setValueAttr:function(_4,_5){ -_5=_5!==false?true:false; -this.select.set("value",dojo.indexOf(this.values,_4)<0?"":_4,_5); -if(!_5){ -this.select._lastValueReported=null; -} -},_getValueAttr:function(){ -return this.select.get("value"); -},focus:function(){ -this.select.focus(); -},_setDisabledAttr:function(_6){ -this.disabled=_6; -this.select.set("disabled",_6); -}}); -dojo.declare("dijit._editor.plugins._FontNameDropDown",dijit._editor.plugins._FontDropDown,{generic:false,command:"fontName",postMixInProperties:function(){ -if(!this.values){ -this.values=this.generic?["serif","sans-serif","monospace","cursive","fantasy"]:["Arial","Times New Roman","Comic Sans MS","Courier New"]; -} -this.inherited(arguments); -},getLabel:function(_7,_8){ -if(this.plainText){ -return _8; -}else{ -return "<div style='font-family: "+_7+"'>"+_8+"</div>"; -} -},_setValueAttr:function(_9,_a){ -_a=_a!==false?true:false; -if(this.generic){ -var _b={"Arial":"sans-serif","Helvetica":"sans-serif","Myriad":"sans-serif","Times":"serif","Times New Roman":"serif","Comic Sans MS":"cursive","Apple Chancery":"cursive","Courier":"monospace","Courier New":"monospace","Papyrus":"fantasy"}; -_9=_b[_9]||_9; -} -this.inherited(arguments,[_9,_a]); -}}); -dojo.declare("dijit._editor.plugins._FontSizeDropDown",dijit._editor.plugins._FontDropDown,{command:"fontSize",values:[1,2,3,4,5,6,7],getLabel:function(_c,_d){ -if(this.plainText){ -return _d; -}else{ -return "<font size="+_c+"'>"+_d+"</font>"; -} -},_setValueAttr:function(_e,_f){ -_f=_f!==false?true:false; -if(_e.indexOf&&_e.indexOf("px")!=-1){ -var _10=parseInt(_e,10); -_e={10:1,13:2,16:3,18:4,24:5,32:6,48:7}[_10]||_e; -} -this.inherited(arguments,[_e,_f]); -}}); -dojo.declare("dijit._editor.plugins._FormatBlockDropDown",dijit._editor.plugins._FontDropDown,{command:"formatBlock",values:["noFormat","p","h1","h2","h3","pre"],postCreate:function(){ -this.inherited(arguments); -this.set("value","noFormat",false); -},getLabel:function(_11,_12){ -if(this.plainText){ -return _12; -}else{ -return "<"+_11+">"+_12+"</"+_11+">"; -} -},_execCommand:function(_13,_14,_15){ -if(_15==="noFormat"){ -var _16; -var end; -var sel=dijit.range.getSelection(_13.window); -if(sel&&sel.rangeCount>0){ -var _17=sel.getRangeAt(0); -var _18,tag; -if(_17){ -_16=_17.startContainer; -end=_17.endContainer; -while(_16&&_16!==_13.editNode&&_16!==_13.document.body&&_16.nodeType!==1){ -_16=_16.parentNode; -} -while(end&&end!==_13.editNode&&end!==_13.document.body&&end.nodeType!==1){ -end=end.parentNode; -} -var _19=dojo.hitch(this,function(_1a,_1b){ -if(_1a.childNodes&&_1a.childNodes.length){ -var i; -for(i=0;i<_1a.childNodes.length;i++){ -var c=_1a.childNodes[i]; -if(c.nodeType==1){ -if(dojo.withGlobal(_13.window,"inSelection",dijit._editor.selection,[c])){ -var tag=c.tagName?c.tagName.toLowerCase():""; -if(dojo.indexOf(this.values,tag)!==-1){ -_1b.push(c); -} -_19(c,_1b); -} -} -} -} +dojo.requireLocalization("dijit._editor", "FontChoice", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins._FontDropDown", + [dijit._Widget, dijit._Templated],{ + // summary: + // Base class for widgets that contains a label (like "Font:") + // and a FilteringSelect drop down to pick a value. + // Used as Toolbar entry. + + // label: [public] String + // The label to apply to this particular FontDropDown. + label: "", + + // widgetsInTemplate: [public] boolean + // Over-ride denoting the template has widgets to parse. + widgetsInTemplate: true, + + // plainText: [public] boolean + // Flag to indicate that the returned label should be plain text + // instead of an example. + plainText: false, + + // templateString: [public] String + // The template used to construct the labeled dropdown. + templateString: + "<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" + + "<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" + + "<input dojoType='dijit.form.FilteringSelect' required='false' labelType='html' labelAttr='label' searchAttr='name' " + + "tabIndex='-1' id='${selectId}' dojoAttachPoint='select' value=''/>" + + "</span>", + + postMixInProperties: function(){ + // summary: + // Over-ride to set specific properties. + this.inherited(arguments); + + this.strings = dojo.i18n.getLocalization("dijit._editor", "FontChoice"); + + // Set some substitution variables used in the template + this.label = this.strings[this.command]; + this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); + this.selectId = this.id + "_select"; + + this.inherited(arguments); + }, + + postCreate: function(){ + // summary: + // Over-ride for the default postCreate action + // This establishes the filtering selects and the like. + + // Initialize the list of items in the drop down by creating data store with items like: + // {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" } + var items = dojo.map(this.values, function(value){ + var name = this.strings[value] || value; + return { + label: this.getLabel(value, name), + name: name, + value: value + }; + }, this); + + this.select.store = new dojo.data.ItemFileReadStore({ + data: { + identifier: "value", + items: items + } + }); + + this.select.set("value", "", false); + this.disabled = this.select.get("disabled"); + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + // value: Object|String + // The value to set in the select. + // priorityChange: + // Optional parameter used to tell the select whether or not to fire + // onChange event. + + //if the value is not a permitted value, just set empty string to prevent showing the warning icon + priorityChange = priorityChange !== false?true:false; + this.select.set('value', dojo.indexOf(this.values,value) < 0 ? "" : value, priorityChange); + if(!priorityChange){ + // Clear the last state in case of updateState calls. Ref: #10466 + this.select._lastValueReported=null; + } + }, + + _getValueAttr: function(){ + // summary: + // Allow retreiving the value from the composite select on + // call to button.get("value"); + return this.select.get('value'); + }, + + focus: function(){ + // summary: + // Over-ride for focus control of this widget. Delegates focus down to the + // filtering select. + this.select.focus(); + }, + + _setDisabledAttr: function(value){ + // summary: + // Over-ride for the button's 'disabled' attribute so that it can be + // disabled programmatically. + + // Save off ths disabled state so the get retrieves it correctly + //without needing to have a function proxy it. + this.disabled = value; + this.select.set("disabled", value); + } }); -var _1c=dojo.hitch(this,function(_1d){ -if(_1d&&_1d.length){ -_13.beginEditing(); -while(_1d.length){ -this._removeFormat(_13,_1d.pop()); -} -_13.endEditing(); -} + + +dojo.declare("dijit._editor.plugins._FontNameDropDown", dijit._editor.plugins._FontDropDown, { + // summary: + // Dropdown to select a font; goes in editor toolbar. + + // generic: Boolean + // Use generic (web standard) font names + generic: false, + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "fontName", + + postMixInProperties: function(){ + // summary: + // Over-ride for the default posr mixin control + if(!this.values){ + this.values = this.generic ? + ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics + ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"]; + } + this.inherited(arguments); + }, + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText){ + return name; + }else{ + return "<div style='font-family: "+value+"'>" + name + "</div>"; + } + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + + priorityChange = priorityChange !== false?true:false; + if(this.generic){ + var map = { + "Arial": "sans-serif", + "Helvetica": "sans-serif", + "Myriad": "sans-serif", + "Times": "serif", + "Times New Roman": "serif", + "Comic Sans MS": "cursive", + "Apple Chancery": "cursive", + "Courier": "monospace", + "Courier New": "monospace", + "Papyrus": "fantasy" +// ,"????": "fantasy" TODO: IE doesn't map fantasy font-family? + }; + value = map[value] || value; + } + this.inherited(arguments, [value, priorityChange]); + } }); -var _1e=[]; -if(_16==end){ -var _1f; -_18=_16; -while(_18&&_18!==_13.editNode&&_18!==_13.document.body){ -if(_18.nodeType==1){ -tag=_18.tagName?_18.tagName.toLowerCase():""; -if(dojo.indexOf(this.values,tag)!==-1){ -_1f=_18; -break; -} -} -_18=_18.parentNode; -} -_19(_16,_1e); -if(_1f){ -_1e=[_1f].concat(_1e); -} -_1c(_1e); -}else{ -_18=_16; -while(dojo.withGlobal(_13.window,"inSelection",dijit._editor.selection,[_18])){ -if(_18.nodeType==1){ -tag=_18.tagName?_18.tagName.toLowerCase():""; -if(dojo.indexOf(this.values,tag)!==-1){ -_1e.push(_18); -} -_19(_18,_1e); -} -_18=_18.nextSibling; -} -_1c(_1e); -} -_13.onDisplayChanged(); -} -} -}else{ -_13.execCommand(_14,_15); -} -},_removeFormat:function(_20,_21){ -if(_20.customUndo){ -while(_21.firstChild){ -dojo.place(_21.firstChild,_21,"before"); -} -_21.parentNode.removeChild(_21); -}else{ -dojo.withGlobal(_20.window,"selectElementChildren",dijit._editor.selection,[_21]); -var _22=dojo.withGlobal(_20.window,"getSelectedHtml",dijit._editor.selection,[null]); -dojo.withGlobal(_20.window,"selectElement",dijit._editor.selection,[_21]); -_20.execCommand("inserthtml",_22||""); -} -}}); -dojo.declare("dijit._editor.plugins.FontChoice",dijit._editor._Plugin,{useDefaultCommand:false,_initButton:function(){ -var _23={fontName:dijit._editor.plugins._FontNameDropDown,fontSize:dijit._editor.plugins._FontSizeDropDown,formatBlock:dijit._editor.plugins._FormatBlockDropDown}[this.command],_24=this.params; -if(this.params.custom){ -_24.values=this.params.custom; -} -var _25=this.editor; -this.button=new _23(dojo.delegate({dir:_25.dir,lang:_25.lang},_24)); -this.connect(this.button.select,"onChange",function(_26){ -this.editor.focus(); -if(this.command=="fontName"&&_26.indexOf(" ")!=-1){ -_26="'"+_26+"'"; -} -if(this.button._execCommand){ -this.button._execCommand(this.editor,this.command,_26); -}else{ -this.editor.execCommand(this.command,_26); -} -this.editor.customUndo=this.editor.customUndo||dojo.isWebKit; + +dojo.declare("dijit._editor.plugins._FontSizeDropDown", dijit._editor.plugins._FontDropDown, { + // summary: + // Dropdown to select a font size; goes in editor toolbar. + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "fontSize", + + // values: [public] Number[] + // The HTML font size values supported by this plugin + values: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // We're stuck using the deprecated FONT tag to correspond + // with the size measurements used by the editor + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText){ + return name; + }else{ + return "<font size=" + value + "'>" + name + "</font>"; + } + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + priorityChange = priorityChange !== false?true:false; + if(value.indexOf && value.indexOf("px") != -1){ + var pixels = parseInt(value, 10); + value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value; + } + + this.inherited(arguments, [value, priorityChange]); + } }); -},updateState:function(){ -var _27=this.editor; -var _28=this.command; -if(!_27||!_27.isLoaded||!_28.length){ -return; -} -if(this.button){ -var _29; -try{ -_29=_27.queryCommandValue(_28)||""; -} -catch(e){ -_29=""; -} -var _2a=dojo.isString(_29)&&_29.match(/'([^']*)'/); -if(_2a){ -_29=_2a[1]; -} -if(_28==="formatBlock"){ -if(!_29||_29=="p"){ -_29=null; -var _2b; -var sel=dijit.range.getSelection(this.editor.window); -if(sel&&sel.rangeCount>0){ -var _2c=sel.getRangeAt(0); -if(_2c){ -_2b=_2c.endContainer; -} -} -while(_2b&&_2b!==_27.editNode&&_2b!==_27.document){ -var tg=_2b.tagName?_2b.tagName.toLowerCase():""; -if(tg&&dojo.indexOf(this.button.values,tg)>-1){ -_29=tg; -break; -} -_2b=_2b.parentNode; -} -if(!_29){ -_29="noFormat"; -} -}else{ -if(dojo.indexOf(this.button.values,_29)<0){ -_29="noFormat"; -} -} -} -if(_29!==this.button.get("value")){ -this.button.set("value",_29,false); -} -} -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -switch(o.args.name){ -case "fontName": -case "fontSize": -case "formatBlock": -o.plugin=new dijit._editor.plugins.FontChoice({command:o.args.name,plainText:o.args.plainText?o.args.plainText:false}); -} + + +dojo.declare("dijit._editor.plugins._FormatBlockDropDown", dijit._editor.plugins._FontDropDown, { + // summary: + // Dropdown to select a format (like paragraph or heading); goes in editor toolbar. + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "formatBlock", + + // values: [public] Array + // The HTML format tags supported by this plugin + values: ["noFormat", "p", "h1", "h2", "h3", "pre"], + + postCreate: function(){ + // Init and set the default value to no formatting. Update state will adjust it + // as needed. + this.inherited(arguments); + this.set("value", "noFormat", false); + }, + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText || value == "noFormat"){ + return name; + }else{ + return "<" + value + ">" + name + "</" + value + ">"; + } + }, + + _execCommand: function(editor, command, choice){ + // summary: + // Over-ride for default exec-command label. + // Allows us to treat 'none' as special. + if(choice === "noFormat"){ + var start; + var end; + var sel = dijit.range.getSelection(editor.window); + if(sel && sel.rangeCount > 0){ + var range = sel.getRangeAt(0); + var node, tag; + if(range){ + start = range.startContainer; + end = range.endContainer; + + // find containing nodes of start/end. + while(start && start !== editor.editNode && + start !== editor.document.body && + start.nodeType !== 1){ + start = start.parentNode; + } + + while(end && end !== editor.editNode && + end !== editor.document.body && + end.nodeType !== 1){ + end = end.parentNode; + } + + var processChildren = dojo.hitch(this, function(node, array){ + if(node.childNodes && node.childNodes.length){ + var i; + for(i = 0; i < node.childNodes.length; i++){ + var c = node.childNodes[i]; + if(c.nodeType == 1){ + if(dojo.withGlobal(editor.window, "inSelection", dijit._editor.selection, [c])){ + var tag = c.tagName? c.tagName.toLowerCase(): ""; + if(dojo.indexOf(this.values, tag) !== -1){ + array.push(c); + } + processChildren(c,array); + } + } + } + } + }); + + var unformatNodes = dojo.hitch(this, function(nodes){ + // summary: + // Internal function to clear format nodes. + // nodes: + // The array of nodes to strip formatting from. + if(nodes && nodes.length){ + editor.beginEditing(); + while(nodes.length){ + this._removeFormat(editor, nodes.pop()); + } + editor.endEditing(); + } + }); + + var clearNodes = []; + if(start == end){ + //Contained within the same block, may be collapsed, but who cares, see if we + // have a block element to remove. + var block; + node = start; + while(node && node !== editor.editNode && node !== editor.document.body){ + if(node.nodeType == 1){ + tag = node.tagName? node.tagName.toLowerCase(): ""; + if(dojo.indexOf(this.values, tag) !== -1){ + block = node; + break; + } + } + node = node.parentNode; + } + + //Also look for all child nodes in the selection that may need to be + //cleared of formatting + processChildren(start, clearNodes); + if(block) { clearNodes = [block].concat(clearNodes); } + unformatNodes(clearNodes); + }else{ + // Probably a multi select, so we have to process it. Whee. + node = start; + while(dojo.withGlobal(editor.window, "inSelection", dijit._editor.selection, [node])){ + if(node.nodeType == 1){ + tag = node.tagName? node.tagName.toLowerCase(): ""; + if(dojo.indexOf(this.values, tag) !== -1){ + clearNodes.push(node); + } + processChildren(node,clearNodes); + } + node = node.nextSibling; + } + unformatNodes(clearNodes); + } + editor.onDisplayChanged(); + } + } + }else{ + editor.execCommand(command, choice); + } + }, + + _removeFormat: function(editor, node){ + // summary: + // function to remove the block format node. + // node: + // The block format node to remove (and leave the contents behind) + if(editor.customUndo){ + // So of course IE doesn't work right with paste-overs. + // We have to do this manually, which is okay since IE already uses + // customUndo and we turned it on for WebKit. WebKit pasted funny, + // so couldn't use the execCommand approach + while(node.firstChild){ + dojo.place(node.firstChild, node, "before"); + } + node.parentNode.removeChild(node); + }else{ + // Everyone else works fine this way, a paste-over and is native + // undo friendly. + dojo.withGlobal(editor.window, + "selectElementChildren", dijit._editor.selection, [node]); + var html = dojo.withGlobal(editor.window, + "getSelectedHtml", dijit._editor.selection, [null]); + dojo.withGlobal(editor.window, + "selectElement", dijit._editor.selection, [node]); + editor.execCommand("inserthtml", html||""); + } + } +}); + +// TODO: for 2.0, split into FontChoice plugin into three separate classes, +// one for each command (and change registry below) +dojo.declare("dijit._editor.plugins.FontChoice", dijit._editor._Plugin,{ + // summary: + // This plugin provides three drop downs for setting style in the editor + // (font, font size, and format block), as controlled by command. + // + // description: + // The commands provided by this plugin are: + // + // * fontName + // | Provides a drop down to select from a list of font names + // * fontSize + // | Provides a drop down to select from a list of font sizes + // * formatBlock + // | Provides a drop down to select from a list of block styles + // | + // + // which can easily be added to an editor by including one or more of the above commands + // in the `plugins` attribute as follows: + // + // | plugins="['fontName','fontSize',...]" + // + // It is possible to override the default dropdown list by providing an Array for the `custom` property when + // instantiating this plugin, e.g. + // + // | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]" + // + // Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with + // [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families) + // + // Note that the editor is often unable to properly handle font styling information defined outside + // the context of the current editor instance, such as pre-populated HTML. + + // useDefaultCommand: [protected] booleam + // Override _Plugin.useDefaultCommand... + // processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + _initButton: function(){ + // summary: + // Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar, + // rather than a simple button. + // tags: + // protected + + // Create the widget to go into the toolbar (the so-called "button") + var clazz = { + fontName: dijit._editor.plugins._FontNameDropDown, + fontSize: dijit._editor.plugins._FontSizeDropDown, + formatBlock: dijit._editor.plugins._FormatBlockDropDown + }[this.command], + params = this.params; + + // For back-compat reasons support setting custom values via "custom" parameter + // rather than "values" parameter + if(this.params.custom){ + params.values = this.params.custom; + } + + var editor = this.editor; + this.button = new clazz(dojo.delegate({dir: editor.dir, lang: editor.lang}, params)); + + // Reflect changes to the drop down in the editor + this.connect(this.button.select, "onChange", function(choice){ + // User invoked change, since all internal updates set priorityChange to false and will + // not trigger an onChange event. + this.editor.focus(); + + if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; } + + // Invoke, the editor already normalizes commands called through its + // execCommand. + if(this.button._execCommand){ + this.button._execCommand(this.editor, this.command, choice); + }else{ + this.editor.execCommand(this.command, choice); + } + }); + }, + + updateState: function(){ + // summary: + // Overrides _Plugin.updateState(). This controls updating the menu + // options to the right values on state changes in the document (that trigger a + // test of the actions.) + // It set value of drop down in toolbar to reflect font/font size/format block + // of text at current caret position. + // tags: + // protected + var _e = this.editor; + var _c = this.command; + if(!_e || !_e.isLoaded || !_c.length){ return; } + + if(this.button){ + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ return; } + var value; + try{ + value = _e.queryCommandValue(_c) || ""; + }catch(e){ + //Firefox may throw error above if the editor is just loaded, ignore it + value = ""; + } + + // strip off single quotes, if any + var quoted = dojo.isString(value) && value.match(/'([^']*)'/); + if(quoted){ value = quoted[1]; } + + if(_c === "formatBlock"){ + if(!value || value == "p"){ + // Some browsers (WebKit) doesn't actually get the tag info right. + // and IE returns paragraph when in a DIV!, so incorrect a lot, + // so we have double-check it. + value = null; + var elem; + // Try to find the current element where the caret is. + var sel = dijit.range.getSelection(this.editor.window); + if(sel && sel.rangeCount > 0){ + var range = sel.getRangeAt(0); + if(range){ + elem = range.endContainer; + } + } + + // Okay, now see if we can find one of the formatting types we're in. + while(elem && elem !== _e.editNode && elem !== _e.document){ + var tg = elem.tagName?elem.tagName.toLowerCase():""; + if(tg && dojo.indexOf(this.button.values, tg) > -1){ + value = tg; + break; + } + elem = elem.parentNode; + } + if(!value){ + // Still no value, so lets select 'none'. + value = "noFormat"; + } + }else{ + // Check that the block format is one allowed, if not, + // null it so that it gets set to empty. + if(dojo.indexOf(this.button.values, value) < 0){ + value = "noFormat"; + } + } + } + if(value !== this.button.get("value")){ + // Set the value, but denote it is not a priority change, so no + // onchange fires. + this.button.set('value', value, false); + } + } + } }); + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + switch(o.args.name){ + case "fontName": case "fontSize": case "formatBlock": + o.plugin = new dijit._editor.plugins.FontChoice({ + command: o.args.name, + plainText: o.args.plainText?o.args.plainText:false + }); + } +}); + } diff --git a/lib/dijit/_editor/plugins/FullScreen.js b/lib/dijit/_editor/plugins/FullScreen.js index 7a6dac55d..6978252c8 100644 --- a/lib/dijit/_editor/plugins/FullScreen.js +++ b/lib/dijit/_editor/plugins/FullScreen.js @@ -1,232 +1,441 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.FullScreen"]){ -dojo._hasResource["dijit._editor.plugins.FullScreen"]=true; +if(!dojo._hasResource["dijit._editor.plugins.FullScreen"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.FullScreen"] = true; dojo.provide("dijit._editor.plugins.FullScreen"); dojo.require("dojo.window"); dojo.require("dojo.i18n"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.Button"); -dojo.requireLocalization("dijit._editor","commands",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins.FullScreen",dijit._editor._Plugin,{zIndex:500,_origState:null,_origiFrameState:null,_resizeHandle:null,isFullscreen:false,toggle:function(){ -this.button.set("checked",!this.button.get("checked")); -},_initButton:function(){ -var _1=dojo.i18n.getLocalization("dijit._editor","commands"),_2=this.editor; -this.button=new dijit.form.ToggleButton({label:_1["fullScreen"],dir:_2.dir,lang:_2.lang,showLabel:false,iconClass:this.iconClassPrefix+" "+this.iconClassPrefix+"FullScreen",tabIndex:"-1",onChange:dojo.hitch(this,"_setFullScreen")}); -},setEditor:function(_3){ -this.editor=_3; -this._initButton(); -this.editor.addKeyHandler(dojo.keys.F11,true,true,dojo.hitch(this,function(e){ -this.toggle(); -dojo.stopEvent(e); -setTimeout(dojo.hitch(this,function(){ -this.editor.focus(); -}),250); -return true; -})); -this.connect(this.editor.domNode,"onkeydown","_containFocus"); -},_containFocus:function(e){ -if(this.isFullscreen){ -var ed=this.editor; -if(!ed.isTabIndent&&ed._fullscreen_oldOnKeyDown&&e.keyCode===dojo.keys.TAB){ -var f=dijit.getFocus(); -var _4=this._getAltViewNode(); -if(f.node==ed.iframe||(_4&&f.node===_4)){ -setTimeout(dojo.hitch(this,function(){ -ed.toolbar.focus(); -}),10); -}else{ -if(_4&&dojo.style(ed.iframe,"display")==="none"){ -setTimeout(dojo.hitch(this,function(){ -dijit.focus(_4); -}),10); -}else{ -setTimeout(dojo.hitch(this,function(){ -ed.focus(); -}),10); -} -} -dojo.stopEvent(e); -}else{ -if(ed._fullscreen_oldOnKeyDown){ -ed._fullscreen_oldOnKeyDown(e); -} -} -} -},_resizeEditor:function(){ -var vp=dojo.window.getBox(); -dojo.marginBox(this.editor.domNode,{w:vp.w,h:vp.h}); -var _5=this.editor.getHeaderHeight(); -var _6=this.editor.getFooterHeight(); -var _7=dojo._getPadBorderExtents(this.editor.domNode); -var _8=dojo._getPadBorderExtents(this.editor.iframe.parentNode); -var _9=dojo._getMarginExtents(this.editor.iframe.parentNode); -var _a=vp.h-(_5+_7.h+_6); -dojo.marginBox(this.editor.iframe.parentNode,{h:_a,w:vp.w}); -dojo.marginBox(this.editor.iframe,{h:_a-(_8.h+_9.h)}); -},_getAltViewNode:function(){ -},_setFullScreen:function(_b){ -var vp=dojo.window.getBox(); -var ed=this.editor; -var _c=dojo.body(); -var _d=ed.domNode.parentNode; -this.isFullscreen=_b; -if(_b){ -while(_d&&_d!==dojo.body()){ -dojo.addClass(_d,"dijitForceStatic"); -_d=_d.parentNode; -} -this._editorResizeHolder=this.editor.resize; -ed.resize=function(){ -}; -ed._fullscreen_oldOnKeyDown=ed.onKeyDown; -ed.onKeyDown=dojo.hitch(this,this._containFocus); -this._origState={}; -this._origiFrameState={}; -var _e=ed.domNode,_f=_e&&_e.style||{}; -this._origState={width:_f.width||"",height:_f.height||"",top:dojo.style(_e,"top")||"",left:dojo.style(_e,"left")||"",position:dojo.style(_e,"position")||"static",marginBox:dojo.marginBox(ed.domNode)}; -var _10=ed.iframe,_11=_10&&_10.style||{}; -var bc=dojo.style(ed.iframe,"backgroundColor"); -this._origiFrameState={backgroundColor:bc||"transparent",width:_11.width||"auto",height:_11.height||"auto",zIndex:_11.zIndex||""}; -dojo.style(ed.domNode,{position:"absolute",top:"0px",left:"0px",zIndex:this.zIndex,width:vp.w+"px",height:vp.h+"px"}); -dojo.style(ed.iframe,{height:"100%",width:"100%",zIndex:this.zIndex,backgroundColor:bc!=="transparent"&&bc!=="rgba(0, 0, 0, 0)"?bc:"white"}); -dojo.style(ed.iframe.parentNode,{height:"95%",width:"100%"}); -if(_c.style&&_c.style.overflow){ -this._oldOverflow=dojo.style(_c,"overflow"); -}else{ -this._oldOverflow=""; -} -if(dojo.isIE&&!dojo.isQuirks){ -if(_c.parentNode&&_c.parentNode.style&&_c.parentNode.style.overflow){ -this._oldBodyParentOverflow=_c.parentNode.style.overflow; -}else{ -try{ -this._oldBodyParentOverflow=dojo.style(_c.parentNode,"overflow"); -} -catch(e){ -this._oldBodyParentOverflow="scroll"; -} -} -dojo.style(_c.parentNode,"overflow","hidden"); -} -dojo.style(_c,"overflow","hidden"); -var _12=function(){ -var vp=dojo.window.getBox(); -if("_prevW" in this&&"_prevH" in this){ -if(vp.w===this._prevW&&vp.h===this._prevH){ -return; -} -}else{ -this._prevW=vp.w; -this._prevH=vp.h; -} -if(this._resizer){ -clearTimeout(this._resizer); -delete this._resizer; -} -this._resizer=setTimeout(dojo.hitch(this,function(){ -delete this._resizer; -this._resizeEditor(); -}),10); -}; -this._resizeHandle=dojo.connect(window,"onresize",this,_12); -this._resizeHandle2=dojo.connect(ed,"resize",dojo.hitch(this,function(){ -if(this._resizer){ -clearTimeout(this._resizer); -delete this._resizer; -} -this._resizer=setTimeout(dojo.hitch(this,function(){ -delete this._resizer; -this._resizeEditor(); -}),10); -})); -this._resizeEditor(); -var dn=this.editor.toolbar.domNode; -setTimeout(function(){ -dojo.window.scrollIntoView(dn); -},250); -}else{ -if(this._resizeHandle){ -dojo.disconnect(this._resizeHandle); -this._resizeHandle=null; -} -if(this._resizeHandle2){ -dojo.disconnect(this._resizeHandle2); -this._resizeHandle2=null; -} -if(this._rst){ -clearTimeout(this._rst); -this._rst=null; -} -while(_d&&_d!==dojo.body()){ -dojo.removeClass(_d,"dijitForceStatic"); -_d=_d.parentNode; -} -if(this._editorResizeHolder){ -this.editor.resize=this._editorResizeHolder; -} -if(!this._origState&&!this._origiFrameState){ -return; -} -if(ed._fullscreen_oldOnKeyDown){ -ed.onKeyDown=ed._fullscreen_oldOnKeyDown; -delete ed._fullscreen_oldOnKeyDown; -} -var _13=this; -setTimeout(function(){ -var mb=_13._origState.marginBox; -var oh=_13._origState.height; -if(dojo.isIE&&!dojo.isQuirks){ -_c.parentNode.style.overflow=_13._oldBodyParentOverflow; -delete _13._oldBodyParentOverflow; -} -dojo.style(_c,"overflow",_13._oldOverflow); -delete _13._oldOverflow; -dojo.style(ed.domNode,_13._origState); -dojo.style(ed.iframe.parentNode,{height:"",width:""}); -dojo.style(ed.iframe,_13._origiFrameState); -delete _13._origState; -delete _13._origiFrameState; -var _14=dijit.getEnclosingWidget(ed.domNode.parentNode); -if(_14&&_14.resize){ -_14.resize(); -}else{ -if(!oh||oh.indexOf("%")<0){ -setTimeout(dojo.hitch(this,function(){ -ed.resize({h:mb.h}); -}),0); -} -} -dojo.window.scrollIntoView(_13.editor.toolbar.domNode); -},100); -} -},destroy:function(){ -if(this._resizeHandle){ -dojo.disconnect(this._resizeHandle); -this._resizeHandle=null; -} -if(this._resizeHandle2){ -dojo.disconnect(this._resizeHandle2); -this._resizeHandle2=null; -} -if(this._resizer){ -clearTimeout(this._resizer); -this._resizer=null; -} -this.inherited(arguments); -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -var _15=o.args.name.toLowerCase(); -if(_15==="fullscreen"){ -o.plugin=new dijit._editor.plugins.FullScreen({zIndex:("zIndex" in o.args)?o.args.zIndex:500}); -} +dojo.requireLocalization("dijit._editor", "commands", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins.FullScreen",dijit._editor._Plugin,{ + // summary: + // This plugin provides FullScreen cabability to the editor. When + // toggled on, it will render the editor into the full window and + // overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11 + // for toggling fullscreen mode. + + // zIndex: [public] Number + // zIndex value used for overlaying the full page. + // default is 500. + zIndex: 500, + + // _origState: [private] Object + // The original view state of the editor. + _origState: null, + + // _origiFrameState: [private] Object + // The original view state of the iframe of the editor. + _origiFrameState: null, + + // _resizeHandle: [private] Object + // Connection point used for handling resize when window resizes. + _resizeHandle: null, + + // isFullscreen: [const] boolean + // Read-Only variable used to denote of the editor is in fullscreen mode or not. + isFullscreen: false, + + toggle: function(){ + // summary: + // Function to allow programmatic toggling of the view. + this.button.set("checked", !this.button.get("checked")); + }, + + _initButton: function(){ + // summary: + // Over-ride for creation of the resize button. + var strings = dojo.i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new dijit.form.ToggleButton({ + label: strings["fullScreen"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen", + tabIndex: "-1", + onChange: dojo.hitch(this, "_setFullScreen") + }); + }, + + setEditor: function(editor){ + // summary: + // Over-ride for the setting of the editor. + // editor: Object + // The editor to configure for this plugin to use. + this.editor = editor; + this._initButton(); + + this.editor.addKeyHandler(dojo.keys.F11, true, true, dojo.hitch(this, function(e){ + // Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode. + this.toggle(); + dojo.stopEvent(e); + setTimeout(dojo.hitch(this, function(){this.editor.focus();}), 250); + return true; + })); + this.connect(this.editor.domNode, "onkeydown", "_containFocus"); + }, + + _containFocus: function(e){ + // summary: + // When in Full Screen mode, it's good to try and retain focus in the editor + // so this function is intended to try and constrain the TAB key. + // e: Event + // The key event. + // tags: + // private + if(this.isFullscreen){ + var ed = this.editor; + if(!ed.isTabIndent && + ed._fullscreen_oldOnKeyDown && + e.keyCode === dojo.keys.TAB){ + // If we're in fullscreen mode, we want to take over how tab moves focus a bit. + // to keep it within the editor since it's hiding the rest of the page. + // IE hates changing focus IN the event handler, so need to put calls + // in a timeout. Gotta love IE. + // Also need to check for alternate view nodes if present and active. + var f = dijit.getFocus(); + var avn = this._getAltViewNode(); + if(f.node == ed.iframe || + (avn && f.node === avn)){ + setTimeout(dojo.hitch(this, function(){ + ed.toolbar.focus(); + }), 10); + }else{ + if(avn && dojo.style(ed.iframe, "display") === "none"){ + setTimeout(dojo.hitch(this, function(){ + dijit.focus(avn); + }), 10); + }else{ + setTimeout(dojo.hitch(this, function(){ + ed.focus(); + }), 10); + } + } + dojo.stopEvent(e); + }else if(ed._fullscreen_oldOnKeyDown){ + // Only call up when it's a different function. Traps corner case event issue + // on IE which caused stack overflow on handler cleanup. + ed._fullscreen_oldOnKeyDown(e); + } + } + }, + + _resizeEditor: function(){ + // summary: + // Function to handle resizing the editor as the viewport + // resizes (window scaled) + // tags: + // private + var vp = dojo.window.getBox(); + dojo.marginBox(this.editor.domNode, { + w: vp.w, + h: vp.h + }); + + //Adjust the inernal heights too, as they can be a bit off. + var hHeight = this.editor.getHeaderHeight(); + var fHeight = this.editor.getFooterHeight(); + var extents = dojo._getPadBorderExtents(this.editor.domNode); + var fcpExtents = dojo._getPadBorderExtents(this.editor.iframe.parentNode); + var fcmExtents = dojo._getMarginExtents(this.editor.iframe.parentNode); + + var cHeight = vp.h - (hHeight + extents.h + fHeight); + dojo.marginBox(this.editor.iframe.parentNode, { + h: cHeight, + w: vp.w + }); + dojo.marginBox(this.editor.iframe, { + h: cHeight - (fcpExtents.h + fcmExtents.h) + }); + }, + + _getAltViewNode: function(){ + // summary: + // This function is intended as a hook point for setting an + // alternate view node for when in full screen mode and the + // editable iframe is hidden. + // tags: + // protected. + }, + + _setFullScreen: function(full){ + // summary: + // Function to handle toggling between full screen and + // regular view. + // tags: + // private + var vp = dojo.window.getBox(); + + //Alias this for shorter code. + var ed = this.editor; + var body = dojo.body(); + var editorParent = ed.domNode.parentNode; + + this.isFullscreen = full; + + if(full){ + //Parent classes can royally screw up this plugin, so we + //have to set eveything to position static. + while(editorParent && editorParent !== dojo.body()){ + dojo.addClass(editorParent, "dijitForceStatic"); + editorParent = editorParent.parentNode; + } + + // Save off the resize function. We want to kill its behavior. + this._editorResizeHolder = this.editor.resize; + ed.resize = function() {} ; + + // Try to constrain focus control. + ed._fullscreen_oldOnKeyDown = ed.onKeyDown; + ed.onKeyDown = dojo.hitch(this, this._containFocus); + + this._origState = {}; + this._origiFrameState = {}; + + // Store the basic editor state we have to restore later. + // Not using dojo.style here, had problems, didn't + // give me stuff like 100%, gave me pixel calculated values. + // Need the exact original values. + var domNode = ed.domNode, + domStyle = domNode && domNode.style || {}; + this._origState = { + width: domStyle.width || "", + height: domStyle.height || "", + top: dojo.style(domNode, "top") || "", + left: dojo.style(domNode, "left") || "", + position: dojo.style(domNode, "position") || "static", + marginBox: dojo.marginBox(ed.domNode) + }; + + // Store the iframe state we have to restore later. + // Not using dojo.style here, had problems, didn't + // give me stuff like 100%, gave me pixel calculated values. + // Need the exact original values. + var iframe = ed.iframe, + iframeStyle = iframe && iframe.style || {}; + + var bc = dojo.style(ed.iframe, "backgroundColor"); + this._origiFrameState = { + backgroundColor: bc || "transparent", + width: iframeStyle.width || "auto", + height: iframeStyle.height || "auto", + zIndex: iframeStyle.zIndex || "" + }; + + // Okay, size everything. + dojo.style(ed.domNode, { + position: "absolute", + top: "0px", + left: "0px", + zIndex: this.zIndex, + width: vp.w + "px", + height: vp.h + "px" + }); + + dojo.style(ed.iframe, { + height: "100%", + width: "100%", + zIndex: this.zIndex, + backgroundColor: bc !== "transparent" && + bc !== "rgba(0, 0, 0, 0)"?bc:"white" + }); + + dojo.style(ed.iframe.parentNode, { + height: "95%", + width: "100%" + }); + + // Store the overflow state we have to restore later. + // IE had issues, so have to check that it's defined. Ugh. + if(body.style && body.style.overflow){ + this._oldOverflow = dojo.style(body, "overflow"); + }else{ + this._oldOverflow = ""; + } + + if(dojo.isIE && !dojo.isQuirks){ + // IE will put scrollbars in anyway, html (parent of body) + // also controls them in standards mode, so we have to + // remove them, argh. + if(body.parentNode && + body.parentNode.style && + body.parentNode.style.overflow){ + this._oldBodyParentOverflow = body.parentNode.style.overflow; + }else{ + try{ + this._oldBodyParentOverflow = dojo.style(body.parentNode, "overflow"); + }catch(e){ + this._oldBodyParentOverflow = "scroll"; + } + } + dojo.style(body.parentNode, "overflow", "hidden"); + } + dojo.style(body, "overflow", "hidden"); + + var resizer = function(){ + // function to handle resize events. + // Will check current VP and only resize if + // different. + var vp = dojo.window.getBox(); + if("_prevW" in this && "_prevH" in this){ + // No actual size change, ignore. + if(vp.w === this._prevW && vp.h === this._prevH){ + return; + } + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + // Timeout it to help avoid spamming resize on IE. + // Works for all browsers. + this._resizer = setTimeout(dojo.hitch(this, function(){ + delete this._resizer; + this._resizeEditor(); + }), 10); + }; + this._resizeHandle = dojo.connect(window, "onresize", this, resizer); + + // Also monitor for direct calls to resize and adapt editor. + this._resizeHandle2 = dojo.connect(ed, "resize", dojo.hitch(this, function(){ + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + this._resizer = setTimeout(dojo.hitch(this, function(){ + delete this._resizer; + this._resizeEditor(); + }), 10); + })); + + // Call it once to work around IE glitchiness. Safe for other browsers too. + this._resizeEditor(); + var dn = this.editor.toolbar.domNode; + setTimeout(function(){dojo.window.scrollIntoView(dn);}, 250); + }else{ + if(this._resizeHandle){ + // Cleanup resizing listeners + dojo.disconnect(this._resizeHandle); + this._resizeHandle = null; + } + if(this._resizeHandle2){ + // Cleanup resizing listeners + dojo.disconnect(this._resizeHandle2); + this._resizeHandle2 = null; + } + if(this._rst){ + clearTimeout(this._rst); + this._rst = null; + } + + //Remove all position static class assigns. + while(editorParent && editorParent !== dojo.body()){ + dojo.removeClass(editorParent, "dijitForceStatic"); + editorParent = editorParent.parentNode; + } + + // Restore resize function + if(this._editorResizeHolder){ + this.editor.resize = this._editorResizeHolder; + } + + if(!this._origState && !this._origiFrameState){ + // If we actually didn't toggle, then don't do anything. + return; + } + if(ed._fullscreen_oldOnKeyDown){ + ed.onKeyDown = ed._fullscreen_oldOnKeyDown; + delete ed._fullscreen_oldOnKeyDown; + } + + // Add a timeout to make sure we don't have a resize firing in the + // background at the time of minimize. + var self = this; + setTimeout(function(){ + // Restore all the editor state. + var mb = self._origState.marginBox; + var oh = self._origState.height; + if(dojo.isIE && !dojo.isQuirks){ + body.parentNode.style.overflow = self._oldBodyParentOverflow; + delete self._oldBodyParentOverflow; + } + dojo.style(body, "overflow", self._oldOverflow); + delete self._oldOverflow; + + dojo.style(ed.domNode, self._origState); + dojo.style(ed.iframe.parentNode, { + height: "", + width: "" + }); + dojo.style(ed.iframe, self._origiFrameState); + delete self._origState; + delete self._origiFrameState; + // In case it is contained in a layout and the layout changed size, + // go ahead and call resize. + var pWidget = dijit.getEnclosingWidget(ed.domNode.parentNode); + if(pWidget && pWidget.resize){ + pWidget.resize(); + }else{ + if(!oh || oh.indexOf("%") < 0){ + // Resize if the original size wasn't set + // or wasn't in percent. Timeout is to avoid + // an IE crash in unit testing. + setTimeout(dojo.hitch(this, function(){ed.resize({h: mb.h});}), 0); + } + } + dojo.window.scrollIntoView(self.editor.toolbar.domNode); + }, 100); + } + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + destroy: function(){ + // summary: + // Over-ride to ensure the resize handle gets cleaned up. + if(this._resizeHandle){ + // Cleanup resizing listeners + dojo.disconnect(this._resizeHandle); + this._resizeHandle = null; + } + if(this._resizeHandle2){ + // Cleanup resizing listeners + dojo.disconnect(this._resizeHandle2); + this._resizeHandle2 = null; + } + if(this._resizer){ + clearTimeout(this._resizer); + this._resizer = null; + } + this.inherited(arguments); + } }); + + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + var name = o.args.name.toLowerCase(); + if(name === "fullscreen"){ + o.plugin = new dijit._editor.plugins.FullScreen({ + zIndex: ("zIndex" in o.args)?o.args.zIndex:500 + }); + } +}); + } diff --git a/lib/dijit/_editor/plugins/LinkDialog.js b/lib/dijit/_editor/plugins/LinkDialog.js index 71de3ad8f..feb5cf9ec 100644 --- a/lib/dijit/_editor/plugins/LinkDialog.js +++ b/lib/dijit/_editor/plugins/LinkDialog.js @@ -1,236 +1,516 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.LinkDialog"]){ -dojo._hasResource["dijit._editor.plugins.LinkDialog"]=true; +if(!dojo._hasResource["dijit._editor.plugins.LinkDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.LinkDialog"] = true; dojo.provide("dijit._editor.plugins.LinkDialog"); dojo.require("dijit._Widget"); -dojo.require("dijit._Templated"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.TooltipDialog"); -dojo.require("dijit.form.Button"); +dojo.require("dijit.form.DropDownButton"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.form.Select"); dojo.require("dijit._editor.range"); dojo.require("dojo.i18n"); dojo.require("dojo.string"); -dojo.requireLocalization("dijit","common",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.requireLocalization("dijit._editor","LinkDialog",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins.LinkDialog",dijit._editor._Plugin,{buttonClass:dijit.form.DropDownButton,useDefaultCommand:false,urlRegExp:"((https?|ftps?|file)\\://|./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]+(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?",emailRegExp:"<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+"+"@"+"((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?",htmlTemplate:"<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\""+" target=\"${targetSelect}\""+">${textInput}</a>",tag:"a",_hostRxp:new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"),_userAtRxp:new RegExp("^([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+@","i"),linkDialogTemplate:["<table><tr><td>","<label for='${id}_urlInput'>${url}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='true' "+"id='${id}_urlInput' name='urlInput' intermediateChanges='true'>","</td></tr><tr><td>","<label for='${id}_textInput'>${text}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' "+"name='textInput' intermediateChanges='true'>","</td></tr><tr><td>","<label for='${id}_targetSelect'>${target}</label>","</td><td>","<select id='${id}_targetSelect' name='targetSelect' dojoType='dijit.form.Select'>","<option selected='selected' value='_self'>${currentWindow}</option>","<option value='_blank'>${newWindow}</option>","<option value='_top'>${topWindow}</option>","<option value='_parent'>${parentWindow}</option>","</select>","</td></tr><tr><td colspan='2'>","<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>","<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>","</td></tr></table>"].join(""),_initButton:function(){ -var _1=this; -this.tag=this.command=="insertImage"?"img":"a"; -var _2=dojo.mixin(dojo.i18n.getLocalization("dijit","common",this.lang),dojo.i18n.getLocalization("dijit._editor","LinkDialog",this.lang)); -var _3=(this.dropDown=new dijit.TooltipDialog({title:_2[this.command+"Title"],execute:dojo.hitch(this,"setValue"),onOpen:function(){ -_1._onOpenDialog(); -dijit.TooltipDialog.prototype.onOpen.apply(this,arguments); -},onCancel:function(){ -setTimeout(dojo.hitch(_1,"_onCloseDialog"),0); -}})); -_2.urlRegExp=this.urlRegExp; -_2.id=dijit.getUniqueId(this.editor.id); -this._uniqueId=_2.id; -this._setContent(_3.title+"<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>"+dojo.string.substitute(this.linkDialogTemplate,_2)); -_3.startup(); -this._urlInput=dijit.byId(this._uniqueId+"_urlInput"); -this._textInput=dijit.byId(this._uniqueId+"_textInput"); -this._setButton=dijit.byId(this._uniqueId+"_setButton"); -this.connect(dijit.byId(this._uniqueId+"_cancelButton"),"onClick",function(){ -this.dropDown.onCancel(); +dojo.requireLocalization("dijit", "common", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); +dojo.requireLocalization("dijit._editor", "LinkDialog", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins.LinkDialog", dijit._editor._Plugin, { + // summary: + // This plugin provides the basis for an 'anchor' (link) dialog and an extension of it + // provides the image link dialog. + // + // description: + // The command provided by this plugin is: + // * createLink + + // Override _Plugin.buttonClass. This plugin is controlled by a DropDownButton + // (which triggers a TooltipDialog). + buttonClass: dijit.form.DropDownButton, + + // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + // urlRegExp: [protected] String + // Used for validating input as correct URL. While file:// urls are not terribly + // useful, they are technically valid. + urlRegExp: "((https?|ftps?|file)\\://|\./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?", + + // emailRegExp: [protected] String + // Used for validating input as correct email address. Taken from dojox.validate + emailRegExp: "<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+" /*username*/ + "@" + + "((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?", // host. + + // htmlTemplate: [protected] String + // String used for templating the HTML to insert at the desired point. + htmlTemplate: "<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\"" + + " target=\"${targetSelect}\"" + + ">${textInput}</a>", + + // tag: [protected] String + // Tag used for the link type. + tag: "a", + + // _hostRxp [private] RegExp + // Regular expression used to validate url fragments (ip address, hostname, etc) + _hostRxp: new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"), + + // _userAtRxp [private] RegExp + // Regular expression used to validate e-mail address fragment. + _userAtRxp: new RegExp("^([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+@", "i"), + + // linkDialogTemplate: [protected] String + // Template for contents of TooltipDialog to pick URL + linkDialogTemplate: [ + "<table><tr><td>", + "<label for='${id}_urlInput'>${url}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' required='true' " + + "id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>", + "</td></tr><tr><td>", + "<label for='${id}_textInput'>${text}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " + + "name='textInput' intermediateChanges='true'/>", + "</td></tr><tr><td>", + "<label for='${id}_targetSelect'>${target}</label>", + "</td><td>", + "<select id='${id}_targetSelect' name='targetSelect' dojoType='dijit.form.Select'>", + "<option selected='selected' value='_self'>${currentWindow}</option>", + "<option value='_blank'>${newWindow}</option>", + "<option value='_top'>${topWindow}</option>", + "<option value='_parent'>${parentWindow}</option>", + "</select>", + "</td></tr><tr><td colspan='2'>", + "<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>", + "<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>", + "</td></tr></table>" + ].join(""), + + _initButton: function(){ + // Override _Plugin._initButton() to initialize DropDownButton and TooltipDialog. + var _this = this; + this.tag = this.command == 'insertImage' ? 'img' : 'a'; + var messages = dojo.mixin(dojo.i18n.getLocalization("dijit", "common", this.lang), + dojo.i18n.getLocalization("dijit._editor", "LinkDialog", this.lang)); + var dropDown = (this.dropDown = new dijit.TooltipDialog({ + title: messages[this.command + "Title"], + execute: dojo.hitch(this, "setValue"), + onOpen: function(){ + _this._onOpenDialog(); + dijit.TooltipDialog.prototype.onOpen.apply(this, arguments); + }, + onCancel: function(){ + setTimeout(dojo.hitch(_this, "_onCloseDialog"),0); + } + })); + messages.urlRegExp = this.urlRegExp; + messages.id = dijit.getUniqueId(this.editor.id); + this._uniqueId = messages.id; + this._setContent(dropDown.title + + "<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" + + dojo.string.substitute(this.linkDialogTemplate, messages)); + dropDown.startup(); + this._urlInput = dijit.byId(this._uniqueId + "_urlInput"); + this._textInput = dijit.byId(this._uniqueId + "_textInput"); + this._setButton = dijit.byId(this._uniqueId + "_setButton"); + this.connect(dijit.byId(this._uniqueId + "_cancelButton"), "onClick", function(){ + this.dropDown.onCancel(); + }); + if(this._urlInput){ + this.connect(this._urlInput, "onChange", "_checkAndFixInput"); + } + if(this._textInput){ + this.connect(this._textInput, "onChange", "_checkAndFixInput"); + } + + // Build up the dual check for http/https/file:, and mailto formats. + this._urlRegExp = new RegExp("^" + this.urlRegExp + "$", "i"); + this._emailRegExp = new RegExp("^" + this.emailRegExp + "$", "i"); + this._urlInput.isValid = dojo.hitch(this, function(){ + // Function over-ride of isValid to test if the input matches a url or a mailto style link. + var value = this._urlInput.get("value"); + return this._urlRegExp.test(value) || this._emailRegExp.test(value); + }); + + this._connectTagEvents(); + this.inherited(arguments); + }, + + _checkAndFixInput: function(){ + // summary: + // A function to listen for onChange events and test the input contents + // for valid information, such as valid urls with http/https/ftp and if + // not present, try and guess if the input url is relative or not, and if + // not, append http:// to it. Also validates other fields as determined by + // the internal _isValid function. + var self = this; + var url = this._urlInput.get("value"); + var fixupUrl = function(url){ + var appendHttp = false; + var appendMailto = false; + if(url && url.length > 1){ + url = dojo.trim(url); + if(url.indexOf("mailto:") !== 0){ + if(url.indexOf("/") > 0){ + if(url.indexOf("://") === -1){ + // Check that it doesn't start with / or ./, which would + // imply 'target server relativeness' + if(url.charAt(0) !== '/' && url.indexOf("./") !== 0){ + if(self._hostRxp.test(url)){ + appendHttp = true; + } + } + } + }else if(self._userAtRxp.test(url)){ + // If it looks like a foo@, append a mailto. + appendMailto = true; + } + } + } + if(appendHttp){ + self._urlInput.set("value", "http://" + url); + } + if(appendMailto){ + self._urlInput.set("value", "mailto:" + url); + } + self._setButton.set("disabled", !self._isValid()); + }; + if(this._delayedCheck){ + clearTimeout(this._delayedCheck); + this._delayedCheck = null; + } + this._delayedCheck = setTimeout(function(){ + fixupUrl(url); + }, 250); + }, + + _connectTagEvents: function(){ + // summary: + // Over-ridable function that connects tag specific events. + this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){ + this.connect(this.editor.editNode, "ondblclick", this._onDblClick); + })); + }, + + _isValid: function(){ + // summary: + // Internal function to allow validating of the inputs + // for a link to determine if set should be disabled or not + // tags: + // protected + return this._urlInput.isValid() && this._textInput.isValid(); + }, + + _setContent: function(staticPanel){ + // summary: + // Helper for _initButton above. Not sure why it's a separate method. + this.dropDown.set({ + parserScope: "dojo", // make parser search for dojoType/data-dojo-type even if page is multi-version + content: staticPanel + }); + }, + + _checkValues: function(args){ + // summary: + // Function to check the values in args and 'fix' them up as needed. + // args: Object + // Content being set. + // tags: + // protected + if(args && args.urlInput){ + args.urlInput = args.urlInput.replace(/"/g, """); + } + return args; + }, + + setValue: function(args){ + // summary: + // Callback from the dialog when user presses "set" button. + // tags: + // private + //TODO: prevent closing popup if the text is empty + this._onCloseDialog(); + if(dojo.isIE < 9){ //see #4151 + var sel = dijit.range.getSelection(this.editor.window); + var range = sel.getRangeAt(0); + var a = range.endContainer; + if(a.nodeType === 3){ + // Text node, may be the link contents, so check parent. + // This plugin doesn't really support nested HTML elements + // in the link, it assumes all link content is text. + a = a.parentNode; + } + if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){ + // Stll nothing, one last thing to try on IE, as it might be 'img' + // and thus considered a control. + a = dojo.withGlobal(this.editor.window, + "getSelectedElement", dijit._editor.selection, [this.tag]); + } + if(a && (a.nodeName && a.nodeName.toLowerCase() === this.tag)){ + // Okay, we do have a match. IE, for some reason, sometimes pastes before + // instead of removing the targetted paste-over element, so we unlink the + // old one first. If we do not the <a> tag remains, but it has no content, + // so isn't readily visible (but is wrong for the action). + if(this.editor.queryCommandEnabled("unlink")){ + // Select all the link childent, then unlink. The following insert will + // then replace the selected text. + dojo.withGlobal(this.editor.window, + "selectElementChildren", dijit._editor.selection, [a]); + this.editor.execCommand("unlink"); + } + } + } + // make sure values are properly escaped, etc. + args = this._checkValues(args); + this.editor.execCommand('inserthtml', + dojo.string.substitute(this.htmlTemplate, args)); + }, + + _onCloseDialog: function(){ + // summary: + // Handler for close event on the dialog + this.editor.focus(); + }, + + _getCurrentValues: function(a){ + // summary: + // Over-ride for getting the values to set in the dropdown. + // a: + // The anchor/link to process for data for the dropdown. + // tags: + // protected + var url, text, target; + if(a && a.tagName.toLowerCase() === this.tag){ + url = a.getAttribute('_djrealurl') || a.getAttribute('href'); + target = a.getAttribute('target') || "_self"; + text = a.textContent || a.innerText; + dojo.withGlobal(this.editor.window, "selectElement", dijit._editor.selection, [a, true]); + }else{ + text = dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText); + } + return {urlInput: url || '', textInput: text || '', targetSelect: target || ''}; //Object; + }, + + _onOpenDialog: function(){ + // summary: + // Handler for when the dialog is opened. + // If the caret is currently in a URL then populate the URL's info into the dialog. + var a; + if(dojo.isIE < 9){ + // IE is difficult to select the element in, using the range unified + // API seems to work reasonably well. + var sel = dijit.range.getSelection(this.editor.window); + var range = sel.getRangeAt(0); + a = range.endContainer; + if(a.nodeType === 3){ + // Text node, may be the link contents, so check parent. + // This plugin doesn't really support nested HTML elements + // in the link, it assumes all link content is text. + a = a.parentNode; + } + if(a && (a.nodeName && a.nodeName.toLowerCase() !== this.tag)){ + // Stll nothing, one last thing to try on IE, as it might be 'img' + // and thus considered a control. + a = dojo.withGlobal(this.editor.window, + "getSelectedElement", dijit._editor.selection, [this.tag]); + } + }else{ + a = dojo.withGlobal(this.editor.window, + "getAncestorElement", dijit._editor.selection, [this.tag]); + } + this.dropDown.reset(); + this._setButton.set("disabled", true); + this.dropDown.set("value", this._getCurrentValues(a)); + }, + + _onDblClick: function(e){ + // summary: + // Function to define a behavior on double clicks on the element + // type this dialog edits to select it and pop up the editor + // dialog. + // e: Object + // The double-click event. + // tags: + // protected. + if(e && e.target){ + var t = e.target; + var tg = t.tagName? t.tagName.toLowerCase() : ""; + if(tg === this.tag && dojo.attr(t,"href")){ + dojo.withGlobal(this.editor.window, + "selectElement", + dijit._editor.selection, [t]); + this.editor.onDisplayChanged(); + + setTimeout(dojo.hitch(this, function(){ + // Focus shift outside the event handler. + // IE doesn't like focus changes in event handles. + this.button.set("disabled", false); + this.button.openDropDown(); + }), 10); + } + } + } }); -if(this._urlInput){ -this.connect(this._urlInput,"onChange","_checkAndFixInput"); -} -if(this._textInput){ -this.connect(this._textInput,"onChange","_checkAndFixInput"); -} -this._urlRegExp=new RegExp("^"+this.urlRegExp+"$","i"); -this._emailRegExp=new RegExp("^"+this.emailRegExp+"$","i"); -this._urlInput.isValid=dojo.hitch(this,function(){ -var _4=this._urlInput.get("value"); -return this._urlRegExp.test(_4)||this._emailRegExp.test(_4); + +dojo.declare("dijit._editor.plugins.ImgLinkDialog", [dijit._editor.plugins.LinkDialog], { + // summary: + // This plugin extends LinkDialog and adds in a plugin for handling image links. + // provides the image link dialog. + // + // description: + // The command provided by this plugin is: + // * insertImage + + // linkDialogTemplate: [protected] String + // Over-ride for template since img dialog doesn't need target that anchor tags may. + linkDialogTemplate: [ + "<table><tr><td>", + "<label for='${id}_urlInput'>${url}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' " + + "required='true' id='${id}_urlInput' name='urlInput' intermediateChanges='true'/>", + "</td></tr><tr><td>", + "<label for='${id}_textInput'>${text}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' " + + "name='textInput' intermediateChanges='true'/>", + "</td></tr><tr><td>", + "</td><td>", + "</td></tr><tr><td colspan='2'>", + "<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>", + "<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>", + "</td></tr></table>" + ].join(""), + + // htmlTemplate: [protected] String + // String used for templating the <img> HTML to insert at the desired point. + htmlTemplate: "<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />", + + // tag: [protected] String + // Tag used for the link type (img). + tag: "img", + + _getCurrentValues: function(img){ + // summary: + // Over-ride for getting the values to set in the dropdown. + // a: + // The anchor/link to process for data for the dropdown. + // tags: + // protected + var url, text; + if(img && img.tagName.toLowerCase() === this.tag){ + url = img.getAttribute('_djrealurl') || img.getAttribute('src'); + text = img.getAttribute('alt'); + dojo.withGlobal(this.editor.window, + "selectElement", dijit._editor.selection, [img, true]); + }else{ + text = dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText); + } + return {urlInput: url || '', textInput: text || ''}; //Object; + }, + + _isValid: function(){ + // summary: + // Over-ride for images. You can have alt text of blank, it is valid. + // tags: + // protected + return this._urlInput.isValid(); + }, + + _connectTagEvents: function(){ + // summary: + // Over-ridable function that connects tag specific events. + this.inherited(arguments); + this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){ + // Use onmousedown instead of onclick. Seems that IE eats the first onclick + // to wrap it in a selector box, then the second one acts as onclick. See #10420 + this.connect(this.editor.editNode, "onmousedown", this._selectTag); + })); + }, + + _selectTag: function(e){ + // summary: + // A simple event handler that lets me select an image if it is clicked on. + // makes it easier to select images in a standard way across browsers. Otherwise + // selecting an image for edit becomes difficult. + // e: Event + // The mousedown event. + // tags: + // private + if(e && e.target){ + var t = e.target; + var tg = t.tagName? t.tagName.toLowerCase() : ""; + if(tg === this.tag){ + dojo.withGlobal(this.editor.window, + "selectElement", + dijit._editor.selection, [t]); + } + } + }, + + _checkValues: function(args){ + // summary: + // Function to check the values in args and 'fix' them up as needed + // (special characters in the url or alt text) + // args: Object + // Content being set. + // tags: + // protected + if(args && args.urlInput){ + args.urlInput = args.urlInput.replace(/"/g, """); + } + if(args && args.textInput){ + args.textInput = args.textInput.replace(/"/g, """); + } + return args; + }, + + _onDblClick: function(e){ + // summary: + // Function to define a behavior on double clicks on the element + // type this dialog edits to select it and pop up the editor + // dialog. + // e: Object + // The double-click event. + // tags: + // protected. + if(e && e.target){ + var t = e.target; + var tg = t.tagName? t.tagName.toLowerCase() : ""; + if(tg === this.tag && dojo.attr(t,"src")){ + dojo.withGlobal(this.editor.window, + "selectElement", + dijit._editor.selection, [t]); + this.editor.onDisplayChanged(); + setTimeout(dojo.hitch(this, function(){ + // Focus shift outside the event handler. + // IE doesn't like focus changes in event handles. + this.button.set("disabled", false); + this.button.openDropDown(); + }), 10); + } + } + } }); -this._connectTagEvents(); -this.inherited(arguments); -},_checkAndFixInput:function(){ -var _5=this; -var _6=this._urlInput.get("value"); -var _7=function(_8){ -var _9=false; -var _a=false; -if(_8&&_8.length>1){ -_8=dojo.trim(_8); -if(_8.indexOf("mailto:")!==0){ -if(_8.indexOf("/")>0){ -if(_8.indexOf("://")===-1){ -if(_8.charAt(0)!=="/"&&_8.indexOf("./")!==0){ -if(_5._hostRxp.test(_8)){ -_9=true; -} -} -} -}else{ -if(_5._userAtRxp.test(_8)){ -_a=true; -} -} -} -} -if(_9){ -_5._urlInput.set("value","http://"+_8); -} -if(_a){ -_5._urlInput.set("value","mailto:"+_8); -} -_5._setButton.set("disabled",!_5._isValid()); -}; -if(this._delayedCheck){ -clearTimeout(this._delayedCheck); -this._delayedCheck=null; -} -this._delayedCheck=setTimeout(function(){ -_7(_6); -},250); -},_connectTagEvents:function(){ -this.editor.onLoadDeferred.addCallback(dojo.hitch(this,function(){ -this.connect(this.editor.editNode,"ondblclick",this._onDblClick); -})); -},_isValid:function(){ -return this._urlInput.isValid()&&this._textInput.isValid(); -},_setContent:function(_b){ -this.dropDown.set("content",_b); -},_checkValues:function(_c){ -if(_c&&_c.urlInput){ -_c.urlInput=_c.urlInput.replace(/"/g,"""); -} -return _c; -},setValue:function(_d){ -this._onCloseDialog(); -if(dojo.isIE){ -var _e=dijit.range.getSelection(this.editor.window); -var _f=_e.getRangeAt(0); -var a=_f.endContainer; -if(a.nodeType===3){ -a=a.parentNode; -} -if(a&&(a.nodeName&&a.nodeName.toLowerCase()!==this.tag)){ -a=dojo.withGlobal(this.editor.window,"getSelectedElement",dijit._editor.selection,[this.tag]); -} -if(a&&(a.nodeName&&a.nodeName.toLowerCase()===this.tag)){ -if(this.editor.queryCommandEnabled("unlink")){ -dojo.withGlobal(this.editor.window,"selectElementChildren",dijit._editor.selection,[a]); -this.editor.execCommand("unlink"); -} -} -} -_d=this._checkValues(_d); -this.editor.execCommand("inserthtml",dojo.string.substitute(this.htmlTemplate,_d)); -},_onCloseDialog:function(){ -this.editor.focus(); -},_getCurrentValues:function(a){ -var url,_10,_11; -if(a&&a.tagName.toLowerCase()===this.tag){ -url=a.getAttribute("_djrealurl")||a.getAttribute("href"); -_11=a.getAttribute("target")||"_self"; -_10=a.textContent||a.innerText; -dojo.withGlobal(this.editor.window,"selectElement",dijit._editor.selection,[a,true]); -}else{ -_10=dojo.withGlobal(this.editor.window,dijit._editor.selection.getSelectedText); -} -return {urlInput:url||"",textInput:_10||"",targetSelect:_11||""}; -},_onOpenDialog:function(){ -var a; -if(dojo.isIE){ -var sel=dijit.range.getSelection(this.editor.window); -var _12=sel.getRangeAt(0); -a=_12.endContainer; -if(a.nodeType===3){ -a=a.parentNode; -} -if(a&&(a.nodeName&&a.nodeName.toLowerCase()!==this.tag)){ -a=dojo.withGlobal(this.editor.window,"getSelectedElement",dijit._editor.selection,[this.tag]); -} -}else{ -a=dojo.withGlobal(this.editor.window,"getAncestorElement",dijit._editor.selection,[this.tag]); -} -this.dropDown.reset(); -this._setButton.set("disabled",true); -this.dropDown.set("value",this._getCurrentValues(a)); -},_onDblClick:function(e){ -if(e&&e.target){ -var t=e.target; -var tg=t.tagName?t.tagName.toLowerCase():""; -if(tg===this.tag&&dojo.attr(t,"href")){ -dojo.withGlobal(this.editor.window,"selectElement",dijit._editor.selection,[t]); -this.editor.onDisplayChanged(); -setTimeout(dojo.hitch(this,function(){ -this.button.set("disabled",false); -this.button.openDropDown(); -}),10); -} -} -}}); -dojo.declare("dijit._editor.plugins.ImgLinkDialog",[dijit._editor.plugins.LinkDialog],{linkDialogTemplate:["<table><tr><td>","<label for='${id}_urlInput'>${url}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' "+"required='true' id='${id}_urlInput' name='urlInput' intermediateChanges='true'>","</td></tr><tr><td>","<label for='${id}_textInput'>${text}</label>","</td><td>","<input dojoType='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' "+"name='textInput' intermediateChanges='true'>","</td></tr><tr><td>","</td><td>","</td></tr><tr><td colspan='2'>","<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>","<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>","</td></tr></table>"].join(""),htmlTemplate:"<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />",tag:"img",_getCurrentValues:function(img){ -var url,_13; -if(img&&img.tagName.toLowerCase()===this.tag){ -url=img.getAttribute("_djrealurl")||img.getAttribute("src"); -_13=img.getAttribute("alt"); -dojo.withGlobal(this.editor.window,"selectElement",dijit._editor.selection,[img,true]); -}else{ -_13=dojo.withGlobal(this.editor.window,dijit._editor.selection.getSelectedText); -} -return {urlInput:url||"",textInput:_13||""}; -},_isValid:function(){ -return this._urlInput.isValid(); -},_connectTagEvents:function(){ -this.inherited(arguments); -this.editor.onLoadDeferred.addCallback(dojo.hitch(this,function(){ -this.connect(this.editor.editNode,"onmousedown",this._selectTag); -})); -},_selectTag:function(e){ -if(e&&e.target){ -var t=e.target; -var tg=t.tagName?t.tagName.toLowerCase():""; -if(tg===this.tag){ -dojo.withGlobal(this.editor.window,"selectElement",dijit._editor.selection,[t]); -} -} -},_checkValues:function(_14){ -if(_14&&_14.urlInput){ -_14.urlInput=_14.urlInput.replace(/"/g,"""); -} -if(_14&&_14.textInput){ -_14.textInput=_14.textInput.replace(/"/g,"""); -} -return _14; -},_onDblClick:function(e){ -if(e&&e.target){ -var t=e.target; -var tg=t.tagName?t.tagName.toLowerCase():""; -if(tg===this.tag&&dojo.attr(t,"src")){ -dojo.withGlobal(this.editor.window,"selectElement",dijit._editor.selection,[t]); -this.editor.onDisplayChanged(); -setTimeout(dojo.hitch(this,function(){ -this.button.set("disabled",false); -this.button.openDropDown(); -}),10); -} -} -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -switch(o.args.name){ -case "createLink": -o.plugin=new dijit._editor.plugins.LinkDialog({command:o.args.name}); -break; -case "insertImage": -o.plugin=new dijit._editor.plugins.ImgLinkDialog({command:o.args.name}); -break; -} + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + switch(o.args.name){ + case "createLink": + o.plugin = new dijit._editor.plugins.LinkDialog({command: o.args.name}); + break; + case "insertImage": + o.plugin = new dijit._editor.plugins.ImgLinkDialog({command: o.args.name}); + break; + } }); + } diff --git a/lib/dijit/_editor/plugins/NewPage.js b/lib/dijit/_editor/plugins/NewPage.js index 14c2cfa62..7e628d364 100644 --- a/lib/dijit/_editor/plugins/NewPage.js +++ b/lib/dijit/_editor/plugins/NewPage.js @@ -1,36 +1,81 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.NewPage"]){ -dojo._hasResource["dijit._editor.plugins.NewPage"]=true; +if(!dojo._hasResource["dijit._editor.plugins.NewPage"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.NewPage"] = true; dojo.provide("dijit._editor.plugins.NewPage"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); -dojo.requireLocalization("dijit._editor","commands",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins.NewPage",dijit._editor._Plugin,{content:"<br>",_initButton:function(){ -var _1=dojo.i18n.getLocalization("dijit._editor","commands"),_2=this.editor; -this.button=new dijit.form.Button({label:_1["newPage"],dir:_2.dir,lang:_2.lang,showLabel:false,iconClass:this.iconClassPrefix+" "+this.iconClassPrefix+"NewPage",tabIndex:"-1",onClick:dojo.hitch(this,"_newPage")}); -},setEditor:function(_3){ -this.editor=_3; -this._initButton(); -},_newPage:function(){ -this.editor.beginEditing(); -this.editor.set("value",this.content); -this.editor.endEditing(); -this.editor.focus(); -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -var _4=o.args.name.toLowerCase(); -if(_4==="newpage"){ -o.plugin=new dijit._editor.plugins.NewPage({content:("content" in o.args)?o.args.content:"<br>"}); -} +dojo.requireLocalization("dijit._editor", "commands", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins.NewPage",dijit._editor._Plugin,{ + // summary: + // This plugin provides a simple 'new page' calability. In other + // words, set content to some default user defined string. + + // content: [public] String + // The default content to insert into the editor as the new page. + // The default is the <br> tag, a single blank line. + content: "<br>", + + _initButton: function(){ + // summary: + // Over-ride for creation of the Print button. + var strings = dojo.i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new dijit.form.Button({ + label: strings["newPage"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "NewPage", + tabIndex: "-1", + onClick: dojo.hitch(this, "_newPage") + }); + }, + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the newPage capability to. + this.editor = editor; + this._initButton(); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _newPage: function(){ + // summary: + // Function to set the content to blank. + // tags: + // private + this.editor.beginEditing(); + this.editor.set("value", this.content); + this.editor.endEditing(); + this.editor.focus(); + } }); + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + var name = o.args.name.toLowerCase(); + if(name === "newpage"){ + o.plugin = new dijit._editor.plugins.NewPage({ + content: ("content" in o.args)?o.args.content:"<br>" + }); + } +}); + } diff --git a/lib/dijit/_editor/plugins/Print.js b/lib/dijit/_editor/plugins/Print.js index b2e739aee..83cf0ddc7 100644 --- a/lib/dijit/_editor/plugins/Print.js +++ b/lib/dijit/_editor/plugins/Print.js @@ -1,65 +1,125 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.Print"]){ -dojo._hasResource["dijit._editor.plugins.Print"]=true; +if(!dojo._hasResource["dijit._editor.plugins.Print"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.Print"] = true; dojo.provide("dijit._editor.plugins.Print"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); -dojo.requireLocalization("dijit._editor","commands",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins.Print",dijit._editor._Plugin,{_initButton:function(){ -var _1=dojo.i18n.getLocalization("dijit._editor","commands"),_2=this.editor; -this.button=new dijit.form.Button({label:_1["print"],dir:_2.dir,lang:_2.lang,showLabel:false,iconClass:this.iconClassPrefix+" "+this.iconClassPrefix+"Print",tabIndex:"-1",onClick:dojo.hitch(this,"_print")}); -},setEditor:function(_3){ -this.editor=_3; -this._initButton(); -this.editor.onLoadDeferred.addCallback(dojo.hitch(this,function(){ -if(!this.editor.iframe.contentWindow["print"]){ -this.button.set("disabled",true); -} -})); -},_print:function(){ -var _4=this.editor.iframe; -if(_4.contentWindow["print"]){ -if(!dojo.isOpera&&!dojo.isChrome){ -dijit.focus(_4); -_4.contentWindow.print(); -}else{ -var _5=this.editor.document; -var _6=this.editor.get("value"); -_6="<html><head><meta http-equiv='Content-Type' "+"content='text/html; charset='UTF-8'></head><body>"+_6+"</body></html>"; -var _7=window.open("javascript: ''","","status=0,menubar=0,location=0,toolbar=0,"+"width=1,height=1,resizable=0,scrollbars=0"); -_7.document.open(); -_7.document.write(_6); -_7.document.close(); -var _8=[]; -var _9=_5.getElementsByTagName("style"); -if(_9){ -var i; -for(i=0;i<_9.length;i++){ -var _a=_9[i].innerHTML; -var _b=_7.document.createElement("style"); -_b.appendChild(_7.document.createTextNode(_a)); -_7.document.getElementsByTagName("head")[0].appendChild(_b); -} -} -_7.print(); -_7.close(); -} -} -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -var _c=o.args.name.toLowerCase(); -if(_c==="print"){ -o.plugin=new dijit._editor.plugins.Print({command:"print"}); -} +dojo.requireLocalization("dijit._editor", "commands", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins.Print",dijit._editor._Plugin,{ + // summary: + // This plugin provides Print cabability to the editor. When + // clicked, the document in the editor frame will be printed. + + _initButton: function(){ + // summary: + // Over-ride for creation of the Print button. + var strings = dojo.i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new dijit.form.Button({ + label: strings["print"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "Print", + tabIndex: "-1", + onClick: dojo.hitch(this, "_print") + }); + }, + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the print capability to. + this.editor = editor; + this._initButton(); + + // Set up a check that we have a print function + // and disable button if we do not. + this.editor.onLoadDeferred.addCallback( + dojo.hitch(this, function(){ + if(!this.editor.iframe.contentWindow["print"]){ + this.button.set("disabled", true); + } + }) + ); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + var disabled = this.get("disabled"); + if(!this.editor.iframe.contentWindow["print"]){ + disabled = true; + } + this.button.set("disabled", disabled); + }, + + _print: function(){ + // summary: + // Function to trigger printing of the editor document + // tags: + // private + var edFrame = this.editor.iframe; + if(edFrame.contentWindow["print"]){ + // IE requires the frame to be focused for + // print to work, but since this is okay for all + // no special casing. + if(!dojo.isOpera && !dojo.isChrome){ + dijit.focus(edFrame); + edFrame.contentWindow.print(); + }else{ + // Neither Opera nor Chrome 3 et you print single frames. + // So, open a new 'window', print it, and close it. + // Also, can't use size 0x0, have to use 1x1 + var edDoc = this.editor.document; + var content = this.editor.get("value"); + content = "<html><head><meta http-equiv='Content-Type' " + + "content='text/html; charset='UTF-8'></head><body>" + + content + "</body></html>"; + var win = window.open("javascript: ''", + "", + "status=0,menubar=0,location=0,toolbar=0," + + "width=1,height=1,resizable=0,scrollbars=0"); + win.document.open(); + win.document.write(content); + win.document.close(); + var styles = []; + var styleNodes = edDoc.getElementsByTagName("style"); + if(styleNodes){ + // Clone over any editor view styles, since we can't print the iframe + // directly. + var i; + for(i = 0; i < styleNodes.length; i++){ + var style = styleNodes[i].innerHTML; + var sNode = win.document.createElement("style"); + sNode.appendChild(win.document.createTextNode(style)); + win.document.getElementsByTagName("head")[0].appendChild(sNode); + } + } + win.print(); + win.close(); + } + } + } +}); + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + var name = o.args.name.toLowerCase(); + if(name === "print"){ + o.plugin = new dijit._editor.plugins.Print({command: "print"}); + } }); + } diff --git a/lib/dijit/_editor/plugins/TabIndent.js b/lib/dijit/_editor/plugins/TabIndent.js index 74cda400f..eb27f69dd 100644 --- a/lib/dijit/_editor/plugins/TabIndent.js +++ b/lib/dijit/_editor/plugins/TabIndent.js @@ -1,33 +1,69 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.TabIndent"]){ -dojo._hasResource["dijit._editor.plugins.TabIndent"]=true; +if(!dojo._hasResource["dijit._editor.plugins.TabIndent"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.TabIndent"] = true; dojo.provide("dijit._editor.plugins.TabIndent"); -dojo.experimental("dijit._editor.plugins.TabIndent"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.ToggleButton"); -dojo.declare("dijit._editor.plugins.TabIndent",dijit._editor._Plugin,{useDefaultCommand:false,buttonClass:dijit.form.ToggleButton,command:"tabIndent",_initButton:function(){ -this.inherited(arguments); -var e=this.editor; -this.connect(this.button,"onChange",function(_1){ -e.set("isTabIndent",_1); -}); -this.updateState(); -},updateState:function(){ -this.button.set("checked",this.editor.isTabIndent,false); -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -switch(o.args.name){ -case "tabIndent": -o.plugin=new dijit._editor.plugins.TabIndent({command:o.args.name}); -} + + +dojo.experimental("dijit._editor.plugins.TabIndent"); + + +dojo.declare("dijit._editor.plugins.TabIndent", + dijit._editor._Plugin, + { + // summary: + // This plugin is used to allow the use of the tab and shift-tab keys + // to indent/outdent list items. This overrides the default behavior + // of moving focus from/to the toolbar + + // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + // Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button + buttonClass: dijit.form.ToggleButton, + + command: "tabIndent", + + _initButton: function(){ + // Override _Plugin._initButton() to setup listener on button click + this.inherited(arguments); + + var e = this.editor; + this.connect(this.button, "onChange", function(val){ + e.set("isTabIndent", val); + }); + + // Set initial checked state of button based on Editor.isTabIndent + this.updateState(); + }, + + updateState: function(){ + // Overrides _Plugin.updateState(). + // Ctrl-m in the editor will switch tabIndent mode on/off, so we need to react to that. + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ + return; + } + this.button.set('checked', this.editor.isTabIndent, false); + } + } +); + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + switch(o.args.name){ + case "tabIndent": + o.plugin = new dijit._editor.plugins.TabIndent({command: o.args.name}); + } }); + } diff --git a/lib/dijit/_editor/plugins/TextColor.js b/lib/dijit/_editor/plugins/TextColor.js index da7bbc9a6..2f24d0424 100644 --- a/lib/dijit/_editor/plugins/TextColor.js +++ b/lib/dijit/_editor/plugins/TextColor.js @@ -1,62 +1,105 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.TextColor"]){ -dojo._hasResource["dijit._editor.plugins.TextColor"]=true; +if(!dojo._hasResource["dijit._editor.plugins.TextColor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.TextColor"] = true; dojo.provide("dijit._editor.plugins.TextColor"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.ColorPalette"); -dojo.declare("dijit._editor.plugins.TextColor",dijit._editor._Plugin,{buttonClass:dijit.form.DropDownButton,useDefaultCommand:false,constructor:function(){ -this.dropDown=new dijit.ColorPalette(); -this.connect(this.dropDown,"onChange",function(_1){ -this.editor.execCommand(this.command,_1); + + +dojo.declare("dijit._editor.plugins.TextColor", dijit._editor._Plugin, { + // summary: + // This plugin provides dropdown color pickers for setting text color and background color + // + // description: + // The commands provided by this plugin are: + // * foreColor - sets the text color + // * hiliteColor - sets the background color + + // Override _Plugin.buttonClass to use DropDownButton (with ColorPalette) to control this plugin + buttonClass: dijit.form.DropDownButton, + + // useDefaultCommand: Boolean + // False as we do not use the default editor command/click behavior. + useDefaultCommand: false, + + constructor: function(){ + this.dropDown = new dijit.ColorPalette(); + this.connect(this.dropDown, "onChange", function(color){ + this.editor.execCommand(this.command, color); + + }); + }, + + updateState: function(){ + // summary: + // Overrides _Plugin.updateState(). This updates the ColorPalette + // to show the color of the currently selected text. + // tags: + // protected + + var _e = this.editor; + var _c = this.command; + if(!_e || !_e.isLoaded || !_c.length){ + return; + } + + if(this.button){ + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ return; } + + var value; + try{ + value = _e.queryCommandValue(_c)|| ""; + }catch(e){ + //Firefox may throw error above if the editor is just loaded, ignore it + value = ""; + } + } + + if(value == ""){ + value = "#000000"; + } + if(value == "transparent"){ + value = "#ffffff"; + } + + if(typeof value == "string"){ + //if RGB value, convert to hex value + if(value.indexOf("rgb")> -1){ + value = dojo.colorFromRgb(value).toHex(); + } + }else{ //it's an integer(IE returns an MS access #) + value =((value & 0x0000ff)<< 16)|(value & 0x00ff00)|((value & 0xff0000)>>> 16); + value = value.toString(16); + value = "#000000".slice(0, 7 - value.length)+ value; + + } + + if(value !== this.dropDown.get('value')){ + this.dropDown.set('value', value, false); + } + } }); -},updateState:function(){ -var _2=this.editor; -var _3=this.command; -if(!_2||!_2.isLoaded||!_3.length){ -return; -} -if(this.button){ -var _4; -try{ -_4=_2.queryCommandValue(_3)||""; -} -catch(e){ -_4=""; -} -} -if(_4==""){ -_4="#000000"; -} -if(_4=="transparent"){ -_4="#ffffff"; -} -if(typeof _4=="string"){ -if(_4.indexOf("rgb")>-1){ -_4=dojo.colorFromRgb(_4).toHex(); -} -}else{ -_4=((_4&255)<<16)|(_4&65280)|((_4&16711680)>>>16); -_4=_4.toString(16); -_4="#000000".slice(0,7-_4.length)+_4; -} -if(_4!==this.dropDown.get("value")){ -this.dropDown.set("value",_4,false); -} -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -switch(o.args.name){ -case "foreColor": -case "hiliteColor": -o.plugin=new dijit._editor.plugins.TextColor({command:o.args.name}); -} + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin", null, function(o){ + if(o.plugin){ + return; + } + switch(o.args.name){ + case "foreColor": + case "hiliteColor": + o.plugin = new dijit._editor.plugins.TextColor({ + command: o.args.name + }); + } }); + } diff --git a/lib/dijit/_editor/plugins/ToggleDir.js b/lib/dijit/_editor/plugins/ToggleDir.js index f5ecb7909..92e3d91c8 100644 --- a/lib/dijit/_editor/plugins/ToggleDir.js +++ b/lib/dijit/_editor/plugins/ToggleDir.js @@ -1,42 +1,80 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.ToggleDir"]){ -dojo._hasResource["dijit._editor.plugins.ToggleDir"]=true; +if(!dojo._hasResource["dijit._editor.plugins.ToggleDir"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.ToggleDir"] = true; dojo.provide("dijit._editor.plugins.ToggleDir"); +dojo.require("dijit._editor._Plugin"); +dojo.require("dijit.form.ToggleButton"); + + dojo.experimental("dijit._editor.plugins.ToggleDir"); + dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.ToggleButton"); -dojo.declare("dijit._editor.plugins.ToggleDir",dijit._editor._Plugin,{useDefaultCommand:false,command:"toggleDir",buttonClass:dijit.form.ToggleButton,_initButton:function(){ -this.inherited(arguments); -this.editor.onLoadDeferred.addCallback(dojo.hitch(this,function(){ -var _1=this.editor.editorObject.contentWindow.document.documentElement; -_1=_1.getElementsByTagName("body")[0]; -var _2=dojo.getComputedStyle(_1).direction=="ltr"; -this.button.set("checked",!_2); -this.connect(this.button,"onChange","_setRtl"); -})); -},updateState:function(){ -},_setRtl:function(_3){ -var _4="ltr"; -if(_3){ -_4="rtl"; -} -var _5=this.editor.editorObject.contentWindow.document.documentElement; -_5=_5.getElementsByTagName("body")[0]; -_5.dir=_4; -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -switch(o.args.name){ -case "toggleDir": -o.plugin=new dijit._editor.plugins.ToggleDir({command:o.args.name}); -} + +dojo.declare("dijit._editor.plugins.ToggleDir", + dijit._editor._Plugin, + { + // summary: + // This plugin is used to toggle direction of the edited document, + // independent of what direction the whole page is. + + // Override _Plugin.useDefaultCommand: processing is done in this plugin + // rather than by sending commands to the Editor + useDefaultCommand: false, + + command: "toggleDir", + + // Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button + buttonClass: dijit.form.ToggleButton, + + _initButton: function(){ + // Override _Plugin._initButton() to setup handler for button click events. + this.inherited(arguments); + this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){ + var editDoc = this.editor.editorObject.contentWindow.document.documentElement; + //IE direction has to toggle on the body, not document itself. + //If you toggle just the document, things get very strange in the + //view. But, the nice thing is this works for all supported browsers. + editDoc = editDoc.getElementsByTagName("body")[0]; + var isLtr = dojo.getComputedStyle(editDoc).direction == "ltr"; + this.button.set("checked", !isLtr); + this.connect(this.button, "onChange", "_setRtl"); + })); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _setRtl: function(rtl){ + // summary: + // Handler for button click events, to switch the text direction of the editor + var dir = "ltr"; + if(rtl){ + dir = "rtl"; + } + var editDoc = this.editor.editorObject.contentWindow.document.documentElement; + editDoc = editDoc.getElementsByTagName("body")[0]; + editDoc.dir/*html node*/ = dir; + } + } +); + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + switch(o.args.name){ + case "toggleDir": + o.plugin = new dijit._editor.plugins.ToggleDir({command: o.args.name}); + } }); + } diff --git a/lib/dijit/_editor/plugins/ViewSource.js b/lib/dijit/_editor/plugins/ViewSource.js index 41ea2970f..e655ad21d 100644 --- a/lib/dijit/_editor/plugins/ViewSource.js +++ b/lib/dijit/_editor/plugins/ViewSource.js @@ -1,317 +1,555 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._editor.plugins.ViewSource"]){ -dojo._hasResource["dijit._editor.plugins.ViewSource"]=true; +if(!dojo._hasResource["dijit._editor.plugins.ViewSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._editor.plugins.ViewSource"] = true; dojo.provide("dijit._editor.plugins.ViewSource"); dojo.require("dojo.window"); dojo.require("dojo.i18n"); dojo.require("dijit._editor._Plugin"); dojo.require("dijit.form.Button"); -dojo.requireLocalization("dijit._editor","commands",null,"ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); -dojo.declare("dijit._editor.plugins.ViewSource",dijit._editor._Plugin,{stripScripts:true,stripComments:true,stripIFrames:true,readOnly:false,_fsPlugin:null,toggle:function(){ -if(dojo.isWebKit){ -this._vsFocused=true; -} -this.button.set("checked",!this.button.get("checked")); -},_initButton:function(){ -var _1=dojo.i18n.getLocalization("dijit._editor","commands"),_2=this.editor; -this.button=new dijit.form.ToggleButton({label:_1["viewSource"],dir:_2.dir,lang:_2.lang,showLabel:false,iconClass:this.iconClassPrefix+" "+this.iconClassPrefix+"ViewSource",tabIndex:"-1",onChange:dojo.hitch(this,"_showSource")}); -if(dojo.isIE==7){ -this._ieFixNode=dojo.create("div",{style:{opacity:"0",zIndex:"-1000",position:"absolute",top:"-1000px"}},dojo.body()); -} -this.button.set("readOnly",false); -},setEditor:function(_3){ -this.editor=_3; -this._initButton(); -this.editor.addKeyHandler(dojo.keys.F12,true,true,dojo.hitch(this,function(e){ -this.button.focus(); -this.toggle(); -dojo.stopEvent(e); -setTimeout(dojo.hitch(this,function(){ -this.editor.focus(); -}),100); -})); -},_showSource:function(_4){ -var ed=this.editor; -var _5=ed._plugins; -var _6; -this._sourceShown=_4; -var _7=this; -try{ -if(!this.sourceArea){ -this._createSourceView(); -} -if(_4){ -ed._sourceQueryCommandEnabled=ed.queryCommandEnabled; -ed.queryCommandEnabled=function(_8){ -var _9=_8.toLowerCase(); -if(_9==="viewsource"){ -return true; -}else{ -return false; -} -}; -this.editor.onDisplayChanged(); -_6=ed.get("value"); -_6=this._filter(_6); -ed.set("value",_6); -this._pluginList=[]; -this._disabledPlugins=dojo.filter(_5,function(p){ -if(p&&p.button&&!p.button.get("disabled")&&!(p instanceof dijit._editor.plugins.ViewSource)){ -p._vs_updateState=p.updateState; -p.updateState=function(){ -return false; -}; -p.button.set("disabled",true); -if(p.command){ -switch(p.command){ -case "bold": -case "italic": -case "underline": -case "strikethrough": -case "superscript": -case "subscript": -p.button.set("checked",false); -break; -default: -break; -} -} -return true; -} -}); -if(this._fsPlugin){ -this._fsPlugin._getAltViewNode=function(){ -return _7.sourceArea; -}; -} -this.sourceArea.value=_6; -var is=dojo.marginBox(ed.iframe.parentNode); -dojo.marginBox(this.sourceArea,{w:is.w,h:is.h}); -dojo.style(ed.iframe,"display","none"); -dojo.style(this.sourceArea,{display:"block"}); -var _a=function(){ -var vp=dojo.window.getBox(); -if("_prevW" in this&&"_prevH" in this){ -if(vp.w===this._prevW&&vp.h===this._prevH){ -return; -}else{ -this._prevW=vp.w; -this._prevH=vp.h; -} -}else{ -this._prevW=vp.w; -this._prevH=vp.h; -} -if(this._resizer){ -clearTimeout(this._resizer); -delete this._resizer; -} -this._resizer=setTimeout(dojo.hitch(this,function(){ -delete this._resizer; -this._resize(); -}),10); -}; -this._resizeHandle=dojo.connect(window,"onresize",this,_a); -setTimeout(dojo.hitch(this,this._resize),100); -this.editor.onNormalizedDisplayChanged(); -}else{ -if(!ed._sourceQueryCommandEnabled){ -return; -} -dojo.disconnect(this._resizeHandle); -delete this._resizeHandle; -ed.queryCommandEnabled=ed._sourceQueryCommandEnabled; -if(!this._readOnly){ -_6=this.sourceArea.value; -_6=this._filter(_6); -ed.beginEditing(); -ed.set("value",_6); -ed.endEditing(); -} -dojo.forEach(this._disabledPlugins,function(p){ -p.button.set("disabled",false); -if(p._vs_updateState){ -p.updateState=p._vs_updateState; -} +dojo.requireLocalization("dijit._editor", "commands", null, "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw"); + + +dojo.declare("dijit._editor.plugins.ViewSource",dijit._editor._Plugin,{ + // summary: + // This plugin provides a simple view source capability. When view + // source mode is enabled, it disables all other buttons/plugins on the RTE. + // It also binds to the hotkey: CTRL-SHIFT-F11 for toggling ViewSource mode. + + // stripScripts: [public] Boolean + // Boolean flag used to indicate if script tags should be stripped from the document. + // Defaults to true. + stripScripts: true, + + // stripComments: [public] Boolean + // Boolean flag used to indicate if comment tags should be stripped from the document. + // Defaults to true. + stripComments: true, + + // stripComments: [public] Boolean + // Boolean flag used to indicate if iframe tags should be stripped from the document. + // Defaults to true. + stripIFrames: true, + + // readOnly: [const] Boolean + // Boolean flag used to indicate if the source view should be readonly or not. + // Cannot be changed after initialization of the plugin. + // Defaults to false. + readOnly: false, + + // _fsPlugin: [private] Object + // Reference to a registered fullscreen plugin so that viewSource knows + // how to scale. + _fsPlugin: null, + + toggle: function(){ + // summary: + // Function to allow programmatic toggling of the view. + + // For Webkit, we have to focus a very particular way. + // when swapping views, otherwise focus doesn't shift right + // but can't focus this way all the time, only for VS changes. + // If we did it all the time, buttons like bold, italic, etc + // break. + if(dojo.isWebKit){this._vsFocused = true;} + this.button.set("checked", !this.button.get("checked")); + + }, + + _initButton: function(){ + // summary: + // Over-ride for creation of the resize button. + var strings = dojo.i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new dijit.form.ToggleButton({ + label: strings["viewSource"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "ViewSource", + tabIndex: "-1", + onChange: dojo.hitch(this, "_showSource") + }); + + // IE 7 has a horrible bug with zoom, so we have to create this node + // to cross-check later. Sigh. + if(dojo.isIE == 7){ + this._ieFixNode = dojo.create("div", { + style: { + opacity: "0", + zIndex: "-1000", + position: "absolute", + top: "-1000px" + } + }, dojo.body()); + } + // Make sure readonly mode doesn't make the wrong cursor appear over the button. + this.button.set("readOnly", false); + }, + + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the print capability to. + this.editor = editor; + this._initButton(); + + this.editor.addKeyHandler(dojo.keys.F12, true, true, dojo.hitch(this, function(e){ + // Move the focus before switching + // It'll focus back. Hiding a focused + // node causes issues. + this.button.focus(); + this.toggle(); + dojo.stopEvent(e); + + // Call the focus shift outside of the handler. + setTimeout(dojo.hitch(this, function(){ + // We over-ride focus, so we just need to call. + this.editor.focus(); + }), 100); + })); + }, + + _showSource: function(source){ + // summary: + // Function to toggle between the source and RTE views. + // source: boolean + // Boolean value indicating if it should be in source mode or not. + // tags: + // private + var ed = this.editor; + var edPlugins = ed._plugins; + var html; + this._sourceShown = source; + var self = this; + try{ + if(!this.sourceArea){ + this._createSourceView(); + } + if(source){ + // Update the QueryCommandEnabled function to disable everything but + // the source view mode. Have to over-ride a function, then kick all + // plugins to check their state. + ed._sourceQueryCommandEnabled = ed.queryCommandEnabled; + ed.queryCommandEnabled = function(cmd){ + var lcmd = cmd.toLowerCase(); + if(lcmd === "viewsource"){ + return true; + }else{ + return false; + } + }; + this.editor.onDisplayChanged(); + html = ed.get("value"); + html = this._filter(html); + ed.set("value", html); + this._pluginList = []; + dojo.forEach(edPlugins, function(p){ + // Turn off any plugins not controlled by queryCommandenabled. + if(!(p instanceof dijit._editor.plugins.ViewSource)){ + p.set("disabled", true) + } + }); + + // We actually do need to trap this plugin and adjust how we + // display the textarea. + if(this._fsPlugin){ + this._fsPlugin._getAltViewNode = function(){ + return self.sourceArea; + }; + } + + this.sourceArea.value = html; + var is = dojo._getMarginSize(ed.iframe.parentNode); + + dojo.marginBox(this.sourceArea, { + w: is.w, + h: is.h + }); + + dojo.style(ed.iframe, "display", "none"); + dojo.style(this.sourceArea, { + display: "block" + }); + + var resizer = function(){ + // function to handle resize events. + // Will check current VP and only resize if + // different. + var vp = dojo.window.getBox(); + + if("_prevW" in this && "_prevH" in this){ + // No actual size change, ignore. + if(vp.w === this._prevW && vp.h === this._prevH){ + return; + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + // Timeout it to help avoid spamming resize on IE. + // Works for all browsers. + this._resizer = setTimeout(dojo.hitch(this, function(){ + delete this._resizer; + this._resize(); + }), 10); + }; + this._resizeHandle = dojo.connect(window, "onresize", this, resizer); + + //Call this on a delay once to deal with IE glitchiness on initial size. + setTimeout(dojo.hitch(this, this._resize), 100); + + //Trigger a check for command enablement/disablement. + this.editor.onNormalizedDisplayChanged(); + + this.editor.__oldGetValue = this.editor.getValue; + this.editor.getValue = dojo.hitch(this, function() { + var txt = this.sourceArea.value; + txt = this._filter(txt); + return txt; + }); + }else{ + // First check that we were in source view before doing anything. + // corner case for being called with a value of false and we hadn't + // actually been in source display mode. + if(!ed._sourceQueryCommandEnabled){ + return; + } + dojo.disconnect(this._resizeHandle); + delete this._resizeHandle; + + if(this.editor.__oldGetValue){ + this.editor.getValue = this.editor.__oldGetValue; + delete this.editor.__oldGetValue; + } + + // Restore all the plugin buttons state. + ed.queryCommandEnabled = ed._sourceQueryCommandEnabled; + if(!this._readOnly){ + html = this.sourceArea.value; + html = this._filter(html); + ed.beginEditing(); + ed.set("value", html); + ed.endEditing(); + } + + dojo.forEach(edPlugins, function(p){ + // Turn back on any plugins we turned off. + p.set("disabled", false); + }); + + dojo.style(this.sourceArea, "display", "none"); + dojo.style(ed.iframe, "display", "block"); + delete ed._sourceQueryCommandEnabled; + + //Trigger a check for command enablement/disablement. + this.editor.onDisplayChanged(); + } + // Call a delayed resize to wait for some things to display in header/footer. + setTimeout(dojo.hitch(this, function(){ + // Make resize calls. + var parent = ed.domNode.parentNode; + if(parent){ + var container = dijit.getEnclosingWidget(parent); + if(container && container.resize){ + container.resize(); + } + } + ed.resize(); + }), 300); + }catch(e){ + console.log(e); + } + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _resize: function(){ + // summary: + // Internal function to resize the source view + // tags: + // private + var ed = this.editor; + var tbH = ed.getHeaderHeight(); + var fH = ed.getFooterHeight(); + var eb = dojo.position(ed.domNode); + + // Styles are now applied to the internal source container, so we have + // to subtract them off. + var containerPadding = dojo._getPadBorderExtents(ed.iframe.parentNode); + var containerMargin = dojo._getMarginExtents(ed.iframe.parentNode); + + var extents = dojo._getPadBorderExtents(ed.domNode); + var mExtents = dojo._getMarginExtents(ed.domNode); + var edb = { + w: eb.w - (extents.w + mExtents.w), + h: eb.h - (tbH + extents.h + mExtents.h + fH) + }; + + // Fullscreen gets odd, so we need to check for the FS plugin and + // adapt. + if(this._fsPlugin && this._fsPlugin.isFullscreen){ + //Okay, probably in FS, adjust. + var vp = dojo.window.getBox(); + edb.w = (vp.w - extents.w); + edb.h = (vp.h - (tbH + extents.h + fH)); + } + + if(dojo.isIE){ + // IE is always off by 2px, so we have to adjust here + // Note that IE ZOOM is broken here. I can't get + //it to scale right. + edb.h -= 2; + } + + // IE has a horrible zoom bug. So, we have to try and account for + // it and fix up the scaling. + if(this._ieFixNode){ + var _ie7zoom = -this._ieFixNode.offsetTop / 1000; + edb.w = Math.floor((edb.w + 0.9) / _ie7zoom); + edb.h = Math.floor((edb.h + 0.9) / _ie7zoom); + } + + dojo.marginBox(this.sourceArea, { + w: edb.w - (containerPadding.w + containerMargin.w), + h: edb.h - (containerPadding.h + containerMargin.h) + }); + + // Scale the parent container too in this case. + dojo.marginBox(ed.iframe.parentNode, { + h: edb.h + }); + }, + + _createSourceView: function(){ + // summary: + // Internal function for creating the source view area. + // tags: + // private + var ed = this.editor; + var edPlugins = ed._plugins; + this.sourceArea = dojo.create("textarea"); + if(this.readOnly){ + dojo.attr(this.sourceArea, "readOnly", true); + this._readOnly = true; + } + dojo.style(this.sourceArea, { + padding: "0px", + margin: "0px", + borderWidth: "0px", + borderStyle: "none" + }); + dojo.place(this.sourceArea, ed.iframe, "before"); + + if(dojo.isIE && ed.iframe.parentNode.lastChild !== ed.iframe){ + // There's some weirdo div in IE used for focus control + // But is messed up scaling the textarea if we don't config + // it some so it doesn't have a varying height. + dojo.style(ed.iframe.parentNode.lastChild,{ + width: "0px", + height: "0px", + padding: "0px", + margin: "0px", + borderWidth: "0px", + borderStyle: "none" + }); + } + + // We also need to take over editor focus a bit here, so that focus calls to + // focus the editor will focus to the right node when VS is active. + ed._viewsource_oldFocus = ed.focus; + var self = this; + ed.focus = function(){ + if(self._sourceShown){ + self.setSourceAreaCaret(); + }else{ + try{ + if(this._vsFocused){ + delete this._vsFocused; + // Must focus edit node in this case (webkit only) or + // focus doesn't shift right, but in normal + // cases we focus with the regular function. + dijit.focus(ed.editNode); + }else{ + ed._viewsource_oldFocus(); + } + }catch(e){ + console.log(e); + } + } + }; + + var i, p; + for(i = 0; i < edPlugins.length; i++){ + // We actually do need to trap this plugin and adjust how we + // display the textarea. + p = edPlugins[i]; + if(p && (p.declaredClass === "dijit._editor.plugins.FullScreen" || + p.declaredClass === (dijit._scopeName + + "._editor.plugins.FullScreen"))){ + this._fsPlugin = p; + break; + } + } + if(this._fsPlugin){ + // Found, we need to over-ride the alt-view node function + // on FullScreen with our own, chain up to parent call when appropriate. + this._fsPlugin._viewsource_getAltViewNode = this._fsPlugin._getAltViewNode; + this._fsPlugin._getAltViewNode = function(){ + return self._sourceShown?self.sourceArea:this._viewsource_getAltViewNode(); + }; + } + + // Listen to the source area for key events as well, as we need to be able to hotkey toggle + // it from there too. + this.connect(this.sourceArea, "onkeydown", dojo.hitch(this, function(e){ + if(this._sourceShown && e.keyCode == dojo.keys.F12 && e.ctrlKey && e.shiftKey){ + this.button.focus(); + this.button.set("checked", false); + setTimeout(dojo.hitch(this, function(){ed.focus();}), 100); + dojo.stopEvent(e); + } + })); + }, + + _stripScripts: function(html){ + // summary: + // Strips out script tags from the HTML used in editor. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + // Look for closed and unclosed (malformed) script attacks. + html = html.replace(/<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>/ig, ""); + html = html.replace(/<\s*script\b([^<>]|\s)*>?/ig, ""); + html = html.replace(/<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>/ig, ""); + } + return html; + }, + + _stripComments: function(html){ + // summary: + // Strips out comments from the HTML used in editor. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + html = html.replace(/<!--(.|\s){1,}?-->/g, ""); + } + return html; + }, + + _stripIFrames: function(html){ + // summary: + // Strips out iframe tags from the content, to avoid iframe script + // style injection attacks. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + html = html.replace(/<\s*iframe[^>]*>((.|\s)*?)<\\?\/\s*iframe\s*>/ig, ""); + } + return html; + }, + + _filter: function(html){ + // summary: + // Internal function to perform some filtering on the HTML. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + if(this.stripScripts){ + html = this._stripScripts(html); + } + if(this.stripComments){ + html = this._stripComments(html); + } + if(this.stripIFrames){ + html = this._stripIFrames(html); + } + } + return html; + }, + + setSourceAreaCaret: function(){ + // summary: + // Internal function to set the caret in the sourceArea + // to 0x0 + var win = dojo.global; + var elem = this.sourceArea; + dijit.focus(elem); + if(this._sourceShown && !this.readOnly){ + if(dojo.isIE){ + if(this.sourceArea.createTextRange){ + var range = elem.createTextRange(); + range.collapse(true); + range.moveStart("character", -99999); // move to 0 + range.moveStart("character", 0); // delta from 0 is the correct position + range.moveEnd("character", 0); + range.select(); + } + }else if(win.getSelection){ + if(elem.setSelectionRange){ + elem.setSelectionRange(0,0); + } + } + } + }, + + destroy: function(){ + // summary: + // Over-ride to remove the node used to correct for IE's + // zoom bug. + if(this._ieFixNode){ + dojo.body().removeChild(this._ieFixNode); + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + if(this._resizeHandle){ + dojo.disconnect(this._resizeHandle); + delete this._resizeHandle; + } + this.inherited(arguments); + } }); -this._disabledPlugins=null; -dojo.style(this.sourceArea,"display","none"); -dojo.style(ed.iframe,"display","block"); -delete ed._sourceQueryCommandEnabled; -this.editor.onDisplayChanged(); -} -setTimeout(dojo.hitch(this,function(){ -var _b=ed.domNode.parentNode; -if(_b){ -var _c=dijit.getEnclosingWidget(_b); -if(_c&&_c.resize){ -_c.resize(); -} -} -ed.resize(); -}),300); -} -catch(e){ -} -},_resize:function(){ -var ed=this.editor; -var _d=ed.getHeaderHeight(); -var fH=ed.getFooterHeight(); -var eb=dojo.position(ed.domNode); -var _e=dojo._getPadBorderExtents(ed.iframe.parentNode); -var _f=dojo._getMarginExtents(ed.iframe.parentNode); -var _10=dojo._getPadBorderExtents(ed.domNode); -var _11=dojo._getMarginExtents(ed.domNode); -var edb={w:eb.w-(_10.w+_11.w),h:eb.h-(_d+_10.h+_11.h+fH)}; -if(this._fsPlugin&&this._fsPlugin.isFullscreen){ -var vp=dojo.window.getBox(); -edb.w=(vp.w-_10.w); -edb.h=(vp.h-(_d+_10.h+fH)); -} -if(dojo.isIE){ -edb.h-=2; -} -if(this._ieFixNode){ -var _12=-this._ieFixNode.offsetTop/1000; -edb.w=Math.floor((edb.w+0.9)/_12); -edb.h=Math.floor((edb.h+0.9)/_12); -} -dojo.marginBox(this.sourceArea,{w:edb.w-(_e.w+_f.w),h:edb.h-(_e.h+_f.h)}); -dojo.marginBox(ed.iframe.parentNode,{h:edb.h}); -},_createSourceView:function(){ -var ed=this.editor; -var _13=ed._plugins; -this.sourceArea=dojo.create("textarea"); -if(this.readOnly){ -dojo.attr(this.sourceArea,"readOnly",true); -this._readOnly=true; -} -dojo.style(this.sourceArea,{padding:"0px",margin:"0px",borderWidth:"0px",borderStyle:"none"}); -dojo.place(this.sourceArea,ed.iframe,"before"); -if(dojo.isIE&&ed.iframe.parentNode.lastChild!==ed.iframe){ -dojo.style(ed.iframe.parentNode.lastChild,{width:"0px",height:"0px",padding:"0px",margin:"0px",borderWidth:"0px",borderStyle:"none"}); -} -ed._viewsource_oldFocus=ed.focus; -var _14=this; -ed.focus=function(){ -if(_14._sourceShown){ -_14.setSourceAreaCaret(); -}else{ -try{ -if(this._vsFocused){ -delete this._vsFocused; -dijit.focus(ed.editNode); -}else{ -ed._viewsource_oldFocus(); -} -} -catch(e){ -} -} -}; -var i,p; -for(i=0;i<_13.length;i++){ -p=_13[i]; -if(p&&(p.declaredClass==="dijit._editor.plugins.FullScreen"||p.declaredClass===(dijit._scopeName+"._editor.plugins.FullScreen"))){ -this._fsPlugin=p; -break; -} -} -if(this._fsPlugin){ -this._fsPlugin._viewsource_getAltViewNode=this._fsPlugin._getAltViewNode; -this._fsPlugin._getAltViewNode=function(){ -return _14._sourceShown?_14.sourceArea:this._viewsource_getAltViewNode(); -}; -} -this.connect(this.sourceArea,"onkeydown",dojo.hitch(this,function(e){ -if(this._sourceShown&&e.keyCode==dojo.keys.F12&&e.ctrlKey&&e.shiftKey){ -this.button.focus(); -this.button.set("checked",false); -setTimeout(dojo.hitch(this,function(){ -ed.focus(); -}),100); -dojo.stopEvent(e); -} -})); -},_stripScripts:function(_15){ -if(_15){ -_15=_15.replace(/<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>/ig,""); -_15=_15.replace(/<\s*script\b([^<>]|\s)*>?/ig,""); -_15=_15.replace(/<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>/ig,""); -} -return _15; -},_stripComments:function(_16){ -if(_16){ -_16=_16.replace(/<!--(.|\s){1,}?-->/g,""); -} -return _16; -},_stripIFrames:function(_17){ -if(_17){ -_17=_17.replace(/<\s*iframe[^>]*>((.|\s)*?)<\\?\/\s*iframe\s*>/ig,""); -} -return _17; -},_filter:function(_18){ -if(_18){ -if(this.stripScripts){ -_18=this._stripScripts(_18); -} -if(this.stripComments){ -_18=this._stripComments(_18); -} -if(this.stripIFrames){ -_18=this._stripIFrames(_18); -} -} -return _18; -},setSourceAreaCaret:function(){ -var win=dojo.global; -var _19=this.sourceArea; -dijit.focus(_19); -if(this._sourceShown&&!this.readOnly){ -if(dojo.isIE){ -if(this.sourceArea.createTextRange){ -var _1a=_19.createTextRange(); -_1a.collapse(true); -_1a.moveStart("character",-99999); -_1a.moveStart("character",0); -_1a.moveEnd("character",0); -_1a.select(); -} -}else{ -if(win.getSelection){ -if(_19.setSelectionRange){ -_19.setSelectionRange(0,0); -} -} -} -} -},destroy:function(){ -if(this._ieFixNode){ -dojo.body().removeChild(this._ieFixNode); -} -if(this._resizer){ -clearTimeout(this._resizer); -delete this._resizer; -} -if(this._resizeHandle){ -dojo.disconnect(this._resizeHandle); -delete this._resizeHandle; -} -this.inherited(arguments); -}}); -dojo.subscribe(dijit._scopeName+".Editor.getPlugin",null,function(o){ -if(o.plugin){ -return; -} -var _1b=o.args.name.toLowerCase(); -if(_1b==="viewsource"){ -o.plugin=new dijit._editor.plugins.ViewSource({readOnly:("readOnly" in o.args)?o.args.readOnly:false,stripComments:("stripComments" in o.args)?o.args.stripComments:true,stripScripts:("stripScripts" in o.args)?o.args.stripScripts:true,stripIFrames:("stripIFrames" in o.args)?o.args.stripIFrames:true}); -} + +// Register this plugin. +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + var name = o.args.name.toLowerCase(); + if(name === "viewsource"){ + o.plugin = new dijit._editor.plugins.ViewSource({ + readOnly: ("readOnly" in o.args)?o.args.readOnly:false, + stripComments: ("stripComments" in o.args)?o.args.stripComments:true, + stripScripts: ("stripScripts" in o.args)?o.args.stripScripts:true, + stripIFrames: ("stripIFrames" in o.args)?o.args.stripIFrames:true + }); + } }); + } |