api-console-assets
Version:
This repo only exists to publish api console components to npm
546 lines (501 loc) • 16 kB
JavaScript
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == 'object' && typeof module == 'object') {// CommonJS
mod(require('./../lib/codemirror'));
} else if (typeof define == 'function' && define.amd) {// AMD
define(['../../lib/codemirror'], mod);
} else {// Plain browser env
mod(CodeMirror);
}
})(function(CodeMirror) {
'use strict';
var HINT_ELEMENT_CLASS = 'CodeMirror-hint';
var ACTIVE_HINT_ELEMENT_CLASS = 'iron-selected';
// This is the old interface, kept around for now to stay
// backwards-compatible.
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) {
// We want a single cursor position.
if (this.listSelections().length > 1 || this.somethingSelected()) {
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 = this.buildOptions(options);
this.widget = null;
this.debounce = 0;
this.tick = 0;
this.startPos = this.cm.getCursor();
this.startLen = this.cm.getLine(this.startPos.line).length;
var self = this;
cm.on('cursorActivity', this.activityFunc = function() {
self.cursorActivity();
});
}
var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
return setTimeout(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();
var line = this.cm.getLine(pos.line);
if (pos.line != this.startPos.line ||
line.length - 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.data) {
CodeMirror.signal(this.data, 'update');
}
if (!this.options.hint.async) {
this.finishUpdate(this.options.hint(this.cm, this.options), first);
} else {
var myTick = ++this.tick;
var self = this;
this.options.hint(this.cm, function(data) {
if (self.tick == myTick) {
self.finishUpdate(data, first);
}
}, this.options);
}
},
finishUpdate: function(data, first) {
this.data = data;
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
if (this.widget) {
this.widget.close();
}
if (data && data.list.length) {
if (picked && data.list.length == 1) {
this.pick(data, 0);
} else {
this.widget = new Widget(this, data);
CodeMirror.signal(data, 'shown');
}
}
},
buildOptions: function(options) {
var editor = this.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];
}
}
}
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(handle.length - 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);
};
// This mechanism is deprecated
} 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;
var cm = completion.cm;
var hints = this.hints = document.createElement('paper-material');
hints.className = 'CodeMirror-hints';
this.selectedHint = data.selectedHint || 0;
var container = document.createElement('paper-menu');
container.selected = 0;
hints.appendChild(container);
hints.elevation = 2;
var completions = data.list;
for (var i = 0; i < completions.length; ++i) {
var elt = container.appendChild(document.createElement('paper-item'));
var cur = completions[i];
var className = HINT_ELEMENT_CLASS + (i !== this.selectedHint ? '' : ' ' +
ACTIVE_HINT_ELEMENT_CLASS);
if (cur.className !== null) {
className = cur.className ? cur.className + ' ' + className : className;
}
elt.className = className;
if (cur.render) {
cur.render(elt, data, cur);
} else {
elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
}
elt.hintId = i;
}
if (hints.children[0].children[0].nodeName === 'DIV') {
this._indexOffset = 1;
} else {
this._indexOffset = 0;
}
var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null, 'local');
var left = pos.left;
var top = pos.bottom;
var below = true;
hints.style.left = left + 'px';
hints.style.top = top + 'px';
// If we're at the edge of the screen, then we want the menu to appear on the left of the
// cursor.
var winW = window.innerWidth || Math.max(document.body.offsetWidth,
document.documentElement.offsetWidth);
var winH = window.innerHeight || Math.max(document.body.offsetHeight,
document.documentElement.offsetHeight);
(completion.options.container || document.body).appendChild(hints);
var box = hints.getBoundingClientRect();
var overlapY = box.bottom - winH;
if (overlapY > 0) {
var height = box.bottom - box.top;
var curTop = pos.top - (pos.bottom - box.top);
if (curTop - height > 0) { // Fits above cursor
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: completions.length,
close: function() {
completion.close();
},
pick: function() {
widget.pick();
},
data: data
}));
if (completion.options.closeOnUnfocus) {
var closingOnBlur;
cm.on('blur', this.onBlur = function() {
closingOnBlur = setTimeout(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();
var 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.children[0], e.target || e.srcElement);
if (t && t.hintId != null) {
widget.changeActive(t.hintId);
widget.pick();
}
});
CodeMirror.on(hints, 'click', function(e) {
var t = getHintElement(hints.children[0], e.target || e.srcElement);
if (t && t.hintId != null) {
widget.changeActive(t.hintId);
if (completion.options.completeOnSingleClick) {
widget.pick();
}
}
});
CodeMirror.on(hints, 'mousedown', function() {
setTimeout(function() {
cm.focus();
}, 20);
});
CodeMirror.signal(data, 'select', completions[0], hints.children[0].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) {
// i += this._indexOffset;
if (i >= this.data.list.length) {
i = avoidWrap ? this.data.list.length - 1 : 0;
} else if (i < 0) {
i = avoidWrap ? 0 : this.data.list.length - 1;
}
if (this.selectedHint === i) {
return;
}
var selectedHint = this.selectedHint + this._indexOffset;
var node = this.hints.children[0].children[selectedHint];
node.classList.remove(ACTIVE_HINT_ELEMENT_CLASS);
selectedHint = i + this._indexOffset;
this.selectedHint = i;
node = this.hints.children[0].children[selectedHint];
node.classList.add(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[selectedHint], node);
},
screenAmount: function() {
return Math.floor(this.hints.clientHeight /
this.hints.children[0].children[0].offsetHeight) || 1;
}
};
CodeMirror.registerHelper('hint', 'auto', function(cm, options) {
var helpers = cm.getHelpers(cm.getCursor(), 'hint');
var words;
if (helpers.length) {
for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, options);
if (cur && cur.list.length) {
return cur;
}
}
} else if (words = cm.getHelper(cm.getCursor(), 'hintWords')) {
if (words) {
return CodeMirror.hint.fromList(cm, {
words: words
});
}
} else if (CodeMirror.hint.anyword) {
return CodeMirror.hint.anyword(cm, options);
}
});
CodeMirror.registerHelper('hint', 'fromList', function(cm, options) {
var cur = cm.getCursor();
var token = cm.getTokenAt(cur);
var found = [];
for (var i = 0; i < options.words.length; i++) {
var word = options.words[i];
if (word.slice(0, token.string.length) === token.string) {
found.push(word);
}
}
if (found.length) {
return {
list: found,
from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)
};
}
});
CodeMirror.commands.autocomplete = CodeMirror.showHint;
var defaultOptions = {
hint: CodeMirror.hint.auto,
completeSingle: true,
alignWithWord: true,
closeCharacters: /[\s()\[\]{};:>,]/,
closeOnUnfocus: true,
completeOnSingleClick: false,
container: null,
customKeys: null,
extraKeys: null
};
CodeMirror.defineOption('hintOptions', null);
});