Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | (function() { |
michael@0 | 2 | "use strict"; |
michael@0 | 3 | |
michael@0 | 4 | var Pos = CodeMirror.Pos; |
michael@0 | 5 | function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } |
michael@0 | 6 | |
michael@0 | 7 | var 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"; |
michael@0 | 8 | var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; |
michael@0 | 9 | var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); |
michael@0 | 10 | |
michael@0 | 11 | function Iter(cm, line, ch, range) { |
michael@0 | 12 | this.line = line; this.ch = ch; |
michael@0 | 13 | this.cm = cm; this.text = cm.getLine(line); |
michael@0 | 14 | this.min = range ? range.from : cm.firstLine(); |
michael@0 | 15 | this.max = range ? range.to - 1 : cm.lastLine(); |
michael@0 | 16 | } |
michael@0 | 17 | |
michael@0 | 18 | function tagAt(iter, ch) { |
michael@0 | 19 | var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); |
michael@0 | 20 | return type && /\btag\b/.test(type); |
michael@0 | 21 | } |
michael@0 | 22 | |
michael@0 | 23 | function nextLine(iter) { |
michael@0 | 24 | if (iter.line >= iter.max) return; |
michael@0 | 25 | iter.ch = 0; |
michael@0 | 26 | iter.text = iter.cm.getLine(++iter.line); |
michael@0 | 27 | return true; |
michael@0 | 28 | } |
michael@0 | 29 | function prevLine(iter) { |
michael@0 | 30 | if (iter.line <= iter.min) return; |
michael@0 | 31 | iter.text = iter.cm.getLine(--iter.line); |
michael@0 | 32 | iter.ch = iter.text.length; |
michael@0 | 33 | return true; |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | function toTagEnd(iter) { |
michael@0 | 37 | for (;;) { |
michael@0 | 38 | var gt = iter.text.indexOf(">", iter.ch); |
michael@0 | 39 | if (gt == -1) { if (nextLine(iter)) continue; else return; } |
michael@0 | 40 | if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } |
michael@0 | 41 | var lastSlash = iter.text.lastIndexOf("/", gt); |
michael@0 | 42 | var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); |
michael@0 | 43 | iter.ch = gt + 1; |
michael@0 | 44 | return selfClose ? "selfClose" : "regular"; |
michael@0 | 45 | } |
michael@0 | 46 | } |
michael@0 | 47 | function toTagStart(iter) { |
michael@0 | 48 | for (;;) { |
michael@0 | 49 | var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; |
michael@0 | 50 | if (lt == -1) { if (prevLine(iter)) continue; else return; } |
michael@0 | 51 | if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } |
michael@0 | 52 | xmlTagStart.lastIndex = lt; |
michael@0 | 53 | iter.ch = lt; |
michael@0 | 54 | var match = xmlTagStart.exec(iter.text); |
michael@0 | 55 | if (match && match.index == lt) return match; |
michael@0 | 56 | } |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | function toNextTag(iter) { |
michael@0 | 60 | for (;;) { |
michael@0 | 61 | xmlTagStart.lastIndex = iter.ch; |
michael@0 | 62 | var found = xmlTagStart.exec(iter.text); |
michael@0 | 63 | if (!found) { if (nextLine(iter)) continue; else return; } |
michael@0 | 64 | if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } |
michael@0 | 65 | iter.ch = found.index + found[0].length; |
michael@0 | 66 | return found; |
michael@0 | 67 | } |
michael@0 | 68 | } |
michael@0 | 69 | function toPrevTag(iter) { |
michael@0 | 70 | for (;;) { |
michael@0 | 71 | var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; |
michael@0 | 72 | if (gt == -1) { if (prevLine(iter)) continue; else return; } |
michael@0 | 73 | if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } |
michael@0 | 74 | var lastSlash = iter.text.lastIndexOf("/", gt); |
michael@0 | 75 | var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); |
michael@0 | 76 | iter.ch = gt + 1; |
michael@0 | 77 | return selfClose ? "selfClose" : "regular"; |
michael@0 | 78 | } |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | function findMatchingClose(iter, tag) { |
michael@0 | 82 | var stack = []; |
michael@0 | 83 | for (;;) { |
michael@0 | 84 | var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); |
michael@0 | 85 | if (!next || !(end = toTagEnd(iter))) return; |
michael@0 | 86 | if (end == "selfClose") continue; |
michael@0 | 87 | if (next[1]) { // closing tag |
michael@0 | 88 | for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { |
michael@0 | 89 | stack.length = i; |
michael@0 | 90 | break; |
michael@0 | 91 | } |
michael@0 | 92 | if (i < 0 && (!tag || tag == next[2])) return { |
michael@0 | 93 | tag: next[2], |
michael@0 | 94 | from: Pos(startLine, startCh), |
michael@0 | 95 | to: Pos(iter.line, iter.ch) |
michael@0 | 96 | }; |
michael@0 | 97 | } else { // opening tag |
michael@0 | 98 | stack.push(next[2]); |
michael@0 | 99 | } |
michael@0 | 100 | } |
michael@0 | 101 | } |
michael@0 | 102 | function findMatchingOpen(iter, tag) { |
michael@0 | 103 | var stack = []; |
michael@0 | 104 | for (;;) { |
michael@0 | 105 | var prev = toPrevTag(iter); |
michael@0 | 106 | if (!prev) return; |
michael@0 | 107 | if (prev == "selfClose") { toTagStart(iter); continue; } |
michael@0 | 108 | var endLine = iter.line, endCh = iter.ch; |
michael@0 | 109 | var start = toTagStart(iter); |
michael@0 | 110 | if (!start) return; |
michael@0 | 111 | if (start[1]) { // closing tag |
michael@0 | 112 | stack.push(start[2]); |
michael@0 | 113 | } else { // opening tag |
michael@0 | 114 | for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { |
michael@0 | 115 | stack.length = i; |
michael@0 | 116 | break; |
michael@0 | 117 | } |
michael@0 | 118 | if (i < 0 && (!tag || tag == start[2])) return { |
michael@0 | 119 | tag: start[2], |
michael@0 | 120 | from: Pos(iter.line, iter.ch), |
michael@0 | 121 | to: Pos(endLine, endCh) |
michael@0 | 122 | }; |
michael@0 | 123 | } |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | CodeMirror.registerHelper("fold", "xml", function(cm, start) { |
michael@0 | 128 | var iter = new Iter(cm, start.line, 0); |
michael@0 | 129 | for (;;) { |
michael@0 | 130 | var openTag = toNextTag(iter), end; |
michael@0 | 131 | if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; |
michael@0 | 132 | if (!openTag[1] && end != "selfClose") { |
michael@0 | 133 | var start = Pos(iter.line, iter.ch); |
michael@0 | 134 | var close = findMatchingClose(iter, openTag[2]); |
michael@0 | 135 | return close && {from: start, to: close.from}; |
michael@0 | 136 | } |
michael@0 | 137 | } |
michael@0 | 138 | }); |
michael@0 | 139 | CodeMirror.tagRangeFinder = CodeMirror.fold.xml; // deprecated |
michael@0 | 140 | |
michael@0 | 141 | CodeMirror.findMatchingTag = function(cm, pos, range) { |
michael@0 | 142 | var iter = new Iter(cm, pos.line, pos.ch, range); |
michael@0 | 143 | if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; |
michael@0 | 144 | var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); |
michael@0 | 145 | var start = end && toTagStart(iter); |
michael@0 | 146 | if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return; |
michael@0 | 147 | var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; |
michael@0 | 148 | |
michael@0 | 149 | if (start[1]) { // closing tag |
michael@0 | 150 | return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; |
michael@0 | 151 | } else { // opening tag |
michael@0 | 152 | iter = new Iter(cm, to.line, to.ch, range); |
michael@0 | 153 | return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; |
michael@0 | 154 | } |
michael@0 | 155 | }; |
michael@0 | 156 | |
michael@0 | 157 | CodeMirror.findEnclosingTag = function(cm, pos, range) { |
michael@0 | 158 | var iter = new Iter(cm, pos.line, pos.ch, range); |
michael@0 | 159 | for (;;) { |
michael@0 | 160 | var open = findMatchingOpen(iter); |
michael@0 | 161 | if (!open) break; |
michael@0 | 162 | var forward = new Iter(cm, pos.line, pos.ch, range); |
michael@0 | 163 | var close = findMatchingClose(forward, open.tag); |
michael@0 | 164 | if (close) return {open: open, close: close}; |
michael@0 | 165 | } |
michael@0 | 166 | }; |
michael@0 | 167 | |
michael@0 | 168 | // Used by addon/edit/closetag.js |
michael@0 | 169 | CodeMirror.scanForClosingTag = function(cm, pos, name, end) { |
michael@0 | 170 | var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); |
michael@0 | 171 | return !!findMatchingClose(iter, name); |
michael@0 | 172 | }; |
michael@0 | 173 | })(); |