Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
5 lars 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
  }
65
 
66
  function parseOptions(_cm, options) {
67
    if (options instanceof Function) return {getAnnotations: options};
68
    if (!options || options === true) options = {};
69
    return options;
70
  }
71
 
72
  function clearMarks(cm) {
73
    var state = cm.state.lint;
74
    if (state.hasGutter) cm.clearGutter(GUTTER_ID);
75
    for (var i = 0; i < state.marked.length; ++i)
76
      state.marked[i].clear();
77
    state.marked.length = 0;
78
  }
79
 
80
  function makeMarker(labels, severity, multiple, tooltips) {
81
    var marker = document.createElement("div"), inner = marker;
82
    marker.className = "CodeMirror-lint-marker-" + severity;
83
    if (multiple) {
84
      inner = marker.appendChild(document.createElement("div"));
85
      inner.className = "CodeMirror-lint-marker-multiple";
86
    }
87
 
88
    if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
89
      showTooltipFor(e, labels, inner);
90
    });
91
 
92
    return marker;
93
  }
94
 
95
  function getMaxSeverity(a, b) {
96
    if (a == "error") return a;
97
    else return b;
98
  }
99
 
100
  function groupByLine(annotations) {
101
    var lines = [];
102
    for (var i = 0; i < annotations.length; ++i) {
103
      var ann = annotations[i], line = ann.from.line;
104
      (lines[line] || (lines[line] = [])).push(ann);
105
    }
106
    return lines;
107
  }
108
 
109
  function annotationTooltip(ann) {
110
    var severity = ann.severity;
111
    if (!severity) severity = "error";
112
    var tip = document.createElement("div");
113
    tip.className = "CodeMirror-lint-message-" + severity;
114
    tip.appendChild(document.createTextNode(ann.message));
115
    return tip;
116
  }
117
 
118
  function startLinting(cm) {
119
    var state = cm.state.lint, options = state.options;
120
    var passOptions = options.options || options; // Support deprecated passing of `options` property in options
121
    var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
122
    if (!getAnnotations) return;
123
    if (options.async || getAnnotations.async)
124
      getAnnotations(cm.getValue(), updateLinting, passOptions, cm);
125
    else
126
      updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm));
127
  }
128
 
129
  function updateLinting(cm, annotationsNotSorted) {
130
    clearMarks(cm);
131
    var state = cm.state.lint, options = state.options;
132
 
133
    var annotations = groupByLine(annotationsNotSorted);
134
 
135
    for (var line = 0; line < annotations.length; ++line) {
136
      var anns = annotations[line];
137
      if (!anns) continue;
138
 
139
      var maxSeverity = null;
140
      var tipLabel = state.hasGutter && document.createDocumentFragment();
141
 
142
      for (var i = 0; i < anns.length; ++i) {
143
        var ann = anns[i];
144
        var severity = ann.severity;
145
        if (!severity) severity = "error";
146
        maxSeverity = getMaxSeverity(maxSeverity, severity);
147
 
148
        if (options.formatAnnotation) ann = options.formatAnnotation(ann);
149
        if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
150
 
151
        if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
152
          className: "CodeMirror-lint-mark-" + severity,
153
          __annotation: ann
154
        }));
155
      }
156
 
157
      if (state.hasGutter)
158
        cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
159
                                                       state.options.tooltips));
160
    }
161
    if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
162
  }
163
 
164
  function onChange(cm) {
165
    var state = cm.state.lint;
166
    if (!state) return;
167
    clearTimeout(state.timeout);
168
    state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
169
  }
170
 
171
  function popupSpanTooltip(ann, e) {
172
    var target = e.target || e.srcElement;
173
    showTooltipFor(e, annotationTooltip(ann), target);
174
  }
175
 
176
  function onMouseOver(cm, e) {
177
    var target = e.target || e.srcElement;
178
    if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
179
    var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
180
    var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
181
    for (var i = 0; i < spans.length; ++i) {
182
      var ann = spans[i].__annotation;
183
      if (ann) return popupSpanTooltip(ann, e);
184
    }
185
  }
186
 
187
  CodeMirror.defineOption("lint", false, function(cm, val, old) {
188
    if (old && old != CodeMirror.Init) {
189
      clearMarks(cm);
190
      if (cm.state.lint.options.lintOnChange !== false)
191
        cm.off("change", onChange);
192
      CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
193
      clearTimeout(cm.state.lint.timeout);
194
      delete cm.state.lint;
195
    }
196
 
197
    if (val) {
198
      var gutters = cm.getOption("gutters"), hasLintGutter = false;
199
      for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
200
      var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
201
      if (state.options.lintOnChange !== false)
202
        cm.on("change", onChange);
203
      if (state.options.tooltips != false)
204
        CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
205
 
206
      startLinting(cm);
207
    }
208
  });
209
 
210
  CodeMirror.defineExtension("performLint", function() {
211
    if (this.state.lint) startLinting(this);
212
  });
213
});