📄 richtext.js
字号:
function isSignificantNode(element) { // see if an node is significant in the current context // for calulating margins return !(element.nodeType==3 && dojo.string.isBlank(element.data)) && dojo.html.getStyle(element, "display") != "none" && !dojo.html.isPositionAbsolute(element); } // walk throuh first/last children to find total collapsed margin size var childMargin = 0; var child = element[childAttr]; while (child) { // skip over insignificant elements (whitespace, etc) while ((!isSignificantNode(child)) && child[childSiblingAttr]) { child = child[childSiblingAttr]; } childMargin = Math.max(childMargin, dojo.html.getPixelValue(child, marginProp, false)); // stop if we hit a bordered/padded element if (!this._hasCollapseableMargin(child, topOrBottom)) break; child = child[childAttr]; } // if this element has a border, return full child margin immediately // as there won't be any margin collapsing if (!this._hasCollapseableMargin(element, topOrBottom)){ return parseInt(childMargin); } // find margin supplied by nearest sibling var contextMargin = 0; var sibling = element[siblingAttr]; while (sibling) { if (isSignificantNode(sibling)) { contextMargin = dojo.html.getPixelValue(sibling, siblingMarginProp, false); break; } sibling = sibling[siblingAttr]; } if (!sibling) { // no sibling, look at parent's margin instead contextMargin = dojo.html.getPixelValue(element.parentNode, marginProp, false); } if (childMargin > elementMargin) { return parseInt(Math.max((childMargin-elementMargin)-contextMargin, 0)); } else { return 0; } }, _drawIframe: function (/*String*/html){ // summary: // Draws an iFrame using the existing one if one exists. // Used by Mozilla, Safari, and Opera // detect firefox < 1.5, which has some iframe loading issues var oldMoz = Boolean(dojo.render.html.moz && ( typeof window.XML == 'undefined')) if(!this.iframe){ var currentDomain = (new dojo.uri.Uri(dojo.doc().location)).host; this.iframe = dojo.doc().createElement("iframe"); // dojo.body().appendChild(this.iframe); with(this.iframe){ style.border = "none"; style.lineHeight = "0"; // squash line height style.verticalAlign = "bottom"; scrolling = this.height ? "auto" : "no"; } } // opera likes this to be outside the with block this.iframe.src = dojo.uri.dojoUri("src/widget/templates/richtextframe.html") + ((dojo.doc().domain != currentDomain) ? ("#"+dojo.doc().domain) : ""); this.iframe.width = this.inheritWidth ? this._oldWidth : "100%"; if(this.height){ this.iframe.style.height = this.height; }else{ var height = this._oldHeight; if(this._hasCollapseableMargin(this.domNode, 'top')){ height += this._firstChildContributingMargin; } if(this._hasCollapseableMargin(this.domNode, 'bottom')){ height += this._lastChildContributingMargin; } this.iframe.height = height; } var tmpContent = dojo.doc().createElement('div'); tmpContent.innerHTML = html; //append tmpContent to under the current domNode so that the margin //calculation below is correct this.editingArea.appendChild(tmpContent); // make relative image urls absolute if(this.relativeImageUrls){ var imgs = tmpContent.getElementsByTagName('img'); for(var i=0; i<imgs.length; i++){ imgs[i].src = (new dojo.uri.Uri(dojo.global().location, imgs[i].src)).toString(); } html = tmpContent.innerHTML; } // fix margins on tmpContent var firstChild = dojo.html.firstElement(tmpContent); var lastChild = dojo.html.lastElement(tmpContent); if(firstChild){ firstChild.style.marginTop = this._firstChildContributingMargin+"px"; } if(lastChild){ lastChild.style.marginBottom = this._lastChildContributingMargin+"px"; } //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); if(dojo.render.html.safari){ this.iframe.src = this.iframe.src; } var _iframeInitialized = false; // now we wait for onload. Janky hack! var ifrFunc = dojo.lang.hitch(this, function(){ if(!_iframeInitialized){ _iframeInitialized = true; }else{ return; } if(!this.editNode){ 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; } // curry the getStyle function var getStyle = (function (domNode) { return function (style) { return dojo.html.getStyle(domNode, style); }; })(this.domNode); var font = getStyle('font-weight') + " " + getStyle('font-size') + " " + getStyle('font-family'); // 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 = "1.0"; var lineHeightStyle = dojo.html.getUnitValue(this.domNode, 'line-height'); if (lineHeightStyle.value && lineHeightStyle.units=="") { lineHeight = lineHeightStyle.value; } dojo.html.insertCssText( 'body,html{background:transparent;padding:0;margin:0;}' + // TODO: left positioning will case contents to disappear out of view // if it gets too wide for the visible area 'body{top:0;left:0;right:0;' + (((this.height)||(dojo.render.html.opera)) ? '' : 'position:fixed;') + 'font:' + font + ';' + 'min-height:' + this.minHeight + ';' + 'line-height:' + lineHeight + '}' + 'p{margin: 1em 0 !important;}' + 'body > *:first-child{padding-top:0 !important;margin-top:' + this._firstChildContributingMargin + 'px !important;}' + // FIXME: test firstChild nodeType 'body > *:last-child{padding-bottom:0 !important;margin-bottom:' + this._lastChildContributingMargin + 'px !important;}' + 'li > ul:-moz-first-node, li > ol:-moz-first-node{padding-top:1.2em;}\n' + 'li{min-height:1.2em;}' + //' p,ul,li { padding-top: 0; padding-bottom: 0; margin-top:0; margin-bottom: 0; }\n' + '', this.document); dojo.html.removeNode(tmpContent); this.document.body.innerHTML = html; if(oldMoz||dojo.render.html.safari){ this.document.designMode = "on"; } this.onLoad(); }else{ dojo.html.removeNode(tmpContent); this.editNode.innerHTML = html; this.onDisplayChanged(); } }); if(this.editNode){ ifrFunc(); // iframe already exists, just set content }else if(dojo.render.html.moz){ // FIXME: if we put this on a delay, we get a height of 20px. // Otherwise we get the correctly specified minHeight value. this.iframe.onload = function(){ setTimeout(ifrFunc, 250); } }else{ // new mozillas, opera, safari this.iframe.onload = 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 = []; if(files.length>0){ for(var i=0;i<files.length;i++){ var url = files[i]; if(url){ this.addStyleSheet(dojo.uri.dojoUri(url)); } } } }, addStyleSheet: function(/*dojo.uri.Uri*/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(dojo.lang.find(this.editingAreaStyleSheets, url) > -1){ dojo.debug("dojo.widget.RichText.addStyleSheet: Style sheet "+url+" is already applied to the editing area!"); return; } //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.uri.Uri(dojo.global().location, url)).toString(); } 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.uri.Uri*/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.uri.Uri(dojo.global().location, url)).toString(); } var index = dojo.lang.find(this.editingAreaStyleSheets, url); if(index == -1){ dojo.debug("dojo.widget.RichText.removeStyleSheet: Style sheet "+url+" is not applied to the editing area so it can not be removed!"); return; } delete this.editingAreaStyleSheets[index]; var links = this.document.getElementsByTagName("link"); for(var i=0;i<links.length;i++){ if(links[i].href == url){ if(dojo.render.html.ie){//we need to empty the href first, to get IE to remove the rendered styles links[i].href=""; } dojo.html.removeNode(links[i]); break; } } }, _drawObject: function (/*String*/html) { // summary: // Draws an active x object, used by IE this.object = dojo.html.createExternalElement(dojo.doc(), "object"); with (this.object) { classid = "clsid:2D360201-FFF5-11D1-8D03-00A0C959BC0A"; width = this.inheritWidth ? this._oldWidth : "100%"; style.height = this.height ? this.height : (this._oldHeight+"px"); Scrollbars = this.height ? true : false; Appearance = this._activeX.appearance.flat; } this.editorObject = this.object; this.editingArea.appendChild(this.object); this.object.attachEvent("DocumentComplete", dojo.lang.hitch(this, "onLoad")); //DisplayChanged is fired too often even no change is made, so we ignore it //and call onDisplayChanged manually in execCommand instead// this.object.attachEvent("DisplayChanged", dojo.lang.hitch(this, "onDisplayChanged")); dojo.lang.forEach(this.events, function(e){ this.object.attachEvent(e.toLowerCase(), dojo.lang.hitch(this, e)); }, this); this.object.DocumentHTML = '<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' + '<html><title></title>' + '<style type="text/css">' + ' body,html { padding: 0; margin: 0; }' + //font: ' + font + '; }' + (this.height ? '' : ' body, { overflow: hidden; }') + '</style>' + //'<base href="' + dojo.global().location + '">' + '<body><div>' + html + '<div></body></html>'; this._cacheLocalBlockFormatNames(); }, //static cache variables shared among all instance of this class _local2NativeFormatNames: {}, _native2LocalFormatNames: {}, //in IE, names for blockformat is locale dependent, so we cache the values here //we use activeX to obtain the list, if success or the names are already cached, //return true _cacheLocalBlockFormatNames: function(){ // summary: // in IE, names for blockformat is locale dependent, so we cache the values here // we use activeX to obtain the list, if success or the names are already cached, // return true if(!this._native2LocalFormatNames['p']){ var obj = this.object; var error = false; if(!obj){ //create obj temporarily try{ obj = dojo.html.createExternalElement(dojo.doc(), "object"); obj.classid = "clsid:2D360201-FFF5-11D1-8D03-00A0C959BC0A"; dojo.body().appendChild(obj); obj.DocumentHTML = "<html><head></head><body></body></html>"; }catch(e){ error = true; } } try{ var oNamesParm = new ActiveXObject("DEGetBlockFmtNamesParam.DEGetBlockFmtNamesParam"); obj.ExecCommand(this._activeX.command['getblockformatnames'], 0, oNamesParm); var vbNamesArray = new VBArray(oNamesParm.Names); var localFormats = vbNamesArray.toArray(); var nativeFormats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', '', '', '','','div']; for(var i=0;i<nativeFormats.length;++i){ if(nativeFormats[i].length>0){ this._local2NativeFormatNames[localFormats[i]] = nativeFormats[i]; this._native2LocalFormatNames[nativeFormats[i]] = localFormats[i]; } } }catch(e){ error = true; } if(obj && !this.object){ //delete the temporary obj dojo.body().removeChild(obj); } } return !error; }, /* Event handlers *****************/ _isResized: function(){ return false; }, onLoad: function(e){ // summary: handler after the content of the document finishes loading this.isLoaded = true; if (this.object){ this.document = this.object.DOM; this.window = this.document.parentWindow; this.editNode = this.document.body.firstChild; this.editingArea.style.height = this.height ? this.height : this.minHeight; if(!this.height){ this.connect(this, "onDisplayChanged", "_updateHeight"); } //pretend the object as an iframe, so that the context menu for the //editor can be placed correctly when shown this.window._frameElement = this.object; }else if (this.iframe && !dojo.render.html.ie){ this.editNode = this.document.body; if(!this.height){ this.connect(this, "onDisplayChanged", "_updateHeight"); } try { // sanity check for Mozilla 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){ } if (dojo.render.html.safari) { /* this.iframe.style.visiblity = "visible"; this.iframe.style.border = "1px solid black"; this.editNode.style.visiblity = "visible"; this.editNode.style.border = "1px solid black"; */ // this.onDisplayChanged(); this.connect(this.editNode, "onblur", "onBlur"); this.connect(this.editNode, "onfocus", "onFocus"); this.connect(this.editNode, "onclick", "onFocus"); this.interval = setInterval(dojo.lang.hitch(this, "onDisplayChanged"), 750); // dojo.raise("onload"); // dojo.debug(this.editNode.parentNode.parentNode.parentNode.nodeName); } else if (dojo.render.html.mozilla || dojo.render.html.opera) { var doc = this.document; var addListener = dojo.event.browser.addListener; var self = this; dojo.lang.forEach(this.events, function(e){ var l = addListener(self.document, e.substr(2).toLowerCase(), dojo.lang.hitch(self, e)); if(e=="onBlur"){ // We need to unhook the blur event listener on close as we // can encounter a garunteed crash in FF if another event is // also fired var unBlur = { unBlur: function(e){ dojo.event.browser.removeListener(doc, "blur", l); } }; dojo.event.connect("before", self, "close", unBlur, "unBlur"); } }); } // FIXME: when scrollbars appear/disappear this needs to be fired }else if(dojo.render.html.ie){ // IE contentEditable if(!this.height){ this.connect(this, "onDisplayChanged", "_updateHeight"); } this.editNode.style.zoom = 1.0; } this._applyEditingAreaStyleSheets(); if(this.focusOnLoad){ this.focus(); } this.onDisplayChanged(e); if(this.onLoadDeferred){ this.onLoadDeferred.callback(true); } },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -