diff options
Diffstat (limited to 'includes/js/dijit/_editor/RichText.js')
-rw-r--r-- | includes/js/dijit/_editor/RichText.js | 1449 |
1 files changed, 0 insertions, 1449 deletions
diff --git a/includes/js/dijit/_editor/RichText.js b/includes/js/dijit/_editor/RichText.js deleted file mode 100644 index 9ece365..0000000 --- a/includes/js/dijit/_editor/RichText.js +++ /dev/null @@ -1,1449 +0,0 @@ -if(!dojo._hasResource["dijit._editor.RichText"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dijit._editor.RichText"] = true; -dojo.provide("dijit._editor.RichText"); - -dojo.require("dijit._Widget"); -dojo.require("dijit._editor.selection"); -dojo.require("dijit._editor.html"); -dojo.require("dojo.i18n"); -dojo.requireLocalization("dijit.form", "Textarea", 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"); - -// used to restore content when user leaves this page then comes back -// but do not try doing dojo.doc.write if we are using xd loading. -// dojo.doc.write will only work if RichText.js is included in the dojo.js -// file. If it is included in dojo.js and you want to allow rich text saving -// for back/forward actions, then set dojo.config.allowXdRichTextSave = true. -if(!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"]){ - if(dojo._postLoad){ - (function(){ - var savetextarea = dojo.doc.createElement('textarea'); - savetextarea.id = dijit._scopeName + "._editor.RichText.savedContent"; - var s = savetextarea.style; - s.display='none'; - s.position='absolute'; - s.top="-100px"; - s.left="-100px"; - s.height="3px"; - s.width="3px"; - dojo.body().appendChild(savetextarea); - })(); - }else{ - //dojo.body() is not available before onLoad is fired - try{ - dojo.doc.write('<textarea id="' + dijit._scopeName + '._editor.RichText.savedContent" ' + - 'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>'); - }catch(e){ } - } -} -dojo.declare("dijit._editor.RichText", dijit._Widget, { - constructor: function(){ - // summary: - // dijit._editor.RichText is the core of the WYSIWYG editor in dojo, which - // provides the basic editing features. It also encapsulates the differences - // of different js engines for various browsers - // - // contentPreFilters: Array - // pre content filter function register array. - // these filters will be executed before the actual - // editing area get the html content - this.contentPreFilters = []; - - // contentPostFilters: Array - // post content filter function register array. - // these will be used on the resulting html - // from contentDomPostFilters. The resuling - // content is the final html (returned by getValue()) - this.contentPostFilters = []; - - // contentDomPreFilters: Array - // pre content dom filter function register array. - // these filters are applied after the result from - // contentPreFilters are set to the editing area - this.contentDomPreFilters = []; - - // contentDomPostFilters: Array - // post content dom filter function register array. - // these filters are executed on the editing area dom - // the result from these will be passed to contentPostFilters - this.contentDomPostFilters = []; - - // editingAreaStyleSheets: Array - // array to store all the stylesheets applied to the editing area - this.editingAreaStyleSheets=[]; - - this._keyHandlers = {}; - this.contentPreFilters.push(dojo.hitch(this, "_preFixUrlAttributes")); - if(dojo.isMoz){ - this.contentPreFilters.push(this._fixContentForMoz); - this.contentPostFilters.push(this._removeMozBogus); - }else if(dojo.isSafari){ - this.contentPostFilters.push(this._removeSafariBogus); - } - //this.contentDomPostFilters.push(this._postDomFixUrlAttributes); - - this.onLoadDeferred = new dojo.Deferred(); - }, - - // inheritWidth: Boolean - // whether to inherit the parent's width or simply use 100% - inheritWidth: false, - - // focusOnLoad: Boolean - // whether focusing into this instance of richtext when page onload - focusOnLoad: false, - - // name: String - // If a save name is specified the content is saved and restored when the user - // leave this page can come back, or if the editor is not properly closed after - // editing has started. - name: "", - - // styleSheets: String - // semicolon (";") separated list of css files for the editing area - styleSheets: "", - - // _content: String - // temporary content storage - _content: "", - - // height: String - // set height to fix the editor at a specific height, with scrolling. - // By default, this is 300px. If you want to have the editor always - // resizes to accommodate the content, use AlwaysShowToolbar plugin - // and set height="" - height: "300px", - - // minHeight: String - // The minimum height that the editor should have - minHeight: "1em", - - // isClosed: Boolean - isClosed: true, - - // isLoaded: Boolean - isLoaded: false, - - // _SEPARATOR: String - // used to concat contents from multiple textareas into a single string - _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@", - - // onLoadDeferred: dojo.Deferred - // deferred which is fired when the editor finishes loading - onLoadDeferred: null, - - postCreate: function(){ - // summary: init - dojo.publish(dijit._scopeName + "._editor.RichText::init", [this]); - this.open(); - this.setupDefaultShortcuts(); - }, - - setupDefaultShortcuts: function(){ - // summary: add some default key handlers - // description: - // Overwrite this to setup your own handlers. The default - // implementation does not use Editor commands, but directly - // executes the builtin commands within the underlying browser - // support. - var exec = function(cmd, arg){ - return arguments.length == 1 ? function(){ this.execCommand(cmd); } : - function(){ this.execCommand(cmd, arg); }; - }; - - var ctrlKeyHandlers = { b: exec("bold"), - i: exec("italic"), - u: exec("underline"), - a: exec("selectall"), - s: function(){ this.save(true); }, - - "1": exec("formatblock", "h1"), - "2": exec("formatblock", "h2"), - "3": exec("formatblock", "h3"), - "4": exec("formatblock", "h4"), - - "\\": exec("insertunorderedlist") }; - - if(!dojo.isIE){ - ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo? - } - - for(var key in ctrlKeyHandlers){ - this.addKeyHandler(key, this.KEY_CTRL, ctrlKeyHandlers[key]); - } - }, - - // events: Array - // events which should be connected to the underlying editing area - events: ["onKeyPress", "onKeyDown", "onKeyUp", "onClick"], - - // events: Array - // events which should be connected to the underlying editing - // area, events in this array will be addListener with - // capture=true - captureEvents: [], - - _editorCommandsLocalized: false, - _localizeEditorCommands: function(){ - if(this._editorCommandsLocalized){ - return; - } - this._editorCommandsLocalized = true; - - //in IE, names for blockformat is locale dependent, so we cache the values here - - //if the normal way fails, we try the hard way to get the list - - //do not use _cacheLocalBlockFormatNames here, as it will - //trigger security warning in IE7 - - //in the array below, ul can not come directly after ol, - //otherwise the queryCommandValue returns Normal for it - var formats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'div', 'ul']; - var localhtml = "", format, i=0; - while((format=formats[i++])){ - if(format.charAt(1) != 'l'){ - localhtml += "<"+format+"><span>content</span></"+format+">"; - }else{ - localhtml += "<"+format+"><li>content</li></"+format+">"; - } - } - //queryCommandValue returns empty if we hide editNode, so move it out of screen temporary - var div=dojo.doc.createElement('div'); - div.style.position = "absolute"; - div.style.left = "-2000px"; - div.style.top = "-2000px"; - dojo.doc.body.appendChild(div); - div.innerHTML = localhtml; - var node = div.firstChild; - while(node){ - dijit._editor.selection.selectElement(node.firstChild); - dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [node.firstChild]); - var nativename = node.tagName.toLowerCase(); - this._local2NativeFormatNames[nativename] = dojo.doc.queryCommandValue("formatblock");//this.queryCommandValue("formatblock"); - this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename; - node = node.nextSibling; - } - dojo.doc.body.removeChild(div); - }, - - open: function(/*DomNode?*/element){ - // summary: - // Transforms the node referenced in this.domNode into a rich text editing - // node. This will result in the creation and replacement with an <iframe> - // if designMode(FF)/contentEditable(IE) is used. - - if((!this.onLoadDeferred)||(this.onLoadDeferred.fired >= 0)){ - this.onLoadDeferred = new dojo.Deferred(); - } - - if(!this.isClosed){ this.close(); } - dojo.publish(dijit._scopeName + "._editor.RichText::open", [ this ]); - - this._content = ""; - if((arguments.length == 1)&&(element["nodeName"])){ this.domNode = element; } // else unchanged - - var html; - if( (this.domNode["nodeName"])&& - (this.domNode.nodeName.toLowerCase() == "textarea")){ - // if we were created from a textarea, then we need to create a - // new editing harness node. - this.textarea = this.domNode; - this.name=this.textarea.name; - html = this._preFilterContent(this.textarea.value); - this.domNode = dojo.doc.createElement("div"); - this.domNode.setAttribute('widgetId',this.id); - this.textarea.removeAttribute('widgetId'); - this.domNode.cssText = this.textarea.cssText; - this.domNode.className += " "+this.textarea.className; - dojo.place(this.domNode, this.textarea, "before"); - var tmpFunc = dojo.hitch(this, function(){ - //some browsers refuse to submit display=none textarea, so - //move the textarea out of screen instead - dojo.attr(this.textarea, 'tabIndex', '-1'); - with(this.textarea.style){ - display = "block"; - position = "absolute"; - left = top = "-1000px"; - - if(dojo.isIE){ //nasty IE bug: abnormal formatting if overflow is not hidden - this.__overflow = overflow; - overflow = "hidden"; - } - } - }); - if(dojo.isIE){ - setTimeout(tmpFunc, 10); - }else{ - tmpFunc(); - } - - // this.domNode.innerHTML = html; - -// if(this.textarea.form){ -// // FIXME: port: this used to be before advice!!! -// dojo.connect(this.textarea.form, "onsubmit", this, function(){ -// // FIXME: should we be calling close() here instead? -// this.textarea.value = this.getValue(); -// }); -// } - }else{ - html = this._preFilterContent(dijit._editor.getChildrenHtml(this.domNode)); - this.domNode.innerHTML = ''; - } - if(html == ""){ html = " "; } - - var content = dojo.contentBox(this.domNode); - // var content = dojo.contentBox(this.srcNodeRef); - this._oldHeight = content.h; - this._oldWidth = content.w; - - // If we're a list item we have to put in a blank line to force the - // bullet to nicely align at the top of text - if( (this.domNode["nodeName"]) && - (this.domNode.nodeName == "LI") ){ - this.domNode.innerHTML = " <br>"; - } - - this.editingArea = dojo.doc.createElement("div"); - this.domNode.appendChild(this.editingArea); - - if(this.name != "" && (!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"])){ - var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent"); - if(saveTextarea.value != ""){ - var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat; - while((dat=datas[i++])){ - var data = dat.split(":"); - if(data[0] == this.name){ - html = data[1]; - datas.splice(i, 1); - break; - } - } - } - - // FIXME: need to do something different for Opera/Safari - this.connect(window, "onbeforeunload", "_saveContent"); - // dojo.connect(window, "onunload", this, "_saveContent"); - } - - this.isClosed = false; - // Safari's selections go all out of whack if we do it inline, - // so for now IE is our only hero - //if(typeof dojo.doc.body.contentEditable != "undefined"){ - if(dojo.isIE || dojo.isSafari || dojo.isOpera){ // contentEditable, easy - - if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){ - console.debug("dijit._editor.RichText: When using cross-domain Dojo builds," - + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl" - + " to the path on your domain to blank.html"); - } - - var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+""); - var ifr = this.editorObject = this.iframe = dojo.doc.createElement('iframe'); - ifr.id = this.id+"_iframe"; - ifr.src = burl; - ifr.style.border = "none"; - ifr.style.width = "100%"; - ifr.frameBorder = 0; - // ifr.style.scrolling = this.height ? "auto" : "vertical"; - this.editingArea.appendChild(ifr); - var h = null; // set later in non-ie6 branch - var loadFunc = dojo.hitch( this, function(){ - if(h){ dojo.disconnect(h); h = null; } - this.window = ifr.contentWindow; - var d = this.document = this.window.document; - d.open(); - d.write(this._getIframeDocTxt(html)); - d.close(); - - if(dojo.isIE >= 7){ - if(this.height){ - ifr.style.height = this.height; - } - if(this.minHeight){ - ifr.style.minHeight = this.minHeight; - } - }else{ - ifr.style.height = this.height ? this.height : this.minHeight; - } - - if(dojo.isIE){ - this._localizeEditorCommands(); - } - - this.onLoad(); - this.savedContent = this.getValue(true); - }); - if(dojo.isIE && dojo.isIE < 7){ // IE 6 is a steaming pile... - var t = setInterval(function(){ - if(ifr.contentWindow.isLoaded){ - clearInterval(t); - loadFunc(); - } - }, 100); - }else{ // blissful sanity! - h = dojo.connect( - ((dojo.isIE) ? ifr.contentWindow : ifr), "onload", loadFunc - ); - } - }else{ // designMode in iframe - this._drawIframe(html); - this.savedContent = this.getValue(true); - } - - // TODO: this is a guess at the default line-height, kinda works - if(this.domNode.nodeName == "LI"){ this.domNode.lastChild.style.marginTop = "-1.2em"; } - this.domNode.className += " RichTextEditable"; - }, - - //static cache variables shared among all instance of this class - _local2NativeFormatNames: {}, - _native2LocalFormatNames: {}, - _localizedIframeTitles: null, - - _getIframeDocTxt: function(/* String */ html){ - var _cs = dojo.getComputedStyle(this.domNode); - if(dojo.isIE || (!this.height && !dojo.isMoz)){ - html="<div>"+html+"</div>"; - } - var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" "); - - // line height is tricky - applying a units value will mess things up. - // if we can't get a non-units value, bail out. - var lineHeight = _cs.lineHeight; - if(lineHeight.indexOf("px") >= 0){ - lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize); - // console.debug(lineHeight); - }else if(lineHeight.indexOf("em")>=0){ - lineHeight = parseFloat(lineHeight); - }else{ - lineHeight = "1.0"; - } - return [ - this.isLeftToRight() ? "<html><head>" : "<html dir='rtl'><head>", - (dojo.isMoz ? "<title>" + this._localizedIframeTitles.iframeEditTitle + "</title>" : ""), - "<style>", - "body,html {", - " background:transparent;", - " font:", font, ";", - " padding: 1em 0 0 0;", - " margin: -1em 0 0 0;", // remove extraneous vertical scrollbar on safari and firefox - " height: 100%;", - "}", - // TODO: left positioning will cause contents to disappear out of view - // if it gets too wide for the visible area - "body{", - " top:0px; left:0px; right:0px;", - ((this.height||dojo.isOpera) ? "" : "position: fixed;"), - // FIXME: IE 6 won't understand min-height? - " min-height:", this.minHeight, ";", - " line-height:", lineHeight, - "}", - "p{ margin: 1em 0 !important; }", - (this.height ? // height:auto undoes the height:100% - "" : "body,html{height:auto;overflow-y:hidden;/*for IE*/} body > div {overflow-x:auto;/*for FF to show vertical scrollbar*/}" - ), - "li > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; } ", - "li{ min-height:1.2em; }", - "</style>", - this._applyEditingAreaStyleSheets(), - "</head><body>"+html+"</body></html>" - ].join(""); // String - }, - - _drawIframe: function(/*String*/html){ - // summary: - // Draws an iFrame using the existing one if one exists. - // Used by Mozilla, Safari, and Opera - - if(!this.iframe){ - var ifr = this.iframe = dojo.doc.createElement("iframe"); - ifr.id=this.id; - // this.iframe.src = "about:blank"; - // dojo.doc.body.appendChild(this.iframe); - // console.debug(this.iframe.contentDocument.open()); - // dojo.body().appendChild(this.iframe); - var ifrs = ifr.style; - // ifrs.border = "1px solid black"; - ifrs.border = "none"; - ifrs.lineHeight = "0"; // squash line height - ifrs.verticalAlign = "bottom"; -// ifrs.scrolling = this.height ? "auto" : "vertical"; - this.editorObject = this.iframe; - // get screen reader text for mozilla here, too - this._localizedIframeTitles = dojo.i18n.getLocalization("dijit.form", "Textarea"); - // need to find any associated label element and update iframe document title - var label=dojo.query('label[for="'+this.id+'"]'); - if(label.length){ - this._localizedIframeTitles.iframeEditTitle = label[0].innerHTML + " " + this._localizedIframeTitles.iframeEditTitle; - } - } - // opera likes this to be outside the with block - // this.iframe.src = "javascript:void(0)";//dojo.uri.dojoUri("src/widget/templates/richtextframe.html") + ((dojo.doc.domain != currentDomain) ? ("#"+dojo.doc.domain) : ""); - this.iframe.style.width = this.inheritWidth ? this._oldWidth : "100%"; - - if(this.height){ - this.iframe.style.height = this.height; - }else{ - this.iframe.height = this._oldHeight; - } - - var tmpContent; - if(this.textarea){ - tmpContent = this.srcNodeRef; - }else{ - tmpContent = dojo.doc.createElement('div'); - tmpContent.style.display="none"; - tmpContent.innerHTML = html; - //append tmpContent to under the current domNode so that the margin - //calculation below is correct - this.editingArea.appendChild(tmpContent); - } - - this.editingArea.appendChild(this.iframe); - - //do we want to show the content before the editing area finish loading here? - //if external style sheets are used for the editing area, the appearance now - //and after loading of the editing area won't be the same (and padding/margin - //calculation above may not be accurate) - // tmpContent.style.display = "none"; - // this.editingArea.appendChild(this.iframe); - - var _iframeInitialized = false; - // console.debug(this.iframe); - // var contentDoc = this.iframe.contentWindow.document; - - - // note that on Safari lower than 420+, we have to get the iframe - // by ID in order to get something w/ a contentDocument property - - var contentDoc = this.iframe.contentDocument; - contentDoc.open(); - if(dojo.isAIR){ - contentDoc.body.innerHTML = html; - }else{ - contentDoc.write(this._getIframeDocTxt(html)); - } - contentDoc.close(); - - // now we wait for onload. Janky hack! - var ifrFunc = dojo.hitch(this, function(){ - if(!_iframeInitialized){ - _iframeInitialized = true; - }else{ return; } - if(!this.editNode){ - try{ - if(this.iframe.contentWindow){ - this.window = this.iframe.contentWindow; - this.document = this.iframe.contentWindow.document - }else if(this.iframe.contentDocument){ - // for opera - this.window = this.iframe.contentDocument.window; - this.document = this.iframe.contentDocument; - } - if(!this.document.body){ - throw 'Error'; - } - }catch(e){ - setTimeout(ifrFunc,500); - _iframeInitialized = false; - return; - } - - dojo._destroyElement(tmpContent); - this.onLoad(); - }else{ - dojo._destroyElement(tmpContent); - this.editNode.innerHTML = html; - this.onDisplayChanged(); - } - this._preDomFilterContent(this.editNode); - }); - - ifrFunc(); - }, - - _applyEditingAreaStyleSheets: function(){ - // summary: - // apply the specified css files in styleSheets - var files = []; - if(this.styleSheets){ - files = this.styleSheets.split(';'); - this.styleSheets = ''; - } - - //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet - files = files.concat(this.editingAreaStyleSheets); - this.editingAreaStyleSheets = []; - - var text='', i=0, url; - while((url=files[i++])){ - var abstring = (new dojo._Url(dojo.global.location, url)).toString(); - this.editingAreaStyleSheets.push(abstring); - text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>' - } - return text; - }, - - addStyleSheet: function(/*dojo._Url*/uri){ - // summary: - // add an external stylesheet for the editing area - // uri: a dojo.uri.Uri pointing to the url of the external css file - var url=uri.toString(); - - //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe - if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){ - url = (new dojo._Url(dojo.global.location, url)).toString(); - } - - if(dojo.indexOf(this.editingAreaStyleSheets, url) > -1){ -// console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied"); - return; - } - - this.editingAreaStyleSheets.push(url); - if(this.document.createStyleSheet){ //IE - this.document.createStyleSheet(url); - }else{ //other browser - var head = this.document.getElementsByTagName("head")[0]; - var stylesheet = this.document.createElement("link"); - with(stylesheet){ - rel="stylesheet"; - type="text/css"; - href=url; - } - head.appendChild(stylesheet); - } - }, - - removeStyleSheet: function(/*dojo._Url*/uri){ - // summary: - // remove an external stylesheet for the editing area - var url=uri.toString(); - //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe - if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){ - url = (new dojo._Url(dojo.global.location, url)).toString(); - } - var index = dojo.indexOf(this.editingAreaStyleSheets, url); - if(index == -1){ -// console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied"); - return; - } - delete this.editingAreaStyleSheets[index]; - dojo.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan() - }, - - disabled: true, - _mozSettingProps: ['styleWithCSS','insertBrOnReturn'], - setDisabled: function(/*Boolean*/ disabled){ - if(dojo.isIE || dojo.isSafari || dojo.isOpera){ - if(dojo.isIE){ this.editNode.unselectable = "on"; } // prevent IE from setting focus - this.editNode.contentEditable = !disabled; - if(dojo.isIE){ - var _this = this; - setTimeout(function(){ _this.editNode.unselectable = "off"; }, 0); - } - }else{ //moz - if(disabled){ - //AP: why isn't this set in the constructor, or put in mozSettingProps as a hash? - this._mozSettings=[false,this.blockNodeForEnter==='BR']; - } - this.document.designMode=(disabled?'off':'on'); - if(!disabled && this._mozSettings){ - dojo.forEach(this._mozSettingProps, function(s,i){ - this.document.execCommand(s,false,this._mozSettings[i]); - },this); - } -// this.document.execCommand('contentReadOnly', false, disabled); -// if(disabled){ -// this.blur(); //to remove the blinking caret -// } - } - this.disabled = disabled; - }, - -/* Event handlers - *****************/ - - _isResized: function(){ return false; }, - - onLoad: function(/* Event */ e){ - // summary: handler after the content of the document finishes loading - this.isLoaded = true; - if(!this.window.__registeredWindow){ - this.window.__registeredWindow=true; - dijit.registerWin(this.window); - } - if(!dojo.isIE && (this.height || dojo.isMoz)){ - this.editNode=this.document.body; - }else{ - this.editNode=this.document.body.firstChild; - var _this = this; - if(dojo.isIE){ // #4996 IE wants to focus the BODY tag - var tabStop = this.tabStop = dojo.doc.createElement('<div tabIndex=-1>'); - this.editingArea.appendChild(tabStop); - this.iframe.onfocus = function(){ _this.editNode.setActive(); } - } - } - - try{ - this.setDisabled(false); - }catch(e){ - // Firefox throws an exception if the editor is initially hidden - // so, if this fails, try again onClick by adding "once" advice - var handle = dojo.connect(this, "onClick", this, function(){ - this.setDisabled(false); - dojo.disconnect(handle); - }); - } - - this._preDomFilterContent(this.editNode); - - var events=this.events.concat(this.captureEvents),i=0,et; - while((et=events[i++])){ - this.connect(this.document, et.toLowerCase(), et); - } - if(!dojo.isIE){ - try{ // sanity check for Mozilla - //AP: what's the point of this? -// this.document.execCommand("useCSS", false, true); // old moz call - this.document.execCommand("styleWithCSS", false, false); // new moz call - //this.document.execCommand("insertBrOnReturn", false, false); // new moz call - }catch(e2){ } - // FIXME: when scrollbars appear/disappear this needs to be fired - }else{ // IE contentEditable - // give the node Layout on IE - this.connect(this.document, "onmousedown", "_onMouseDown"); // #4996 fix focus - this.editNode.style.zoom = 1.0; - } - - if(this.focusOnLoad){ - setTimeout(dojo.hitch(this, "focus"), 0); // have to wait for IE to set unselectable=off - } - - this.onDisplayChanged(e); - if(this.onLoadDeferred){ - this.onLoadDeferred.callback(true); - } - }, - - onKeyDown: function(/* Event */ e){ - // summary: Fired on keydown - - // we need this event at the moment to get the events from control keys - // such as the backspace. It might be possible to add this to Dojo, so that - // keyPress events can be emulated by the keyDown and keyUp detection. - if(dojo.isIE){ - if(e.keyCode == dojo.keys.TAB && e.shiftKey && !e.ctrlKey && !e.altKey){ - // focus the BODY so the browser will tab away from it instead - this.iframe.focus(); - }else if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey){ - // focus the BODY so the browser will tab away from it instead - this.tabStop.focus(); - }else if(e.keyCode === dojo.keys.BACKSPACE && this.document.selection.type === "Control"){ - // IE has a bug where if a non-text object is selected in the editor, - // hitting backspace would act as if the browser's back button was - // clicked instead of deleting the object. see #1069 - dojo.stopEvent(e); - this.execCommand("delete"); - }else if((65 <= e.keyCode&&e.keyCode <= 90) || - (e.keyCode>=37&&e.keyCode<=40) // FIXME: get this from connect() instead! - ){ //arrow keys - e.charCode = e.keyCode; - this.onKeyPress(e); - } - }else if(dojo.isMoz){ - if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey && this.iframe){ - // update iframe document title for screen reader - this.iframe.contentDocument.title = this._localizedIframeTitles.iframeFocusTitle; - - // Place focus on the iframe. A subsequent tab or shift tab will put focus - // on the correct control. - this.iframe.focus(); // this.focus(); won't work - dojo.stopEvent(e); - }else if(e.keyCode == dojo.keys.TAB && e.shiftKey){ - // if there is a toolbar, set focus to it, otherwise ignore - if(this.toolbar){ - this.toolbar.focus(); - } - dojo.stopEvent(e); - } - } - }, - - onKeyUp: function(e){ - // summary: Fired on keyup - return; - }, - - KEY_CTRL: 1, - KEY_SHIFT: 2, - - onKeyPress: function(e){ - // summary: Fired on keypress - - // handle the various key events - var modifiers = (e.ctrlKey && !e.altKey) ? this.KEY_CTRL : 0 | e.shiftKey ? this.KEY_SHIFT : 0; - - var key = e.keyChar || e.keyCode; - if(this._keyHandlers[key]){ - // console.debug("char:", e.key); - var handlers = this._keyHandlers[key], i = 0, h; - while((h = handlers[i++])){ - if(modifiers == h.modifiers){ - if(!h.handler.apply(this,arguments)){ - e.preventDefault(); - } - break; - } - } - } - - // function call after the character has been inserted - setTimeout(dojo.hitch(this, function(){ - this.onKeyPressed(e); - }), 1); - }, - - addKeyHandler: function(/*String*/key, /*Int*/modifiers, /*Function*/handler){ - // summary: add a handler for a keyboard shortcut - if(!dojo.isArray(this._keyHandlers[key])){ this._keyHandlers[key] = []; } - this._keyHandlers[key].push({ - modifiers: modifiers || 0, - handler: handler - }); - }, - - onKeyPressed: function(/*Event*/e){ - this.onDisplayChanged(/*e*/); // can't pass in e - }, - - onClick: function(/*Event*/e){ -// console.info('onClick',this._tryDesignModeOn); - this.onDisplayChanged(e); - }, - - _onMouseDown: function(/*Event*/e){ // IE only to prevent 2 clicks to focus - if(!this._focused && !this.disabled){ - this.focus(); - } - }, - - _onBlur: function(e){ - this.inherited(arguments); - var _c=this.getValue(true); - if(_c!=this.savedContent){ - this.onChange(_c); - this.savedContent=_c; - } - if(dojo.isMoz && this.iframe){ - this.iframe.contentDocument.title = this._localizedIframeTitles.iframeEditTitle; - } - }, - _initialFocus: true, - _onFocus: function(/*Event*/e){ - // summary: Fired on focus - this.inherited(arguments); - if(dojo.isMoz && this._initialFocus){ - this._initialFocus = false; - if(this.editNode.innerHTML.replace(/^\s+|\s+$/g, "") == " "){ - this.placeCursorAtStart(); -// this.execCommand("selectall"); -// this.window.getSelection().collapseToStart(); - } - } - }, - - // TODO: why is this needed - should we deprecate this ? - blur: function(){ - // summary: remove focus from this instance - if(!dojo.isIE && this.window.document.documentElement && this.window.document.documentElement.focus){ - this.window.document.documentElement.focus(); - }else if(dojo.doc.body.focus){ - dojo.doc.body.focus(); - } - }, - - focus: function(){ - // summary: move focus to this instance - if(!dojo.isIE){ - dijit.focus(this.iframe); - }else if(this.editNode && this.editNode.focus){ - // editNode may be hidden in display:none div, lets just punt in this case - //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe - // if we fire the event manually and let the browser handle the focusing, the latest - // cursor position is focused like in FF - this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE -// }else{ -// TODO: should we throw here? -// console.debug("Have no idea how to focus into the editor!"); - } - }, - -// _lastUpdate: 0, - updateInterval: 200, - _updateTimer: null, - onDisplayChanged: function(/*Event*/e){ - // summary: - // This event will be fired everytime the display context - // changes and the result needs to be reflected in the UI. - // description: - // If you don't want to have update too often, - // onNormalizedDisplayChanged should be used instead - -// var _t=new Date(); - if(!this._updateTimer){ -// this._lastUpdate=_t; - if(this._updateTimer){ - clearTimeout(this._updateTimer); - } - this._updateTimer=setTimeout(dojo.hitch(this,this.onNormalizedDisplayChanged),this.updateInterval); - } - }, - onNormalizedDisplayChanged: function(){ - // summary: - // This event is fired every updateInterval ms or more - // description: - // If something needs to happen immidiately after a - // user change, please use onDisplayChanged instead - this._updateTimer=null; - }, - onChange: function(newContent){ - // summary: - // this is fired if and only if the editor loses focus and - // the content is changed - -// console.log('onChange',newContent); - }, - _normalizeCommand: function(/*String*/cmd){ - // summary: - // Used as the advice function by dojo.connect to map our - // normalized set of commands to those supported by the target - // browser - - var command = cmd.toLowerCase(); - if(command == "hilitecolor" && !dojo.isMoz){ - command = "backcolor"; - } - - return command; - }, - - queryCommandAvailable: function(/*String*/command){ - // summary: - // Tests whether a command is supported by the host. Clients SHOULD check - // whether a command is supported before attempting to use it, behaviour - // for unsupported commands is undefined. - // command: The command to test for - var ie = 1; - var mozilla = 1 << 1; - var safari = 1 << 2; - var opera = 1 << 3; - var safari420 = 1 << 4; - - var gt420 = dojo.isSafari; - - function isSupportedBy(browsers){ - return { - ie: Boolean(browsers & ie), - mozilla: Boolean(browsers & mozilla), - safari: Boolean(browsers & safari), - safari420: Boolean(browsers & safari420), - opera: Boolean(browsers & opera) - } - } - - var supportedBy = null; - - switch(command.toLowerCase()){ - case "bold": case "italic": case "underline": - case "subscript": case "superscript": - case "fontname": case "fontsize": - case "forecolor": case "hilitecolor": - case "justifycenter": case "justifyfull": case "justifyleft": - case "justifyright": case "delete": case "selectall": case "toggledir": - supportedBy = isSupportedBy(mozilla | ie | safari | opera); - break; - - case "createlink": case "unlink": case "removeformat": - case "inserthorizontalrule": case "insertimage": - case "insertorderedlist": case "insertunorderedlist": - case "indent": case "outdent": case "formatblock": - case "inserthtml": case "undo": case "redo": case "strikethrough": - supportedBy = isSupportedBy(mozilla | ie | opera | safari420); - break; - - case "blockdirltr": case "blockdirrtl": - case "dirltr": case "dirrtl": - case "inlinedirltr": case "inlinedirrtl": - supportedBy = isSupportedBy(ie); - break; - case "cut": case "copy": case "paste": - supportedBy = isSupportedBy( ie | mozilla | safari420); - break; - - case "inserttable": - supportedBy = isSupportedBy(mozilla | ie); - break; - - case "insertcell": case "insertcol": case "insertrow": - case "deletecells": case "deletecols": case "deleterows": - case "mergecells": case "splitcell": - supportedBy = isSupportedBy(ie | mozilla); - break; - - default: return false; - } - - return (dojo.isIE && supportedBy.ie) || - (dojo.isMoz && supportedBy.mozilla) || - (dojo.isSafari && supportedBy.safari) || - (gt420 && supportedBy.safari420) || - (dojo.isOpera && supportedBy.opera); // Boolean return true if the command is supported, false otherwise - }, - - execCommand: function(/*String*/command, argument){ - // summary: Executes a command in the Rich Text area - // command: The command to execute - // argument: An optional argument to the command - var returnValue; - - //focus() is required for IE to work - //In addition, focus() makes sure after the execution of - //the command, the editor receives the focus as expected - this.focus(); - - command = this._normalizeCommand(command); - if(argument != undefined){ - if(command == "heading"){ - throw new Error("unimplemented"); - }else if((command == "formatblock") && dojo.isIE){ - argument = '<'+argument+'>'; - } - } - if(command == "inserthtml"){ - argument=this._preFilterContent(argument); - if(dojo.isIE){ - var insertRange = this.document.selection.createRange(); - if(this.document.selection.type.toUpperCase()=='CONTROL'){ - var n=insertRange.item(0); - while(insertRange.length){ - insertRange.remove(insertRange.item(0)); - } - n.outerHTML=argument; - }else{ - insertRange.pasteHTML(argument); - } - insertRange.select(); - //insertRange.collapse(true); - returnValue=true; - }else if(dojo.isMoz && !argument.length){ - //mozilla can not inserthtml an empty html to delete current selection - //so we delete the selection instead in this case - dojo.withGlobal(this.window,'remove',dijit._editor.selection); - returnValue=true; - }else{ - returnValue=this.document.execCommand(command, false, argument); - } - }else if( - (command == "unlink")&& - (this.queryCommandEnabled("unlink"))&& - (dojo.isMoz || dojo.isSafari) - ){ - // fix up unlink in Mozilla to unlink the link and not just the selection - - // grab selection - // Mozilla gets upset if we just store the range so we have to - // get the basic properties and recreate to save the selection - var selection = this.window.getSelection(); - // var selectionRange = selection.getRangeAt(0); - // var selectionStartContainer = selectionRange.startContainer; - // var selectionStartOffset = selectionRange.startOffset; - // var selectionEndContainer = selectionRange.endContainer; - // var selectionEndOffset = selectionRange.endOffset; - - // select our link and unlink - var a = dojo.withGlobal(this.window, "getAncestorElement",dijit._editor.selection, ['a']); - dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [a]); - - returnValue=this.document.execCommand("unlink", false, null); - }else if((command == "hilitecolor")&&(dojo.isMoz)){ -// // mozilla doesn't support hilitecolor properly when useCSS is -// // set to false (bugzilla #279330) - - this.document.execCommand("styleWithCSS", false, true); - returnValue = this.document.execCommand(command, false, argument); - this.document.execCommand("styleWithCSS", false, false); - - }else if((dojo.isIE)&&( (command == "backcolor")||(command == "forecolor") )){ - // Tested under IE 6 XP2, no problem here, comment out - // IE weirdly collapses ranges when we exec these commands, so prevent it -// var tr = this.document.selection.createRange(); - argument = arguments.length > 1 ? argument : null; - returnValue = this.document.execCommand(command, false, argument); - - // timeout is workaround for weird IE behavior were the text - // selection gets correctly re-created, but subsequent input - // apparently isn't bound to it -// setTimeout(function(){tr.select();}, 1); - }else{ - argument = arguments.length > 1 ? argument : null; -// if(dojo.isMoz){ -// this.document = this.iframe.contentWindow.document -// } - - if(argument || command!="createlink"){ - returnValue = this.document.execCommand(command, false, argument); - } - } - - this.onDisplayChanged(); - return returnValue; - }, - - queryCommandEnabled: function(/*String*/command){ - // summary: check whether a command is enabled or not - - if(this.disabled){ return false; } - command = this._normalizeCommand(command); - if(dojo.isMoz || dojo.isSafari){ - if(command == "unlink"){ // mozilla returns true always - // console.debug(dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, ['a'])); - return dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, ['a']); - }else if(command == "inserttable"){ - return true; - } - } - //see #4109 - if(dojo.isSafari){ - if(command == "copy"){ - command = "cut"; - }else if(command == "paste"){ - return true; - } - } - - // return this.document.queryCommandEnabled(command); - var elem = dojo.isIE ? this.document.selection.createRange() : this.document; - return elem.queryCommandEnabled(command); - }, - - queryCommandState: function(command){ - // summary: check the state of a given command - - if(this.disabled){ return false; } - command = this._normalizeCommand(command); - return this.document.queryCommandState(command); - }, - - queryCommandValue: function(command){ - // summary: check the value of a given command - - if(this.disabled){ return false; } - command = this._normalizeCommand(command); - if(dojo.isIE && command == "formatblock"){ - return this._local2NativeFormatNames[this.document.queryCommandValue(command)]; - } - return this.document.queryCommandValue(command); - }, - - // Misc. - - placeCursorAtStart: function(){ - // summary: - // place the cursor at the start of the editing area - this.focus(); - - //see comments in placeCursorAtEnd - var isvalid=false; - if(dojo.isMoz){ - var first=this.editNode.firstChild; - while(first){ - if(first.nodeType == 3){ - if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){ - isvalid=true; - dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [first]); - break; - } - }else if(first.nodeType == 1){ - isvalid=true; - dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [first]); - break; - } - first = first.nextSibling; - } - }else{ - isvalid=true; - dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]); - } - if(isvalid){ - dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [true]); - } - }, - - placeCursorAtEnd: function(){ - // summary: - // place the cursor at the end of the editing area - this.focus(); - - //In mozilla, if last child is not a text node, we have to use selectElementChildren on this.editNode.lastChild - //otherwise the cursor would be placed at the end of the closing tag of this.editNode.lastChild - var isvalid=false; - if(dojo.isMoz){ - var last=this.editNode.lastChild; - while(last){ - if(last.nodeType == 3){ - if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){ - isvalid=true; - dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]); - break; - } - }else if(last.nodeType == 1){ - isvalid=true; - if(last.lastChild){ - dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last.lastChild]); - }else{ - dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]); - } - break; - } - last = last.previousSibling; - } - }else{ - isvalid=true; - dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]); - } - if(isvalid){ - dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [false]); - } - }, - - getValue: function(/*Boolean?*/nonDestructive){ - // summary: - // return the current content of the editing area (post filters are applied) - if(this.textarea){ - if(this.isClosed || !this.isLoaded){ - return this.textarea.value; - } - } - - return this._postFilterContent(null, nonDestructive); - }, - - setValue: function(/*String*/html){ - // summary: - // this function set the content. No undo history is preserved - - if(!this.isLoaded){ - // try again after the editor is finished loading - this.onLoadDeferred.addCallback(dojo.hitch(this, function(){ - this.setValue(html); - })); - return; - } - - if(this.textarea && (this.isClosed || !this.isLoaded)){ - this.textarea.value=html; - }else{ - html = this._preFilterContent(html); - var node = this.isClosed ? this.domNode : this.editNode; - node.innerHTML = html; - this._preDomFilterContent(node); - } - - this.onDisplayChanged(); - }, - - replaceValue: function(/*String*/html){ - // summary: - // this function set the content while trying to maintain the undo stack - // (now only works fine with Moz, this is identical to setValue in all - // other browsers) - if(this.isClosed){ - this.setValue(html); - }else if(this.window && this.window.getSelection && !dojo.isMoz){ // Safari - // look ma! it's a totally f'd browser! - this.setValue(html); - }else if(this.window && this.window.getSelection){ // Moz - html = this._preFilterContent(html); - this.execCommand("selectall"); - if(dojo.isMoz && !html){ html = " " } - this.execCommand("inserthtml", html); - this._preDomFilterContent(this.editNode); - }else if(this.document && this.document.selection){//IE - //In IE, when the first element is not a text node, say - //an <a> tag, when replacing the content of the editing - //area, the <a> tag will be around all the content - //so for now, use setValue for IE too - this.setValue(html); - } - }, - - _preFilterContent: function(/*String*/html){ - // summary: - // filter the input before setting the content of the editing area - var ec = html; - dojo.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } }); - return ec; - }, - _preDomFilterContent: function(/*DomNode*/dom){ - // summary: - // filter the input - dom = dom || this.editNode; - dojo.forEach(this.contentDomPreFilters, function(ef){ - if(ef && dojo.isFunction(ef)){ - ef(dom); - } - }, this); - }, - - _postFilterContent: function(/*DomNode|DomNode[]|String?*/dom,/*Boolean?*/nonDestructive){ - // summary: - // filter the output after getting the content of the editing area - var ec; - if(!dojo.isString(dom)){ - dom = dom || this.editNode; - if(this.contentDomPostFilters.length){ - if(nonDestructive && dom['cloneNode']){ - dom = dom.cloneNode(true); - } - dojo.forEach(this.contentDomPostFilters, function(ef){ - dom = ef(dom); - }); - } - ec = dijit._editor.getChildrenHtml(dom); - }else{ - ec = dom; - } - - if(!ec.replace(/^(?:\s|\xA0)+/g, "").replace(/(?:\s|\xA0)+$/g,"").length){ ec = ""; } - - // if(dojo.isIE){ - // //removing appended <P> </P> for IE - // ec = ec.replace(/(?:<p> </p>[\n\r]*)+$/i,""); - // } - dojo.forEach(this.contentPostFilters, function(ef){ - ec = ef(ec); - }); - - return ec; - }, - - _saveContent: function(/*Event*/e){ - // summary: - // Saves the content in an onunload event if the editor has not been closed - var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent"); - saveTextarea.value += this._SEPARATOR + this.name + ":" + this.getValue(); - }, - - escapeXml: function(/*String*/str, /*Boolean*/noSingleQuotes){ - dojo.deprecated('dijit.Editor::escapeXml is deprecated','use dijit._editor.escapeXml instead', 2); - return dijit._editor.escapeXml(str,noSingleQuotes); - }, - - getNodeHtml: function(/* DomNode */node){ - dojo.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit._editor.getNodeHtml instead', 2); - return dijit._editor.getNodeHtml(node); - }, - - getNodeChildrenHtml: function(/* DomNode */dom){ - dojo.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit._editor.getChildrenHtml instead', 2); - return dijit._editor.getChildrenHtml(dom); - }, - - close: function(/*Boolean*/save, /*Boolean*/force){ - // summary: - // Kills the editor and optionally writes back the modified contents to the - // element from which it originated. - // save: - // Whether or not to save the changes. If false, the changes are discarded. - // force: - if(this.isClosed){return false; } - - if(!arguments.length){ save = true; } - this._content = this.getValue(); - var changed = (this.savedContent != this._content); - - // line height is squashed for iframes - // FIXME: why was this here? if(this.iframe){ this.domNode.style.lineHeight = null; } - - if(this.interval){ clearInterval(this.interval); } - - if(this.textarea){ - with(this.textarea.style){ - position = ""; - left = top = ""; - if(dojo.isIE){ - overflow = this.__overflow; - this.__overflow = null; - } - } - this.textarea.value = save ? this._content : this.savedContent; - dojo._destroyElement(this.domNode); - this.domNode = this.textarea; - }else{ -// if(save){ - //why we treat moz differently? comment out to fix #1061 -// if(dojo.isMoz){ -// var nc = dojo.doc.createElement("span"); -// this.domNode.appendChild(nc); -// nc.innerHTML = this.editNode.innerHTML; -// }else{ -// this.domNode.innerHTML = this._content; -// } -// } - this.domNode.innerHTML = save ? this._content : this.savedContent; - } - - dojo.removeClass(this.domNode, "RichTextEditable"); - this.isClosed = true; - this.isLoaded = false; - // FIXME: is this always the right thing to do? - delete this.editNode; - - if(this.window && this.window._frameElement){ - this.window._frameElement = null; - } - - this.window = null; - this.document = null; - this.editingArea = null; - this.editorObject = null; - - return changed; // Boolean: whether the content has been modified - }, - - destroyRendering: function(){ - // summary: stub - }, - - destroy: function(){ - this.destroyRendering(); - if(!this.isClosed){ this.close(false); } - this.inherited("destroy",arguments); - //dijit._editor.RichText.superclass.destroy.call(this); - }, - - _removeMozBogus: function(/* String */ html){ - return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, ''); // String - }, - _removeSafariBogus: function(/* String */ html){ - return html.replace(/\sclass="webkit-block-placeholder"/gi, ''); // String - }, - _fixContentForMoz: function(/* String */ html){ - // summary: - // Moz can not handle strong/em tags correctly, convert them to b/i - return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2') - .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String - }, - - _srcInImgRegex : /(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi , - _hrefInARegex : /(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi , - - _preFixUrlAttributes: function(/* String */ html){ - return html.replace(this._hrefInARegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') - .replace(this._srcInImgRegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String - } -}); - -} |