PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.8.23.4
Pods – Custom Content Types and Fields v2.8.23.4
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / ui / js / codemirror / addon / mode / show-hint.js
pods / ui / js / codemirror / addon / mode Last commit date
loadmode.js 2 weeks ago overlay.js 2 weeks ago show-hint.js 2 weeks ago
show-hint.js
390 lines
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
14 var HINT_ELEMENT_CLASS = "CodeMirror-hint";
15 var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
16
17 // This is the old interface, kept around for now to stay
18 // backwards-compatible.
19 CodeMirror.showHint = function(cm, getHints, options) {
20 if (!getHints) return cm.showHint(options);
21 if (options && options.async) getHints.async = true;
22 var newOpts = {hint: getHints};
23 if (options) for (var prop in options) newOpts[prop] = options[prop];
24 return cm.showHint(newOpts);
25 };
26
27 CodeMirror.defineExtension("showHint", function(options) {
28 // We want a single cursor position.
29 if (this.listSelections().length > 1 || this.somethingSelected()) return;
30
31 if (this.state.completionActive) this.state.completionActive.close();
32 var completion = this.state.completionActive = new Completion(this, options);
33 var getHints = completion.options.hint;
34 if (!getHints) return;
35
36 CodeMirror.signal(this, "startCompletion", this);
37 if (getHints.async)
38 getHints(this, function(hints) { completion.showHints(hints); }, completion.options);
39 else
40 return completion.showHints(getHints(this, completion.options));
41 });
42
43 function Completion(cm, options) {
44 this.cm = cm;
45 this.options = this.buildOptions(options);
46 this.widget = this.onClose = null;
47 }
48
49 Completion.prototype = {
50 close: function() {
51 if (!this.active()) return;
52 this.cm.state.completionActive = null;
53
54 if (this.widget) this.widget.close();
55 if (this.onClose) this.onClose();
56 CodeMirror.signal(this.cm, "endCompletion", this.cm);
57 },
58
59 active: function() {
60 return this.cm.state.completionActive == this;
61 },
62
63 pick: function(data, i) {
64 var completion = data.list[i];
65 if (completion.hint) completion.hint(this.cm, data, completion);
66 else this.cm.replaceRange(getText(completion), completion.from || data.from,
67 completion.to || data.to, "complete");
68 CodeMirror.signal(data, "pick", completion);
69 this.close();
70 },
71
72 showHints: function(data) {
73 if (!data || !data.list.length || !this.active()) return this.close();
74
75 if (this.options.completeSingle && data.list.length == 1)
76 this.pick(data, 0);
77 else
78 this.showWidget(data);
79 },
80
81 showWidget: function(data) {
82 this.widget = new Widget(this, data);
83 CodeMirror.signal(data, "shown");
84
85 var debounce = 0, completion = this, finished;
86 var closeOn = this.options.closeCharacters;
87 var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
88
89 var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
90 return setTimeout(fn, 1000/60);
91 };
92 var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
93
94 function done() {
95 if (finished) return;
96 finished = true;
97 completion.close();
98 completion.cm.off("cursorActivity", activity);
99 if (data) CodeMirror.signal(data, "close");
100 }
101
102 function update() {
103 if (finished) return;
104 CodeMirror.signal(data, "update");
105 var getHints = completion.options.hint;
106 if (getHints.async)
107 getHints(completion.cm, finishUpdate, completion.options);
108 else
109 finishUpdate(getHints(completion.cm, completion.options));
110 }
111 function finishUpdate(data_) {
112 data = data_;
113 if (finished) return;
114 if (!data || !data.list.length) return done();
115 if (completion.widget) completion.widget.close();
116 completion.widget = new Widget(completion, data);
117 }
118
119 function clearDebounce() {
120 if (debounce) {
121 cancelAnimationFrame(debounce);
122 debounce = 0;
123 }
124 }
125
126 function activity() {
127 clearDebounce();
128 var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
129 if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
130 pos.ch < startPos.ch || completion.cm.somethingSelected() ||
131 (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
132 completion.close();
133 } else {
134 debounce = requestAnimationFrame(update);
135 if (completion.widget) completion.widget.close();
136 }
137 }
138 this.cm.on("cursorActivity", activity);
139 this.onClose = done;
140 },
141
142 buildOptions: function(options) {
143 var editor = this.cm.options.hintOptions;
144 var out = {};
145 for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
146 if (editor) for (var prop in editor)
147 if (editor[prop] !== undefined) out[prop] = editor[prop];
148 if (options) for (var prop in options)
149 if (options[prop] !== undefined) out[prop] = options[prop];
150 return out;
151 }
152 };
153
154 function getText(completion) {
155 if (typeof completion == "string") return completion;
156 else return completion.text;
157 }
158
159 function buildKeyMap(completion, handle) {
160 var baseMap = {
161 Up: function() {handle.moveFocus(-1);},
162 Down: function() {handle.moveFocus(1);},
163 PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
164 PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
165 Home: function() {handle.setFocus(0);},
166 End: function() {handle.setFocus(handle.length - 1);},
167 Enter: handle.pick,
168 Tab: handle.pick,
169 Esc: handle.close
170 };
171 var custom = completion.options.customKeys;
172 var ourMap = custom ? {} : baseMap;
173 function addBinding(key, val) {
174 var bound;
175 if (typeof val != "string")
176 bound = function(cm) { return val(cm, handle); };
177 // This mechanism is deprecated
178 else if (baseMap.hasOwnProperty(val))
179 bound = baseMap[val];
180 else
181 bound = val;
182 ourMap[key] = bound;
183 }
184 if (custom)
185 for (var key in custom) if (custom.hasOwnProperty(key))
186 addBinding(key, custom[key]);
187 var extra = completion.options.extraKeys;
188 if (extra)
189 for (var key in extra) if (extra.hasOwnProperty(key))
190 addBinding(key, extra[key]);
191 return ourMap;
192 }
193
194 function getHintElement(hintsElement, el) {
195 while (el && el != hintsElement) {
196 if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
197 el = el.parentNode;
198 }
199 }
200
201 function Widget(completion, data) {
202 this.completion = completion;
203 this.data = data;
204 var widget = this, cm = completion.cm;
205
206 var hints = this.hints = document.createElement("ul");
207 hints.className = "CodeMirror-hints";
208 this.selectedHint = data.selectedHint || 0;
209
210 var completions = data.list;
211 for (var i = 0; i < completions.length; ++i) {
212 var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
213 var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
214 if (cur.className != null) className = cur.className + " " + className;
215 elt.className = className;
216 if (cur.render) cur.render(elt, data, cur);
217 else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
218 elt.hintId = i;
219 }
220
221 var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
222 var left = pos.left, top = pos.bottom, below = true;
223 hints.style.left = left + "px";
224 hints.style.top = top + "px";
225 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
226 var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
227 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
228 (completion.options.container || document.body).appendChild(hints);
229 var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
230 if (overlapY > 0) {
231 var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
232 if (curTop - height > 0) { // Fits above cursor
233 hints.style.top = (top = pos.top - height) + "px";
234 below = false;
235 } else if (height > winH) {
236 hints.style.height = (winH - 5) + "px";
237 hints.style.top = (top = pos.bottom - box.top) + "px";
238 var cursor = cm.getCursor();
239 if (data.from.ch != cursor.ch) {
240 pos = cm.cursorCoords(cursor);
241 hints.style.left = (left = pos.left) + "px";
242 box = hints.getBoundingClientRect();
243 }
244 }
245 }
246 var overlapX = box.right - winW;
247 if (overlapX > 0) {
248 if (box.right - box.left > winW) {
249 hints.style.width = (winW - 5) + "px";
250 overlapX -= (box.right - box.left) - winW;
251 }
252 hints.style.left = (left = pos.left - overlapX) + "px";
253 }
254
255 cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
256 moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
257 setFocus: function(n) { widget.changeActive(n); },
258 menuSize: function() { return widget.screenAmount(); },
259 length: completions.length,
260 close: function() { completion.close(); },
261 pick: function() { widget.pick(); },
262 data: data
263 }));
264
265 if (completion.options.closeOnUnfocus) {
266 var closingOnBlur;
267 cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
268 cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
269 }
270
271 var startScroll = cm.getScrollInfo();
272 cm.on("scroll", this.onScroll = function() {
273 var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
274 var newTop = top + startScroll.top - curScroll.top;
275 var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
276 if (!below) point += hints.offsetHeight;
277 if (point <= editor.top || point >= editor.bottom) return completion.close();
278 hints.style.top = newTop + "px";
279 hints.style.left = (left + startScroll.left - curScroll.left) + "px";
280 });
281
282 CodeMirror.on(hints, "dblclick", function(e) {
283 var t = getHintElement(hints, e.target || e.srcElement);
284 if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
285 });
286
287 CodeMirror.on(hints, "click", function(e) {
288 var t = getHintElement(hints, e.target || e.srcElement);
289 if (t && t.hintId != null) {
290 widget.changeActive(t.hintId);
291 if (completion.options.completeOnSingleClick) widget.pick();
292 }
293 });
294
295 CodeMirror.on(hints, "mousedown", function() {
296 setTimeout(function(){cm.focus();}, 20);
297 });
298
299 CodeMirror.signal(data, "select", completions[0], hints.firstChild);
300 return true;
301 }
302
303 Widget.prototype = {
304 close: function() {
305 if (this.completion.widget != this) return;
306 this.completion.widget = null;
307 this.hints.parentNode.removeChild(this.hints);
308 this.completion.cm.removeKeyMap(this.keyMap);
309
310 var cm = this.completion.cm;
311 if (this.completion.options.closeOnUnfocus) {
312 cm.off("blur", this.onBlur);
313 cm.off("focus", this.onFocus);
314 }
315 cm.off("scroll", this.onScroll);
316 },
317
318 pick: function() {
319 this.completion.pick(this.data, this.selectedHint);
320 },
321
322 changeActive: function(i, avoidWrap) {
323 if (i >= this.data.list.length)
324 i = avoidWrap ? this.data.list.length - 1 : 0;
325 else if (i < 0)
326 i = avoidWrap ? 0 : this.data.list.length - 1;
327 if (this.selectedHint == i) return;
328 var node = this.hints.childNodes[this.selectedHint];
329 node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
330 node = this.hints.childNodes[this.selectedHint = i];
331 node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
332 if (node.offsetTop < this.hints.scrollTop)
333 this.hints.scrollTop = node.offsetTop - 3;
334 else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
335 this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
336 CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
337 },
338
339 screenAmount: function() {
340 return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
341 }
342 };
343
344 CodeMirror.registerHelper("hint", "auto", function(cm, options) {
345 var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
346 if (helpers.length) {
347 for (var i = 0; i < helpers.length; i++) {
348 var cur = helpers[i](cm, options);
349 if (cur && cur.list.length) return cur;
350 }
351 } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
352 if (words) return CodeMirror.hint.fromList(cm, {words: words});
353 } else if (CodeMirror.hint.anyword) {
354 return CodeMirror.hint.anyword(cm, options);
355 }
356 });
357
358 CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
359 var cur = cm.getCursor(), token = cm.getTokenAt(cur);
360 var found = [];
361 for (var i = 0; i < options.words.length; i++) {
362 var word = options.words[i];
363 if (word.slice(0, token.string.length) == token.string)
364 found.push(word);
365 }
366
367 if (found.length) return {
368 list: found,
369 from: CodeMirror.Pos(cur.line, token.start),
370 to: CodeMirror.Pos(cur.line, token.end)
371 };
372 });
373
374 CodeMirror.commands.autocomplete = CodeMirror.showHint;
375
376 var defaultOptions = {
377 hint: CodeMirror.hint.auto,
378 completeSingle: true,
379 alignWithWord: true,
380 closeCharacters: /[\s()\[\]{};:>,]/,
381 closeOnUnfocus: true,
382 completeOnSingleClick: false,
383 container: null,
384 customKeys: null,
385 extraKeys: null
386 };
387
388 CodeMirror.defineOption("hintOptions", null);
389 });
390