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