⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htmlarea.js

📁 網葉編輯器 ?W葉編輯器 網葉編輯器
💻 JS
📖 第 1 页 / 共 5 页
字号:
      } else {
        alert("ERROR: IFRAME can't be initialized.");
      }
    }
    if (HTMLArea.is_gecko) {
      // enable editable mode for Mozilla
      doc.designMode = "on";
    }
    editor._doc = doc;
    doc.open();
    var html = "<html>\n";
    html += "<head>\n";
    html += "<style>" + editor.config.pageStyle + "</style>\n";
    html += "</head>\n";
    html += "<body>\n";
    html += editor._textArea.value;
    html += "</body>\n";
    html += "</html>";
    doc.write(html);
    doc.close();

    if (HTMLArea.is_ie) {
      // enable editable mode for IE.	 For some reason this
      // doesn't work if done in the same place as for Gecko
      // (above).
      doc.body.contentEditable = true;
    }

    editor.focusEditor();
    // intercept some events; for updating the toolbar & keyboard handlers
    HTMLArea._addEvents
            (doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"],
                    function (event) {
                      return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event);
                    });
    editor.updateToolbar();
  }
  ;
  setTimeout(initIframe, HTMLArea.is_gecko ? 10 : 0);
};

// Switches editor mode; parameter can be "textmode" or "wysiwyg".  If no
// parameter was passed this function toggles between modes.
HTMLArea.prototype.setMode = function(mode) {
  if (typeof mode == "undefined") {
    mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode");
  }
  switch (mode) {
    case "textmode":
      this._textArea.value = this.getHTML();
      this._iframe.style.display = "none";
      this._textArea.style.display = "block";
      if (this.config.statusBar) {
        this._statusBar.innerHTML = HTMLArea.I18N.msg["TEXT_MODE"];
      }
      break;
    case "wysiwyg":
      if (HTMLArea.is_gecko) {
        // disable design mode before changing innerHTML
        this._doc.designMode = "off";
      }
      this._doc.body.innerHTML = this.getHTML();
      this._iframe.style.display = "block";
      this._textArea.style.display = "none";
      if (HTMLArea.is_gecko) {
        // we need to refresh that info for Moz-1.3a
        this._doc.designMode = "on";
      }
      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();
};

/***************************************************
 *  Category: PLUGINS
 ***************************************************/

// Create the specified plugin and register it with this HTMLArea
HTMLArea.prototype.registerPlugin = function(pluginName) {
  this.plugins[pluginName] = eval("new " + pluginName + "(this);");
};

// 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 editorurl = '';
  if (typeof _editor_url != "undefined") {
    editorurl = _editor_url + "/";
  }
  var dir = editorurl + "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";
  document.write("<script type='text/javascript' src='" + dir + "/" + plugin + "'></script>");
  document.write("<script type='text/javascript' src='" + dir + "/lang/" + HTMLArea.I18N.lang + ".js'></script>");
};

/***************************************************
 *  Category: EDITOR UTILITIES
 ***************************************************/

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;
};

// updates enabled/disable/active state of the toolbar elements
HTMLArea.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 = '';
      // 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() {
          // TO DO: 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) {
          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;
          }
        }
        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;
      default:
        try {
          btn.state("active", (!text && doc.queryCommandState(cmd)));
        } catch (e) {
        }
    }
  }
};

/** 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) {
      case 3: // Node.TEXT_NODE
      // we have to split it at the caret position.
        if (toBeInserted.nodeType == 3) {
          // do optimized insertion
          node.insertData(pos, toBeInserted.data);
          range = this._createRange();
          range.setEnd(node, pos + toBeInserted.length);
          range.setStart(node, pos + toBeInserted.length);
          sel.addRange(range);
        } else {
          node = node.splitText(pos);
          var selnode = toBeInserted;
          if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
            selnode = selnode.firstChild;
          }
          node.parentNode.insertBefore(toBeInserted, node);
          this.selectNodeContents(selnode);
          this.updateToolbar();
        }
        break;
      case 1: // Node.ELEMENT_NODE
        var selnode = toBeInserted;
        if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
          selnode = selnode.firstChild;
        }
        node.insertBefore(toBeInserted, node.childNodes[pos]);
        this.selectNodeContents(selnode);
        this.updateToolbar();
        break;
    }
  } else {
    return null;
    // this function not yet used for IE <FIXME>
  }
};

// Returns the deepest node that contains both endpoints of the selection.
HTMLArea.prototype.getParentElement = function() {
  var sel = this._getSelection();
  var range = this._createRange(sel);
  if (HTMLArea.is_ie) {
    return range.parentElement ? range.parentElement() : this._doc.body;
  } else {
    var p = range.commonAncestorContainer;
    while (p.nodeType == 3) {
      p = p.parentNode;
    }
    return p;
  }
};

// Returns an array with all the ancestor nodes of the selection.
HTMLArea.prototype.getAllAncestors = function() {
  var p = this.getParentElement();
  var a = [];
  while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
    a.push(p);
    p = p.parentNode;
  }
  a.push(this._doc.body);
  return a;
};

// Selects the contents inside the given node
HTMLArea.prototype.selectNodeContents = function(node, pos) {
  this.focusEditor();
  this.forceRedraw();
  var range;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -