diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js
index d5a4ab64..070978e2 100644
--- a/lib/ace/mode/html.js
+++ b/lib/ace/mode/html.js
@@ -39,11 +39,13 @@ var Tokenizer = require("../tokenizer").Tokenizer;
var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
var HtmlBehaviour = require("./behaviour/html").HtmlBehaviour;
var HtmlFoldMode = require("./folding/html").FoldMode;
+var HtmlCompletions = require("./html_completions").HtmlCompletions;
var Mode = function() {
var highlighter = new HtmlHighlightRules();
this.$tokenizer = new Tokenizer(highlighter.getRules());
this.$behaviour = new HtmlBehaviour();
+ this.$completer = new HtmlCompletions();
this.$embeds = highlighter.getEmbeds();
this.createModeDelegates({
@@ -55,226 +57,6 @@ var Mode = function() {
};
oop.inherits(Mode, TextMode);
-var commonAttributes = [
- "accesskey",
- "class",
- "contenteditable",
- "contextmenu",
- "dir",
- "draggable",
- "dropzone",
- "hidden",
- "id",
- "lang",
- "spellcheck",
- "style",
- "tabindex",
- "title",
- "translate"
-];
-
-var eventAttributes = [
- "onabort",
- "onblur",
- "oncancel",
- "oncanplay",
- "oncanplaythrough",
- "onchange",
- "onclick",
- "onclose",
- "oncontextmenu",
- "oncuechange",
- "ondblclick",
- "ondrag",
- "ondragend",
- "ondragenter",
- "ondragleave",
- "ondragover",
- "ondragstart",
- "ondrop",
- "ondurationchange",
- "onemptied",
- "onended",
- "onerror",
- "onfocus",
- "oninput",
- "oninvalid",
- "onkeydown",
- "onkeypress",
- "onkeyup",
- "onload",
- "onloadeddata",
- "onloadedmetadata",
- "onloadstart",
- "onmousedown",
- "onmousemove",
- "onmouseout",
- "onmouseover",
- "onmouseup",
- "onmousewheel",
- "onpause",
- "onplay",
- "onplaying",
- "onprogress",
- "onratechange",
- "onreset",
- "onscroll",
- "onseeked",
- "onseeking",
- "onselect",
- "onshow",
- "onstalled",
- "onsubmit",
- "onsuspend",
- "ontimeupdate",
- "onvolumechange",
- "onwaiting"
-];
-
-var globalAttributes = commonAttributes.concat(eventAttributes);
-
-var attributeMap = {
- "html": ["manifest"],
- "head": [],
- "title": [],
- "base": ["href", "target"],
- "link": ["href", "hreflang", "rel", "media", "type", "sizes"],
- "meta": ["http-equiv", "name", "content", "charset"],
- "style": ["type", "media", "scoped"],
- "script": ["charset", "type", "src", "defer", "async"],
- "noscript": ["href"],
- "body": ["onafterprint", "onbeforeprint", "onbeforeunload", "onhashchange", "onmessage", "onoffline", "onpopstate", "onredo", "onresize", "onstorage", "onundo", "onunload"],
- "section": [],
- "nav": [],
- "article": ["pubdate"],
- "aside": [],
- "h1": [],
- "h2": [],
- "h3": [],
- "h4": [],
- "h5": [],
- "h6": [],
- "header": [],
- "footer": [],
- "address": [],
- "main": [],
- "p": [],
- "hr": [],
- "pre": [],
- "blockquote": ["cite"],
- "ol": ["start", "reversed"],
- "ul": [],
- "li": ["value"],
- "dl": [],
- "dt": [],
- "dd": [],
- "figure": [],
- "figcaption": [],
- "div": [],
- "a": ["href", "target", "ping", "rel", "media", "hreflang", "type"],
- "em": [],
- "strong": [],
- "small": [],
- "s": [],
- "cite": [],
- "q": ["cite"],
- "dfn": [],
- "abbr": [],
- "data": [],
- "time": ["datetime"],
- "code": [],
- "var": [],
- "samp": [],
- "kbd": [],
- "sub": [],
- "sup": [],
- "i": [],
- "b": [],
- "u": [],
- "mark": [],
- "ruby": [],
- "rt": [],
- "rp": [],
- "bdi": [],
- "bdo": [],
- "span": [],
- "br": [],
- "wbr": [],
- "ins": ["cite", "datetime"],
- "del": ["cite", "datetime"],
- "img": ["alt", "src", "height", "width", "usemap", "ismap"],
- "iframe": ["name", "src", "height", "width", "sandbox", "seamless"],
- "embed": ["src", "height", "width", "type"],
- "object": ["param", "data", "type", "height" , "width", "usemap", "name", "form", "classid"],
- "param": ["name", "value"],
- "video": ["src", "autobuffer", "autoplay", "loop", "controls", "width", "height", "poster"],
- "audio": ["src", "autobuffer", "autoplay", "loop", "controls"],
- "source": ["src", "type", "media"],
- "track": ["kind", "src", "srclang", "label", "default"],
- "canvas": ["width", "height"],
- "map": ["name"],
- "area": ["shape", "coords", "href", "hreflang", "alt", "target", "media", "rel", "ping", "type"],
- "svg": [],
- "math": [],
- "table": ["summary"],
- "caption": [],
- "colgroup": ["span"],
- "col": ["span"],
- "tbody": [],
- "thead": [],
- "tfoot": [],
- "tr": [],
- "td": ["headers", "rowspan", "colspan"],
- "th": ["headers", "rowspan", "colspan", "scope"],
- "form": ["accept-charset", "action", "autocomplete", "enctype", "method", "name", "novalidate", "target"],
- "fieldset": ["disabled", "form", "name"],
- "legend": [],
- "label": ["form", "for"],
- "input": ["type", "accept", "alt", "autocomplete", "checked", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "max", "maxlength", "min", "multiple", "pattern", "placeholder", "readonly", "required", "size", "src", "step", "width", "files", "value"],
- "button": ["autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "value", "type"],
- "select": ["autofocus", "disabled", "form", "multiple", "name", "size"],
- "datalist": [],
- "optgroup": ["disabled", "label"],
- "option": ["disabled", "selected", "label", "value"],
- "textarea": ["autofocus", "disabled", "form", "maxlength", "name", "placeholder", "readonly", "required", "rows", "cols", "wrap"],
- "keygen": ["autofocus", "challenge", "disabled", "form", "keytype", "name"],
- "output": ["for", "form", "name"],
- "progress": ["value", "max"],
- "meter": ["value", "min", "max", "low", "high", "optimum"],
- "details": ["open"],
- "summary": [],
- "command": ["type", "label", "icon", "disabled", "checked", "radiogroup", "command"],
- "menu": ["type", "label"],
- "dialog": ["open"]
-};
-
-var allElements = Object.keys(attributeMap);
-
-
-var TokenIterator = require("../token_iterator").TokenIterator;
-
-function hasType(token, type) {
- var tokenTypes = token.type.split('.');
- return type.split('.').every(function(type){
- return (tokenTypes.indexOf(type) !== -1);
- });
-}
-
-function findTagName(iterator) {
- var token = iterator.getCurrentToken();
- if (!token || !hasType(token, 'tag') && !(hasType(token, 'text') && token.value.match('/'))){
- do {
- token = iterator.stepBackward();
- } while (token && (hasType(token, 'string') || hasType(token, 'operator') || hasType(token, 'attribute-name') || hasType(token, 'text')));
- }
- if (!token || !hasType(token, 'tag-name') || iterator.stepBackward().value.match('/')) {
- return
- }
- var element = token.value;
-
- return element;
-}
-
(function() {
this.blockComment = {start: ""};
@@ -287,54 +69,9 @@ function findTagName(iterator) {
return false;
};
- this.getCompletions = function(state, session, pos, prefix, callback) {
- var iterator = new TokenIterator(session, pos.row, pos.column);
- var token = iterator.getCurrentToken();
-
- if (!token)
- return [];
-
- // tag name
- if (hasType(token, "tag-name") || (token.value == '<' && hasType(token, "text"))) {
- var elements = allElements;
- if (prefix) {
- elements = elements.filter(function(element){
- return element.indexOf(prefix) === 0;
- });
- }
- return elements.map(function(element){
- return {
- value: element,
- meta: "tag"
- };
- });
- }
-
- // tag attribute
- if (hasType(token, 'text') || hasType(token, 'attribute-name')) {
- var tagName = findTagName(iterator);
- if (!tagName)
- return [];
- var attributes = globalAttributes;
- if (tagName in attributeMap) {
- attributes = attributes.concat(attributeMap[tagName]);
- }
- if (prefix) {
- attributes = attributes.filter(function(attribute){
- return attribute.indexOf(prefix) === 0;
- });
- }
- return attributes.map(function(attribute){
- return {
- caption: attribute,
- snippet: attribute + '="$0"',
- meta: "attribute"
- };
- });
- }
-
- return [];
- }
+ this.getCompletions = function(state, session, pos, prefix) {
+ return this.$completer.getCompletions(state, session, pos, prefix);
+ };
}).call(Mode.prototype);
diff --git a/lib/ace/mode/html_completions.js b/lib/ace/mode/html_completions.js
new file mode 100644
index 00000000..283b7137
--- /dev/null
+++ b/lib/ace/mode/html_completions.js
@@ -0,0 +1,313 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Ajax.org B.V. nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var TokenIterator = require("../token_iterator").TokenIterator;
+
+var commonAttributes = [
+ "accesskey",
+ "class",
+ "contenteditable",
+ "contextmenu",
+ "dir",
+ "draggable",
+ "dropzone",
+ "hidden",
+ "id",
+ "lang",
+ "spellcheck",
+ "style",
+ "tabindex",
+ "title",
+ "translate"
+];
+
+var eventAttributes = [
+ "onabort",
+ "onblur",
+ "oncancel",
+ "oncanplay",
+ "oncanplaythrough",
+ "onchange",
+ "onclick",
+ "onclose",
+ "oncontextmenu",
+ "oncuechange",
+ "ondblclick",
+ "ondrag",
+ "ondragend",
+ "ondragenter",
+ "ondragleave",
+ "ondragover",
+ "ondragstart",
+ "ondrop",
+ "ondurationchange",
+ "onemptied",
+ "onended",
+ "onerror",
+ "onfocus",
+ "oninput",
+ "oninvalid",
+ "onkeydown",
+ "onkeypress",
+ "onkeyup",
+ "onload",
+ "onloadeddata",
+ "onloadedmetadata",
+ "onloadstart",
+ "onmousedown",
+ "onmousemove",
+ "onmouseout",
+ "onmouseover",
+ "onmouseup",
+ "onmousewheel",
+ "onpause",
+ "onplay",
+ "onplaying",
+ "onprogress",
+ "onratechange",
+ "onreset",
+ "onscroll",
+ "onseeked",
+ "onseeking",
+ "onselect",
+ "onshow",
+ "onstalled",
+ "onsubmit",
+ "onsuspend",
+ "ontimeupdate",
+ "onvolumechange",
+ "onwaiting"
+];
+
+var globalAttributes = commonAttributes.concat(eventAttributes);
+
+var attributeMap = {
+ "html": ["manifest"],
+ "head": [],
+ "title": [],
+ "base": ["href", "target"],
+ "link": ["href", "hreflang", "rel", "media", "type", "sizes"],
+ "meta": ["http-equiv", "name", "content", "charset"],
+ "style": ["type", "media", "scoped"],
+ "script": ["charset", "type", "src", "defer", "async"],
+ "noscript": ["href"],
+ "body": ["onafterprint", "onbeforeprint", "onbeforeunload", "onhashchange", "onmessage", "onoffline", "onpopstate", "onredo", "onresize", "onstorage", "onundo", "onunload"],
+ "section": [],
+ "nav": [],
+ "article": ["pubdate"],
+ "aside": [],
+ "h1": [],
+ "h2": [],
+ "h3": [],
+ "h4": [],
+ "h5": [],
+ "h6": [],
+ "header": [],
+ "footer": [],
+ "address": [],
+ "main": [],
+ "p": [],
+ "hr": [],
+ "pre": [],
+ "blockquote": ["cite"],
+ "ol": ["start", "reversed"],
+ "ul": [],
+ "li": ["value"],
+ "dl": [],
+ "dt": [],
+ "dd": [],
+ "figure": [],
+ "figcaption": [],
+ "div": [],
+ "a": ["href", "target", "ping", "rel", "media", "hreflang", "type"],
+ "em": [],
+ "strong": [],
+ "small": [],
+ "s": [],
+ "cite": [],
+ "q": ["cite"],
+ "dfn": [],
+ "abbr": [],
+ "data": [],
+ "time": ["datetime"],
+ "code": [],
+ "var": [],
+ "samp": [],
+ "kbd": [],
+ "sub": [],
+ "sup": [],
+ "i": [],
+ "b": [],
+ "u": [],
+ "mark": [],
+ "ruby": [],
+ "rt": [],
+ "rp": [],
+ "bdi": [],
+ "bdo": [],
+ "span": [],
+ "br": [],
+ "wbr": [],
+ "ins": ["cite", "datetime"],
+ "del": ["cite", "datetime"],
+ "img": ["alt", "src", "height", "width", "usemap", "ismap"],
+ "iframe": ["name", "src", "height", "width", "sandbox", "seamless"],
+ "embed": ["src", "height", "width", "type"],
+ "object": ["param", "data", "type", "height" , "width", "usemap", "name", "form", "classid"],
+ "param": ["name", "value"],
+ "video": ["src", "autobuffer", "autoplay", "loop", "controls", "width", "height", "poster"],
+ "audio": ["src", "autobuffer", "autoplay", "loop", "controls"],
+ "source": ["src", "type", "media"],
+ "track": ["kind", "src", "srclang", "label", "default"],
+ "canvas": ["width", "height"],
+ "map": ["name"],
+ "area": ["shape", "coords", "href", "hreflang", "alt", "target", "media", "rel", "ping", "type"],
+ "svg": [],
+ "math": [],
+ "table": ["summary"],
+ "caption": [],
+ "colgroup": ["span"],
+ "col": ["span"],
+ "tbody": [],
+ "thead": [],
+ "tfoot": [],
+ "tr": [],
+ "td": ["headers", "rowspan", "colspan"],
+ "th": ["headers", "rowspan", "colspan", "scope"],
+ "form": ["accept-charset", "action", "autocomplete", "enctype", "method", "name", "novalidate", "target"],
+ "fieldset": ["disabled", "form", "name"],
+ "legend": [],
+ "label": ["form", "for"],
+ "input": ["type", "accept", "alt", "autocomplete", "checked", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "max", "maxlength", "min", "multiple", "pattern", "placeholder", "readonly", "required", "size", "src", "step", "width", "files", "value"],
+ "button": ["autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "value", "type"],
+ "select": ["autofocus", "disabled", "form", "multiple", "name", "size"],
+ "datalist": [],
+ "optgroup": ["disabled", "label"],
+ "option": ["disabled", "selected", "label", "value"],
+ "textarea": ["autofocus", "disabled", "form", "maxlength", "name", "placeholder", "readonly", "required", "rows", "cols", "wrap"],
+ "keygen": ["autofocus", "challenge", "disabled", "form", "keytype", "name"],
+ "output": ["for", "form", "name"],
+ "progress": ["value", "max"],
+ "meter": ["value", "min", "max", "low", "high", "optimum"],
+ "details": ["open"],
+ "summary": [],
+ "command": ["type", "label", "icon", "disabled", "checked", "radiogroup", "command"],
+ "menu": ["type", "label"],
+ "dialog": ["open"]
+};
+
+var allElements = Object.keys(attributeMap);
+
+function hasType(token, type) {
+ var tokenTypes = token.type.split('.');
+ return type.split('.').every(function(type){
+ return (tokenTypes.indexOf(type) !== -1);
+ });
+}
+
+function findTagName(session, pos) {
+ var iterator = new TokenIterator(session, pos.row, pos.column);
+ var token = iterator.getCurrentToken();
+ if (!token || !hasType(token, 'tag') && !(hasType(token, 'text') && token.value.match('/'))){
+ do {
+ token = iterator.stepBackward();
+ } while (token && (hasType(token, 'string') || hasType(token, 'operator') || hasType(token, 'attribute-name') || hasType(token, 'text')));
+ }
+ if (token && hasType(token, 'tag-name') && !iterator.stepBackward().value.match('/'))
+ return token.value;
+}
+
+var HtmlCompletions = function() {
+
+};
+
+(function() {
+
+ this.getCompletions = function(state, session, pos, prefix) {
+ var token = session.getTokenAt(pos.row, pos.column);
+
+ if (!token)
+ return [];
+
+ // tag name
+ if (hasType(token, "tag-name") || (token.value == '<' && hasType(token, "text")))
+ return this.getTagCompletions(state, session, pos, prefix);
+
+ // tag attribute
+ if (hasType(token, 'text') || hasType(token, 'attribute-name'))
+ return this.getAttributeCompetions(state, session, pos, prefix);
+
+ return [];
+ };
+
+ this.getTagCompletions = function(state, session, pos, prefix) {
+ var elements = allElements;
+ if (prefix) {
+ elements = elements.filter(function(element){
+ return element.indexOf(prefix) === 0;
+ });
+ }
+ return elements.map(function(element){
+ return {
+ value: element,
+ meta: "tag"
+ };
+ });
+ };
+
+ this.getAttributeCompetions = function(state, session, pos, prefix) {
+ var tagName = findTagName(session, pos);
+ if (!tagName)
+ return [];
+ var attributes = globalAttributes;
+ if (tagName in attributeMap) {
+ attributes = attributes.concat(attributeMap[tagName]);
+ }
+ if (prefix) {
+ attributes = attributes.filter(function(attribute){
+ return attribute.indexOf(prefix) === 0;
+ });
+ }
+ return attributes.map(function(attribute){
+ return {
+ caption: attribute,
+ snippet: attribute + '="$0"',
+ meta: "attribute"
+ };
+ });
+ };
+
+}).call(HtmlCompletions.prototype);
+
+exports.HtmlCompletions = HtmlCompletions;
+});