(function (mod){ if (typeof exports == "object" && typeof module == "object") mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) define(["../../lib/codemirror"] , mod); else mod(CodeMirror); } )(function (CodeMirror){ "use strict"; var HINT_ELEMENT_CLASS = "CodeMirror-hint"; var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; CodeMirror.showHint = function (cm, getHints, options){ if (!getHints) return cm.showHint(options); if (options && options.async) getHints.async = true ; var newOpts = { hint: getHints} ; if (options) for (var prop in options)newOpts[prop] = options[prop]; return cm.showHint(newOpts); } ; CodeMirror.defineExtension("showHint", function (options){ options = parseOptions(this, this.getCursor("start"), options); var selections = this.listSelections(); if (_AN_Read_length("length", selections) > 1) return ; if (this.somethingSelected()) { if (!options.hint.supportsSelection) return ; for (var i = 0; i < _AN_Read_length("length", selections); i++ )if (selections[i].head.line != selections[i].anchor.line) return ; } if (this.state.completionActive) this.state.completionActive.close(); var completion = this.state.completionActive = new Completion(this, options); if (!completion.options.hint) return ; CodeMirror.signal(this, "startCompletion", this); completion.update(true ); } ); function Completion(cm, options){ this.cm = cm; this.options = options; this.widget = null ; this.debounce = 0; this.tick = 0; this.startPos = this.cm.getCursor("start"); this.startLen = _AN_Read_length("length", this.cm.getLine(this.startPos.line)) - _AN_Read_length("length", this.cm.getSelection()); var self = this; cm.on("cursorActivity", this.activityFunc = function (){ self.cursorActivity(); } ); } var requestAnimationFrame = window.requestAnimationFrame || function (fn){ return _AN_Call_settimeout("setTimeout", window, fn, 1000 / 60); } ; var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; Completion.prototype = { close: function (){ if (!this.active()) return ; this.cm.state.completionActive = null ; this.tick = null ; this.cm.off("cursorActivity", this.activityFunc); if (this.widget && this.data) CodeMirror.signal(this.data, "close"); if (this.widget) this.widget.close(); CodeMirror.signal(this.cm, "endCompletion", this.cm); } , active: function (){ return this.cm.state.completionActive == this; } , pick: function (data, i){ var completion = data.list[i]; if (completion.hint) completion.hint(this.cm, data, completion); else this.cm.replaceRange(getText(completion), completion.from || data.from, completion.to || data.to, "complete"); CodeMirror.signal(data, "pick", completion); this.close(); } , cursorActivity: function (){ if (this.debounce) { cancelAnimationFrame(this.debounce); this.debounce = 0; } var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); if (pos.line != this.startPos.line || _AN_Read_length("length", line) - pos.ch != this.startLen - this.startPos.ch || pos.ch < this.startPos.ch || this.cm.somethingSelected() || (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { this.close(); } else { var self = this; this.debounce = requestAnimationFrame(function (){ self.update(); } ); if (this.widget) this.widget.disable(); } } , update: function (first){ if (this.tick == null ) return ; if (!this.options.hint.async) { this.finishUpdate(this.options.hint(this.cm, this.options), first); } else { var myTick = ++this.tick, self = this; this.options.hint(this.cm, function (data){ if (self.tick == myTick) self.finishUpdate(data, first); } , this.options); } } , finishUpdate: function (data, first){ if (this.data) CodeMirror.signal(this.data, "update"); var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); if (this.widget) this.widget.close(); if (data && this.data && isNewCompletion(this.data, data)) return ; this.data = data; if (data && _AN_Read_length("length", data.list)) { if (picked && _AN_Read_length("length", data.list) == 1) { this.pick(data, 0); } else { this.widget = new Widget(this, data); CodeMirror.signal(data, "shown"); } } } } ; function isNewCompletion(old, nw){ var moved = CodeMirror.cmpPos(nw.from, old.from); return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch; } function parseOptions(cm, pos, options){ var editor = cm.options.hintOptions; var out = { } ; for (var prop in defaultOptions)out[prop] = defaultOptions[prop]; if (editor) for (var prop in editor)if (editor[prop] !== undefined) out[prop] = editor[prop]; if (options) for (var prop in options)if (options[prop] !== undefined) out[prop] = options[prop]; if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos); return out; } function getText(completion){ if (typeof completion == "string") return completion; else return completion.text; } function buildKeyMap(completion, handle){ var baseMap = { Up: function (){ handle.moveFocus(-1); } , Down: function (){ handle.moveFocus(1); } , PageUp: function (){ handle.moveFocus(- handle.menuSize() + 1, true ); } , PageDown: function (){ handle.moveFocus(handle.menuSize() - 1, true ); } , Home: function (){ handle.setFocus(0); } , End: function (){ handle.setFocus(_AN_Read_length("length", handle) - 1); } , Enter: handle.pick, Tab: handle.pick, Esc: handle.close} ; var custom = completion.options.customKeys; var ourMap = custom? { } : baseMap; function addBinding(key, val){ var bound; if (typeof val != "string") bound = function (cm){ return val(cm, handle); } ; else if (baseMap.hasOwnProperty(val)) bound = baseMap[val]; else bound = val; ourMap[key] = bound; } if (custom) for (var key in custom)if (custom.hasOwnProperty(key)) addBinding(key, custom[key]); var extra = completion.options.extraKeys; if (extra) for (var key in extra)if (extra.hasOwnProperty(key)) addBinding(key, extra[key]); return ourMap; } function getHintElement(hintsElement, el){ while (el && el != hintsElement){ if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; el = el.parentNode; } } function Widget(completion, data){ this.completion = completion; this.data = data; this.picked = false ; var widget = this, cm = completion.cm; var hints = this.hints = _AN_Call_createelement("createElement", document, "ul"); hints.className = "CodeMirror-hints"; this.selectedHint = data.selectedHint || 0; var completions = data.list; for (var i = 0; i < _AN_Read_length("length", completions); ++i){ var elt = _AN_Call_appendchild("appendChild", hints, _AN_Call_createelement("createElement", document, "li")), cur = completions[i]; var className = HINT_ELEMENT_CLASS + (i != this.selectedHint? "": " " + ACTIVE_HINT_ELEMENT_CLASS); if (cur.className != null ) className = cur.className + " " + className; elt.className = className; if (cur.render) cur.render(elt, data, cur); else _AN_Call_appendchild("appendChild", elt, document.createTextNode(cur.displayText || getText(cur))); elt.hintId = i; } var pos = cm.cursorCoords(completion.options.alignWithWord? data.from: null ); var left = pos.left, top = pos.bottom, below = true ; hints.style.left = left + "px"; hints.style.top = top + "px"; var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); _AN_Call_appendchild("appendChild", (completion.options.container || document.body), hints); var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; if (overlapY > 0) { var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); if (curTop - height > 0) { hints.style.top = (top = pos.top - height) + "px"; below = false ; } else if (height > winH) { hints.style.height = (winH - 5) + "px"; hints.style.top = (top = pos.bottom - box.top) + "px"; var cursor = cm.getCursor(); if (data.from.ch != cursor.ch) { pos = cm.cursorCoords(cursor); hints.style.left = (left = pos.left) + "px"; box = hints.getBoundingClientRect(); } } } var overlapX = box.right - winW; if (overlapX > 0) { if (box.right - box.left > winW) { hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } hints.style.left = (left = pos.left - overlapX) + "px"; } cm.addKeyMap(this.keyMap = buildKeyMap(completion, { moveFocus: function (n, avoidWrap){ widget.changeActive(widget.selectedHint + n, avoidWrap); } , setFocus: function (n){ widget.changeActive(n); } , menuSize: function (){ return widget.screenAmount(); } , length: _AN_Read_length("length", completions), close: function (){ completion.close(); } , pick: function (){ widget.pick(); } , data: data} )); if (completion.options.closeOnUnfocus) { var closingOnBlur; cm.on("blur", this.onBlur = function (){ closingOnBlur = _AN_Call_settimeout("setTimeout", window, function (){ completion.close(); } , 100); } ); cm.on("focus", this.onFocus = function (){ clearTimeout(closingOnBlur); } ); } var startScroll = cm.getScrollInfo(); cm.on("scroll", this.onScroll = function (){ var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); var newTop = top + startScroll.top - curScroll.top; var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); if (!below) point += hints.offsetHeight; if (point <= editor.top || point >= editor.bottom) return completion.close(); hints.style.top = newTop + "px"; hints.style.left = (left + startScroll.left - curScroll.left) + "px"; } ); CodeMirror.on(hints, "dblclick", function (e){ var t = getHintElement(hints, _AN_Read_target("target", e) || e.srcElement); if (t && t.hintId != null ) { widget.changeActive(t.hintId); widget.pick(); } } ); CodeMirror.on(hints, "click", function (e){ var t = getHintElement(hints, _AN_Read_target("target", e) || e.srcElement); if (t && t.hintId != null ) { widget.changeActive(t.hintId); if (completion.options.completeOnSingleClick) widget.pick(); } } ); CodeMirror.on(hints, "mousedown", function (){ _AN_Call_settimeout("setTimeout", window, function (){ cm.focus(); } , 20); } ); CodeMirror.signal(data, "select", completions[0], hints.firstChild); return true ; } Widget.prototype = { close: function (){ if (this.completion.widget != this) return ; this.completion.widget = null ; this.hints.parentNode.removeChild(this.hints); this.completion.cm.removeKeyMap(this.keyMap); var cm = this.completion.cm; if (this.completion.options.closeOnUnfocus) { cm.off("blur", this.onBlur); cm.off("focus", this.onFocus); } cm.off("scroll", this.onScroll); } , disable: function (){ this.completion.cm.removeKeyMap(this.keyMap); var widget = this; this.keyMap = { Enter: function (){ widget.picked = true ; } } ; this.completion.cm.addKeyMap(this.keyMap); } , pick: function (){ this.completion.pick(this.data, this.selectedHint); } , changeActive: function (i, avoidWrap){ if (i >= _AN_Read_length("length", this.data.list)) i = avoidWrap? _AN_Read_length("length", this.data.list) - 1: 0; else if (i < 0) i = avoidWrap? 0: _AN_Read_length("length", this.data.list) - 1; if (this.selectedHint == i) return ; var node = this.hints.childNodes[this.selectedHint]; node.className = _AN_Call_replace("replace", node.className, " " + ACTIVE_HINT_ELEMENT_CLASS, ""); node = this.hints.childNodes[this.selectedHint = i]; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; if (node.offsetTop < this.hints.scrollTop) this.hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); } , screenAmount: function (){ return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; } } ; function applicableHelpers(cm, helpers){ if (!cm.somethingSelected()) return helpers; var result = [] ; for (var i = 0; i < _AN_Read_length("length", helpers); i++ )if (helpers[i].supportsSelection) result.push(helpers[i]); return result; } function resolveAutoHints(cm, pos){ var helpers = cm.getHelpers(pos, "hint"), words; if (helpers.length) { var async = false , resolved; for (var i = 0; i < _AN_Read_length("length", helpers); i++ )if (helpers[i].async) async = true ; if (async) { resolved = function (cm, callback, options){ var app = applicableHelpers(cm, helpers); function run(i, result){ if (i == _AN_Read_length("length", app)) return callback(null ); var helper = app[i]; if (helper.async) { helper(cm, function (result){ if (result) callback(result); else run(i + 1); } , options); } else { var result = helper(cm, options); if (result) callback(result); else run(i + 1); } } run(0); } ; resolved.async = true ; } else { resolved = function (cm, options){ var app = applicableHelpers(cm, helpers); for (var i = 0; i < _AN_Read_length("length", app); i++ ){ var cur = app[i](cm, options); if (cur && _AN_Read_length("length", cur.list)) return cur; } } ; } resolved.supportsSelection = true ; return resolved; } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { return function (cm){ return CodeMirror.hint.fromList(cm, { words: words} ); } ; } else if (CodeMirror.hint.anyword) { return function (cm, options){ return CodeMirror.hint.anyword(cm, options); } ; } else { return function (){ } ; } } CodeMirror.registerHelper("hint", "auto", { resolve: resolveAutoHints} ); CodeMirror.registerHelper("hint", "fromList", function (cm, options){ var cur = cm.getCursor(), token = cm.getTokenAt(cur); var to = CodeMirror.Pos(cur.line, token.end); if (token.string && /\w/.test(token.string[_AN_Read_length("length", token.string) - 1])) { var term = token.string, from = CodeMirror.Pos(cur.line, token.start); } else { var term = "", from = to; } var found = [] ; for (var i = 0; i < _AN_Read_length("length", options.words); i++ ){ var word = options.words[i]; if (word.slice(0, _AN_Read_length("length", term)) == term) found.push(word); } if (found.length) return { list: found, from: from, to: to} ; } ); CodeMirror.commands.autocomplete = CodeMirror.showHint; var defaultOptions = { hint: CodeMirror.hint.auto, completeSingle: true , alignWithWord: true , closeCharacters: /[\s()\[\]{};:>,]/, closeOnUnfocus: true , completeOnSingleClick: true , container: null , customKeys: null , extraKeys: null } ; CodeMirror.defineOption("hintOptions", null ); } );