diff options
Diffstat (limited to 'includes/js/dijit/_editor/plugins')
-rw-r--r-- | includes/js/dijit/_editor/plugins/AlwaysShowToolbar.js | 140 | ||||
-rw-r--r-- | includes/js/dijit/_editor/plugins/EnterKeyHandling.js | 416 | ||||
-rw-r--r-- | includes/js/dijit/_editor/plugins/FontChoice.js | 167 | ||||
-rw-r--r-- | includes/js/dijit/_editor/plugins/LinkDialog.js | 147 | ||||
-rw-r--r-- | includes/js/dijit/_editor/plugins/TextColor.js | 40 | ||||
-rw-r--r-- | includes/js/dijit/_editor/plugins/ToggleDir.js | 40 |
6 files changed, 950 insertions, 0 deletions
diff --git a/includes/js/dijit/_editor/plugins/AlwaysShowToolbar.js b/includes/js/dijit/_editor/plugins/AlwaysShowToolbar.js new file mode 100644 index 0000000..9879e88 --- /dev/null +++ b/includes/js/dijit/_editor/plugins/AlwaysShowToolbar.js @@ -0,0 +1,140 @@ +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){ + this.editor = e; +// setTimeout(dojo.hitch(this,this.enable), 10000); + e.onLoadDeferred.addCallback(dojo.hitch(this, this.enable)); +// this.scrollInterval = setInterval(dojo.hitch(this, "globalOnScrollHandler"), 100); + }, + enable: function(d){ + 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.marginBox(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.marginBox(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(height != this._lastHeight){ + this._lastHeight = height; + // this.editorObject.style.height = this._lastHeight + "px"; + dojo.marginBox(e.iframe, { h: this._lastHeight }); +// this.iframe.height=this._lastHeight+10+'px'; +// this.iframe.style.height=this._lastHeight+'px'; + } + }, + _lastHeight: 0, + globalOnScrollHandler: function(){ + var isIE = dojo.isIE && dojo.isIE<7; + if(!this._handleScroll){ return; } + var tdn = this.editor.toolbar.domNode; + var db = dojo.body; + + if(!this._scrollSetUp){ + this._scrollSetUp = true; + this._scrollThreshold = dojo._abs(tdn, true).y; +// console.log("threshold:", this._scrollThreshold); + //what's this for?? comment out for now +// if((isIE)&&(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.marginBox(tdn); + this.editor.iframe.style.marginTop = tdnbox.h+"px"; + + if(isIE){ + s.left = dojo._abs(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(isIE){ + 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(){ + this._IEOriginalPos = null; + this._handleScroll = false; + dojo.forEach(this._connects, dojo.disconnect); +// clearInterval(this.scrollInterval); + + if(dojo.isIE && dojo.isIE<7){ + dojo.removeClass(this.editor.toolbar.domNode, 'dijitIEFixedToolbar'); + } + } +}); + +} diff --git a/includes/js/dijit/_editor/plugins/EnterKeyHandling.js b/includes/js/dijit/_editor/plugins/EnterKeyHandling.js new file mode 100644 index 0000000..083743d --- /dev/null +++ b/includes/js/dijit/_editor/plugins/EnterKeyHandling.js @@ -0,0 +1,416 @@ +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.declare("dijit._editor.plugins.EnterKeyHandling", dijit._editor._Plugin, { + // summary: this plugin tries to handle enter key events to make all + // browsers have identical behaviors. + + // 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. + blockNodeForEnter: 'P', + constructor: function(args){ + if(args){ + dojo.mixin(this,args); + } + }, + setEditor: function(editor){ + this.editor = editor; + if(this.blockNodeForEnter == 'BR'){ + if(dojo.isIE){ + editor.contentDomPreFilters.push(dojo.hitch(this, "regularPsToSingleLinePs")); + editor.contentDomPostFilters.push(dojo.hitch(this, "singleLinePsToRegularPs")); + editor.onLoadDeferred.addCallback(dojo.hitch(this, "_fixNewLineBehaviorForIE")); + }else{ + editor.onLoadDeferred.addCallback(dojo.hitch(this,function(d){ + try{ + this.editor.document.execCommand("insertBrOnReturn", false, true); + }catch(e){} + return d; + })); + } + }else if(this.blockNodeForEnter){ + //add enter key handler + // FIXME: need to port to the new event code!! + dojo['require']('dijit._editor.range'); + var h = dojo.hitch(this,this.handleEnterKey); + editor.addKeyHandler(13, 0, h); //enter + editor.addKeyHandler(13, 2, h); //shift+enter + this.connect(this.editor,'onKeyPressed','onKeyPressed'); + } + }, + connect: function(o,f,tf){ + if(!this._connects){ + this._connects=[]; + } + this._connects.push(dojo.connect(o,f,this,tf)); + }, + destroy: function(){ + dojo.forEach(this._connects,dojo.disconnect); + this._connects=[]; + }, + onKeyPressed: function(e){ + if(this._checkListLater){ + if(dojo.withGlobal(this.editor.window, 'isCollapsed', dijit)){ + if(!dojo.withGlobal(this.editor.window, 'hasAncestorElement', dijit._editor.selection, ['LI'])){ + //circulate the undo detection code by calling RichText::execCommand directly + dijit._editor.RichText.prototype.execCommand.apply(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){ + //the following won't work, it will move the caret to the last list item in the previous list +// var newrange = dijit.range.create(); +// newrange.setStart(block.firstChild,0); +// var selection = dijit.range.getSelection(this.editor.window) +// selection.removeAllRanges(); +// selection.addRange(newrange); + //move to the start by move backward one char + var r = this.editor.document.selection.createRange(); + r.move('character',-1); + r.select(); + } + }else{ + alert('onKeyPressed: Can not find the new block node'); //FIXME + } + } + } + this._checkListLater = false; + }else if(this._pressedEnterInBlock){ + //the new created is the original current P, so we have previousSibling below + this.removeTrailingBr(this._pressedEnterInBlock.previousSibling); + delete this._pressedEnterInBlock; + } + }, + bogusHtmlContent: ' ', + blockNodes: /^(?:H1|H2|H3|H4|H5|H6|LI)$/, + handleEnterKey: function(e){ + // summary: manually handle enter key event to make the behavior consistant across + // all supported browsers. See property blockNodeForEnter for available options + if(!this.blockNodeForEnter){ return true; } //let browser handle this + var selection, range, newrange; + if(e.shiftKey //shift+enter always generates <br> + || this.blockNodeForEnter=='BR'){ + var parent = dojo.withGlobal(this.editor.window, "getParentElement", dijit._editor.selection); + var header = dijit.range.getAncestor(parent,this.editor.blockNodes); + if(header){ + if(header.tagName=='LI'){ + return true; //let brower handle + } + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + } + if(dijit.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){ + dojo.place(this.editor.document.createElement('br'), header, "before"); + }else if(dijit.range.atEndOfContainer(header, range.startContainer, range.startOffset)){ + dojo.place(this.editor.document.createElement('br'), header, "after"); + newrange = dijit.range.create(); + newrange.setStartAfter(header); + + selection.removeAllRanges(); + selection.addRange(newrange); + }else{ + return true; //let brower handle + } + }else{ + //don't change this: do not call this.execCommand, as that may have other logic in subclass + // FIXME + dijit._editor.RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>'); + } + return false; + } + var _letBrowserHandle = true; + //blockNodeForEnter is either P or DIV + //first remove selection + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + } + + var block = dijit.range.getBlockAncestor(range.endContainer, null, this.editor.editNode); + + if((this._checkListLater = (block.blockNode && block.blockNode.tagName == 'LI'))){ + return true; + } + + //text node directly under body, let's wrap them in a node + if(!block.blockNode){ + this.editor.document.execCommand('formatblock', false, this.blockNodeForEnter); + //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.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length){ + this.removeTrailingBr(block.blockNode); + return false; + } + }else{ + block.blockNode = this.editor.editNode; + } + selection = dijit.range.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + var newblock = this.editor.document.createElement(this.blockNodeForEnter); + newblock.innerHTML=this.bogusHtmlContent; + this.removeTrailingBr(block.blockNode); + if(dijit.range.atEndOfContainer(block.blockNode, range.endContainer, range.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(); + newrange.setStart(newblock,0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + newblock.scrollIntoView(false); + } + }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){ + //browser does not scroll the caret position into view, do it manually + newblock.nextSibling.scrollIntoView(false); + } + _letBrowserHandle = false; + }else{ //press enter in the middle of P + 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; + }, + removeTrailingBr: function(container){ + 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 && para.lastChild.tagName=='BR')){ + + dojo._destroyElement(para.lastChild); + } + } + if(!para.childNodes.length){ + para.innerHTML=this.bogusHtmlContent; + } + }, + _fixNewLineBehaviorForIE: function(d){ + if(this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS === undefined){ + var lineFixingStyles = "p{margin:0 !important;}"; + var insertCssText = function( + /*String*/ cssStr, + /*Document*/ doc, + /*String*/ URI) + { + // summary: + // Attempt to insert CSS rules into the document through inserting a + // style element + + // DomNode Style = insertCssText(String ".dojoMenu {color: green;}"[, DomDoc document, dojo.uri.Uri Url ]) + if(!cssStr){ + return null; // HTMLStyleElement + } + if(!doc){ doc = document; } +// if(URI){// fix paths in cssStr +// cssStr = dojo.html.fixPathsInCssText(cssStr, URI); +// } + var style = doc.createElement("style"); + style.setAttribute("type", "text/css"); + // IE is b0rken enough to require that we add the element to the doc + // before changing it's properties + var head = doc.getElementsByTagName("head")[0]; + if(!head){ // must have a head tag + console.debug("No head tag in document, aborting styles"); + return null; // HTMLStyleElement + }else{ + head.appendChild(style); + } + if(style.styleSheet){// IE + var setFunc = function(){ + try{ + style.styleSheet.cssText = cssStr; + }catch(e){ console.debug(e); } + }; + if(style.styleSheet.disabled){ + setTimeout(setFunc, 10); + }else{ + setFunc(); + } + }else{ // w3c + var cssText = doc.createTextNode(cssStr); + style.appendChild(cssText); + } + return style; // HTMLStyleElement + } + insertCssText(lineFixingStyles, this.editor.document); + this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS = true; + // this.regularPsToSingleLinePs(this.editNode); + return d; + } + return null; + }, + regularPsToSingleLinePs: function(element, noWhiteSpaceInEmptyP){ + function wrapLinesInPs(el){ + // move "lines" of top-level text nodes into ps + function wrapNodes(nodes){ + // nodes are assumed to all be siblings + var newP = nodes[0].ownerDocument.createElement('p'); // FIXME: not very idiomatic + nodes[0].parentNode.insertBefore(newP, nodes[0]); + dojo.forEach(nodes, function(node){ + newP.appendChild(node); + }); + } + + var currentNodeIndex = 0; + var nodesInLine = []; + var currentNode; + while(currentNodeIndex < el.childNodes.length){ + currentNode = el.childNodes[currentNodeIndex]; + if( (currentNode.nodeName!='BR') && + (currentNode.nodeType==1) && + (dojo.style(currentNode, "display")!="block") + ){ + nodesInLine.push(currentNode); + }else{ + // hit line delimiter; process nodesInLine if there are any + var nextCurrentNode = currentNode.nextSibling; + if(nodesInLine.length){ + wrapNodes(nodesInLine); + currentNodeIndex = (currentNodeIndex+1)-nodesInLine.length; + if(currentNode.nodeName=="BR"){ + dojo._destroyElement(currentNode); + } + } + nodesInLine = []; + } + currentNodeIndex++; + } + if(nodesInLine.length){ wrapNodes(nodesInLine); } + } + + function splitP(el){ + // split a paragraph into seperate paragraphs at BRs + var currentNode = null; + var trailingNodes = []; + var lastNodeIndex = el.childNodes.length-1; + for(var i=lastNodeIndex; i>=0; i--){ + currentNode = el.childNodes[i]; + if(currentNode.nodeName=="BR"){ + var newP = currentNode.ownerDocument.createElement('p'); + dojo.place(newP, el, "after"); + if (trailingNodes.length==0 && i != lastNodeIndex) { + newP.innerHTML = " " + } + dojo.forEach(trailingNodes, function(node){ + newP.appendChild(node); + }); + dojo._destroyElement(currentNode); + trailingNodes = []; + }else{ + trailingNodes.unshift(currentNode); + } + } + } + + var pList = []; + var ps = element.getElementsByTagName('p'); + dojo.forEach(ps, function(p){ pList.push(p); }); + dojo.forEach(pList, function(p){ + if( (p.previousSibling) && + (p.previousSibling.nodeName == 'P' || dojo.style(p.previousSibling, 'display') != 'block') + ){ + var newP = p.parentNode.insertBefore(this.document.createElement('p'), p); + // this is essential to prevent IE from losing the P. + // if it's going to be innerHTML'd later we need + // to add the to _really_ force the issue + newP.innerHTML = noWhiteSpaceInEmptyP ? "" : " "; + } + splitP(p); + },this.editor); + wrapLinesInPs(element); + return element; + }, + + singleLinePsToRegularPs: function(element){ + function getParagraphParents(node){ + var ps = node.getElementsByTagName('p'); + var parents = []; + for(var i=0; i<ps.length; i++){ + var p = ps[i]; + var knownParent = false; + for(var k=0; k < parents.length; k++){ + if(parents[k] === p.parentNode){ + knownParent = true; + break; + } + } + if(!knownParent){ + parents.push(p.parentNode); + } + } + return parents; + } + + function isParagraphDelimiter(node){ + if(node.nodeType != 1 || node.tagName != 'P'){ + return dojo.style(node, 'display') == 'block'; + }else{ + if(!node.childNodes.length || node.innerHTML==" "){ return true; } + //return node.innerHTML.match(/^(<br\ ?\/?>| |\ \;)$/i); + } + return false; + } + + var paragraphContainers = getParagraphParents(element); + for(var i=0; i<paragraphContainers.length; i++){ + var container = paragraphContainers[i]; + var firstPInBlock = null; + var node = container.firstChild; + var deleteNode = null; + while(node){ + if(node.nodeType != "1" || node.tagName != 'P'){ + firstPInBlock = null; + }else if (isParagraphDelimiter(node)){ + deleteNode = node; + firstPInBlock = null; + }else{ + if(firstPInBlock == null){ + firstPInBlock = node; + }else{ + if( (!firstPInBlock.lastChild || firstPInBlock.lastChild.nodeName != 'BR') && + (node.firstChild) && + (node.firstChild.nodeName != 'BR') + ){ + firstPInBlock.appendChild(this.editor.document.createElement('br')); + } + while(node.firstChild){ + firstPInBlock.appendChild(node.firstChild); + } + deleteNode = node; + } + } + node = node.nextSibling; + if(deleteNode){ + dojo._destroyElement(deleteNode); + deleteNode = null; + } + } + } + return element; + } +}); + +} diff --git a/includes/js/dijit/_editor/plugins/FontChoice.js b/includes/js/dijit/_editor/plugins/FontChoice.js new file mode 100644 index 0000000..642237b --- /dev/null +++ b/includes/js/dijit/_editor/plugins/FontChoice.js @@ -0,0 +1,167 @@ +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.form.FilteringSelect"); +dojo.require("dojo.data.ItemFileReadStore"); +dojo.require("dojo.i18n"); + +dojo.requireLocalization("dijit._editor", "FontChoice", null, "zh,pt,da,tr,ru,de,sv,ja,he,ROOT,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu"); + +dojo.declare("dijit._editor.plugins.FontChoice", + dijit._editor._Plugin, + { + // summary: + // This plugin provides three dropdowns for setting font information in the editor + // + // description: + // The commands provided by this plugin are: + // + // * fontName + // | Provides a dropdown to select from a list of generic font names + // * fontSize + // | Provides a dropdown to select from a list of pre-defined font sizes + // * formatBlock + // | Provides a dropdown to select from a list of 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. + + _uniqueId: 0, + + buttonClass: dijit.form.FilteringSelect, + + _initButton: function(){ + //TODO: would be nice to be able to handle comma-separated font lists and search within them + var cmd = this.command; + var names = this.custom || + { + fontName: this.generic ? ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics + ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"], + fontSize: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE + formatBlock: ["p", "h1", "h2", "h3", "pre"] + }[cmd]; + var strings = dojo.i18n.getLocalization("dijit._editor", "FontChoice"); + var items = dojo.map(names, function(value){ + var name = strings[value] || value; + var label = name; + switch(cmd){ + case "fontName": + label = "<div style='font-family: "+value+"'>" + name + "</div>"; + break; + case "fontSize": + // we're stuck using the deprecated FONT tag to correspond with the size measurements used by the editor + label = "<font size="+value+"'>"+name+"</font>"; + break; + case "formatBlock": + label = "<" + value + ">" + name + "</" + value + ">"; + } + return { label: label, name: name, value: value }; + }); + items.push({label: "", name:"", value:""}); // FilteringSelect doesn't like unmatched blank strings + + dijit._editor.plugins.FontChoice.superclass._initButton.apply(this, + [{ labelType: "html", labelAttr: "label", searchAttr: "name", store: new dojo.data.ItemFileReadStore( + { data: { identifier: "value", items: items } })}]); + + this.button.setValue(""); + + this.connect(this.button, "onChange", function(choice){ + if(this.updating){ return; } + // FIXME: IE is really messed up here!! + if(dojo.isIE && "_savedSelection" in this){ + var b = this._savedSelection; + delete this._savedSelection; + this.editor.focus(); + this.editor._moveToBookmark(b); + }else{ +// this.editor.focus(); + dijit.focus(this._focusHandle); + } + if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; } + this.editor.execCommand(this.editor._normalizeCommand(this.command), choice); + }); + }, + + updateState: function(){ + this.inherited(arguments); + var _e = this.editor; + var _c = this.command; + if(!_e || !_e.isLoaded || !_c.length){ return; } + if(this.button){ + var value = _e.queryCommandValue(this.editor._normalizeCommand(_c)) || ""; + // strip off single quotes, if any + var quoted = dojo.isString(value) && value.match(/'([^']*)'/); + if(quoted){ value = quoted[1]; } +//console.log("selected " + value); + if(this.generic && _c == "fontName"){ + 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? + }; +//console.log("mapped to " + map[value]); + value = map[value] || value; + }else if(_c == "fontSize" && value.indexOf && value.indexOf("px") != -1){ + var pixels = parseInt(value); + value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value; + } + this.updating = true; + this.button.setValue(value); + delete this.updating; + } + + // FIXME: IE is *really* b0rken + if(dojo.isIE){ + this._savedSelection = this.editor._getBookmark(); + } + this._focusHandle = dijit.getFocus(this.editor.iframe); + }, + + setToolbar: function(){ + this.inherited(arguments); + + var forRef = this.button; + if(!forRef.id){ forRef.id = dijit._scopeName+"EditorButton-"+this.command+(this._uniqueId++); } //TODO: is this necessary? FilteringSelects always seem to have an id? + var label = dojo.doc.createElement("label"); + dojo.addClass(label, "dijit dijitReset dijitLeft dijitInline"); + label.setAttribute("for", forRef.id); + var strings = dojo.i18n.getLocalization("dijit._editor", "FontChoice"); + label.appendChild(dojo.doc.createTextNode(strings[this.command])); + dojo.place(label, this.button.domNode, "before"); + } + } +); + +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}); + } +}); + +} diff --git a/includes/js/dijit/_editor/plugins/LinkDialog.js b/includes/js/dijit/_editor/plugins/LinkDialog.js new file mode 100644 index 0000000..9015058 --- /dev/null +++ b/includes/js/dijit/_editor/plugins/LinkDialog.js @@ -0,0 +1,147 @@ +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.Dialog"); +dojo.require("dijit.form.Button"); +dojo.require("dijit.form.ValidationTextBox"); +dojo.require("dojo.i18n"); +dojo.require("dojo.string"); +dojo.requireLocalization("dijit._editor", "LinkDialog", null, "zh,pt,da,tr,ru,de,ROOT,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu"); + +dojo.declare("dijit._editor.plugins.LinkDialog", + dijit._editor._Plugin, + { + // summary: + // This plugin provides dialogs for inserting links and images into the editor + // + // description: + // The commands provided by this plugin are: + // * createLink + // * insertImage + + buttonClass: dijit.form.DropDownButton, + useDefaultCommand: false, + urlRegExp: "((https?|ftps?)\\://|)(([0-9a-zA-Z]([-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?\\.)+(arpa|aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|xxx|jobs|mobi|post|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|eu|es|et|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sk|sl|sm|sn|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)|(((\\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])))(\\:(0|[1-9]\\d*))?(/([^?#\\s/]+/)*)?([^?#\\s/]+(\\?[^?#\\s/]*)?(#[A-Za-z][\\w.:-]*)?)?", + 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'>", + "</td></tr><tr><td>", + "<label for='${id}_textInput'>${text}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' name='textInput'>", + "</td></tr><tr><td colspan='2'>", + "<button dojoType='dijit.form.Button' type='submit'>${set}</button>", + "</td></tr></table>" + ].join(""), + + _initButton: function(){ + var _this = this; + this.tag = this.command == 'insertImage' ? 'img' : 'a'; + var messages = 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); + }, + onClose: dojo.hitch(this, "_onCloseDialog") + })); + messages.urlRegExp = this.urlRegExp; + messages.id = dijit.getUniqueId(this.editor.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.inherited(arguments); + }, + + _setContent: function(staticPanel){ + this.dropDown.setContent(staticPanel); + }, + + setValue: function(args){ + // summary: callback from the dialog when user hits "set" button + //TODO: prevent closing popup if the text is empty + this._onCloseDialog(); + if(dojo.isIE){ //see #4151 + var a = dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.tag]); + if(a){ + dojo.withGlobal(this.editor.window, "selectElement", dijit._editor.selection, [a]); + } + } + args.tag = this.tag; + args.refAttr = this.tag == 'img' ? 'src' : 'href'; + //TODO: textInput should be formatted by escapeXml + var template = "<${tag} ${refAttr}='${urlInput}' _djrealurl='${urlInput}'" + + (args.tag == 'img' ? " alt='${textInput}'>" : ">${textInput}") + + "</${tag}>"; + this.editor.execCommand('inserthtml', dojo.string.substitute(template, args)); + }, + + _onCloseDialog: function(){ + // FIXME: IE is really messed up here!! + if(dojo.isIE){ + if("_savedSelection" in this){ + var b = this._savedSelection; + delete this._savedSelection; + this.editor.focus(); + this.editor._moveToBookmark(b); + } + }else{ + this.editor.focus(); + } + }, + + _onOpenDialog: function(){ + var a = dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.tag]); + var url, text; + if(a){ + url = a.getAttribute('_djrealurl'); + text = this.tag == 'img' ? a.getAttribute('alt') : 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); + } + // FIXME: IE is *really* b0rken + if(dojo.isIE){ + this._savedSelection = this.editor._getBookmark(); + } + this.dropDown.reset(); + this.dropDown.setValues({urlInput: url || '', textInput: text || ''}); + //dijit.focus(this.urlInput); + }/*, + +//TODO we don't show this state anymore + updateState: function(){ + // summary: change shading on button if we are over a link (or not) + + var _e = this.editor; + if(!_e || !_e.isLoaded){ return; } + if(this.button){ + // display button differently if there is an existing link associated with the current selection + var hasA = dojo.withGlobal(this.editor.window, "hasAncestorElement", dijit._editor.selection, [this.tag]); + this.button.setAttribute('checked', hasA); + } + } +*/ + } +); + +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + switch(o.args.name){ + case "createLink": case "insertImage": + o.plugin = new dijit._editor.plugins.LinkDialog({command: o.args.name}); + } +}); + +} diff --git a/includes/js/dijit/_editor/plugins/TextColor.js b/includes/js/dijit/_editor/plugins/TextColor.js new file mode 100644 index 0000000..fef3911 --- /dev/null +++ b/includes/js/dijit/_editor/plugins/TextColor.js @@ -0,0 +1,40 @@ +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, + { + // 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 + + buttonClass: dijit.form.DropDownButton, + +//TODO: set initial focus/selection state? + + constructor: function(){ + this.dropDown = new dijit.ColorPalette(); + this.connect(this.dropDown, "onChange", function(color){ + this.editor.execCommand(this.command, color); + }); + } + } +); + +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/includes/js/dijit/_editor/plugins/ToggleDir.js b/includes/js/dijit/_editor/plugins/ToggleDir.js new file mode 100644 index 0000000..7aaae70 --- /dev/null +++ b/includes/js/dijit/_editor/plugins/ToggleDir.js @@ -0,0 +1,40 @@ +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.experimental("dijit._editor.plugins.ToggleDir"); + +dojo.require("dijit._editor._Plugin"); + +dojo.declare("dijit._editor.plugins.ToggleDir", + dijit._editor._Plugin, + { + //summary: This plugin is used to toggle direction of the edited document only, + // no matter what direction the whole page is. + + useDefaultCommand: false, + command: "toggleDir", + + _initButton: function(){ + this.inherited("_initButton", arguments); + this.connect(this.button, "onClick", this._toggleDir); + }, + + updateState: function(){},//overwrite + + _toggleDir: function(){ + var editDoc = this.editor.editorObject.contentWindow.document.documentElement; + var isLtr = dojo.getComputedStyle(editDoc).direction == "ltr"; + editDoc.dir/*html node*/ = isLtr ? "rtl" : "ltr"; + } + } +); + +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}); + } +}); + +} |