1" Vim completion script
2" Language:	Java Script
3" Maintainer:	Jay Sitter (jay@jaysitter.com)
4" URL: https://github.com/jsit/javascriptcomplete.vim/
5" Previous Maintainer:	Mikolaj Machowski ( mikmach AT wp DOT pl )
6" Last Change:	2020 Jul 30
7
8function! javascriptcomplete#CompleteJS(findstart, base)
9  if a:findstart
10	" locate the start of the word
11	let line = getline('.')
12	let start = col('.') - 1
13	let curline = line('.')
14	let compl_begin = col('.') - 2
15	" Bit risky but JS is rather limited language and local chars shouldn't
16	" fint way into names
17	while start >= 0 && line[start - 1] =~ '\k'
18		let start -= 1
19	endwhile
20	let b:compl_context = getline('.')[0:compl_begin]
21	return start
22  else
23	" Initialize base return lists
24	let res = []
25	let res2 = []
26	" a:base is very short - we need context
27	" Shortcontext is context without a:base, useful for checking if we are
28	" looking for objects and for what objects we are looking for
29	let context = b:compl_context
30	let shortcontext = substitute(context, a:base.'$', '', '')
31	unlet! b:compl_context
32
33	if exists("b:jsrange")
34		let file = getline(b:jsrange[0],b:jsrange[1])
35		unlet! b:jsrange
36
37		if len(b:js_extfiles) > 0
38			let file = b:js_extfiles + file
39		endif
40
41	else
42		let file = getline(1, '$')
43	endif
44
45
46	" Completion of properties, methods, etc. {{{
47	if shortcontext =~ '\.$'
48		" Complete methods and properties for objects
49		" DOM separate
50		let doms = ['style.']
51		" Arrays
52		let arrayprop = ['constructor', 'index', 'input', 'length', 'prototype']
53		let arraymeth = ['concat', 'join', 'pop', 'push', 'reverse', 'shift',
54					\ 'splice', 'sort', 'toSource', 'toString', 'unshift', 'valueOf',
55					\ 'watch', 'unwatch']
56		call map(arraymeth, 'v:val."("')
57		let arrays = arrayprop + arraymeth
58
59		" Boolean - complete subset of array values
60		" properties - constructor, prototype
61		" methods    - toSource, toString, valueOf
62
63		" Date
64		" properties - constructor, prototype
65		let datemeth = ['getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds',
66					\ 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset',
67					\ 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds',
68					\ 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds',
69					\ 'getYear', 'parse', 'parse',
70					\ 'setDate', 'setDay', 'setFullYear', 'setHours', 'setMilliseconds',
71					\ 'setMinutes', 'setMonth', 'setSeconds',
72					\ 'setUTCDate', 'setUTCDay', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds',
73					\ 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'setTime',
74					\ 'toGMTString', 'toLocaleString', 'toLocaleDateString', 'toLocaleTimeString',
75					\ 'toSource', 'toString', 'toUTCString', 'UTC', 'valueOf', 'watch', 'unwatch']
76		call map(datemeth, 'v:val."("')
77		let dates = datemeth
78
79		" Function
80		let funcprop = ['arguments', 'arguments.callee', 'arguments.caller', 'arguments.length',
81					\ 'arity', 'constructor', 'length', 'prototype']
82		let funcmeth = ['apply', 'call', 'toSource', 'toString', 'valueOf']
83		call map(funcmeth, 'v:val."("')
84		let funcs = funcprop + funcmeth
85
86		" Math
87		let mathprop = ['E', 'LN2', 'LN10', 'LOG2E', 'LOG10E', 'PI', 'SQRT1_2', 'SQRT']
88		let mathmeth = ['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor',
89					\ 'log', 'max', 'min', 'pow', 'random', 'round', 'sin', 'sqrt', 'tan',
90					\ 'watch', 'unwatch']
91		call map(mathmeth, 'v:val."("')
92		let maths = mathprop + mathmeth
93
94		" Number
95		let numbprop = ['MAX_VALUE', 'MIN_VALUE', 'NaN', 'NEGATIVE_INFINITY', 'POSITIVE_INFINITY',
96					\ 'constructor', 'prototype']
97		let numbmeth = ['toExponential', 'toFixed', 'toPrecision', 'toSource', 'toString', 'valueOf',
98					\ 'watch', 'unwatch']
99		call map(numbmeth, 'v:val."("')
100		let numbs = numbprop + numbmeth
101
102		" Object
103		let objeprop = ['constructor', 'prototype']
104		let objemeth = ['eval', 'toSource', 'toString', 'unwatch', 'watch', 'valueOf']
105		call map(objemeth, 'v:val."("')
106		let objes = objeprop + objemeth
107
108		" RegExp
109		let regeprop = ['constructor', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'prototype']
110		let regemeth = ['exec', 'test', 'toSource', 'toString', 'watch', 'unwatch']
111		call map(regemeth, 'v:val."("')
112		let reges = regeprop + regemeth
113
114		" String
115		let striprop = ['constructor', 'length', 'prototype']
116		let strimeth = ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat',
117					\ 'fixed', 'fontcolor', 'fontsize', 'fromCharCode', 'indexOf', 'italics',
118					\ 'lastIndexOf', 'link', 'match', 'replace', 'search', 'slice', 'small',
119					\ 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLowerCase',
120					\ 'toSource', 'toString', 'toUpperCase', 'watch', 'unwatch']
121		call map(strimeth, 'v:val."("')
122		let stris = striprop + strimeth
123
124		" User created properties
125		let user_props1 = filter(copy(file), 'v:val =~ "this\\.\\k"')
126		let juser_props1 = join(user_props1, ' ')
127		let user_props1 = split(juser_props1, '\zethis\.')
128		unlet! juser_props1
129		call map(user_props1, 'matchstr(v:val, "this\\.\\zs\\k\\+\\ze")')
130
131		let user_props2 = filter(copy(file), 'v:val =~ "\\.prototype\\.\\k"')
132		let juser_props2 = join(user_props2, ' ')
133		let user_props2 = split(juser_props2, '\zeprototype\.')
134		unlet! juser_props2
135		call map(user_props2, 'matchstr(v:val, "prototype\\.\\zs\\k\\+\\ze")')
136		let user_props = user_props1 + user_props2
137
138		" HTML DOM properties
139		" Anchors - anchor.
140		let anchprop = ['accessKey', 'charset', 'coords', 'href', 'hreflang', 'id', 'innerHTML',
141					\ 'name', 'rel', 'rev', 'shape', 'tabIndex', 'target', 'type', 'onBlur', 'onFocus']
142		let anchmeth = ['blur', 'focus']
143		call map(anchmeth, 'v:val."("')
144		let anths = anchprop + anchmeth
145		" Area - area.
146		let areaprop = ['accessKey', 'alt', 'coords', 'hash', 'host', 'hostname', 'href', 'id',
147					\ 'noHref', 'pathname', 'port', 'protocol', 'search', 'shape', 'tabIndex', 'target']
148		let areameth = ['onClick', 'onDblClick', 'onMouseOut', 'onMouseOver']
149		call map(areameth, 'v:val."("')
150		let areas = areaprop + areameth
151		" Base - base.
152		let baseprop = ['href', 'id', 'target']
153		let bases = baseprop
154		" Body - body.
155		let bodyprop = ['aLink', 'background', 'gbColor', 'id', 'link', 'scrollLeft', 'scrollTop',
156					\ 'text', 'vLink']
157		let bodys = bodyprop
158		" Document - document.
159		let docuprop = ['anchors', 'body', 'characterSet', 'doctype',
160					\ 'documentElement', 'documentURI', 'embeds', 'fonts', 'forms',
161					\ 'head', 'hidden', 'images', 'implementation', 'lastStyleSheetSet',
162					\ 'links', 'plugins', 'preferredStyleSheetSet', 'scripts',
163					\ 'scrollingElement', 'selectedStyleSheetSet', 'styleSheetSets',
164					\ 'timeline', 'visibilityState', 'cookie', 'defaultView',
165					\ 'designMode', 'dir', 'domain', 'lastModified', 'location',
166					\ 'readyState', 'referrer', 'title', 'URL', 'activeElement',
167					\ 'fullscreenElement', 'styleSheets']
168		let documeth = ['adoptNode', 'close', 'createAttribute',
169					\ 'createAttributeNS', 'createCDATASection', 'createComment',
170					\ 'createDocumentFragment', 'createElement', 'createElementNS',
171					\ 'createEvent', 'createExpression', 'createNSResolver',
172					\ 'createNodeIterator', 'createProcessingInstruction', 'createRange',
173					\ 'createTextNode', 'createTouchList', 'createTreeWalker',
174					\ 'enableStyleSheetsForSet', 'evaluate', 'focus', 'getElementById',
175					\ 'getElementById', 'getElementsByClassName', 'getElementsByName',
176					\ 'getElementsByTagName', 'getElementsByTagNameNS',
177					\ 'hasStorageAccess', 'importNode', 'onClick', 'onDblClick',
178					\ 'onFocus', 'onKeyDown', 'onKeyPress', 'onKeyUp', 'onMouseDown',
179					\ 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp',
180					\ 'onResize', 'open', 'querySelector', 'querySelectorAll',
181					\ 'requestStorageAccess', 'write', 'writeln']
182
183		call map(documeth, 'v:val."("')
184		let docuxprop = ['attributes', 'childNodes', 'doctype', 'documentElement', 'firstChild',
185					\ 'implementation', 'namespaceURI', 'nextSibling', 'nodeName', 'nodeType',
186					\ 'nodeValue', 'ownerDocument', 'parentNode', 'previousSibling']
187		let docuxmeth = ['createAttribute', 'createCDATASection',
188					\ 'createComment', 'createDocument', 'createDocumentFragment',
189					\ 'createElement', 'createEntityReference', 'createProcessingInstruction',
190					\ 'createTextNode']
191		call map(docuxmeth, 'v:val."("')
192		let docus = docuprop + docuxprop + documeth + docuxmeth
193		" Form - form.
194		let formprop = ['elements', 'acceptCharset', 'action', 'encoding', 'enctype', 'id', 'length',
195					\ 'method', 'name', 'tabIndex', 'target']
196		let formmeth = ['reset', 'submit', 'onReset', 'onSubmit']
197		call map(formmeth, 'v:val."("')
198		let forms = formprop + formmeth
199		" Frame - frame.
200		let framprop = ['contentDocument', 'frameBorder', 'id', 'longDesc', 'marginHeight', 'marginWidth',
201					\ 'name', 'noResize', 'scrolling', 'src']
202		let frammeth = ['blur', 'focus']
203		call map(frammeth, 'v:val."("')
204		let frams = framprop + frammeth
205		" Frameset - frameset.
206		let fsetprop = ['cols', 'id', 'rows']
207		let fsetmeth = ['blur', 'focus']
208		call map(fsetmeth, 'v:val."("')
209		let fsets = fsetprop + fsetmeth
210		" History - history.
211		let histprop = ['length']
212		let histmeth = ['back', 'forward', 'go']
213		call map(histmeth, 'v:val."("')
214		let hists = histprop + histmeth
215		" Iframe - iframe.
216		let ifraprop = ['align', 'frameBorder', 'height', 'id', 'longDesc', 'marginHeight', 'marginWidth',
217					\ 'name', 'scrolling', 'src', 'width']
218		let ifras = ifraprop
219		" Image - image.
220		let imagprop = ['align', 'alt', 'border', 'complete', 'height', 'hspace', 'id', 'isMap', 'longDesc',
221					\ 'lowSrc', 'name', 'src', 'useMap', 'vspace', 'width']
222		let imagmeth = ['onAbort', 'onError', 'onLoad']
223		call map(imagmeth, 'v:val."("')
224		let imags = histprop + imagmeth
225		" Button - accessible only by other properties
226		let buttprop = ['accessKey', 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
227		let buttmeth = ['blur', 'click', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
228		call map(buttmeth, 'v:val."("')
229		let butts = buttprop + buttmeth
230		" Checkbox - accessible only by other properties
231		let checprop = ['accept', 'accessKey', 'align', 'alt', 'checked', 'defaultChecked',
232					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
233		let checmeth = ['blur', 'click', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
234		call map(checmeth, 'v:val."("')
235		let checs = checprop + checmeth
236		" File upload - accessible only by other properties
237		let fileprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
238					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
239		let filemeth = ['blur', 'focus', 'onBlur', 'onClick', 'onFocus', 'onMouseDown', 'onMouseUp']
240		call map(filemeth, 'v:val."("')
241		let files = fileprop + filemeth
242		" Hidden - accessible only by other properties
243		let hiddprop = ['defaultValue', 'form', 'id', 'name', 'type', 'value']
244		let hidds = hiddprop
245		" Password - accessible only by other properties
246		let passprop = ['accept', 'accessKey', 'defaultValue',
247					\ 'disabled', 'form', 'id', 'maxLength', 'name', 'readOnly', 'size', 'tabIndex',
248					\ 'type', 'value']
249		let passmeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus', 'onKeyDown',
250					\ 'onKeyPress', 'onKeyUp']
251		call map(passmeth, 'v:val."("')
252		let passs = passprop + passmeth
253		" Radio - accessible only by other properties
254		let radiprop = ['accept', 'accessKey', 'align', 'alt', 'checked', 'defaultChecked',
255					\ 'disabled', 'form', 'id', 'name', 'tabIndex', 'type', 'value']
256		let radimeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus']
257		call map(radimeth, 'v:val."("')
258		let radis = radiprop + radimeth
259		" Reset - accessible only by other properties
260		let reseprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
261					\ 'disabled', 'form', 'id', 'name', 'size', 'tabIndex', 'type', 'value']
262		let resemeth = ['blur', 'click', 'focus', 'select', 'onBlur', 'onFocus']
263		call map(resemeth, 'v:val."("')
264		let reses = reseprop + resemeth
265		" Submit - accessible only by other properties
266		let submprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
267					\ 'disabled', 'form', 'id', 'name', 'size', 'tabIndex', 'type', 'value']
268		let submmeth = ['blur', 'click', 'focus', 'select', 'onClick', 'onSelectStart']
269		call map(submmeth, 'v:val."("')
270		let subms = submprop + submmeth
271		" Text - accessible only by other properties
272		let textprop = ['accept', 'accessKey', 'align', 'alt', 'defaultValue',
273					\ 'disabled', 'form', 'id', 'maxLength', 'name', 'readOnly',
274					\ 'size', 'tabIndex', 'type', 'value']
275		let textmeth = ['blur', 'focus', 'select', 'onBlur', 'onChange', 'onFocus', 'onKeyDown',
276					\ 'onKeyPress', 'onKeyUp', 'onSelect']
277		call map(textmeth, 'v:val."("')
278		let texts = textprop + textmeth
279		" Link - link.
280		let linkprop = ['charset', 'disabled', 'href', 'hreflang', 'id', 'media',
281					\ 'rel', 'rev', 'target', 'type']
282		let linkmeth = ['onLoad']
283		call map(linkmeth, 'v:val."("')
284		let links = linkprop + linkmeth
285		" Location - location.
286		let locaprop = ['href', 'hash', 'host', 'hostname', 'pathname', 'port', 'protocol',
287					\ 'search']
288		let locameth = ['assign', 'reload', 'replace']
289		call map(locameth, 'v:val."("')
290		let locas = locaprop + locameth
291		" Meta - meta.
292		let metaprop = ['charset', 'content', 'disabled', 'httpEquiv', 'name', 'scheme']
293		let metas = metaprop
294		" Navigator - navigator.
295		let naviprop = ['plugins', 'appCodeName', 'appName', 'appVersion', 'cookieEnabled',
296					\ 'platform', 'userAgent']
297		let navimeth = ['javaEnabled', 'taintEnabled']
298		call map(navimeth, 'v:val."("')
299		let navis = naviprop + navimeth
300		" Object - object.
301		let objeprop = ['align', 'archive', 'border', 'code', 'codeBase', 'codeType', 'data',
302					\ 'declare', 'form', 'height', 'hspace', 'id', 'name', 'standby', 'tabIndex',
303					\ 'type', 'useMap', 'vspace', 'width']
304		let objes = objeprop
305		" Option - accessible only by other properties
306		let optiprop = ['defaultSelected',
307					\ 'disabled', 'form', 'id', 'index', 'label', 'selected', 'text', 'value']
308		let optis = optiprop
309		" Screen - screen.
310		let screprop = ['availHeight', 'availWidth', 'colorDepth', 'height', 'width']
311		let scres = screprop
312		" Select - accessible only by other properties
313		let seleprop = ['options', 'disabled', 'form', 'id', 'length', 'multiple', 'name',
314					\ 'selectedIndex', 'size', 'tabIndex', 'type', 'value']
315		let selemeth = ['blur', 'focus', 'remove', 'onBlur', 'onChange', 'onFocus']
316		call map(selemeth, 'v:val."("')
317		let seles = seleprop + selemeth
318		" Style - style.
319		let stylprop = ['background', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
320					\ 'backgroundPosition', 'backgroundRepeat',
321					\ 'border', 'borderBottom', 'borderLeft', 'borderRight', 'borderTop',
322					\ 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor',
323					\ 'borderBottomStyle', 'borderLeftStyle', 'borderRightStyle', 'borderTopStyle',
324					\ 'borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth',
325					\ 'borderColor', 'borderStyle', 'borderWidth', 'margin', 'marginBottom',
326					\ 'marginLeft', 'marginRight', 'marginTop', 'outline', 'outlineStyle', 'outlineWidth',
327					\ 'outlineColor', 'outlineStyle', 'outlineWidth', 'padding', 'paddingBottom',
328					\ 'paddingLeft', 'paddingRight', 'paddingTop',
329					\ 'clear', 'clip', 'clipBottom', 'clipLeft', 'clipRight', 'clipTop', 'content',
330					\ 'counterIncrement', 'counterReset', 'cssFloat', 'cursor', 'direction',
331					\ 'display', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight',
332					\ 'minWidth', 'overflow', 'overflowX', 'overflowY', 'verticalAlign', 'visibility',
333					\ 'width',
334					\ 'listStyle', 'listStyleImage', 'listStylePosition', 'listStyleType',
335					\ 'cssText', 'bottom', 'height', 'left', 'position', 'right', 'top', 'width', 'zindex',
336					\ 'orphans', 'widows', 'page', 'pageBreakAfter', 'pageBreakBefore', 'pageBreakInside',
337					\ 'borderCollapse', 'borderSpacing', 'captionSide', 'emptyCells', 'tableLayout',
338					\ 'color', 'font', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
339					\ 'fontStyle', 'fontVariant', 'fontWeight', 'letterSpacing', 'lineHeight', 'quotes',
340					\ 'textAlign', 'textIndent', 'textShadow', 'textTransform', 'textUnderlinePosition',
341					\ 'unicodeBidi', 'whiteSpace', 'wordSpacing']
342		let styls = stylprop
343		" Table - table.
344		let tablprop = ['rows', 'tBodies', 'align', 'bgColor', 'border', 'caption', 'cellPadding',
345					\ 'cellSpacing', 'frame', 'height', 'rules', 'summary', 'tFoot', 'tHead', 'width']
346		let tablmeth = ['createCaption', 'createTFoot', 'createTHead', 'deleteCaption', 'deleteRow',
347					\ 'deleteTFoot', 'deleteTHead', 'insertRow']
348		call map(tablmeth, 'v:val."("')
349		let tabls = tablprop + tablmeth
350		" Table data - TableData.
351		let tdatprop = ['abbr', 'align', 'axis', 'bgColor', 'cellIndex', 'ch', 'chOff',
352					\ 'colSpan', 'headers', 'noWrap', 'rowSpan', 'scope', 'vAlign', 'width']
353		let tdats = tdatprop
354		" Table row - TableRow.
355		let trowprop = ['cells', 'align', 'bgColor', 'ch', 'chOff', 'rowIndex', 'sectionRowIndex',
356					\ 'vAlign']
357		let trowmeth = ['deleteCell', 'insertCell']
358		call map(trowmeth, 'v:val."("')
359		let trows = trowprop + trowmeth
360		" Textarea - accessible only by other properties
361		let tareprop = ['accessKey', 'cols', 'defaultValue',
362					\ 'disabled', 'form', 'id', 'name', 'readOnly', 'rows',
363					\ 'tabIndex', 'type', 'value', 'selectionStart', 'selectionEnd']
364		let taremeth = ['blur', 'focus', 'select', 'onBlur', 'onChange', 'onFocus']
365		call map(taremeth, 'v:val."("')
366		let tares = tareprop + taremeth
367		" Window - window.
368		let windprop = ['frames', 'closed', 'defaultStatus', 'encodeURI', 'event', 'history',
369					\ 'length', 'location', 'name', 'onload', 'opener', 'parent', 'screen', 'self',
370					\ 'status', 'top', 'XMLHttpRequest', 'ActiveXObject']
371		let windmeth = ['alert', 'blur', 'clearInterval', 'clearTimeout', 'close', 'confirm', 'focus',
372					\ 'moveBy', 'moveTo', 'open', 'print', 'prompt', 'scrollBy', 'scrollTo', 'setInterval',
373					\ 'setTimeout']
374		call map(windmeth, 'v:val."("')
375		let winds = windprop + windmeth
376		" XMLHttpRequest - access by new xxx()
377		let xmlhprop = ['onreadystatechange', 'readyState', 'responseText', 'responseXML',
378					\ 'status', 'statusText', 'parseError']
379		let xmlhmeth = ['abort', 'getAllResponseHeaders', 'getResponseHeaders', 'open',
380					\ 'send', 'setRequestHeader']
381		call map(xmlhmeth, 'v:val."("')
382		let xmlhs = xmlhprop + xmlhmeth
383
384		" XML DOM
385		" Attributes - element.attributes[x].
386		let xdomattrprop = ['name', 'specified', 'value']
387		" Element - anyelement.
388		let xdomelemprop = ['attributes', 'childNodes', 'firstChild', 'lastChild',
389					\ 'namespaceURI', 'nextSibling', 'nodeName', 'nodeType', 'nodeValue',
390					\ 'ownerDocument', 'parentNode', 'prefix', 'previousSibling', 'tagName']
391		let xdomelemmeth = ['appendChild', 'addEventListener', 'cloneNode',
392					\ 'dispatchEvent', 'getAttribute', 'getAttributeNode',
393					\ 'getElementsByTagName', 'hasChildNodes', 'insertBefore',
394					\ 'normalize', 'removeAttribute', 'removeAttributeNode',
395					\ 'removeChild', 'removeEventListener', 'replaceChild',
396					\ 'setAttribute', 'setAttributeNode']
397		call map(xdomelemmeth, 'v:val."("')
398		let xdomelems = xdomelemprop + xdomelemmeth
399		" Node - anynode.
400		let xdomnodeprop = ['attributes', 'childNodes', 'firstChild', 'lastChild',
401					\ 'namespaceURI', 'nextSibling', 'nodeName', 'nodeType', 'nodeValue',
402					\ 'ownerDocument', 'parentNode', 'prefix', 'previousSibling']
403		let xdomnodemeth = ['appendChild', 'cloneNode',
404					\ 'hasChildNodes', 'insertBefore', 'removeChild', 'replaceChild']
405		call map(xdomnodemeth, 'v:val."("')
406		let xdomnodes = xdomnodeprop + xdomnodemeth
407		" NodeList
408		let xdomnliss = ['length', 'item(']
409		" Error - parseError.
410		let xdomerror = ['errorCode', 'reason', 'line', 'linepos', 'srcText', 'url', 'filepos']
411
412		" Find object type declaration to reduce number of suggestions. {{{
413		" 1. Get object name
414		" 2. Find object declaration line
415		" 3. General declaration follows "= new Type" syntax, additional else
416		"    for regexp "= /re/"
417		" 4. Make correction for Microsoft.XMLHTTP ActiveXObject
418		" 5. Repeat for external files
419		let object = matchstr(shortcontext, '\zs\k\+\ze\(\[.\{-}\]\)\?\.$')
420		if len(object) > 0
421			let decl_line = search(object.'.\{-}=\s*new\s*', 'bn')
422			if decl_line > 0
423				let object_type = matchstr(getline(decl_line), object.'.\{-}=\s*new\s*\zs\k\+\ze')
424				if object_type == 'ActiveXObject' && matchstr(getline(decl_line), object.'.\{-}=\s*new\s*ActiveXObject\s*(.Microsoft\.XMLHTTP.)') != ''
425						let object_type = 'XMLHttpRequest'
426				endif
427			else
428				let decl_line = search('var\s*'.object.'\s*=\s*\/', 'bn')
429				if decl_line > 0
430					let object_type = 'RegExp'
431				endif
432			endif
433			" We didn't find var declaration in current file but we may have
434			" something in external files.
435			if decl_line == 0 && exists("b:js_extfiles")
436				let dext_line = filter(copy(b:js_extfiles), 'v:val =~ "'.object.'.\\{-}=\\s*new\\s*"')
437				if len(dext_line) > 0
438					let object_type = matchstr(dext_line[-1], object.'.\{-}=\s*new\s*\zs\k\+\ze')
439					if object_type == 'ActiveXObject' && matchstr(dext_line[-1], object.'.\{-}=\s*new\s*ActiveXObject\s*(.Microsoft\.XMLHTTP.)') != ''
440							let object_type = 'XMLHttpRequest'
441					endif
442				else
443					let dext_line = filter(copy(b:js_extfiles), 'v:val =~ "var\s*'.object.'\\s*=\\s*\\/"')
444					if len(dext_line) > 0
445						let object_type = 'RegExp'
446					endif
447				endif
448			endif
449		endif
450		" }}}
451
452		if !exists('object_type')
453			let object_type = ''
454		endif
455
456		if object_type == 'Date'
457			let values = dates
458		elseif object_type == 'Image'
459			let values = imags
460		elseif object_type == 'Array'
461			let values = arrays
462		elseif object_type == 'Boolean'
463			" TODO: a bit more than real boolean
464			let values = arrays
465		elseif object_type == 'XMLHttpRequest'
466			let values = xmlhs
467		elseif object_type == 'String'
468			let values = stris
469		elseif object_type == 'RegExp'
470			let values = reges
471		elseif object_type == 'Math'
472			let values = maths
473		endif
474
475		if !exists('values')
476		" List of properties
477		if shortcontext =~ 'Math\.$'
478			let values = maths
479		elseif shortcontext =~ 'anchors\(\[.\{-}\]\)\?\.$'
480			let values = anths
481		elseif shortcontext =~ 'area\.$'
482			let values = areas
483		elseif shortcontext =~ 'base\.$'
484			let values = bases
485		elseif shortcontext =~ 'body\.$'
486			let values = bodys
487		elseif shortcontext =~ 'document\.$'
488			let values = docus
489		elseif shortcontext =~ 'forms\(\[.\{-}\]\)\?\.$'
490			let values = forms
491		elseif shortcontext =~ 'frameset\.$'
492			let values = fsets
493		elseif shortcontext =~ 'history\.$'
494			let values = hists
495		elseif shortcontext =~ 'iframe\.$'
496			let values = ifras
497		elseif shortcontext =~ 'images\(\[.\{-}\]\)\?\.$'
498			let values = imags
499		elseif shortcontext =~ 'links\(\[.\{-}\]\)\?\.$'
500			let values = links
501		elseif shortcontext =~ 'location\.$'
502			let values = locas
503		elseif shortcontext =~ 'meta\.$'
504			let values = metas
505		elseif shortcontext =~ 'navigator\.$'
506			let values = navis
507		elseif shortcontext =~ 'object\.$'
508			let values = objes
509		elseif shortcontext =~ 'screen\.$'
510			let values = scres
511		elseif shortcontext =~ 'style\.$'
512			let values = styls
513		elseif shortcontext =~ 'table\.$'
514			let values = tabls
515		elseif shortcontext =~ 'TableData\.$'
516			let values = tdats
517		elseif shortcontext =~ 'TableRow\.$'
518			let values = trows
519		elseif shortcontext =~ 'window\.$'
520			let values = winds
521		elseif shortcontext =~ 'parseError\.$'
522			let values = xdomerror
523		elseif shortcontext =~ 'attributes\[\d\+\]\.$'
524			let values = xdomattrprop
525		else
526			let values = user_props + arrays + dates + funcs + maths + numbs + objes + reges + stris
527			let values += doms + anths + areas + bases + bodys + docus + forms + frams + fsets + hists
528			let values += ifras + imags + links + locas + metas + navis + objes + scres
529			let values += tabls + trows + tares + winds
530			let values += xdomnodes + xdomnliss + xdomelems
531		endif
532		endif
533
534		for m in values
535			if m =~? '^'.a:base
536				call add(res, m)
537			elseif m =~? a:base
538				call add(res2, m)
539			endif
540		endfor
541
542		unlet! values
543		return res + res2
544
545	endif
546	" }}}
547
548	" Get variables data.
549	let variables = filter(copy(file), 'v:val =~ "var\\s"')
550	call map(variables, 'matchstr(v:val, ".\\{-}var\\s\\+\\zs.*\\ze")')
551	call map(variables, 'substitute(v:val, ";\\|$", ",", "g")')
552	let vars = []
553	" This loop (and next one) is necessary to get variable names from
554	" constructs like: var var1, var2, var3 = "something";
555	for i in range(len(variables))
556		let comma_separated = split(variables[i], ',\s*')
557		call map(comma_separated, 'matchstr(v:val, "\\k\\+")')
558		let vars += comma_separated
559	endfor
560
561	let variables = sort(vars)
562	unlet! vars
563
564	" Add "no var" variables.
565	let undeclared_variables = filter(copy(file), 'v:val =~ "^\\s*\\k\\+\\s*="')
566	let u_vars = []
567	for i in range(len(undeclared_variables))
568		let  split_equal = split(undeclared_variables[i], '\s*=')
569		call map(split_equal, 'matchstr(v:val, "\\k\\+$")')
570		let u_vars += split_equal
571	endfor
572
573	let variables += sort(u_vars)
574	unlet! u_vars
575
576	" Get functions
577	let functions = filter(copy(file), 'v:val =~ "^\\s*function\\s"')
578	let arguments = copy(functions)
579	call map(functions, 'matchstr(v:val, "^\\s*function\\s\\+\\zs\\k\\+")')
580	call map(functions, 'v:val."("')
581	let functions = sort(functions)
582
583	" Create table to keep arguments for additional 'menu' info
584	let b:js_menuinfo = {}
585	for i in arguments
586		let g:ia = i
587		let f_elements = matchlist(i, 'function\s\+\(\k\+\)\s*(\(.\{-}\))')
588		if len(f_elements) >= 3
589			let b:js_menuinfo[f_elements[1].'('] = f_elements[2]
590		endif
591	endfor
592
593	" Get functions arguments
594	call map(arguments, 'matchstr(v:val, "function.\\{-}(\\zs.\\{-}\\ze)")')
595	let jargs = join(arguments, ',')
596	let jargs = substitute(jargs, '\s', '', 'g')
597	let arguments = split(jargs, ',')
598	let arguments = sort(arguments)
599
600	" Built-in functions
601	let builtin = ['alert(', 'confirm(']
602
603	" Top-level HTML DOM objects
604	let htmldom = ['document', 'anchor', 'area', 'base', 'body', 'document', 'event', 'form', 'frame', 'frameset', 'history', 'iframe', 'image', 'input', 'link', 'location', 'meta', 'navigator', 'object', 'option', 'screen', 'select', 'table', 'tableData', 'tableHeader', 'tableRow', 'textarea', 'window']
605	call map(htmldom, 'v:val."."')
606
607	" Top-level properties
608	let properties = ['decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent',
609				\ 'eval', 'Infinity', 'isFinite', 'isNaN', 'NaN', 'Number', 'parseFloat',
610				\ 'parseInt', 'String', 'undefined', 'escape', 'unescape']
611
612	" Keywords
613	let keywords = ["Array", "Boolean", "Date", "Function", "Math", "Number", "Object", "RegExp", "String", "XMLHttpRequest", "ActiveXObject", "abstract", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double ", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in ", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super ", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with"]
614
615	let values = variables + functions + htmldom + arguments + builtin + properties + keywords
616
617	for m in values
618		if m =~? '^'.a:base
619			call add(res, m)
620		elseif m =~? a:base
621			call add(res2, m)
622		endif
623	endfor
624
625	let menu = res + res2
626	let final_menu = []
627	for i in range(len(menu))
628		let item = menu[i]
629		if item =~ '($'
630			let kind = 'f'
631			if has_key(b:js_menuinfo, item)
632				let m_info = b:js_menuinfo[item]
633			else
634				let m_info = ''
635			endif
636		else
637			let kind = 'v'
638			let m_info = ''
639		endif
640		let final_menu += [{'word':item, 'menu':m_info, 'kind':kind}]
641	endfor
642	let g:fm = final_menu
643	return final_menu
644
645endfunction
646
647" vim:set foldmethod=marker:
648