html_completions.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2010, Ajax.org B.V.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ajax.org B.V. nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ***** END LICENSE BLOCK ***** */
  30. define(function(require, exports, module) {
  31. "use strict";
  32. var TokenIterator = require("../token_iterator").TokenIterator;
  33. var commonAttributes = [
  34. "accesskey",
  35. "class",
  36. "contenteditable",
  37. "contextmenu",
  38. "dir",
  39. "draggable",
  40. "dropzone",
  41. "hidden",
  42. "id",
  43. "inert",
  44. "itemid",
  45. "itemprop",
  46. "itemref",
  47. "itemscope",
  48. "itemtype",
  49. "lang",
  50. "spellcheck",
  51. "style",
  52. "tabindex",
  53. "title",
  54. "translate"
  55. ];
  56. var eventAttributes = [
  57. "onabort",
  58. "onblur",
  59. "oncancel",
  60. "oncanplay",
  61. "oncanplaythrough",
  62. "onchange",
  63. "onclick",
  64. "onclose",
  65. "oncontextmenu",
  66. "oncuechange",
  67. "ondblclick",
  68. "ondrag",
  69. "ondragend",
  70. "ondragenter",
  71. "ondragleave",
  72. "ondragover",
  73. "ondragstart",
  74. "ondrop",
  75. "ondurationchange",
  76. "onemptied",
  77. "onended",
  78. "onerror",
  79. "onfocus",
  80. "oninput",
  81. "oninvalid",
  82. "onkeydown",
  83. "onkeypress",
  84. "onkeyup",
  85. "onload",
  86. "onloadeddata",
  87. "onloadedmetadata",
  88. "onloadstart",
  89. "onmousedown",
  90. "onmousemove",
  91. "onmouseout",
  92. "onmouseover",
  93. "onmouseup",
  94. "onmousewheel",
  95. "onpause",
  96. "onplay",
  97. "onplaying",
  98. "onprogress",
  99. "onratechange",
  100. "onreset",
  101. "onscroll",
  102. "onseeked",
  103. "onseeking",
  104. "onselect",
  105. "onshow",
  106. "onstalled",
  107. "onsubmit",
  108. "onsuspend",
  109. "ontimeupdate",
  110. "onvolumechange",
  111. "onwaiting"
  112. ];
  113. var globalAttributes = commonAttributes.concat(eventAttributes);
  114. var attributeMap = {
  115. "html": {"manifest": 1},
  116. "head": {},
  117. "title": {},
  118. "base": {"href": 1, "target": 1},
  119. "link": {"href": 1, "hreflang": 1, "rel": {"stylesheet": 1, "icon": 1}, "media": {"all": 1, "screen": 1, "print": 1}, "type": {"text/css": 1, "image/png": 1, "image/jpeg": 1, "image/gif": 1}, "sizes": 1},
  120. "meta": {"http-equiv": {"content-type": 1}, "name": {"description": 1, "keywords": 1}, "content": {"text/html; charset=UTF-8": 1}, "charset": 1},
  121. "style": {"type": 1, "media": {"all": 1, "screen": 1, "print": 1}, "scoped": 1},
  122. "script": {"charset": 1, "type": {"text/javascript": 1}, "src": 1, "defer": 1, "async": 1},
  123. "noscript": {"href": 1},
  124. "body": {"onafterprint": 1, "onbeforeprint": 1, "onbeforeunload": 1, "onhashchange": 1, "onmessage": 1, "onoffline": 1, "onpopstate": 1, "onredo": 1, "onresize": 1, "onstorage": 1, "onundo": 1, "onunload": 1},
  125. "section": {},
  126. "nav": {},
  127. "article": {"pubdate": 1},
  128. "aside": {},
  129. "h1": {},
  130. "h2": {},
  131. "h3": {},
  132. "h4": {},
  133. "h5": {},
  134. "h6": {},
  135. "header": {},
  136. "footer": {},
  137. "address": {},
  138. "main": {},
  139. "p": {},
  140. "hr": {},
  141. "pre": {},
  142. "blockquote": {"cite": 1},
  143. "ol": {"start": 1, "reversed": 1},
  144. "ul": {},
  145. "li": {"value": 1},
  146. "dl": {},
  147. "dt": {},
  148. "dd": {},
  149. "figure": {},
  150. "figcaption": {},
  151. "div": {},
  152. "a": {"href": 1, "target": {"_blank": 1, "top": 1}, "ping": 1, "rel": {"nofollow": 1, "alternate": 1, "author": 1, "bookmark": 1, "help": 1, "license": 1, "next": 1, "noreferrer": 1, "prefetch": 1, "prev": 1, "search": 1, "tag": 1}, "media": 1, "hreflang": 1, "type": 1},
  153. "em": {},
  154. "strong": {},
  155. "small": {},
  156. "s": {},
  157. "cite": {},
  158. "q": {"cite": 1},
  159. "dfn": {},
  160. "abbr": {},
  161. "data": {},
  162. "time": {"datetime": 1},
  163. "code": {},
  164. "var": {},
  165. "samp": {},
  166. "kbd": {},
  167. "sub": {},
  168. "sup": {},
  169. "i": {},
  170. "b": {},
  171. "u": {},
  172. "mark": {},
  173. "ruby": {},
  174. "rt": {},
  175. "rp": {},
  176. "bdi": {},
  177. "bdo": {},
  178. "span": {},
  179. "br": {},
  180. "wbr": {},
  181. "ins": {"cite": 1, "datetime": 1},
  182. "del": {"cite": 1, "datetime": 1},
  183. "img": {"alt": 1, "src": 1, "height": 1, "width": 1, "usemap": 1, "ismap": 1},
  184. "iframe": {"name": 1, "src": 1, "height": 1, "width": 1, "sandbox": {"allow-same-origin": 1, "allow-top-navigation": 1, "allow-forms": 1, "allow-scripts": 1}, "seamless": {"seamless": 1}},
  185. "embed": {"src": 1, "height": 1, "width": 1, "type": 1},
  186. "object": {"param": 1, "data": 1, "type": 1, "height" : 1, "width": 1, "usemap": 1, "name": 1, "form": 1, "classid": 1},
  187. "param": {"name": 1, "value": 1},
  188. "video": {"src": 1, "autobuffer": 1, "autoplay": {"autoplay": 1}, "loop": {"loop": 1}, "controls": {"controls": 1}, "width": 1, "height": 1, "poster": 1, "muted": {"muted": 1}, "preload": {"auto": 1, "metadata": 1, "none": 1}},
  189. "audio": {"src": 1, "autobuffer": 1, "autoplay": {"autoplay": 1}, "loop": {"loop": 1}, "controls": {"controls": 1}, "muted": {"muted": 1}, "preload": {"auto": 1, "metadata": 1, "none": 1 }},
  190. "source": {"src": 1, "type": 1, "media": 1},
  191. "track": {"kind": 1, "src": 1, "srclang": 1, "label": 1, "default": 1},
  192. "canvas": {"width": 1, "height": 1},
  193. "map": {"name": 1},
  194. "area": {"shape": 1, "coords": 1, "href": 1, "hreflang": 1, "alt": 1, "target": 1, "media": 1, "rel": 1, "ping": 1, "type": 1},
  195. "svg": {},
  196. "math": {},
  197. "table": {"summary": 1},
  198. "caption": {},
  199. "colgroup": {"span": 1},
  200. "col": {"span": 1},
  201. "tbody": {},
  202. "thead": {},
  203. "tfoot": {},
  204. "tr": {},
  205. "td": {"headers": 1, "rowspan": 1, "colspan": 1},
  206. "th": {"headers": 1, "rowspan": 1, "colspan": 1, "scope": 1},
  207. "form": {"accept-charset": 1, "action": 1, "autocomplete": 1, "enctype": {"multipart/form-data": 1, "application/x-www-form-urlencoded": 1}, "method": {"get": 1, "post": 1}, "name": 1, "novalidate": 1, "target": {"_blank": 1, "top": 1}},
  208. "fieldset": {"disabled": 1, "form": 1, "name": 1},
  209. "legend": {},
  210. "label": {"form": 1, "for": 1},
  211. "input": {
  212. "type": {"text": 1, "password": 1, "hidden": 1, "checkbox": 1, "submit": 1, "radio": 1, "file": 1, "button": 1, "reset": 1, "image": 31, "color": 1, "date": 1, "datetime": 1, "datetime-local": 1, "email": 1, "month": 1, "number": 1, "range": 1, "search": 1, "tel": 1, "time": 1, "url": 1, "week": 1},
  213. "accept": 1, "alt": 1, "autocomplete": {"on": 1, "off": 1}, "autofocus": {"autofocus": 1}, "checked": {"checked": 1}, "disabled": {"disabled": 1}, "form": 1, "formaction": 1, "formenctype": {"application/x-www-form-urlencoded": 1, "multipart/form-data": 1, "text/plain": 1}, "formmethod": {"get": 1, "post": 1}, "formnovalidate": {"formnovalidate": 1}, "formtarget": {"_blank": 1, "_self": 1, "_parent": 1, "_top": 1}, "height": 1, "list": 1, "max": 1, "maxlength": 1, "min": 1, "multiple": {"multiple": 1}, "pattern": 1, "placeholder": 1, "readonly": {"readonly": 1}, "required": {"required": 1}, "size": 1, "src": 1, "step": 1, "width": 1, "files": 1, "value": 1},
  214. "button": {"autofocus": 1, "disabled": {"disabled": 1}, "form": 1, "formaction": 1, "formenctype": 1, "formmethod": 1, "formnovalidate": 1, "formtarget": 1, "name": 1, "value": 1, "type": {"button": 1, "submit": 1}},
  215. "select": {"autofocus": 1, "disabled": 1, "form": 1, "multiple": {"multiple": 1}, "name": 1, "size": 1, "readonly":{"readonly": 1}},
  216. "datalist": {},
  217. "optgroup": {"disabled": 1, "label": 1},
  218. "option": {"disabled": 1, "selected": 1, "label": 1, "value": 1},
  219. "textarea": {"autofocus": {"autofocus": 1}, "disabled": {"disabled": 1}, "form": 1, "maxlength": 1, "name": 1, "placeholder": 1, "readonly": {"readonly": 1}, "required": {"required": 1}, "rows": 1, "cols": 1, "wrap": {"on": 1, "off": 1, "hard": 1, "soft": 1}},
  220. "keygen": {"autofocus": 1, "challenge": {"challenge": 1}, "disabled": {"disabled": 1}, "form": 1, "keytype": {"rsa": 1, "dsa": 1, "ec": 1}, "name": 1},
  221. "output": {"for": 1, "form": 1, "name": 1},
  222. "progress": {"value": 1, "max": 1},
  223. "meter": {"value": 1, "min": 1, "max": 1, "low": 1, "high": 1, "optimum": 1},
  224. "details": {"open": 1},
  225. "summary": {},
  226. "command": {"type": 1, "label": 1, "icon": 1, "disabled": 1, "checked": 1, "radiogroup": 1, "command": 1},
  227. "menu": {"type": 1, "label": 1},
  228. "dialog": {"open": 1}
  229. };
  230. var elements = Object.keys(attributeMap);
  231. function is(token, type) {
  232. return token.type.lastIndexOf(type + ".xml") > -1;
  233. }
  234. function findTagName(session, pos) {
  235. var iterator = new TokenIterator(session, pos.row, pos.column);
  236. var token = iterator.getCurrentToken();
  237. while (token && !is(token, "tag-name")){
  238. token = iterator.stepBackward();
  239. }
  240. if (token)
  241. return token.value;
  242. }
  243. function findAttributeName(session, pos) {
  244. var iterator = new TokenIterator(session, pos.row, pos.column);
  245. var token = iterator.getCurrentToken();
  246. while (token && !is(token, "attribute-name")){
  247. token = iterator.stepBackward();
  248. }
  249. if (token)
  250. return token.value;
  251. }
  252. var HtmlCompletions = function() {
  253. };
  254. (function() {
  255. this.getCompletions = function(state, session, pos, prefix) {
  256. var token = session.getTokenAt(pos.row, pos.column);
  257. if (!token)
  258. return [];
  259. // tag name
  260. if (is(token, "tag-name") || is(token, "tag-open") || is(token, "end-tag-open"))
  261. return this.getTagCompletions(state, session, pos, prefix);
  262. // tag attribute
  263. if (is(token, "tag-whitespace") || is(token, "attribute-name"))
  264. return this.getAttributeCompletions(state, session, pos, prefix);
  265. // tag attribute values
  266. if (is(token, "attribute-value"))
  267. return this.getAttributeValueCompletions(state, session, pos, prefix);
  268. // HTML entities
  269. var line = session.getLine(pos.row).substr(0, pos.column);
  270. if (/&[A-z]*$/i.test(line))
  271. return this.getHTMLEntityCompletions(state, session, pos, prefix);
  272. return [];
  273. };
  274. this.getTagCompletions = function(state, session, pos, prefix) {
  275. return elements.map(function(element){
  276. return {
  277. value: element,
  278. meta: "tag",
  279. score: Number.MAX_VALUE
  280. };
  281. });
  282. };
  283. this.getAttributeCompletions = function(state, session, pos, prefix) {
  284. var tagName = findTagName(session, pos);
  285. if (!tagName)
  286. return [];
  287. var attributes = globalAttributes;
  288. if (tagName in attributeMap) {
  289. attributes = attributes.concat(Object.keys(attributeMap[tagName]));
  290. }
  291. return attributes.map(function(attribute){
  292. return {
  293. caption: attribute,
  294. snippet: attribute + '="$0"',
  295. meta: "attribute",
  296. score: Number.MAX_VALUE
  297. };
  298. });
  299. };
  300. this.getAttributeValueCompletions = function(state, session, pos, prefix) {
  301. var tagName = findTagName(session, pos);
  302. var attributeName = findAttributeName(session, pos);
  303. if (!tagName)
  304. return [];
  305. var values = [];
  306. if (tagName in attributeMap && attributeName in attributeMap[tagName] && typeof attributeMap[tagName][attributeName] === "object") {
  307. values = Object.keys(attributeMap[tagName][attributeName]);
  308. }
  309. return values.map(function(value){
  310. return {
  311. caption: value,
  312. snippet: value,
  313. meta: "attribute value",
  314. score: Number.MAX_VALUE
  315. };
  316. });
  317. };
  318. this.getHTMLEntityCompletions = function(state, session, pos, prefix) {
  319. var values = ['Á', 'á', 'Â', 'â', '´', 'Æ', 'æ', 'À', 'à', 'ℵ', 'Α', 'α', '&', '∧', '∠', 'Å', 'å', '≈', 'Ã', 'ã', 'Ä', 'ä', '„', 'Β', 'β', '¦', '•', '∩', 'Ç', 'ç', '¸', '¢', 'Χ', 'χ', 'ˆ', '♣', '≅', '©', '↵', '∪', '¤', '‡', '†', '⇓', '↓', '°', 'Δ', 'δ', '♦', '÷', 'É', 'é', 'Ê', 'ê', 'È', 'è', '∅', ' ', ' ', 'Ε', 'ε', '≡', 'Η', 'η', 'Ð', 'ð', 'Ë', 'ë', '€', '∃', 'ƒ', '∀', '½', '¼', '¾', '⁄', 'Γ', 'γ', '≥', '>', '⇔', '↔', '♥', '…', 'Í', 'í', 'Î', 'î', '¡', 'Ì', 'ì', 'ℑ', '∞', '∫', 'Ι', 'ι', '¿', '∈', 'Ï', 'ï', 'Κ', 'κ', 'Λ', 'λ', '⟨', '«', '⇐', '←', '⌈', '“', '≤', '⌊', '∗', '◊', '‎', '‹', '‘', '<', '¯', '—', 'µ', '·', '−', 'Μ', 'μ', '∇', ' ', '–', '≠', '∋', '¬', '∉', '⊄', 'Ñ', 'ñ', 'Ν', 'ν', 'Ó', 'ó', 'Ô', 'ô', 'Œ', 'œ', 'Ò', 'ò', '‾', 'Ω', 'ω', 'Ο', 'ο', '⊕', '∨', 'ª', 'º', 'Ø', 'ø', 'Õ', 'õ', '⊗', 'Ö', 'ö', '¶', '∂', '‰', '⊥', 'Φ', 'φ', 'Π', 'π', 'ϖ', '±', '£', '″', '′', '∏', '∝', 'Ψ', 'ψ', '"', '√', '⟩', '»', '⇒', '→', '⌉', '”', 'ℜ', '®', '⌋', 'Ρ', 'ρ', '‏', '›', '’', '‚', 'Š', 'š', '⋅', '§', '­', 'Σ', 'σ', 'ς', '∼', '♠', '⊂', '⊆', '∑', '⊃', '¹', '²', '³', '⊇', 'ß', 'Τ', 'τ', '∴', 'Θ', 'θ', 'ϑ', ' ', 'Þ', 'þ', '˜', '×', '™', 'Ú', 'ú', '⇑', '↑', 'Û', 'û', 'Ù', 'ù', '¨', 'ϒ', 'Υ', 'υ', 'Ü', 'ü', '℘', 'Ξ', 'ξ', 'Ý', 'ý', '¥', 'Ÿ', 'ÿ', 'Ζ', 'ζ', '‍', '‌'];
  320. return values.map(function(value){
  321. return {
  322. caption: value,
  323. snippet: value.substr(1),
  324. meta: "html entity",
  325. score: Number.MAX_VALUE
  326. };
  327. });
  328. };
  329. }).call(HtmlCompletions.prototype);
  330. exports.HtmlCompletions = HtmlCompletions;
  331. });