codemirror3, thanks Roberto
This commit is contained in:
+582
@@ -0,0 +1,582 @@
|
||||
(function () {
|
||||
function htmlHint(editor, htmlStructure, getToken) {
|
||||
var cur = editor.getCursor();
|
||||
var token = getToken(editor, cur);
|
||||
var keywords = [];
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var from = {line: cur.line, ch: cur.ch};
|
||||
var to = {line: cur.line, ch: cur.ch};
|
||||
var flagClean = true;
|
||||
|
||||
var text = editor.getRange({line: 0, ch: 0}, cur);
|
||||
|
||||
var open = text.lastIndexOf('<');
|
||||
var close = text.lastIndexOf('>');
|
||||
var tokenString = token.string.replace("<","");
|
||||
|
||||
if(open > close) {
|
||||
var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur);
|
||||
if(last == "<") {
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
keywords.push(htmlStructure[i].tag);
|
||||
}
|
||||
from.ch = token.start + 1;
|
||||
} else {
|
||||
var counter = 0;
|
||||
var found = function(token, type, position) {
|
||||
counter++;
|
||||
if(counter > 50) return;
|
||||
if(token.type == type) {
|
||||
return token;
|
||||
} else {
|
||||
position.ch = token.start;
|
||||
var newToken = editor.getTokenAt(position);
|
||||
return found(newToken, type, position);
|
||||
}
|
||||
};
|
||||
|
||||
var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch});
|
||||
var node = nodeToken.string.substring(1);
|
||||
|
||||
if(token.type === null && token.string.trim() === "") {
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
if(htmlStructure[i].tag == node) {
|
||||
for(j = 0; j < htmlStructure[i].attr.length; j++) {
|
||||
keywords.push(htmlStructure[i].attr[j].key + "=\"\" ");
|
||||
}
|
||||
|
||||
for(k = 0; k < globalAttributes.length; k++) {
|
||||
keywords.push(globalAttributes[k].key + "=\"\" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(token.type == "string") {
|
||||
tokenString = tokenString.substring(1, tokenString.length - 1);
|
||||
var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch});
|
||||
var attribute = attributeToken.string;
|
||||
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
if(htmlStructure[i].tag == node) {
|
||||
for(j = 0; j < htmlStructure[i].attr.length; j++) {
|
||||
if(htmlStructure[i].attr[j].key == attribute) {
|
||||
for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) {
|
||||
keywords.push(htmlStructure[i].attr[j].values[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < globalAttributes.length; j++) {
|
||||
if(globalAttributes[j].key == attribute) {
|
||||
for(k = 0; k < globalAttributes[j].values.length; k++) {
|
||||
keywords.push(globalAttributes[j].values[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
from.ch = token.start + 1;
|
||||
} else if(token.type == "attribute") {
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
if(htmlStructure[i].tag == node) {
|
||||
for(j = 0; j < htmlStructure[i].attr.length; j++) {
|
||||
keywords.push(htmlStructure[i].attr[j].key + "=\"\" ");
|
||||
}
|
||||
|
||||
for(k = 0; k < globalAttributes.length; k++) {
|
||||
keywords.push(globalAttributes[k].key + "=\"\" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
from.ch = token.start;
|
||||
} else if(token.type == "tag") {
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
keywords.push(htmlStructure[i].tag);
|
||||
}
|
||||
|
||||
from.ch = token.start + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(i = 0; i < htmlStructure.length; i++) {
|
||||
keywords.push("<" + htmlStructure[i].tag);
|
||||
}
|
||||
|
||||
tokenString = ("<" + tokenString).trim();
|
||||
from.ch = token.start;
|
||||
}
|
||||
|
||||
if(flagClean === true && tokenString.trim() === "") {
|
||||
flagClean = false;
|
||||
}
|
||||
|
||||
if(flagClean) {
|
||||
keywords = cleanResults(tokenString, keywords);
|
||||
}
|
||||
|
||||
return {list: keywords, from: from, to: to};
|
||||
}
|
||||
|
||||
|
||||
var cleanResults = function(text, keywords) {
|
||||
var results = [];
|
||||
var i = 0;
|
||||
|
||||
for(i = 0; i < keywords.length; i++) {
|
||||
if(keywords[i].substring(0, text.length) == text) {
|
||||
results.push(keywords[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
var htmlStructure = [
|
||||
{tag: '!DOCTYPE', attr: []},
|
||||
{tag: 'a', attr: [
|
||||
{key: 'href', values: ["#"]},
|
||||
{key: 'target', values: ["_blank","_self","_top","_parent"]},
|
||||
{key: 'ping', values: [""]},
|
||||
{key: 'media', values: ["#"]},
|
||||
{key: 'hreflang', values: ["en","es"]},
|
||||
{key: 'type', values: []}
|
||||
]},
|
||||
{tag: 'abbr', attr: []},
|
||||
{tag: 'acronym', attr: []},
|
||||
{tag: 'address', attr: []},
|
||||
{tag: 'applet', attr: []},
|
||||
{tag: 'area', attr: [
|
||||
{key: 'alt', values: [""]},
|
||||
{key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]},
|
||||
{key: 'shape', values: ["default","rect","circle","poly"]},
|
||||
{key: 'href', values: ["#"]},
|
||||
{key: 'target', values: ["#"]},
|
||||
{key: 'ping', values: []},
|
||||
{key: 'media', values: []},
|
||||
{key: 'hreflang', values: []},
|
||||
{key: 'type', values: []}
|
||||
|
||||
]},
|
||||
{tag: 'article', attr: []},
|
||||
{tag: 'aside', attr: []},
|
||||
{tag: 'audio', attr: [
|
||||
{key: 'src', values: []},
|
||||
{key: 'crossorigin', values: ["anonymous","use-credentials"]},
|
||||
{key: 'preload', values: ["none","metadata","auto"]},
|
||||
{key: 'autoplay', values: ["","autoplay"]},
|
||||
{key: 'mediagroup', values: []},
|
||||
{key: 'loop', values: ["","loop"]},
|
||||
{key: 'controls', values: ["","controls"]}
|
||||
]},
|
||||
{tag: 'b', attr: []},
|
||||
{tag: 'base', attr: [
|
||||
{key: 'href', values: ["#"]},
|
||||
{key: 'target', values: ["_blank","_self","_top","_parent"]}
|
||||
]},
|
||||
{tag: 'basefont', attr: []},
|
||||
{tag: 'bdi', attr: []},
|
||||
{tag: 'bdo', attr: []},
|
||||
{tag: 'big', attr: []},
|
||||
{tag: 'blockquote', attr: [
|
||||
{key: 'cite', values: ["http://"]}
|
||||
]},
|
||||
{tag: 'body', attr: []},
|
||||
{tag: 'br', attr: []},
|
||||
{tag: 'button', attr: [
|
||||
{key: 'autofocus', values: ["","autofocus"]},
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'form', values: []},
|
||||
{key: 'formaction', values: []},
|
||||
{key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
|
||||
{key: 'formmethod', values: ["get","post","put","delete"]},
|
||||
{key: 'formnovalidate', values: ["","novalidate"]},
|
||||
{key: 'formtarget', values: ["_blank","_self","_top","_parent"]},
|
||||
{key: 'name', values: []},
|
||||
{key: 'type', values: ["submit","reset","button"]},
|
||||
{key: 'value', values: []}
|
||||
]},
|
||||
{tag: 'canvas', attr: [
|
||||
{key: 'width', values: []},
|
||||
{key: 'height', values: []}
|
||||
]},
|
||||
{tag: 'caption', attr: []},
|
||||
{tag: 'center', attr: []},
|
||||
{tag: 'cite', attr: []},
|
||||
{tag: 'code', attr: []},
|
||||
{tag: 'col', attr: [
|
||||
{key: 'span', values: []}
|
||||
]},
|
||||
{tag: 'colgroup', attr: [
|
||||
{key: 'span', values: []}
|
||||
]},
|
||||
{tag: 'command', attr: [
|
||||
{key: 'type', values: ["command","checkbox","radio"]},
|
||||
{key: 'label', values: []},
|
||||
{key: 'icon', values: []},
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'checked', values: ["","checked"]},
|
||||
{key: 'radiogroup', values: []},
|
||||
{key: 'command', values: []},
|
||||
{key: 'title', values: []}
|
||||
]},
|
||||
{tag: 'data', attr: [
|
||||
{key: 'value', values: []}
|
||||
]},
|
||||
{tag: 'datagrid', attr: [
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'multiple', values: ["","multiple"]}
|
||||
]},
|
||||
{tag: 'datalist', attr: [
|
||||
{key: 'data', values: []}
|
||||
]},
|
||||
{tag: 'dd', attr: []},
|
||||
{tag: 'del', attr: [
|
||||
{key: 'cite', values: []},
|
||||
{key: 'datetime', values: []}
|
||||
]},
|
||||
{tag: 'details', attr: [
|
||||
{key: 'open', values: ["","open"]}
|
||||
]},
|
||||
{tag: 'dfn', attr: []},
|
||||
{tag: 'dir', attr: []},
|
||||
{tag: 'div', attr: [
|
||||
{key: 'id', values: []},
|
||||
{key: 'class', values: []},
|
||||
{key: 'style', values: []}
|
||||
]},
|
||||
{tag: 'dl', attr: []},
|
||||
{tag: 'dt', attr: []},
|
||||
{tag: 'em', attr: []},
|
||||
{tag: 'embed', attr: [
|
||||
{key: 'src', values: []},
|
||||
{key: 'type', values: []},
|
||||
{key: 'width', values: []},
|
||||
{key: 'height', values: []}
|
||||
]},
|
||||
{tag: 'eventsource', attr: [
|
||||
{key: 'src', values: []}
|
||||
]},
|
||||
{tag: 'fieldset', attr: [
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'form', values: []},
|
||||
{key: 'name', values: []}
|
||||
]},
|
||||
{tag: 'figcaption', attr: []},
|
||||
{tag: 'figure', attr: []},
|
||||
{tag: 'font', attr: []},
|
||||
{tag: 'footer', attr: []},
|
||||
{tag: 'form', attr: [
|
||||
{key: 'accept-charset', values: ["UNKNOWN","utf-8"]},
|
||||
{key: 'action', values: []},
|
||||
{key: 'autocomplete', values: ["on","off"]},
|
||||
{key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
|
||||
{key: 'method', values: ["get","post","put","delete","dialog"]},
|
||||
{key: 'name', values: []},
|
||||
{key: 'novalidate', values: ["","novalidate"]},
|
||||
{key: 'target', values: ["_blank","_self","_top","_parent"]}
|
||||
]},
|
||||
{tag: 'frame', attr: []},
|
||||
{tag: 'frameset', attr: []},
|
||||
{tag: 'h1', attr: []},
|
||||
{tag: 'h2', attr: []},
|
||||
{tag: 'h3', attr: []},
|
||||
{tag: 'h4', attr: []},
|
||||
{tag: 'h5', attr: []},
|
||||
{tag: 'h6', attr: []},
|
||||
{tag: 'head', attr: []},
|
||||
{tag: 'header', attr: []},
|
||||
{tag: 'hgroup', attr: []},
|
||||
{tag: 'hr', attr: []},
|
||||
{tag: 'html', attr: [
|
||||
{key: 'manifest', values: []}
|
||||
]},
|
||||
{tag: 'i', attr: []},
|
||||
{tag: 'iframe', attr: [
|
||||
{key: 'src', values: []},
|
||||
{key: 'srcdoc', values: []},
|
||||
{key: 'name', values: []},
|
||||
{key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]},
|
||||
{key: 'seamless', values: ["","seamless"]},
|
||||
{key: 'width', values: []},
|
||||
{key: 'height', values: []}
|
||||
]},
|
||||
{tag: 'img', attr: [
|
||||
{key: 'alt', values: []},
|
||||
{key: 'src', values: []},
|
||||
{key: 'crossorigin', values: ["anonymous","use-credentials"]},
|
||||
{key: 'ismap', values: []},
|
||||
{key: 'usemap', values: []},
|
||||
{key: 'width', values: []},
|
||||
{key: 'height', values: []}
|
||||
]},
|
||||
{tag: 'input', attr: [
|
||||
{key: 'accept', values: ["audio/*","video/*","image/*"]},
|
||||
{key: 'alt', values: []},
|
||||
{key: 'autocomplete', values: ["on","off"]},
|
||||
{key: 'autofocus', values: ["","autofocus"]},
|
||||
{key: 'checked', values: ["","checked"]},
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'dirname', values: []},
|
||||
{key: 'form', values: []},
|
||||
{key: 'formaction', values: []},
|
||||
{key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
|
||||
{key: 'formmethod', values: ["get","post","put","delete"]},
|
||||
{key: 'formnovalidate', values: ["","novalidate"]},
|
||||
{key: 'formtarget', values: ["_blank","_self","_top","_parent"]},
|
||||
{key: 'height', values: []},
|
||||
{key: 'list', values: []},
|
||||
{key: 'max', values: []},
|
||||
{key: 'maxlength', values: []},
|
||||
{key: 'min', values: []},
|
||||
{key: 'multiple', values: ["","multiple"]},
|
||||
{key: 'name', values: []},
|
||||
{key: 'pattern', values: []},
|
||||
{key: 'placeholder', values: []},
|
||||
{key: 'readonly', values: ["","readonly"]},
|
||||
{key: 'required', values: ["","required"]},
|
||||
{key: 'size', values: []},
|
||||
{key: 'src', values: []},
|
||||
{key: 'step', values: []},
|
||||
{key: 'type', values: [
|
||||
"hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local",
|
||||
"number","range","color","checkbox","radio","file","submit","image","reset","button"
|
||||
]},
|
||||
{key: 'value', values: []},
|
||||
{key: 'width', values: []}
|
||||
]},
|
||||
{tag: 'ins', attr: [
|
||||
{key: 'cite', values: []},
|
||||
{key: 'datetime', values: []}
|
||||
]},
|
||||
{tag: 'kbd', attr: []},
|
||||
{tag: 'keygen', attr: [
|
||||
{key: 'autofocus', values: ["","autofocus"]},
|
||||
{key: 'challenge', values: []},
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'form', values: []},
|
||||
{key: 'keytype', values: ["RSA"]},
|
||||
{key: 'name', values: []}
|
||||
]},
|
||||
{tag: 'label', attr: [
|
||||
{key: 'for', values: []},
|
||||
{key: 'form', values: []}
|
||||
]},
|
||||
{tag: 'legend', attr: []},
|
||||
{tag: 'li', attr: [
|
||||
{key: 'value', values: []}
|
||||
]},
|
||||
{tag: 'link', attr: [
|
||||
{key: 'href', values: []},
|
||||
{key: 'hreflang', values: ["en","es"]},
|
||||
{key: 'media', values: [
|
||||
"all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses",
|
||||
"resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3",
|
||||
"device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait",
|
||||
"orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2"
|
||||
]},
|
||||
{key: 'type', values: []},
|
||||
{key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]}
|
||||
]},
|
||||
{tag: 'map', attr: [
|
||||
{key: 'name', values: []}
|
||||
]},
|
||||
{tag: 'mark', attr: []},
|
||||
{tag: 'menu', attr: [
|
||||
{key: 'type', values: ["list","context","toolbar"]},
|
||||
{key: 'label', values: []}
|
||||
]},
|
||||
{tag: 'meta', attr: [
|
||||
{key: 'charset', attr: ["utf-8"]},
|
||||
{key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]},
|
||||
{key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]},
|
||||
{key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]}
|
||||
]},
|
||||
{tag: 'meter', attr: [
|
||||
{key: 'value', values: []},
|
||||
{key: 'min', values: []},
|
||||
{key: 'low', values: []},
|
||||
{key: 'high', values: []},
|
||||
{key: 'max', values: []},
|
||||
{key: 'optimum', values: []}
|
||||
]},
|
||||
{tag: 'nav', attr: []},
|
||||
{tag: 'noframes', attr: []},
|
||||
{tag: 'noscript', attr: []},
|
||||
{tag: 'object', attr: [
|
||||
{key: 'data', values: []},
|
||||
{key: 'type', values: []},
|
||||
{key: 'typemustmatch', values: ["","typemustmatch"]},
|
||||
{key: 'name', values: []},
|
||||
{key: 'usemap', values: []},
|
||||
{key: 'form', values: []},
|
||||
{key: 'width', values: []},
|
||||
{key: 'height', values: []}
|
||||
]},
|
||||
{tag: 'ol', attr: [
|
||||
{key: 'reversed', values: ["", "reversed"]},
|
||||
{key: 'start', values: []},
|
||||
{key: 'type', values: ["1","a","A","i","I"]}
|
||||
]},
|
||||
{tag: 'optgroup', attr: [
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'label', values: []}
|
||||
]},
|
||||
{tag: 'option', attr: [
|
||||
{key: 'disabled', values: ["", "disabled"]},
|
||||
{key: 'label', values: []},
|
||||
{key: 'selected', values: ["", "selected"]},
|
||||
{key: 'value', values: []}
|
||||
]},
|
||||
{tag: 'output', attr: [
|
||||
{key: 'for', values: []},
|
||||
{key: 'form', values: []},
|
||||
{key: 'name', values: []}
|
||||
]},
|
||||
{tag: 'p', attr: []},
|
||||
{tag: 'param', attr: [
|
||||
{key: 'name', values: []},
|
||||
{key: 'value', values: []}
|
||||
]},
|
||||
{tag: 'pre', attr: []},
|
||||
{tag: 'progress', attr: [
|
||||
{key: 'value', values: []},
|
||||
{key: 'max', values: []}
|
||||
]},
|
||||
{tag: 'q', attr: [
|
||||
{key: 'cite', values: []}
|
||||
]},
|
||||
{tag: 'rp', attr: []},
|
||||
{tag: 'rt', attr: []},
|
||||
{tag: 'ruby', attr: []},
|
||||
{tag: 's', attr: []},
|
||||
{tag: 'samp', attr: []},
|
||||
{tag: 'script', attr: [
|
||||
{key: 'type', values: ["text/javascript"]},
|
||||
{key: 'src', values: []},
|
||||
{key: 'async', values: ["","async"]},
|
||||
{key: 'defer', values: ["","defer"]},
|
||||
{key: 'charset', values: ["utf-8"]}
|
||||
]},
|
||||
{tag: 'section', attr: []},
|
||||
{tag: 'select', attr: [
|
||||
{key: 'autofocus', values: ["", "autofocus"]},
|
||||
{key: 'disabled', values: ["", "disabled"]},
|
||||
{key: 'form', values: []},
|
||||
{key: 'multiple', values: ["", "multiple"]},
|
||||
{key: 'name', values: []},
|
||||
{key: 'size', values: []}
|
||||
]},
|
||||
{tag: 'small', attr: []},
|
||||
{tag: 'source', attr: [
|
||||
{key: 'src', values: []},
|
||||
{key: 'type', values: []},
|
||||
{key: 'media', values: []}
|
||||
]},
|
||||
{tag: 'span', attr: []},
|
||||
{tag: 'strike', attr: []},
|
||||
{tag: 'strong', attr: []},
|
||||
{tag: 'style', attr: [
|
||||
{key: 'type', values: ["text/css"]},
|
||||
{key: 'media', values: ["all","braille","print","projection","screen","speech"]},
|
||||
{key: 'scoped', values: []}
|
||||
]},
|
||||
{tag: 'sub', attr: []},
|
||||
{tag: 'summary', attr: []},
|
||||
{tag: 'sup', attr: []},
|
||||
{tag: 'table', attr: [
|
||||
{key: 'border', values: []}
|
||||
]},
|
||||
{tag: 'tbody', attr: []},
|
||||
{tag: 'td', attr: [
|
||||
{key: 'colspan', values: []},
|
||||
{key: 'rowspan', values: []},
|
||||
{key: 'headers', values: []}
|
||||
]},
|
||||
{tag: 'textarea', attr: [
|
||||
{key: 'autofocus', values: ["","autofocus"]},
|
||||
{key: 'disabled', values: ["","disabled"]},
|
||||
{key: 'dirname', values: []},
|
||||
{key: 'form', values: []},
|
||||
{key: 'maxlength', values: []},
|
||||
{key: 'name', values: []},
|
||||
{key: 'placeholder', values: []},
|
||||
{key: 'readonly', values: ["","readonly"]},
|
||||
{key: 'required', values: ["","required"]},
|
||||
{key: 'rows', values: []},
|
||||
{key: 'cols', values: []},
|
||||
{key: 'wrap', values: ["soft","hard"]}
|
||||
]},
|
||||
{tag: 'tfoot', attr: []},
|
||||
{tag: 'th', attr: [
|
||||
{key: 'colspan', values: []},
|
||||
{key: 'rowspan', values: []},
|
||||
{key: 'headers', values: []},
|
||||
{key: 'scope', values: ["row","col","rowgroup","colgroup"]}
|
||||
]},
|
||||
{tag: 'thead', attr: []},
|
||||
{tag: 'time', attr: [
|
||||
{key: 'datetime', values: []}
|
||||
]},
|
||||
{tag: 'title', attr: []},
|
||||
{tag: 'tr', attr: []},
|
||||
{tag: 'track', attr: [
|
||||
{key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]},
|
||||
{key: 'src', values: []},
|
||||
{key: 'srclang', values: ["en","es"]},
|
||||
{key: 'label', values: []},
|
||||
{key: 'default', values: []}
|
||||
]},
|
||||
{tag: 'tt', attr: []},
|
||||
{tag: 'u', attr: []},
|
||||
{tag: 'ul', attr: []},
|
||||
{tag: 'var', attr: []},
|
||||
{tag: 'video', attr: [
|
||||
{key: "src", values: []},
|
||||
{key: "crossorigin", values: ["anonymous","use-credentials"]},
|
||||
{key: "poster", values: []},
|
||||
{key: "preload", values: ["auto","metadata","none"]},
|
||||
{key: "autoplay", values: ["","autoplay"]},
|
||||
{key: "mediagroup", values: ["movie"]},
|
||||
{key: "loop", values: ["","loop"]},
|
||||
{key: "muted", values: ["","muted"]},
|
||||
{key: "controls", values: ["","controls"]},
|
||||
{key: "width", values: []},
|
||||
{key: "height", values: []}
|
||||
]},
|
||||
{tag: 'wbr', attr: []}
|
||||
];
|
||||
|
||||
var globalAttributes = [
|
||||
{key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]},
|
||||
{key: "class", values: []},
|
||||
{key: "contenteditable", values: ["true", "false"]},
|
||||
{key: "contextmenu", values: []},
|
||||
{key: "dir", values: ["ltr","rtl","auto"]},
|
||||
{key: "draggable", values: ["true","false","auto"]},
|
||||
{key: "dropzone", values: ["copy","move","link","string:","file:"]},
|
||||
{key: "hidden", values: ["hidden"]},
|
||||
{key: "id", values: []},
|
||||
{key: "inert", values: ["inert"]},
|
||||
{key: "itemid", values: []},
|
||||
{key: "itemprop", values: []},
|
||||
{key: "itemref", values: []},
|
||||
{key: "itemscope", values: ["itemscope"]},
|
||||
{key: "itemtype", values: []},
|
||||
{key: "lang", values: ["en","es"]},
|
||||
{key: "spellcheck", values: ["true","false"]},
|
||||
{key: "style", values: []},
|
||||
{key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]},
|
||||
{key: "title", values: []},
|
||||
{key: "translate", values: ["yes","no"]},
|
||||
{key: "onclick", values: []},
|
||||
{key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]}
|
||||
];
|
||||
|
||||
CodeMirror.htmlHint = function(editor) {
|
||||
if(String.prototype.trim == undefined) {
|
||||
String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');};
|
||||
}
|
||||
return htmlHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); });
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,142 @@
|
||||
(function () {
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, keywords, getToken, options) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
||||
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
type: token.string == "." ? "property" : null};
|
||||
}
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.type == "property") {
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (tprop.string != ".") return;
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (tprop.string == ')') {
|
||||
var level = 1;
|
||||
do {
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
switch (tprop.string) {
|
||||
case ')': level++; break;
|
||||
case '(': level--; break;
|
||||
default: break;
|
||||
}
|
||||
} while (level > 0);
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (tprop.type.indexOf("variable") === 0)
|
||||
tprop.type = "function";
|
||||
else return; // no clue
|
||||
}
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
return {list: getCompletions(token, context, keywords, options),
|
||||
from: Pos(cur.line, token.start),
|
||||
to: Pos(cur.line, token.end)};
|
||||
}
|
||||
|
||||
CodeMirror.javascriptHint = function(editor, options) {
|
||||
return scriptHint(editor, javascriptKeywords,
|
||||
function (e, cur) {return e.getTokenAt(cur);},
|
||||
options);
|
||||
};
|
||||
|
||||
function getCoffeeScriptToken(editor, cur) {
|
||||
// This getToken, it is for coffeescript, imitates the behavior of
|
||||
// getTokenAt method in javascript.js, that is, returning "property"
|
||||
// type and treat "." as indepenent token.
|
||||
var token = editor.getTokenAt(cur);
|
||||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
||||
token.end = token.start;
|
||||
token.string = '.';
|
||||
token.type = "property";
|
||||
}
|
||||
else if (/^\.[\w$_]*$/.test(token.string)) {
|
||||
token.type = "property";
|
||||
token.start++;
|
||||
token.string = token.string.replace(/\./, '');
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
CodeMirror.coffeescriptHint = function(editor, options) {
|
||||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
|
||||
};
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
|
||||
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
|
||||
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
|
||||
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
|
||||
|
||||
function getCompletions(token, context, keywords, options) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.type.indexOf("variable") === 0) {
|
||||
if (options && options.additionalContext)
|
||||
base = options.additionalContext[obj.string];
|
||||
base = base || window[obj.string];
|
||||
} else if (obj.type == "string") {
|
||||
base = "";
|
||||
} else if (obj.type == "atom") {
|
||||
base = 1;
|
||||
} else if (obj.type == "function") {
|
||||
if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
||||
(typeof window.jQuery == 'function'))
|
||||
base = window.jQuery();
|
||||
else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
|
||||
base = window._();
|
||||
}
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
else {
|
||||
// If not, just look in the window object and any local scope
|
||||
// (reading into JS mode internals to get at the local and global variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
|
||||
gatherCompletions(window);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,117 @@
|
||||
(function () {
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, _keywords, getToken) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == ":" ? "pig-type" : null};
|
||||
}
|
||||
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
|
||||
var completionList = getCompletions(token, context);
|
||||
completionList = completionList.sort();
|
||||
//prevent autocomplete for last word, instead show dropdown with one word
|
||||
if(completionList.length == 1) {
|
||||
completionList.push(" ");
|
||||
}
|
||||
|
||||
return {list: completionList,
|
||||
from: CodeMirror.Pos(cur.line, token.start),
|
||||
to: CodeMirror.Pos(cur.line, token.end)};
|
||||
}
|
||||
|
||||
CodeMirror.pigHint = function(editor) {
|
||||
return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
|
||||
};
|
||||
|
||||
var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
|
||||
+ "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
|
||||
+ "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
|
||||
+ "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
|
||||
+ "NEQ MATCHES TRUE FALSE";
|
||||
var pigKeywordsU = pigKeywords.split(" ");
|
||||
var pigKeywordsL = pigKeywords.toLowerCase().split(" ");
|
||||
|
||||
var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP";
|
||||
var pigTypesU = pigTypes.split(" ");
|
||||
var pigTypesL = pigTypes.toLowerCase().split(" ");
|
||||
|
||||
var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
|
||||
+ "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
|
||||
+ "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
|
||||
+ "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
|
||||
+ "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
|
||||
+ "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
|
||||
+ "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
|
||||
+ "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
|
||||
+ "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
|
||||
+ "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
|
||||
var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
|
||||
var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
|
||||
var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs "
|
||||
+ "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax "
|
||||
+ "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum "
|
||||
+ "InvokeForDouble InvokeForFloat InvokeForInt InvokeForLong InvokeForString Invoker "
|
||||
+ "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize "
|
||||
+ "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax "
|
||||
+ "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" ");
|
||||
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
|
||||
function gatherCompletions(obj) {
|
||||
if(obj == ":") {
|
||||
forEach(pigTypesL, maybeAdd);
|
||||
}
|
||||
else {
|
||||
forEach(pigBuiltinsU, maybeAdd);
|
||||
forEach(pigBuiltinsL, maybeAdd);
|
||||
forEach(pigBuiltinsC, maybeAdd);
|
||||
forEach(pigTypesU, maybeAdd);
|
||||
forEach(pigTypesL, maybeAdd);
|
||||
forEach(pigKeywordsU, maybeAdd);
|
||||
forEach(pigKeywordsL, maybeAdd);
|
||||
}
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
|
||||
if (obj.type == "variable")
|
||||
base = obj.string;
|
||||
else if(obj.type == "variable-3")
|
||||
base = ":" + obj.string;
|
||||
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,93 @@
|
||||
(function () {
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, _keywords, getToken) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == ":" ? "python-type" : null};
|
||||
}
|
||||
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
|
||||
var completionList = getCompletions(token, context);
|
||||
completionList = completionList.sort();
|
||||
//prevent autocomplete for last word, instead show dropdown with one word
|
||||
if(completionList.length == 1) {
|
||||
completionList.push(" ");
|
||||
}
|
||||
|
||||
return {list: completionList,
|
||||
from: CodeMirror.Pos(cur.line, token.start),
|
||||
to: CodeMirror.Pos(cur.line, token.end)};
|
||||
}
|
||||
|
||||
CodeMirror.pythonHint = function(editor) {
|
||||
return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
|
||||
};
|
||||
|
||||
var pythonKeywords = "and del from not while as elif global or with assert else if pass yield"
|
||||
+ "break except import print class exec in raise continue finally is return def for lambda try";
|
||||
var pythonKeywordsL = pythonKeywords.split(" ");
|
||||
var pythonKeywordsU = pythonKeywords.toUpperCase().split(" ");
|
||||
|
||||
var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str "
|
||||
+ "any eval isinstance pow sum basestring execfile issubclass print super"
|
||||
+ "bin file iter property tuple bool filter len range type"
|
||||
+ "bytearray float list raw_input unichr callable format locals reduce unicode"
|
||||
+ "chr frozenset long reload vars classmethod getattr map repr xrange"
|
||||
+ "cmp globals max reversed zip compile hasattr memoryview round __import__"
|
||||
+ "complex hash min set apply delattr help next setattr buffer"
|
||||
+ "dict hex object slice coerce dir id oct sorted intern ";
|
||||
var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" ");
|
||||
var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" ");
|
||||
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
|
||||
function gatherCompletions(_obj) {
|
||||
forEach(pythonBuiltinsL, maybeAdd);
|
||||
forEach(pythonBuiltinsU, maybeAdd);
|
||||
forEach(pythonKeywordsL, maybeAdd);
|
||||
forEach(pythonKeywordsU, maybeAdd);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
|
||||
if (obj.type == "variable")
|
||||
base = obj.string;
|
||||
else if(obj.type == "variable-3")
|
||||
base = ":" + obj.string;
|
||||
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,38 @@
|
||||
.CodeMirror-hints {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
border-radius: 3px;
|
||||
border: 1px solid silver;
|
||||
|
||||
background: white;
|
||||
font-size: 90%;
|
||||
font-family: monospace;
|
||||
|
||||
max-height: 20em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-hint {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
max-width: 19em;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.CodeMirror-hint-active {
|
||||
background: #08f;
|
||||
color: white;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
CodeMirror.showHint = function(cm, getHints, options) {
|
||||
if (!options) options = {};
|
||||
var startCh = cm.getCursor().ch, continued = false;
|
||||
var closeOn = options.closeCharacters || /[\s()\[\]{};:]/;
|
||||
|
||||
function startHinting() {
|
||||
// We want a single cursor position.
|
||||
if (cm.somethingSelected()) return;
|
||||
|
||||
if (options.async)
|
||||
getHints(cm, showHints, options);
|
||||
else
|
||||
return showHints(getHints(cm, options));
|
||||
}
|
||||
|
||||
function getText(completion) {
|
||||
if (typeof completion == "string") return completion;
|
||||
else return completion.text;
|
||||
}
|
||||
|
||||
function pickCompletion(cm, data, completion) {
|
||||
if (completion.hint) completion.hint(cm, data, completion);
|
||||
else cm.replaceRange(getText(completion), data.from, data.to);
|
||||
}
|
||||
|
||||
function showHints(data) {
|
||||
if (!data || !data.list.length) return;
|
||||
var completions = data.list;
|
||||
// When there is only one completion, use it directly.
|
||||
if (!continued && options.completeSingle !== false && completions.length == 1) {
|
||||
pickCompletion(cm, data, completions[0]);
|
||||
CodeMirror.signal(data, "close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build the select widget
|
||||
var hints = document.createElement("ul"), selectedHint = 0;
|
||||
hints.className = "CodeMirror-hints";
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var elt = hints.appendChild(document.createElement("li")), completion = completions[i];
|
||||
var className = "CodeMirror-hint" + (i ? "" : " CodeMirror-hint-active");
|
||||
if (completion.className != null) className = completion.className + " " + className;
|
||||
elt.className = className;
|
||||
if (completion.render) completion.render(elt, data, completion);
|
||||
else elt.appendChild(document.createTextNode(completion.displayText || getText(completion)));
|
||||
elt.hintId = i;
|
||||
}
|
||||
var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null);
|
||||
var left = pos.left, top = pos.bottom, below = true;
|
||||
hints.style.left = left + "px";
|
||||
hints.style.top = top + "px";
|
||||
document.body.appendChild(hints);
|
||||
CodeMirror.signal(data, "shown");
|
||||
|
||||
// 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);
|
||||
var box = hints.getBoundingClientRect();
|
||||
var overlapX = box.right - winW, overlapY = box.bottom - winH;
|
||||
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";
|
||||
}
|
||||
if (overlapY > 0) {
|
||||
var height = box.bottom - box.top;
|
||||
if (box.top - (pos.bottom - pos.top) - height > 0) {
|
||||
overlapY = height + (pos.bottom - pos.top);
|
||||
below = false;
|
||||
} else if (height > winH) {
|
||||
hints.style.height = (winH - 5) + "px";
|
||||
overlapY -= height - winH;
|
||||
}
|
||||
hints.style.top = (top = pos.bottom - overlapY) + "px";
|
||||
}
|
||||
|
||||
function changeActive(i) {
|
||||
i = Math.max(0, Math.min(i, completions.length - 1));
|
||||
if (selectedHint == i) return;
|
||||
var node = hints.childNodes[selectedHint];
|
||||
node.className = node.className.replace(" CodeMirror-hint-active", "");
|
||||
node = hints.childNodes[selectedHint = i];
|
||||
node.className += " CodeMirror-hint-active";
|
||||
if (node.offsetTop < hints.scrollTop)
|
||||
hints.scrollTop = node.offsetTop - 3;
|
||||
else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight)
|
||||
hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3;
|
||||
CodeMirror.signal(data, "select", completions[selectedHint], node);
|
||||
}
|
||||
|
||||
function screenAmount() {
|
||||
return Math.floor(hints.clientHeight / hints.firstChild.offsetHeight) || 1;
|
||||
}
|
||||
|
||||
var ourMap, baseMap = {
|
||||
Up: function() {changeActive(selectedHint - 1);},
|
||||
Down: function() {changeActive(selectedHint + 1);},
|
||||
PageUp: function() {changeActive(selectedHint - screenAmount());},
|
||||
PageDown: function() {changeActive(selectedHint + screenAmount());},
|
||||
Home: function() {changeActive(0);},
|
||||
End: function() {changeActive(completions.length - 1);},
|
||||
Enter: pick,
|
||||
Tab: pick,
|
||||
Esc: close
|
||||
};
|
||||
if (options.customKeys) {
|
||||
ourMap = {};
|
||||
for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) {
|
||||
var val = options.customKeys[key];
|
||||
if (baseMap.hasOwnProperty(val)) val = baseMap[val];
|
||||
ourMap[key] = val;
|
||||
}
|
||||
} else ourMap = baseMap;
|
||||
|
||||
cm.addKeyMap(ourMap);
|
||||
cm.on("cursorActivity", cursorActivity);
|
||||
var closingOnBlur;
|
||||
function onBlur(){ closingOnBlur = setTimeout(close, 100); };
|
||||
function onFocus(){ clearTimeout(closingOnBlur); };
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("focus", onFocus);
|
||||
var startScroll = cm.getScrollInfo();
|
||||
function onScroll() {
|
||||
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
|
||||
var newTop = top + startScroll.top - curScroll.top, point = newTop;
|
||||
if (!below) point += hints.offsetHeight;
|
||||
if (point <= editor.top || point >= editor.bottom) return close();
|
||||
hints.style.top = newTop + "px";
|
||||
hints.style.left = (left + startScroll.left - curScroll.left) + "px";
|
||||
}
|
||||
cm.on("scroll", onScroll);
|
||||
CodeMirror.on(hints, "dblclick", function(e) {
|
||||
var t = e.target || e.srcElement;
|
||||
if (t.hintId != null) {selectedHint = t.hintId; pick();}
|
||||
});
|
||||
CodeMirror.on(hints, "click", function(e) {
|
||||
var t = e.target || e.srcElement;
|
||||
if (t.hintId != null) changeActive(t.hintId);
|
||||
});
|
||||
CodeMirror.on(hints, "mousedown", function() {
|
||||
setTimeout(function(){cm.focus();}, 20);
|
||||
});
|
||||
|
||||
var done = false, once;
|
||||
function close(willContinue) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
clearTimeout(once);
|
||||
hints.parentNode.removeChild(hints);
|
||||
cm.removeKeyMap(ourMap);
|
||||
cm.off("cursorActivity", cursorActivity);
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("focus", onFocus);
|
||||
cm.off("scroll", onScroll);
|
||||
if (willContinue !== true) CodeMirror.signal(data, "close");
|
||||
}
|
||||
function pick() {
|
||||
pickCompletion(cm, data, completions[selectedHint]);
|
||||
close();
|
||||
}
|
||||
var once, lastPos = cm.getCursor(), lastLen = cm.getLine(lastPos.line).length;
|
||||
function cursorActivity() {
|
||||
clearTimeout(once);
|
||||
|
||||
var pos = cm.getCursor(), line = cm.getLine(pos.line);
|
||||
if (pos.line != lastPos.line || line.length - pos.ch != lastLen - lastPos.ch ||
|
||||
pos.ch < startCh || cm.somethingSelected() ||
|
||||
(pos.ch && closeOn.test(line.charAt(pos.ch - 1))))
|
||||
close();
|
||||
else
|
||||
once = setTimeout(function(){close(true); continued = true; startHinting();}, 70);
|
||||
}
|
||||
CodeMirror.signal(data, "select", completions[0], hints.firstChild);
|
||||
return true;
|
||||
}
|
||||
|
||||
return startHinting();
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
(function() {
|
||||
|
||||
CodeMirror.xmlHints = [];
|
||||
|
||||
CodeMirror.xmlHint = function(cm) {
|
||||
|
||||
var cursor = cm.getCursor();
|
||||
|
||||
if (cursor.ch > 0) {
|
||||
|
||||
var text = cm.getRange(CodeMirror.Pos(0, 0), cursor);
|
||||
var typed = '';
|
||||
var simbol = '';
|
||||
for(var i = text.length - 1; i >= 0; i--) {
|
||||
if(text[i] == ' ' || text[i] == '<') {
|
||||
simbol = text[i];
|
||||
break;
|
||||
}
|
||||
else {
|
||||
typed = text[i] + typed;
|
||||
}
|
||||
}
|
||||
|
||||
text = text.slice(0, text.length - typed.length);
|
||||
|
||||
var path = getActiveElement(text) + simbol;
|
||||
var hints = CodeMirror.xmlHints[path];
|
||||
|
||||
if(typeof hints === 'undefined')
|
||||
hints = [''];
|
||||
else {
|
||||
hints = hints.slice(0);
|
||||
for (var i = hints.length - 1; i >= 0; i--) {
|
||||
if(hints[i].indexOf(typed) != 0)
|
||||
hints.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
list: hints,
|
||||
from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length),
|
||||
to: cursor
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var getActiveElement = function(text) {
|
||||
|
||||
var element = '';
|
||||
|
||||
if(text.length >= 0) {
|
||||
|
||||
var regex = new RegExp('<([^!?][^\\s/>]*)[\\s\\S]*?>', 'g');
|
||||
|
||||
var matches = [];
|
||||
var match;
|
||||
while ((match = regex.exec(text)) != null) {
|
||||
matches.push({
|
||||
tag: match[1],
|
||||
selfclose: (match[0].slice(match[0].length - 2) === '/>')
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = matches.length - 1, skip = 0; i >= 0; i--) {
|
||||
|
||||
var item = matches[i];
|
||||
|
||||
if (item.tag[0] == '/')
|
||||
{
|
||||
skip++;
|
||||
}
|
||||
else if (item.selfclose == false)
|
||||
{
|
||||
if (skip > 0)
|
||||
{
|
||||
skip--;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = '<' + item.tag + '>' + element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
element += getOpenTag(text);
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
var getOpenTag = function(text) {
|
||||
|
||||
var open = text.lastIndexOf('<');
|
||||
var close = text.lastIndexOf('>');
|
||||
|
||||
if (close < open)
|
||||
{
|
||||
text = text.slice(open);
|
||||
|
||||
if(text != '<') {
|
||||
|
||||
var space = text.indexOf(' ');
|
||||
if(space < 0)
|
||||
space = text.indexOf('\t');
|
||||
if(space < 0)
|
||||
space = text.indexOf('\n');
|
||||
|
||||
if (space < 0)
|
||||
space = text.length;
|
||||
|
||||
return text.slice(0, space);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user