File modules/editor/codemirror/addon/hint/show-hint.min.js

Last commit: Tue May 22 22:39:53 2018 +0200	Jan Dankert	Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.
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 options = parseOptions(this, this.getCursor("start"), options); 29 var selections = this.listSelections() 30 if (selections.length > 1) return; 31 // By default, don't allow completion when something is selected. 32 // A hint function can have a `supportsSelection` property to 33 // indicate that it can handle selections. 34 if (this.somethingSelected()) { 35 if (!options.hint.supportsSelection) return; 36 // Don't try with cross-line selections 37 for (var i = 0; i < selections.length; i++) 38 if (selections[i].head.line != selections[i].anchor.line) return; 39 } 40 41 if (this.state.completionActive) this.state.completionActive.close(); 42 var completion = this.state.completionActive = new Completion(this, options); 43 if (!completion.options.hint) return; 44 45 CodeMirror.signal(this, "startCompletion", this); 46 completion.update(true); 47 }); 48 49 function Completion(cm, options) { 50 this.cm = cm; 51 this.options = options; 52 this.widget = null; 53 this.debounce = 0; 54 this.tick = 0; 55 this.startPos = this.cm.getCursor("start"); 56 this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; 57 58 var self = this; 59 cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); 60 } 61 62 var requestAnimationFrame = window.requestAnimationFrame || function(fn) { 63 return setTimeout(fn, 1000/60); 64 }; 65 var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; 66 67 Completion.prototype = { 68 close: function() { 69 if (!this.active()) return; 70 this.cm.state.completionActive = null; 71 this.tick = null; 72 this.cm.off("cursorActivity", this.activityFunc); 73 74 if (this.widget && this.data) CodeMirror.signal(this.data, "close"); 75 if (this.widget) this.widget.close(); 76 CodeMirror.signal(this.cm, "endCompletion", this.cm); 77 }, 78 79 active: function() { 80 return this.cm.state.completionActive == this; 81 }, 82 83 pick: function(data, i) { 84 var completion = data.list[i]; 85 if (completion.hint) completion.hint(this.cm, data, completion); 86 else this.cm.replaceRange(getText(completion), completion.from || data.from, 87 completion.to || data.to, "complete"); 88 CodeMirror.signal(data, "pick", completion); 89 this.close(); 90 }, 91 92 cursorActivity: function() { 93 if (this.debounce) { 94 cancelAnimationFrame(this.debounce); 95 this.debounce = 0; 96 } 97 98 var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); 99 if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || 100 pos.ch < this.startPos.ch || this.cm.somethingSelected() || 101 (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { 102 this.close(); 103 } else { 104 var self = this; 105 this.debounce = requestAnimationFrame(function() {self.update();}); 106 if (this.widget) this.widget.disable(); 107 } 108 }, 109 110 update: function(first) { 111 if (this.tick == null) return 112 var self = this, myTick = ++this.tick 113 fetchHints(this.options.hint, this.cm, this.options, function(data) { 114 if (self.tick == myTick) self.finishUpdate(data, first) 115 }) 116 }, 117 118 finishUpdate: function(data, first) { 119 if (this.data) CodeMirror.signal(this.data, "update"); 120 121 var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); 122 if (this.widget) this.widget.close(); 123 124 this.data = data; 125 126 if (data && data.list.length) { 127 if (picked && data.list.length == 1) { 128 this.pick(data, 0); 129 } else { 130 this.widget = new Widget(this, data); 131 CodeMirror.signal(data, "shown"); 132 } 133 } 134 } 135 }; 136 137 function parseOptions(cm, pos, options) { 138 var editor = cm.options.hintOptions; 139 var out = {}; 140 for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; 141 if (editor) for (var prop in editor) 142 if (editor[prop] !== undefined) out[prop] = editor[prop]; 143 if (options) for (var prop in options) 144 if (options[prop] !== undefined) out[prop] = options[prop]; 145 if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) 146 return out; 147 } 148 149 function getText(completion) { 150 if (typeof completion == "string") return completion; 151 else return completion.text; 152 } 153 154 function buildKeyMap(completion, handle) { 155 var baseMap = { 156 Up: function() {handle.moveFocus(-1);}, 157 Down: function() {handle.moveFocus(1);}, 158 PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, 159 PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, 160 Home: function() {handle.setFocus(0);}, 161 End: function() {handle.setFocus(handle.length - 1);}, 162 Enter: handle.pick, 163 Tab: handle.pick, 164 Esc: handle.close 165 }; 166 var custom = completion.options.customKeys; 167 var ourMap = custom ? {} : baseMap; 168 function addBinding(key, val) { 169 var bound; 170 if (typeof val != "string") 171 bound = function(cm) { return val(cm, handle); }; 172 // This mechanism is deprecated 173 else if (baseMap.hasOwnProperty(val)) 174 bound = baseMap[val]; 175 else 176 bound = val; 177 ourMap[key] = bound; 178 } 179 if (custom) 180 for (var key in custom) if (custom.hasOwnProperty(key)) 181 addBinding(key, custom[key]); 182 var extra = completion.options.extraKeys; 183 if (extra) 184 for (var key in extra) if (extra.hasOwnProperty(key)) 185 addBinding(key, extra[key]); 186 return ourMap; 187 } 188 189 function getHintElement(hintsElement, el) { 190 while (el && el != hintsElement) { 191 if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; 192 el = el.parentNode; 193 } 194 } 195 196 function Widget(completion, data) { 197 this.completion = completion; 198 this.data = data; 199 this.picked = false; 200 var widget = this, cm = completion.cm; 201 202 var hints = this.hints = document.createElement("ul"); 203 hints.className = "CodeMirror-hints"; 204 this.selectedHint = data.selectedHint || 0; 205 206 var completions = data.list; 207 for (var i = 0; i < completions.length; ++i) { 208 var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; 209 var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); 210 if (cur.className != null) className = cur.className + " " + className; 211 elt.className = className; 212 if (cur.render) cur.render(elt, data, cur); 213 else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); 214 elt.hintId = i; 215 } 216 217 var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); 218 var left = pos.left, top = pos.bottom, below = true; 219 hints.style.left = left + "px"; 220 hints.style.top = top + "px"; 221 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. 222 var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); 223 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); 224 (completion.options.container || document.body).appendChild(hints); 225 var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; 226 var scrolls = hints.scrollHeight > hints.clientHeight + 1 227 var startScroll = cm.getScrollInfo(); 228 229 if (overlapY > 0) { 230 var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); 231 if (curTop - height > 0) { // Fits above cursor 232 hints.style.top = (top = pos.top - height) + "px"; 233 below = false; 234 } else if (height > winH) { 235 hints.style.height = (winH - 5) + "px"; 236 hints.style.top = (top = pos.bottom - box.top) + "px"; 237 var cursor = cm.getCursor(); 238 if (data.from.ch != cursor.ch) { 239 pos = cm.cursorCoords(cursor); 240 hints.style.left = (left = pos.left) + "px"; 241 box = hints.getBoundingClientRect(); 242 } 243 } 244 } 245 var overlapX = box.right - winW; 246 if (overlapX > 0) { 247 if (box.right - box.left > winW) { 248 hints.style.width = (winW - 5) + "px"; 249 overlapX -= (box.right - box.left) - winW; 250 } 251 hints.style.left = (left = pos.left - overlapX) + "px"; 252 } 253 if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) 254 node.style.paddingRight = cm.display.nativeBarWidth + "px" 255 256 cm.addKeyMap(this.keyMap = buildKeyMap(completion, { 257 moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, 258 setFocus: function(n) { widget.changeActive(n); }, 259 menuSize: function() { return widget.screenAmount(); }, 260 length: completions.length, 261 close: function() { completion.close(); }, 262 pick: function() { widget.pick(); }, 263 data: data 264 })); 265 266 if (completion.options.closeOnUnfocus) { 267 var closingOnBlur; 268 cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); 269 cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); 270 } 271 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[this.selectedHint], hints.childNodes[this.selectedHint]); 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 disable: function() { 319 this.completion.cm.removeKeyMap(this.keyMap); 320 var widget = this; 321 this.keyMap = {Enter: function() { widget.picked = true; }}; 322 this.completion.cm.addKeyMap(this.keyMap); 323 }, 324 325 pick: function() { 326 this.completion.pick(this.data, this.selectedHint); 327 }, 328 329 changeActive: function(i, avoidWrap) { 330 if (i >= this.data.list.length) 331 i = avoidWrap ? this.data.list.length - 1 : 0; 332 else if (i < 0) 333 i = avoidWrap ? 0 : this.data.list.length - 1; 334 if (this.selectedHint == i) return; 335 var node = this.hints.childNodes[this.selectedHint]; 336 node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); 337 node = this.hints.childNodes[this.selectedHint = i]; 338 node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; 339 if (node.offsetTop < this.hints.scrollTop) 340 this.hints.scrollTop = node.offsetTop - 3; 341 else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) 342 this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; 343 CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); 344 }, 345 346 screenAmount: function() { 347 return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; 348 } 349 }; 350 351 function applicableHelpers(cm, helpers) { 352 if (!cm.somethingSelected()) return helpers 353 var result = [] 354 for (var i = 0; i < helpers.length; i++) 355 if (helpers[i].supportsSelection) result.push(helpers[i]) 356 return result 357 } 358 359 function fetchHints(hint, cm, options, callback) { 360 if (hint.async) { 361 hint(cm, callback, options) 362 } else { 363 var result = hint(cm, options) 364 if (result && result.then) result.then(callback) 365 else callback(result) 366 } 367 } 368 369 function resolveAutoHints(cm, pos) { 370 var helpers = cm.getHelpers(pos, "hint"), words 371 if (helpers.length) { 372 var resolved = function(cm, callback, options) { 373 var app = applicableHelpers(cm, helpers); 374 function run(i) { 375 if (i == app.length) return callback(null) 376 fetchHints(app[i], cm, options, function(result) { 377 if (result && result.list.length > 0) callback(result) 378 else run(i + 1) 379 }) 380 } 381 run(0) 382 } 383 resolved.async = true 384 resolved.supportsSelection = true 385 return resolved 386 } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { 387 return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } 388 } else if (CodeMirror.hint.anyword) { 389 return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } 390 } else { 391 return function() {} 392 } 393 } 394 395 CodeMirror.registerHelper("hint", "auto", { 396 resolve: resolveAutoHints 397 }); 398 399 CodeMirror.registerHelper("hint", "fromList", function(cm, options) { 400 var cur = cm.getCursor(), token = cm.getTokenAt(cur); 401 var to = CodeMirror.Pos(cur.line, token.end); 402 if (token.string && /\w/.test(token.string[token.string.length - 1])) { 403 var term = token.string, from = CodeMirror.Pos(cur.line, token.start); 404 } else { 405 var term = "", from = to; 406 } 407 var found = []; 408 for (var i = 0; i < options.words.length; i++) { 409 var word = options.words[i]; 410 if (word.slice(0, term.length) == term) 411 found.push(word); 412 } 413 414 if (found.length) return {list: found, from: from, to: to}; 415 }); 416 417 CodeMirror.commands.autocomplete = CodeMirror.showHint; 418 419 var defaultOptions = { 420 hint: CodeMirror.hint.auto, 421 completeSingle: true, 422 alignWithWord: true, 423 closeCharacters: /[\s()\[\]{};:>,]/, 424 closeOnUnfocus: true, 425 completeOnSingleClick: true, 426 container: null, 427 customKeys: null, 428 extraKeys: null 429 }; 430 431 CodeMirror.defineOption("hintOptions", null); 432 });
Download modules/editor/codemirror/addon/hint/show-hint.min.js
History Tue, 22 May 2018 22:39:53 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.