Path: blob/master/web-gui/buildyourownbotnet/assets/js/codemirror/addon/fold/xml-fold.js
1293 views
(function() {1"use strict";23var Pos = CodeMirror.Pos;4function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }56var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";7var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";8var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");910function Iter(cm, line, ch, range) {11this.line = line; this.ch = ch;12this.cm = cm; this.text = cm.getLine(line);13this.min = range ? range.from : cm.firstLine();14this.max = range ? range.to - 1 : cm.lastLine();15}1617function tagAt(iter, ch) {18var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));19return type && /\btag\b/.test(type);20}2122function nextLine(iter) {23if (iter.line >= iter.max) return;24iter.ch = 0;25iter.text = iter.cm.getLine(++iter.line);26return true;27}28function prevLine(iter) {29if (iter.line <= iter.min) return;30iter.text = iter.cm.getLine(--iter.line);31iter.ch = iter.text.length;32return true;33}3435function toTagEnd(iter) {36for (;;) {37var gt = iter.text.indexOf(">", iter.ch);38if (gt == -1) { if (nextLine(iter)) continue; else return; }39if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }40var lastSlash = iter.text.lastIndexOf("/", gt);41var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));42iter.ch = gt + 1;43return selfClose ? "selfClose" : "regular";44}45}46function toTagStart(iter) {47for (;;) {48var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;49if (lt == -1) { if (prevLine(iter)) continue; else return; }50if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }51xmlTagStart.lastIndex = lt;52iter.ch = lt;53var match = xmlTagStart.exec(iter.text);54if (match && match.index == lt) return match;55}56}5758function toNextTag(iter) {59for (;;) {60xmlTagStart.lastIndex = iter.ch;61var found = xmlTagStart.exec(iter.text);62if (!found) { if (nextLine(iter)) continue; else return; }63if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }64iter.ch = found.index + found[0].length;65return found;66}67}68function toPrevTag(iter) {69for (;;) {70var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;71if (gt == -1) { if (prevLine(iter)) continue; else return; }72if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }73var lastSlash = iter.text.lastIndexOf("/", gt);74var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));75iter.ch = gt + 1;76return selfClose ? "selfClose" : "regular";77}78}7980function findMatchingClose(iter, tag) {81var stack = [];82for (;;) {83var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);84if (!next || !(end = toTagEnd(iter))) return;85if (end == "selfClose") continue;86if (next[1]) { // closing tag87for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {88stack.length = i;89break;90}91if (i < 0 && (!tag || tag == next[2])) return {92tag: next[2],93from: Pos(startLine, startCh),94to: Pos(iter.line, iter.ch)95};96} else { // opening tag97stack.push(next[2]);98}99}100}101function findMatchingOpen(iter, tag) {102var stack = [];103for (;;) {104var prev = toPrevTag(iter);105if (!prev) return;106if (prev == "selfClose") { toTagStart(iter); continue; }107var endLine = iter.line, endCh = iter.ch;108var start = toTagStart(iter);109if (!start) return;110if (start[1]) { // closing tag111stack.push(start[2]);112} else { // opening tag113for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {114stack.length = i;115break;116}117if (i < 0 && (!tag || tag == start[2])) return {118tag: start[2],119from: Pos(iter.line, iter.ch),120to: Pos(endLine, endCh)121};122}123}124}125126CodeMirror.registerHelper("fold", "xml", function(cm, start) {127var iter = new Iter(cm, start.line, 0);128for (;;) {129var openTag = toNextTag(iter), end;130if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;131if (!openTag[1] && end != "selfClose") {132var start = Pos(iter.line, iter.ch);133var close = findMatchingClose(iter, openTag[2]);134return close && {from: start, to: close.from};135}136}137});138CodeMirror.tagRangeFinder = CodeMirror.fold.xml; // deprecated139140CodeMirror.findMatchingTag = function(cm, pos, range) {141var iter = new Iter(cm, pos.line, pos.ch, range);142if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;143var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);144var start = end && toTagStart(iter);145if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return;146var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};147148if (start[1]) { // closing tag149return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};150} else { // opening tag151iter = new Iter(cm, to.line, to.ch, range);152return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};153}154};155156CodeMirror.findEnclosingTag = function(cm, pos, range) {157var iter = new Iter(cm, pos.line, pos.ch, range);158for (;;) {159var open = findMatchingOpen(iter);160if (!open) break;161var forward = new Iter(cm, pos.line, pos.ch, range);162var close = findMatchingClose(forward, open.tag);163if (close) return {open: open, close: close};164}165};166167// Used by addon/edit/closetag.js168CodeMirror.scanForClosingTag = function(cm, pos, name, end) {169var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);170return !!findMatchingClose(iter, name);171};172})();173174175