📄 htmlarea.js
字号:
this._textArea.style.display = "none"; if (HTMLArea.is_gecko) { // we need to refresh that info for Moz-1.3a try { this._doc.designMode = "on"; } catch(e) {}; } if (this.config.statusBar) { this._statusBar.innerHTML = ''; this._statusBar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": ")); this._statusBar.appendChild(this._statusBarTree); } break; default: alert("Mode <" + mode + "> not defined!"); return false; } this._editMode = mode; this.focusEditor();};HTMLArea.prototype.setFullHTML = function(html) { var save_multiline = RegExp.multiline; RegExp.multiline = true; if (html.match(HTMLArea.RE_doctype)) { this.setDoctype(RegExp.$1); html = html.replace(HTMLArea.RE_doctype, ""); } RegExp.multiline = save_multiline; if (!HTMLArea.is_ie) { if (html.match(HTMLArea.RE_head)) this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1; if (html.match(HTMLArea.RE_body)) this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1; } else { var html_re = /<html>((.|\n)*?)<\/html>/i; html = html.replace(html_re, "$1"); this._doc.open(); this._doc.write(html); this._doc.close(); this._doc.body.contentEditable = true; return true; }};/*************************************************** * Category: PLUGINS ***************************************************/// this is the variant of the function above where the plugin arguments are// already packed in an array. Externally, it should be only used in the// full-screen editor code, in order to initialize plugins with the same// parameters as in the opener window.HTMLArea.prototype.registerPlugin2 = function(plugin, args) { if (typeof plugin == "string") plugin = eval(plugin); var obj = new plugin(this, args); if (obj) { var clone = {}; var info = plugin._pluginInfo; for (var i in info) clone[i] = info[i]; clone.instance = obj; clone.args = args; this.plugins[plugin._pluginInfo.name] = clone; } else alert("Can't register plugin " + plugin.toString() + ".");};// Create the specified plugin and register it with this HTMLAreaHTMLArea.prototype.registerPlugin = function() { var plugin = arguments[0]; var args = []; for (var i = 1; i < arguments.length; ++i) args.push(arguments[i]); this.registerPlugin2(plugin, args);};// static function that loads the required plugin and lang file, based on the// language loaded already for HTMLArea. You better make sure that the plugin// _has_ that language, otherwise shit might happen ;-)HTMLArea.loadPlugin = function(pluginName) { var dir = _editor_url + "plugins/" + pluginName; var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, function (str, l1, l2, l3) { return l1 + "-" + l2.toLowerCase() + l3; }).toLowerCase() + ".js"; var plugin_file = dir + "/" + plugin; var plugin_lang = dir + "/lang/" + HTMLArea.I18N.lang + ".js"; HTMLArea._scripts.push(plugin_file, plugin_lang); document.write("<script type='text/javascript' src='" + plugin_file + "'></script>"); document.write("<script type='text/javascript' src='" + plugin_lang + "'></script>");};HTMLArea.loadStyle = function(style, plugin) { var url = _editor_url || ''; if (typeof plugin != "undefined") { url += "plugins/" + plugin + "/"; } url += style; document.write("<style type='text/css'>@import url(" + url + ");</style>");};HTMLArea.loadStyle("htmlarea.css");/*************************************************** * Category: EDITOR UTILITIES ***************************************************/// The following function is a slight variation of the word cleaner code posted// by Weeezl (user @ InteractiveTools forums).HTMLArea.prototype._wordClean = function() { var D = this.getInnerHTML(); if (D.indexOf('class=Mso') >= 0) { // make one line D = D.replace(/\r\n/g, ' '). replace(/\n/g, ' '). replace(/\r/g, ' '). replace(/\ \;/g,' '); // keep tags, strip attributes D = D.replace(/ class=[^\s|>]*/gi,''). //replace(/<p [^>]*TEXT-ALIGN: justify[^>]*>/gi,'<p align="justify">'). replace(/ style=\"[^>]*\"/gi,''). replace(/ align=[^\s|>]*/gi,''); //clean up tags D = D.replace(/<b [^>]*>/gi,'<b>'). replace(/<i [^>]*>/gi,'<i>'). replace(/<li [^>]*>/gi,'<li>'). replace(/<ul [^>]*>/gi,'<ul>'); // replace outdated tags D = D.replace(/<b>/gi,'<strong>'). replace(/<\/b>/gi,'</strong>'); // mozilla doesn't like <em> tags D = D.replace(/<em>/gi,'<i>'). replace(/<\/em>/gi,'</i>'); // kill unwanted tags D = D.replace(/<\?xml:[^>]*>/g, ''). // Word xml replace(/<\/?st1:[^>]*>/g,''). // Word SmartTags replace(/<\/?[a-z]\:[^>]*>/g,''). // All other funny Word non-HTML stuff replace(/<\/?font[^>]*>/gi,''). // Disable if you want to keep font formatting replace(/<\/?span[^>]*>/gi,' '). replace(/<\/?div[^>]*>/gi,' '). replace(/<\/?pre[^>]*>/gi,' '). replace(/<\/?h[1-6][^>]*>/gi,' '); //remove empty tags //D = D.replace(/<strong><\/strong>/gi,''). //replace(/<i><\/i>/gi,''). //replace(/<P[^>]*><\/P>/gi,''); // nuke double tags oldlen = D.length + 1; while(oldlen > D.length) { oldlen = D.length; // join us now and free the tags, we'll be free hackers, we'll be free... ;-) D = D.replace(/<([a-z][a-z]*)> *<\/\1>/gi,' '). replace(/<([a-z][a-z]*)> *<([a-z][^>]*)> *<\/\1>/gi,'<$2>'); } D = D.replace(/<([a-z][a-z]*)><\1>/gi,'<$1>'). replace(/<\/([a-z][a-z]*)><\/\1>/gi,'<\/$1>'); // nuke double spaces D = D.replace(/ */gi,' '); this.setHTML(D); this.updateToolbar(); }};HTMLArea.prototype.forceRedraw = function() { this._doc.body.style.visibility = "hidden"; this._doc.body.style.visibility = "visible"; // this._doc.body.innerHTML = this.getInnerHTML();};// focuses the iframe window. returns a reference to the editor document.HTMLArea.prototype.focusEditor = function() { switch (this._editMode) { case "wysiwyg" : this._iframe.contentWindow.focus(); break; case "textmode": this._textArea.focus(); break; default : alert("ERROR: mode " + this._editMode + " is not defined"); } return this._doc;};// takes a snapshot of the current text (for undo)HTMLArea.prototype._undoTakeSnapshot = function() { ++this._undoPos; if (this._undoPos >= this.config.undoSteps) { // remove the first element this._undoQueue.shift(); --this._undoPos; } // use the fasted method (getInnerHTML); var take = true; var txt = this.getInnerHTML(); if (this._undoPos > 0) take = (this._undoQueue[this._undoPos - 1] != txt); if (take) { this._undoQueue[this._undoPos] = txt; } else { this._undoPos--; }};HTMLArea.prototype.undo = function() { if (this._undoPos > 0) { var txt = this._undoQueue[--this._undoPos]; if (txt) this.setHTML(txt); else ++this._undoPos; }};HTMLArea.prototype.redo = function() { if (this._undoPos < this._undoQueue.length - 1) { var txt = this._undoQueue[++this._undoPos]; if (txt) this.setHTML(txt); else --this._undoPos; }};// updates enabled/disable/active state of the toolbar elementsHTMLArea.prototype.updateToolbar = function(noStatus) { var doc = this._doc; var text = (this._editMode == "textmode"); var ancestors = null; if (!text) { ancestors = this.getAllAncestors(); if (this.config.statusBar && !noStatus) { this._statusBarTree.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; // clear for (var i = ancestors.length; --i >= 0;) { var el = ancestors[i]; if (!el) { // hell knows why we get here; this // could be a classic example of why // it's good to check for conditions // that are impossible to happen ;-) continue; } var a = document.createElement("a"); a.href = "#"; a.el = el; a.editor = this; a.onclick = function() { this.blur(); this.editor.selectNodeContents(this.el); this.editor.updateToolbar(true); return false; }; a.oncontextmenu = function() { // TODO: add context menu here this.blur(); var info = "Inline style:\n\n"; info += this.el.style.cssText.split(/;\s*/).join(";\n"); alert(info); return false; }; var txt = el.tagName.toLowerCase(); a.title = el.style.cssText; if (el.id) { txt += "#" + el.id; } if (el.className) { txt += "." + el.className; } a.appendChild(document.createTextNode(txt)); this._statusBarTree.appendChild(a); if (i != 0) { this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb))); } } } } for (var i in this._toolbarObjects) { var btn = this._toolbarObjects[i]; var cmd = i; var inContext = true; if (btn.context && !text) { inContext = false; var context = btn.context; var attrs = []; if (/(.*)\[(.*?)\]/.test(context)) { context = RegExp.$1; attrs = RegExp.$2.split(","); } context = context.toLowerCase(); var match = (context == "*"); for (var k in ancestors) { if (!ancestors[k]) { // the impossible really happens. continue; } if (match || (ancestors[k].tagName.toLowerCase() == context)) { inContext = true; for (var ka in attrs) { if (!eval("ancestors[k]." + attrs[ka])) { inContext = false; break; } } if (inContext) { break; } } } } btn.state("enabled", (!text || btn.text) && inContext); if (typeof cmd == "function") { continue; } // look-it-up in the custom dropdown boxes var dropdown = this.config.customSelects[cmd]; if ((!text || btn.text) && (typeof dropdown != "undefined")) { dropdown.refresh(this); continue; } switch (cmd) { case "fontname": case "fontsize": case "formatblock": if (!text) try { var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); if (!value) { // FIXME: what do we do here? break; } // HACK -- retrieve the config option for this // combo box. We rely on the fact that the // variable in config has the same name as // button name in the toolbar. var options = this.config[cmd]; var k = 0; // btn.element.selectedIndex = 0; for (var j in options) { // FIXME: the following line is scary. if ((j.toLowerCase() == value) || (options[j].substr(0, value.length).toLowerCase() == value)) { btn.element.selectedIndex = k; break; } ++k; } } catch(e) {}; break; case "textindicator": if (!text) { try {with (btn.element.style) { backgroundColor = HTMLArea._makeColor( doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); if (/transparent/i.test(backgroundColor)) { // Mozilla backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor")); } color = HTMLArea._makeColor(doc.queryCommandValue("forecolor")); fontFamily = doc.queryCommandValue("fontname"); fontWeight = doc.queryCommandState("bold") ? "bold" : "normal"; fontStyle = doc.queryCommandState("italic") ? "italic" : "normal"; }} catch (e) { // alert(e + "\n\n" + cmd); } } break; case "htmlmode": btn.state("active", text); break; case "lefttoright": case "righttoleft": var el = this.getParentElement(); while (el && !HTMLArea.isBlockElement(el)) el = el.parentNode; if (el) btn.state("active", (el.style.direction == ((cmd == "righttoleft") ? "rtl" : "ltr"))); break; default: try { btn.state("active", (!text && doc.queryCommandState(cmd))); } catch (e) {} } } // take undo snapshots if (this._customUndo && !this._timerUndo) { this._undoTakeSnapshot(); var editor = this; this._timerUndo = setTimeout(function() { editor._timerUndo = null; }, this.config.undoTimeout); } // check if any plugins have registered refresh handlers for (var i in this.plugins) { var plugin = this.plugins[i].instance; if (typeof plugin.onUpdateToolbar == "function") plugin.onUpdateToolbar(); }};/** Returns a node after which we can insert other nodes, in the current * selection. The selection is removed. It splits a text node, if needed. */HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) { if (!HTMLArea.is_ie) { var sel = this._getSelection(); var range = this._createRange(sel); // remove the current selection sel.removeAllRanges(); range.deleteContents(); var node = range.startContainer; var pos = range.startOffset; switch (node.nodeType) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -