Вход Регистрация
Файл: engine/skins/mirror/addon/edit/closetag.js
Строк: 311
<?php
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://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.
 *
 * 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(cmvalold) {
    if (
old != CodeMirror.Init && old)
      
cm.removeKeyMap("autoCloseTags");
    if (!
val) return;
    var 
map = {name"autoCloseTags"};
    if (
typeof val != "object" || val.whenClosing)
      
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
    if (
typeof val != "object" || val.whenOpening)
      
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 = [];
    for (var 
0ranges.lengthi++) {
      if (!
ranges[i].empty()) return CodeMirror.Pass;
      var 
pos ranges[i].headtok cm.getTokenAt(pos);
      var 
inner CodeMirror.innerMode(cm.getMode(), tok.state), state inner.state;
      if (
inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;

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

      var 
tagName state.tagName;
      if (
tok.end pos.chtagName tagName.slice(0tagName.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" && state.type == "closeTag" ||
          tok.string.indexOf("
/") == (tok.string.length - 1) || // match something like <someTagName />
          dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
          closingTagExists(cm, tagName, pos, state, true))
        return CodeMirror.Pass;

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

    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 (info.indent) {
        cm.indentLine(info.newPos.line, null, true);
        cm.indentLine(info.newPos.line + 1, null, true);
      }
    }
  }

  function autoCloseSlash(cm) {
    if (cm.getOption("
disableInput")) return CodeMirror.Pass;
    var ranges = cm.listSelections(), replacements = [];
    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 (tok.type == "
string" || tok.string.charAt(0) != "<" ||
          tok.start != pos.ch - 1 || inner.mode.name != "
xml" ||
          !state.context || !state.context.tagName ||
          closingTagExists(cm, state.context.tagName, pos, state))
        return CodeMirror.Pass;
      replacements[i] = "
/" + state.context.tagName + ">";
    }
    cm.replaceSelections(replacements);
  }

  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, tagName, pos, state, 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;
    var cx = state.context;
    // 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.
    for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
    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;
  }
});
?>
Онлайн: 2
Реклама