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
|| 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', '
'); } 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
, 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| |\ \;)$/i); } return false; } var paragraphContainers = getParagraphParents(element); for(var i=0; i