Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/media/editors/codemirror/addon/edit/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/media/editors/codemirror/addon/edit/closetag.js

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

/**
 * Tag-closer extension for CodeMirror.
 *
 * This extension adds an "autoCloseTags" option that can be set
to
 * either true to get the default behavior, or an object to further
 * configure its behavior.
 *
 * These are supported options:
 *
 * `whenClosing` (default true)
 *   Whether to autoclose when the '/' of a closing tag is typed.
 * `whenOpening` (default true)
 *   Whether to autoclose the tag when the final '>' of an
opening
 *   tag is typed.
 * `dontCloseTags` (default is empty tags for HTML, none for XML)
 *   An array of tag names that should not be autoclosed.
 * `indentTags` (default is block tags for HTML, none for XML)
 *   An array of tag names that should, when opened, cause a
 *   blank line to be added inside the tag, and the blank line and
 *   closing line to be indented.
 * `emptyTags` (default is none)
 *   An array of XML tag names that should be autoclosed with
'/>'.
 *
 * See demos/closetag.html for a usage example.
 */

(function(mod) {
  if (typeof exports == "object" && typeof module ==
"object") // CommonJS
    mod(require("../../lib/codemirror"),
require("../fold/xml-fold"));
  else if (typeof define == "function" && define.amd) //
AMD
    define(["../../lib/codemirror",
"../fold/xml-fold"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  CodeMirror.defineOption("autoCloseTags", false, function(cm,
val, old) {
    if (old != CodeMirror.Init && old)
      cm.removeKeyMap("autoCloseTags");
    if (!val) return;
    var map = {name: "autoCloseTags"};
    if (typeof val != "object" || val.whenClosing !== false)
      map["'/'"] = function(cm) { return
autoCloseSlash(cm); };
    if (typeof val != "object" || val.whenOpening !== false)
      map["'>'"] = function(cm) { return
autoCloseGT(cm); };
    cm.addKeyMap(map);
  });

  var htmlDontClose = ["area", "base", "br",
"col", "command", "embed", "hr",
"img", "input", "keygen", "link",
"meta", "param",
                       "source", "track",
"wbr"];
  var htmlIndent = ["applet", "blockquote",
"body", "button", "div", "dl",
"fieldset", "form", "frameset",
"h1", "h2", "h3", "h4",
                    "h5", "h6", "head",
"html", "iframe", "layer",
"legend", "object", "ol", "p",
"select", "table", "ul"];

  function autoCloseGT(cm) {
    if (cm.getOption("disableInput")) return CodeMirror.Pass;
    var ranges = cm.listSelections(), replacements = [];
    var opt = cm.getOption("autoCloseTags");
    for (var i = 0; i < ranges.length; i++) {
      if (!ranges[i].empty()) return CodeMirror.Pass;
      var pos = ranges[i].head, tok = cm.getTokenAt(pos);
      var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state =
inner.state;
      var tagInfo = inner.mode.xmlCurrentTag &&
inner.mode.xmlCurrentTag(state)
      var tagName = tagInfo && tagInfo.name
      if (!tagName) return CodeMirror.Pass

      var html = inner.mode.configuration == "html";
      var dontCloseTags = (typeof opt == "object" &&
opt.dontCloseTags) || (html && htmlDontClose);
      var indentTags = (typeof opt == "object" &&
opt.indentTags) || (html && htmlIndent);

      if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length -
tok.end + pos.ch);
      var lowerTagName = tagName.toLowerCase();
      // Don't process the '>' at the end of an end-tag
or self-closing tag
      if (!tagName ||
          tok.type == "string" && (tok.end != pos.ch ||
!/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) ||
tok.string.length == 1) ||
          tok.type == "tag" && tagInfo.close ||
          tok.string.indexOf("/") == (pos.ch - tok.start - 1) ||
// match something like <someTagName />
          dontCloseTags && indexOf(dontCloseTags, lowerTagName)
> -1 ||
          closingTagExists(cm, inner.mode.xmlCurrentContext &&
inner.mode.xmlCurrentContext(state) || [], tagName, pos, true))
        return CodeMirror.Pass;

      var emptyTags = typeof opt == "object" &&
opt.emptyTags;
      if (emptyTags && indexOf(emptyTags, tagName) > -1) {
        replacements[i] = { text: "/>", newPos:
CodeMirror.Pos(pos.line, pos.ch + 2) };
        continue;
      }

      var indent = indentTags && indexOf(indentTags, lowerTagName)
> -1;
      replacements[i] = {indent: indent,
                         text: ">" + (indent ?
"\n\n" : "") + "</" + tagName +
">",
                         newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) :
CodeMirror.Pos(pos.line, pos.ch + 1)};
    }

    var dontIndentOnAutoClose = (typeof opt == "object"
&& opt.dontIndentOnAutoClose);
    for (var i = ranges.length - 1; i >= 0; i--) {
      var info = replacements[i];
      cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor,
"+insert");
      var sel = cm.listSelections().slice(0);
      sel[i] = {head: info.newPos, anchor: info.newPos};
      cm.setSelections(sel);
      if (!dontIndentOnAutoClose && info.indent) {
        cm.indentLine(info.newPos.line, null, true);
        cm.indentLine(info.newPos.line + 1, null, true);
      }
    }
  }

  function autoCloseCurrent(cm, typingSlash) {
    var ranges = cm.listSelections(), replacements = [];
    var head = typingSlash ? "/" : "</";
    var opt = cm.getOption("autoCloseTags");
    var dontIndentOnAutoClose = (typeof opt == "object"
&& opt.dontIndentOnSlash);
    for (var i = 0; i < ranges.length; i++) {
      if (!ranges[i].empty()) return CodeMirror.Pass;
      var pos = ranges[i].head, tok = cm.getTokenAt(pos);
      var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state =
inner.state;
      if (typingSlash && (tok.type == "string" ||
tok.string.charAt(0) != "<" ||
                          tok.start != pos.ch - 1))
        return CodeMirror.Pass;
      // Kludge to get around the fact that we are not in XML mode
      // when completing in JS/CSS snippet in htmlmixed mode. Does not
      // work for other XML embedded languages (there is no general
      // way to go from a mixed mode to its current XML state).
      var replacement, mixed = inner.mode.name != "xml"
&& cm.getMode().name == "htmlmixed"
      if (mixed && inner.mode.name == "javascript") {
        replacement = head + "script";
      } else if (mixed && inner.mode.name == "css") {
        replacement = head + "style";
      } else {
        var context = inner.mode.xmlCurrentContext &&
inner.mode.xmlCurrentContext(state)
        if (!context || (context.length && closingTagExists(cm,
context, context[context.length - 1], pos)))
          return CodeMirror.Pass;
        replacement = head + context[context.length - 1]
      }
      if (cm.getLine(pos.line).charAt(tok.end) != ">")
replacement += ">";
      replacements[i] = replacement;
    }
    cm.replaceSelections(replacements);
    ranges = cm.listSelections();
    if (!dontIndentOnAutoClose) {
        for (var i = 0; i < ranges.length; i++)
            if (i == ranges.length - 1 || ranges[i].head.line < ranges[i
+ 1].head.line)
                cm.indentLine(ranges[i].head.line);
    }
  }

  function autoCloseSlash(cm) {
    if (cm.getOption("disableInput")) return CodeMirror.Pass;
    return autoCloseCurrent(cm, true);
  }

  CodeMirror.commands.closeTag = function(cm) { return
autoCloseCurrent(cm); };

  function indexOf(collection, elt) {
    if (collection.indexOf) return collection.indexOf(elt);
    for (var i = 0, e = collection.length; i < e; ++i)
      if (collection[i] == elt) return i;
    return -1;
  }

  // If xml-fold is loaded, we use its functionality to try and verify
  // whether a given tag is actually unclosed.
  function closingTagExists(cm, context, tagName, pos, newTag) {
    if (!CodeMirror.scanForClosingTag) return false;
    var end = Math.min(cm.lastLine() + 1, pos.line + 500);
    var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
    if (!nextClose || nextClose.tag != tagName) return false;
    // If the immediate wrapping context contains onCx instances of
    // the same tag, a closing tag only exists if there are at least
    // that many closing tags of that type following.
    var onCx = newTag ? 1 : 0
    for (var i = context.length - 1; i >= 0; i--) {
      if (context[i] == tagName) ++onCx
      else break
    }
    pos = nextClose.to;
    for (var i = 1; i < onCx; i++) {
      var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
      if (!next || next.tag != tagName) return false;
      pos = next.to;
    }
    return true;
  }
});