/* ***** 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; });