github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/app/public/codemirror/addon/lint/lint.js (about) 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 (function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11 })(function(CodeMirror) { 12 "use strict"; 13 var GUTTER_ID = "CodeMirror-lint-markers"; 14 15 function showTooltip(e, content) { 16 var tt = document.createElement("div"); 17 tt.className = "CodeMirror-lint-tooltip"; 18 tt.appendChild(content.cloneNode(true)); 19 document.body.appendChild(tt); 20 21 function position(e) { 22 if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); 23 tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; 24 tt.style.left = (e.clientX + 5) + "px"; 25 } 26 CodeMirror.on(document, "mousemove", position); 27 position(e); 28 if (tt.style.opacity != null) tt.style.opacity = 1; 29 return tt; 30 } 31 function rm(elt) { 32 if (elt.parentNode) elt.parentNode.removeChild(elt); 33 } 34 function hideTooltip(tt) { 35 if (!tt.parentNode) return; 36 if (tt.style.opacity == null) rm(tt); 37 tt.style.opacity = 0; 38 setTimeout(function() { rm(tt); }, 600); 39 } 40 41 function showTooltipFor(e, content, node) { 42 var tooltip = showTooltip(e, content); 43 function hide() { 44 CodeMirror.off(node, "mouseout", hide); 45 if (tooltip) { hideTooltip(tooltip); tooltip = null; } 46 } 47 var poll = setInterval(function() { 48 if (tooltip) for (var n = node;; n = n.parentNode) { 49 if (n && n.nodeType == 11) n = n.host; 50 if (n == document.body) return; 51 if (!n) { hide(); break; } 52 } 53 if (!tooltip) return clearInterval(poll); 54 }, 400); 55 CodeMirror.on(node, "mouseout", hide); 56 } 57 58 function LintState(cm, options, hasGutter) { 59 this.marked = []; 60 this.options = options; 61 this.timeout = null; 62 this.hasGutter = hasGutter; 63 this.onMouseOver = function(e) { onMouseOver(cm, e); }; 64 this.waitingFor = 0 65 } 66 67 function parseOptions(_cm, options) { 68 if (options instanceof Function) return {getAnnotations: options}; 69 if (!options || options === true) options = {}; 70 return options; 71 } 72 73 function clearMarks(cm) { 74 var state = cm.state.lint; 75 if (state.hasGutter) cm.clearGutter(GUTTER_ID); 76 for (var i = 0; i < state.marked.length; ++i) 77 state.marked[i].clear(); 78 state.marked.length = 0; 79 } 80 81 function makeMarker(labels, severity, multiple, tooltips) { 82 var marker = document.createElement("div"), inner = marker; 83 marker.className = "CodeMirror-lint-marker-" + severity; 84 if (multiple) { 85 inner = marker.appendChild(document.createElement("div")); 86 inner.className = "CodeMirror-lint-marker-multiple"; 87 } 88 89 if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { 90 showTooltipFor(e, labels, inner); 91 }); 92 93 return marker; 94 } 95 96 function getMaxSeverity(a, b) { 97 if (a == "error") return a; 98 else return b; 99 } 100 101 function groupByLine(annotations) { 102 var lines = []; 103 for (var i = 0; i < annotations.length; ++i) { 104 var ann = annotations[i], line = ann.from.line; 105 (lines[line] || (lines[line] = [])).push(ann); 106 } 107 return lines; 108 } 109 110 function annotationTooltip(ann) { 111 var severity = ann.severity; 112 if (!severity) severity = "error"; 113 var tip = document.createElement("div"); 114 tip.className = "CodeMirror-lint-message-" + severity; 115 tip.appendChild(document.createTextNode(ann.message)); 116 return tip; 117 } 118 119 function lintAsync(cm, getAnnotations, passOptions) { 120 var state = cm.state.lint 121 var id = ++state.waitingFor 122 function abort() { 123 id = -1 124 cm.off("change", abort) 125 } 126 cm.on("change", abort) 127 getAnnotations(cm.getValue(), function(annotations, arg2) { 128 cm.off("change", abort) 129 if (state.waitingFor != id) return 130 if (arg2 && annotations instanceof CodeMirror) annotations = arg2 131 updateLinting(cm, annotations) 132 }, passOptions, cm); 133 } 134 135 function startLinting(cm) { 136 var state = cm.state.lint, options = state.options; 137 var passOptions = options.options || options; // Support deprecated passing of `options` property in options 138 var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); 139 if (!getAnnotations) return; 140 if (options.async || getAnnotations.async) { 141 lintAsync(cm, getAnnotations, passOptions) 142 } else { 143 updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm)); 144 } 145 } 146 147 function updateLinting(cm, annotationsNotSorted) { 148 clearMarks(cm); 149 var state = cm.state.lint, options = state.options; 150 151 var annotations = groupByLine(annotationsNotSorted); 152 153 for (var line = 0; line < annotations.length; ++line) { 154 var anns = annotations[line]; 155 if (!anns) continue; 156 157 var maxSeverity = null; 158 var tipLabel = state.hasGutter && document.createDocumentFragment(); 159 160 for (var i = 0; i < anns.length; ++i) { 161 var ann = anns[i]; 162 var severity = ann.severity; 163 if (!severity) severity = "error"; 164 maxSeverity = getMaxSeverity(maxSeverity, severity); 165 166 if (options.formatAnnotation) ann = options.formatAnnotation(ann); 167 if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); 168 169 if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { 170 className: "CodeMirror-lint-mark-" + severity, 171 __annotation: ann 172 })); 173 } 174 175 if (state.hasGutter) 176 cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, 177 state.options.tooltips)); 178 } 179 if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); 180 } 181 182 function onChange(cm) { 183 var state = cm.state.lint; 184 if (!state) return; 185 clearTimeout(state.timeout); 186 state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); 187 } 188 189 function popupSpanTooltip(ann, e) { 190 var target = e.target || e.srcElement; 191 showTooltipFor(e, annotationTooltip(ann), target); 192 } 193 194 function onMouseOver(cm, e) { 195 var target = e.target || e.srcElement; 196 if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; 197 var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; 198 var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); 199 for (var i = 0; i < spans.length; ++i) { 200 var ann = spans[i].__annotation; 201 if (ann) return popupSpanTooltip(ann, e); 202 } 203 } 204 205 CodeMirror.defineOption("lint", false, function(cm, val, old) { 206 if (old && old != CodeMirror.Init) { 207 clearMarks(cm); 208 if (cm.state.lint.options.lintOnChange !== false) 209 cm.off("change", onChange); 210 CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); 211 clearTimeout(cm.state.lint.timeout); 212 delete cm.state.lint; 213 } 214 215 if (val) { 216 var gutters = cm.getOption("gutters"), hasLintGutter = false; 217 for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; 218 var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); 219 if (state.options.lintOnChange !== false) 220 cm.on("change", onChange); 221 if (state.options.tooltips != false) 222 CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); 223 224 startLinting(cm); 225 } 226 }); 227 228 CodeMirror.defineExtension("performLint", function() { 229 if (this.state.lint) startLinting(this); 230 }); 231 });