html_completions.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. "lang",
  44. "spellcheck",
  45. "style",
  46. "tabindex",
  47. "title",
  48. "translate"
  49. ];
  50. var eventAttributes = [
  51. "onabort",
  52. "onblur",
  53. "oncancel",
  54. "oncanplay",
  55. "oncanplaythrough",
  56. "onchange",
  57. "onclick",
  58. "onclose",
  59. "oncontextmenu",
  60. "oncuechange",
  61. "ondblclick",
  62. "ondrag",
  63. "ondragend",
  64. "ondragenter",
  65. "ondragleave",
  66. "ondragover",
  67. "ondragstart",
  68. "ondrop",
  69. "ondurationchange",
  70. "onemptied",
  71. "onended",
  72. "onerror",
  73. "onfocus",
  74. "oninput",
  75. "oninvalid",
  76. "onkeydown",
  77. "onkeypress",
  78. "onkeyup",
  79. "onload",
  80. "onloadeddata",
  81. "onloadedmetadata",
  82. "onloadstart",
  83. "onmousedown",
  84. "onmousemove",
  85. "onmouseout",
  86. "onmouseover",
  87. "onmouseup",
  88. "onmousewheel",
  89. "onpause",
  90. "onplay",
  91. "onplaying",
  92. "onprogress",
  93. "onratechange",
  94. "onreset",
  95. "onscroll",
  96. "onseeked",
  97. "onseeking",
  98. "onselect",
  99. "onshow",
  100. "onstalled",
  101. "onsubmit",
  102. "onsuspend",
  103. "ontimeupdate",
  104. "onvolumechange",
  105. "onwaiting"
  106. ];
  107. var globalAttributes = commonAttributes.concat(eventAttributes);
  108. var attributeMap = {
  109. "html": ["manifest"],
  110. "head": [],
  111. "title": [],
  112. "base": ["href", "target"],
  113. "link": ["href", "hreflang", "rel", "media", "type", "sizes"],
  114. "meta": ["http-equiv", "name", "content", "charset"],
  115. "style": ["type", "media", "scoped"],
  116. "script": ["charset", "type", "src", "defer", "async"],
  117. "noscript": ["href"],
  118. "body": ["onafterprint", "onbeforeprint", "onbeforeunload", "onhashchange", "onmessage", "onoffline", "onpopstate", "onredo", "onresize", "onstorage", "onundo", "onunload"],
  119. "section": [],
  120. "nav": [],
  121. "article": ["pubdate"],
  122. "aside": [],
  123. "h1": [],
  124. "h2": [],
  125. "h3": [],
  126. "h4": [],
  127. "h5": [],
  128. "h6": [],
  129. "header": [],
  130. "footer": [],
  131. "address": [],
  132. "main": [],
  133. "p": [],
  134. "hr": [],
  135. "pre": [],
  136. "blockquote": ["cite"],
  137. "ol": ["start", "reversed"],
  138. "ul": [],
  139. "li": ["value"],
  140. "dl": [],
  141. "dt": [],
  142. "dd": [],
  143. "figure": [],
  144. "figcaption": [],
  145. "div": [],
  146. "a": ["href", "target", "ping", "rel", "media", "hreflang", "type"],
  147. "em": [],
  148. "strong": [],
  149. "small": [],
  150. "s": [],
  151. "cite": [],
  152. "q": ["cite"],
  153. "dfn": [],
  154. "abbr": [],
  155. "data": [],
  156. "time": ["datetime"],
  157. "code": [],
  158. "var": [],
  159. "samp": [],
  160. "kbd": [],
  161. "sub": [],
  162. "sup": [],
  163. "i": [],
  164. "b": [],
  165. "u": [],
  166. "mark": [],
  167. "ruby": [],
  168. "rt": [],
  169. "rp": [],
  170. "bdi": [],
  171. "bdo": [],
  172. "span": [],
  173. "br": [],
  174. "wbr": [],
  175. "ins": ["cite", "datetime"],
  176. "del": ["cite", "datetime"],
  177. "img": ["alt", "src", "height", "width", "usemap", "ismap"],
  178. "iframe": ["name", "src", "height", "width", "sandbox", "seamless"],
  179. "embed": ["src", "height", "width", "type"],
  180. "object": ["param", "data", "type", "height" , "width", "usemap", "name", "form", "classid"],
  181. "param": ["name", "value"],
  182. "video": ["src", "autobuffer", "autoplay", "loop", "controls", "width", "height", "poster"],
  183. "audio": ["src", "autobuffer", "autoplay", "loop", "controls"],
  184. "source": ["src", "type", "media"],
  185. "track": ["kind", "src", "srclang", "label", "default"],
  186. "canvas": ["width", "height"],
  187. "map": ["name"],
  188. "area": ["shape", "coords", "href", "hreflang", "alt", "target", "media", "rel", "ping", "type"],
  189. "svg": [],
  190. "math": [],
  191. "table": ["summary"],
  192. "caption": [],
  193. "colgroup": ["span"],
  194. "col": ["span"],
  195. "tbody": [],
  196. "thead": [],
  197. "tfoot": [],
  198. "tr": [],
  199. "td": ["headers", "rowspan", "colspan"],
  200. "th": ["headers", "rowspan", "colspan", "scope"],
  201. "form": ["accept-charset", "action", "autocomplete", "enctype", "method", "name", "novalidate", "target"],
  202. "fieldset": ["disabled", "form", "name"],
  203. "legend": [],
  204. "label": ["form", "for"],
  205. "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"],
  206. "button": ["autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "value", "type"],
  207. "select": ["autofocus", "disabled", "form", "multiple", "name", "size"],
  208. "datalist": [],
  209. "optgroup": ["disabled", "label"],
  210. "option": ["disabled", "selected", "label", "value"],
  211. "textarea": ["autofocus", "disabled", "form", "maxlength", "name", "placeholder", "readonly", "required", "rows", "cols", "wrap"],
  212. "keygen": ["autofocus", "challenge", "disabled", "form", "keytype", "name"],
  213. "output": ["for", "form", "name"],
  214. "progress": ["value", "max"],
  215. "meter": ["value", "min", "max", "low", "high", "optimum"],
  216. "details": ["open"],
  217. "summary": [],
  218. "command": ["type", "label", "icon", "disabled", "checked", "radiogroup", "command"],
  219. "menu": ["type", "label"],
  220. "dialog": ["open"]
  221. };
  222. var allElements = Object.keys(attributeMap);
  223. function hasType(token, type) {
  224. var tokenTypes = token.type.split('.');
  225. return type.split('.').every(function(type){
  226. return (tokenTypes.indexOf(type) !== -1);
  227. });
  228. }
  229. function findTagName(session, pos) {
  230. var iterator = new TokenIterator(session, pos.row, pos.column);
  231. var token = iterator.getCurrentToken();
  232. if (!token || !hasType(token, 'tag') && !(hasType(token, 'text') && token.value.match('/'))){
  233. do {
  234. token = iterator.stepBackward();
  235. } while (token && (hasType(token, 'string') || hasType(token, 'operator') || hasType(token, 'attribute-name') || hasType(token, 'text')));
  236. }
  237. if (token && hasType(token, 'tag-name') && !iterator.stepBackward().value.match('/'))
  238. return token.value;
  239. }
  240. var HtmlCompletions = function() {
  241. };
  242. (function() {
  243. this.getCompletions = function(state, session, pos, prefix) {
  244. var token = session.getTokenAt(pos.row, pos.column);
  245. if (!token)
  246. return [];
  247. // tag name
  248. if (hasType(token, "tag-name") || (token.value == '<' && hasType(token, "text")))
  249. return this.getTagCompletions(state, session, pos, prefix);
  250. // tag attribute
  251. if (hasType(token, 'text') || hasType(token, 'attribute-name'))
  252. return this.getAttributeCompetions(state, session, pos, prefix);
  253. return [];
  254. };
  255. this.getTagCompletions = function(state, session, pos, prefix) {
  256. var elements = allElements;
  257. if (prefix) {
  258. elements = elements.filter(function(element){
  259. return element.indexOf(prefix) === 0;
  260. });
  261. }
  262. return elements.map(function(element){
  263. return {
  264. value: element,
  265. meta: "tag"
  266. };
  267. });
  268. };
  269. this.getAttributeCompetions = function(state, session, pos, prefix) {
  270. var tagName = findTagName(session, pos);
  271. if (!tagName)
  272. return [];
  273. var attributes = globalAttributes;
  274. if (tagName in attributeMap) {
  275. attributes = attributes.concat(attributeMap[tagName]);
  276. }
  277. if (prefix) {
  278. attributes = attributes.filter(function(attribute){
  279. return attribute.indexOf(prefix) === 0;
  280. });
  281. }
  282. return attributes.map(function(attribute){
  283. return {
  284. caption: attribute,
  285. snippet: attribute + '="$0"',
  286. meta: "attribute"
  287. };
  288. });
  289. };
  290. }).call(HtmlCompletions.prototype);
  291. exports.HtmlCompletions = HtmlCompletions;
  292. });