2 // This script was created
5 // Copyright (c) 2004-2005 Mircho Mirev
7 // :: feel free to use it BUT
8 // :: if you want to use this code PLEASE send me a note
9 // :: and please keep this disclaimer intact
11 // xmlrpc support by Reini Urban for PhpWiki, 2006-12-29
13 function cAutocomplete( sInputId )
20 cAutocomplete.CS_NAME = 'Autocomplete component'
21 cAutocomplete.CS_OBJ_NAME = 'AC_COMPONENT'
22 cAutocomplete.CS_LIST_PREFIX = 'ACL_'
23 cAutocomplete.CS_BUTTON_PREFIX = 'ACB_'
24 cAutocomplete.CS_INPUT_PREFIX = 'AC_'
25 cAutocomplete.CS_HIDDEN_INPUT_PREFIX = 'ACH_'
26 cAutocomplete.CS_INPUT_CLASSNAME = 'dropdown'
28 cAutocomplete.CB_AUTOINIT = true
30 cAutocomplete.CB_AUTOCOMPLETE = false
32 cAutocomplete.CB_FORCECORRECT = false
34 //the separator when autocompleting multiple values
35 cAutocomplete.CB_MATCHSUBSTRING = false
36 cAutocomplete.CS_SEPARATOR = ','
38 //the separator of associative arrays
39 cAutocomplete.CS_ARRAY_SEPARATOR = ','
41 //match the input string only against the begining of the strings
42 //or anywhere in the string
43 cAutocomplete.CB_MATCHSTRINGBEGIN = true
45 cAutocomplete.CN_OFFSET_TOP = 2
46 cAutocomplete.CN_OFFSET_LEFT = -1
48 cAutocomplete.CN_LINE_HEIGHT = 19
49 cAutocomplete.CN_NUMBER_OF_LINES = 10
50 cAutocomplete.CN_HEIGHT_FIX = 2
52 cAutocomplete.CN_CLEAR_TIMEOUT = 300
53 cAutocomplete.CN_SHOW_TIMEOUT = 400
54 cAutocomplete.CN_REMOTE_SHOW_TIMEOUT = 1000
55 cAutocomplete.CN_MARK_TIMEOUT = 400
57 cAutocomplete.hListDisplayed = null
58 cAutocomplete.nCount = 0
60 cAutocomplete.autoInit = function()
66 var nInputsLength = document.getElementsByTagName( 'INPUT' ).length
67 for( nI = 0; nI < nInputsLength; nI++ )
69 if( document.getElementsByTagName( 'INPUT' )[ nI ].type.toLowerCase() == 'text' )
71 sLangAtt = document.getElementsByTagName( 'INPUT' )[ nI ].getAttribute( 'acdropdown' )
72 if( sLangAtt != null && sLangAtt.length > 0 )
74 if( document.getElementsByTagName( 'INPUT' )[ nI ].id == null || document.getElementsByTagName( 'INPUT' )[ nI ].id.length == 0 )
76 document.getElementsByTagName( 'INPUT' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
78 hACE = new cAutocomplete( document.getElementsByTagName( 'INPUT' )[ nI ].id )
83 var nTALength = document.getElementsByTagName( 'TEXTAREA' ).length
84 for( nI = 0; nI < nTALength; nI++ )
86 sLangAtt = document.getElementsByTagName( 'TEXTAREA' )[ nI ].getAttribute( 'acdropdown' )
87 if( sLangAtt != null && sLangAtt.length > 0 )
89 if( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id == null || document.getElementsByTagName( 'TEXTAREA' )[ nI ].id.length == 0 )
91 document.getElementsByTagName( 'TEXTAREA' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
93 hACE = new cAutocomplete( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id )
98 var nSelectsLength = document.getElementsByTagName( 'SELECT' ).length
100 for( nI = 0; nI < nSelectsLength; nI++ )
102 aSelect = document.getElementsByTagName( 'SELECT' )[ nI ]
103 sLangAtt = aSelect.getAttribute( 'acdropdown' )
104 if( sLangAtt != null && sLangAtt.length > 0 )
106 if( aSelect.id == null || aSelect.id.length == 0 )
108 aSelect.id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount
110 hACE = new cAutocomplete( aSelect.id )
117 if( cAutocomplete.CB_AUTOINIT )
119 if( window.attachEvent )
121 window.attachEvent( 'onload', cAutocomplete.autoInit )
123 else if( window.addEventListener )
125 window.addEventListener( 'load', cAutocomplete.autoInit, false )
129 cAutocomplete.prototype.init = function( sInputId )
131 /*this.bDebug = false*/
132 /*this.bDebug = true*/
134 this.sInputId = sInputId
135 this.sListId = cAutocomplete.CS_LIST_PREFIX + sInputId
137 this.sObjName = cAutocomplete.CS_OBJ_NAME + '_obj_' + (cAutocomplete.nCount++)
138 this.hObj = this.sObjName
140 this.hActiveSelection = null
141 this.nSelectedItemIdx = -1
143 //the value of the input before the list is displayed
144 this.sLastActiveValue = ''
145 this.sActiveValue = ''
146 this.bListDisplayed = false
147 this.nItemsDisplayed = 0
149 //if I transform a select option or the supplied array is associative I create a hidden input
150 //with the name of the original input and replace the original input's name
151 this.bAssociative = true
152 this.sHiddenInputId = null
153 this.bHasButton = false
157 //the search array object
158 this.aSearchData = new Array()
161 //the length of the last matched typed string
162 this.nLastMatchLength = 0
164 this.bForceCorrect = cAutocomplete.CB_FORCECORRECT
165 var sForceCorrect = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_forcecorrect' )
166 if( sForceCorrect != null && sForceCorrect.length > 0 )
168 this.bForceCorrect = eval( sForceCorrect )
171 //match a only from the beginning or anywhere in the values
172 this.bMatchBegin = cAutocomplete.CB_MATCHSTRINGBEGIN
173 var sMatchBegin = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchbegin' )
174 if( sMatchBegin != null && sMatchBegin.length > 0 )
176 this.bMatchBegin = eval( sMatchBegin )
178 //match substrings separated by cAutocomplete.CS_SEPARATOR
179 this.bMatchSubstring = cAutocomplete.CB_MATCHSUBSTRING
180 var sMatchSubstring = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchsubstring' )
181 if( sMatchSubstring != null && sMatchSubstring.length > 0 )
183 this.bMatchSubstring = eval( sMatchSubstring )
186 //autocomplete with the first option from the list
187 this.bAutoComplete = cAutocomplete.CB_AUTOCOMPLETE
188 this.bAutocompleted = false
189 var sAutoComplete = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_complete' )
190 if( sAutoComplete != null && sAutoComplete.length > 0 )
192 this.bAutoComplete = eval( sAutoComplete )
195 this.formatOptions = null
196 var sFormatFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_format' )
197 if( sFormatFunction != null && sFormatFunction.length > 0 )
199 this.formatOptions = eval( sFormatFunction )
201 //onselect callback function - get called when a new option is selected, either by changing the focus in the list by using the keyboard or by
202 //clicking on it with the mouse
204 var sOnSelectFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_onselect' )
205 if( sOnSelectFunction != null && sOnSelectFunction.length > 0 )
207 this.onSelect = eval( sOnSelectFunction )
210 //if we have remote list then we postpone the list creation and set associative off
211 if( this.getListArrayType() == 'url' || this.getListArrayType() == 'xmlrpc' )
213 this.bAssociative = false
214 this.bRemoteList = true
215 this.sListURL = this.getListURL()
216 this.hXMLHttp = XmlHttp.create()
217 this.bXMLRPC = (this.getListArrayType() == 'xmlrpc')
222 this.bRemoteList = false
225 //you can turn associative type on or off (separate name-value pairs)
226 //with the autocomplete_assoc="true" or "false" attribute.
227 //for remote search it is off
228 var sAssociative = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_assoc' )
229 if( sAssociative != null && sAssociative.length > 0 )
231 this.bAssociative = eval( sAssociative )
235 this.initListContainer()
239 eval( this.hObj + '= this' )
242 cAutocomplete.prototype.initInput = function()
244 var hInput = document.getElementById( this.sInputId )
245 hInput.hAutocomplete = this
246 var hContainer = document.getElementById( this.sListId )
247 hContainer.hAutocomplete = this
249 //any element ( and it's children ) with display:none have offset values of 0 ( in mozilla )
250 var nWidth = hInput.offsetWidth
251 if( !nWidth || nWidth == 0 )
253 //any element ( and it's children ) with display:none have offset values of 0 ( in mozilla )
254 var hOWInput = hInput.cloneNode( true )
255 hOWInput.style.position = 'absolute'
256 hOWInput.style.top = '-1000px'
257 document.body.appendChild( hOWInput )
258 var nWidth = hOWInput.offsetWidth
259 document.body.removeChild( hOWInput )
262 var sInputName = hInput.name
263 var hForm = hInput.form
264 var bHasButton = false
265 var sHiddenValue = hInput.value
266 var sValue = hInput.type.toLowerCase() == 'text' ? hInput.value : ''
268 var sHasButton = hInput.getAttribute( 'autocomplete_button' )
269 if( sHasButton != null && sHasButton.length > 0 )
274 //if it is a select - I unconditionally add a button
275 if( hInput.type.toLowerCase() == 'select-one' )
278 if( hInput.selectedIndex >= 0 )
280 sHiddenValue = hInput.options[ hInput.selectedIndex ].value
281 sValue = hInput.options[ hInput.selectedIndex ].text
285 //this is the case when the control is a transformed select or the list supplied is of the type - key,value not only values
288 var hHiddenInput = document.createElement( 'INPUT' )
289 hHiddenInput.id = cAutocomplete.CS_HIDDEN_INPUT_PREFIX + this.sInputId
290 hHiddenInput.type = 'hidden'
291 hForm.appendChild( hHiddenInput )
293 if( this.bAssociative )
295 hHiddenInput.name = sInputName
296 hInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
300 hHiddenInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
303 hHiddenInput.value = sHiddenValue
304 this.sHiddenInputId = hHiddenInput.id
309 this.bHasButton = true
311 var hInputContainer = document.createElement( 'DIV' )
312 hInputContainer.className = 'acinputContainer'
313 hInputContainer.style.width = nWidth
315 var hInputButton = document.createElement( 'INPUT' )
316 hInputButton.id = cAutocomplete.CS_BUTTON_PREFIX + this.sInputId
317 hInputButton.type = 'button'
318 hInputButton.className = 'button'
319 hInputButton.tabIndex = hInput.tabIndex + 1
320 hInputButton.hAutocomplete = this
322 var hNewInput = document.createElement( 'INPUT' )
323 if( this.bAssociative )
325 hNewInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName
329 hNewInput.name = sInputName
332 hNewInput.type = 'text'
333 hNewInput.value = sValue
334 hNewInput.style.width = nWidth-22
335 hNewInput.className = cAutocomplete.CS_INPUT_CLASSNAME
336 hNewInput.tabIndex = hInput.tabIndex
337 hNewInput.hAutocomplete = this
339 hInputContainer.appendChild( hNewInput )
340 hInputContainer.appendChild( hInputButton )
342 hInput.parentNode.replaceChild( hInputContainer, hInput )
344 hNewInput.id = this.sInputId
348 if( hInput.attachEvent )
350 hInput.attachEvent( 'onkeyup', cAutocomplete.onInputKeyUp )
351 hInput.attachEvent( 'onkeyup', cAutocomplete.saveCaretPosition )
352 hInput.attachEvent( 'onkeydown', cAutocomplete.onInputKeyDown )
353 hInput.attachEvent( 'onblur', cAutocomplete.onInputBlur )
354 hInput.attachEvent( 'onfocus', cAutocomplete.onInputFocus )
358 hInputButton.attachEvent( 'onclick', cAutocomplete.onButtonClick )
361 else if( hInput.addEventListener )
363 hInput.addEventListener( 'keyup', cAutocomplete.onInputKeyUp, false )
364 hInput.addEventListener( 'keyup', cAutocomplete.saveCaretPosition, false )
365 hInput.addEventListener( 'keydown', cAutocomplete.onInputKeyDown, false )
366 hInput.addEventListener( 'keypress', cAutocomplete.onInputKeyPress, false )
367 hInput.addEventListener( 'blur', cAutocomplete.onInputBlur, false )
368 hInput.addEventListener( 'focus', cAutocomplete.onInputFocus, false )
372 hInputButton.addEventListener( 'click', cAutocomplete.onButtonClick, false )
376 //I don't need the standard autocomplete
377 hInput.setAttribute( 'autocomplete', 'OFF' )
381 if( hForm.attachEvent )
383 hForm.attachEvent( 'onsubmit', cAutocomplete.onFormSubmit )
384 if (this.bDebug) { this.debug ("attachEvent added") }
386 else if( hForm.addEventListener )
388 hForm.addEventListener( 'submit', cAutocomplete.onFormSubmit, false )
389 if (this.bDebug) { this.debug ("addEventListener") }
394 cAutocomplete.prototype.initListContainer = function()
396 var hInput = document.getElementById( this.sInputId )
397 var hContainer = document.createElement( 'DIV' )
398 hContainer.className = 'autocomplete_holder'
399 hContainer.id = this.sListId
400 hContainer.style.zIndex = 10000 + cAutocomplete.nCount
401 hContainer.hAutocomplete = this
403 var hFirstBorder = document.createElement( 'DIV' )
404 hFirstBorder.className = 'autocomplete_firstborder'
405 var hSecondBorder = document.createElement( 'DIV' )
406 hSecondBorder.className = 'autocomplete_secondborder'
408 var hList = document.createElement( 'UL' )
409 hList.className = 'autocomplete'
411 hSecondBorder.appendChild( hList )
412 hFirstBorder.appendChild( hSecondBorder )
413 hContainer.appendChild( hFirstBorder )
414 document.body.appendChild( hContainer )
416 if( hContainer.attachEvent )
418 hContainer.attachEvent( 'onblur', cAutocomplete.onListBlur )
419 hContainer.attachEvent( 'onfocus', cAutocomplete.onListFocus )
421 else if( hInput.addEventListener )
423 hContainer.addEventListener( 'blur', cAutocomplete.onListBlur, false )
424 hContainer.addEventListener( 'focus', cAutocomplete.onListFocus, false )
428 if( hContainer.attachEvent )
430 hContainer.attachEvent( 'onclick', cAutocomplete.onItemClick )
432 else if( hContainer.addEventListener )
434 hContainer.addEventListener( 'click', cAutocomplete.onItemClick, false )
438 cAutocomplete.prototype.createList = function()
440 var hInput = document.getElementById( this.sInputId )
441 var hContainer = document.getElementById( this.sListId )
442 var hList = hContainer.getElementsByTagName( 'UL' )[0]
445 hList = hList.parentNode.removeChild( hList )
446 while( hList.hasChildNodes() )
448 hList.removeChild( hList.childNodes[ 0 ] )
453 var hListItemLink = null
457 var hArr = this.aData
460 for( hArrKey in hArr )
462 sArrEl = hArr[ hArrKey ]
463 hListItem = document.createElement( 'LI' )
464 hListItemLink = document.createElement( 'A' )
465 hListItemLink.setAttribute( 'itemvalue', hArrKey )
467 /* so you can attach data to the element */
468 /* it's a hack but seems to work */
469 var sArrData = sArrEl.split( cAutocomplete.CS_ARRAY_SEPARATOR )
470 if( sArrData.length > 1 )
472 this.aData[ hArrKey ] = sArrData[ 0 ]
473 hListItemLink.setAttribute( 'itemdata', sArrEl.substring( sArrEl.indexOf( cAutocomplete.CS_ARRAY_SEPARATOR ) + 1 ) )
474 sRealText = sArrData[ 0 ]
480 /* end of attach data to the element */
482 hListItemLink.href = '#'
483 hListItemLink.appendChild( document.createTextNode( sRealText ) )
484 hListItemLink.realText = sRealText
485 if( nI == this.nSelectedItemIdx )
487 this.hActiveSelection = hListItemLink
488 this.hActiveSelection.className = 'selected'
490 hListItem.appendChild( hListItemLink )
491 hList.appendChild( hListItem )
492 this.aSearchData[ nI++ ] = sRealText.toLowerCase()
494 var hSecondBorder = hContainer.firstChild.firstChild
495 hSecondBorder.appendChild( hList )
496 this.bListUpdated = false
499 /* list array functions */
501 cAutocomplete.prototype.initListArray = function()
503 var hInput = document.getElementById( this.sInputId )
506 if( hInput.type.toLowerCase() == 'select-one' )
509 for( var nI = 0; nI < hInput.options.length; nI++ )
511 hArrKey = hInput.options.item( nI ).value
512 sArrEl = hInput.options.item( nI ).text
513 hArr[ hArrKey ] = sArrEl
514 if( hInput.options.item( nI ).selected )
516 this.nSelectedItemIdx = nI
522 var sAA = hInput.getAttribute( 'autocomplete_list' )
523 var sAAS = hInput.getAttribute( 'autocomplete_list_sort' )
525 var sArrayType = this.getListArrayType()
530 hArr = eval( sAA.substring( 6 ) )
535 var hTmpArray = sAA.substring( 5 ).split( '|' )
537 for( hKey in hTmpArray )
539 aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR )
540 if( aValueArr.length == 1 )
542 hArr[ hKey ] = hTmpArray[ hKey ]
543 this.bAssociative = false
547 hArr[ aValueArr[ 0 ] ] = aValueArr[ 1 ]
552 if( sAAS != null && eval( sAAS ) )
555 this.aData = hArr.sort()
559 this.setArray( hArr )
562 cAutocomplete.prototype.setArray = function( sArray )
564 if( typeof sArray == 'string' )
566 this.aData = eval( sArray )
572 this.bListUpdated = true
575 //use this function to change the list of autocomplete values to a new one
576 //supply as an argument the name as a literal of an JS array object
577 //well things changed - you can supply an actual array too
578 cAutocomplete.prototype.setListArray = function( sArray )
580 this.setArray( sArray )
581 this.updateAndShowList()
584 cAutocomplete.prototype.getListArrayType = function()
586 var hInput = document.getElementById( this.sInputId )
587 var sAA = hInput.getAttribute( 'autocomplete_list' )
588 if( sAA != null && sAA.length > 0 )
590 if( sAA.indexOf( 'array:' ) >= 0 )
594 else if( sAA.indexOf( 'list:' ) >= 0 )
598 else if( sAA.indexOf( 'url:' ) >= 0 )
602 else if( sAA.indexOf( 'xmlrpc:' ) >= 0 )
609 cAutocomplete.prototype.getListURL = function()
611 var hInput = document.getElementById( this.sInputId )
612 var sAA = hInput.getAttribute( 'autocomplete_list' )
613 if( sAA != null && sAA.length > 0 )
615 if( sAA.indexOf( 'url:' ) >= 0 )
617 return sAA.substring( 4 )
619 if( sAA.indexOf( 'xmlrpc:' ) >= 0 )
621 return sAA.substring( 7 )
626 cAutocomplete.prototype.setListURL = function( sURL )
628 this.sListURL = sURL;
631 cAutocomplete.prototype.onXmlHttpLoad = function( )
633 if( this.hXMLHttp.readyState == 4 )
635 var hError = this.hXMLHttp.parseError
636 if( hError && hError.errorCode != 0 )
638 alert( hError.reason )
642 this.afterRemoteLoad()
647 cAutocomplete.prototype.onXMLRPCHttpLoad = function( )
649 if( this.hXMLHttp.readyState == 4 )
651 var hError = this.hXMLHttp.parseError
652 if( hError && hError.errorCode != 0 )
654 alert( hError.reason )
658 this.afterRemoteLoadXMLRPC()
663 cAutocomplete.prototype.loadXMLRPCListArray = function()
665 // encoding: "xmlrpc:wiki.titleSearch [S] 4"
666 // or "xmlrpc:http://localhost/wiki/?wiki.titleSearch [S] 4"
667 // encode the methodname as optional query_arg and the args space separated
668 var sURL = this.sListURL
669 var xmlrpc_url = data_path + '/RPC2.php'
670 var aMethodArgs = sURL.split( ' ' )
671 var sMethodName = aMethodArgs[ 0 ]
672 var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
673 sStartWith = sStartWith.replace( /^\s/, '' )
674 sStartWith = sStartWith.replace( /\s$/, '' )
676 if( sMethodName.indexOf( '?' ) > 0 )
678 sMethodName = sMethodName.replace( '/^.+\?/', '' )
679 sURL = sURL.replace( '/\?.+$/', '' )
686 if (sMethodName.length < 1)
688 var hInput = document.getElementById( this.sInputId )
689 hInput.value = this.sActiveValue
693 // Construct the xmlrpc request.
694 // Which charset to send? for sure we get back utf-8
695 var sRequest = '<?xml version=\'1.0\' encoding="utf-8" ?>\n'
696 sRequest += '<methodCall><methodName>'+sMethodName+'</methodName>\n'
697 if (aMethodArgs.length <= 1) // the first arg is the name
699 sRequest += '<params/>\n'
703 sRequest += '<params>\n'
704 for( var nI = 1; nI < aMethodArgs.length; nI++ )
706 var sArg = aMethodArgs[ nI ];
707 //this.debug('sMethodName: "'+sMethodName+'" sArg['+nI+']: "'+sArg+'"')
708 if( sArg.indexOf( '[S]' ) >= 0 )
710 //this.debug('sArg['+nI+']: "'+sArg+'" sStartWith: "'+sStartWith+'"')
711 sArg = sArg.replace( '[S]', sStartWith )
713 // We could parse a prepended "(int)" cast.
714 // Can only do string args so far
715 if (sArg == 'debug') {
718 sRequest += '<param><value><string>'
720 sRequest += '</string></value></param>\n'
723 sRequest += '</params>\n'
725 sRequest += '</methodCall>'
727 sURL += '?start_debug=1'
728 this.debug('url: "'+sURL+'" sRequest: "'+sRequest.substring(20)+'"')
730 this.hXMLHttp.open( 'POST', sURL, true )
732 this.hXMLHttp.onreadystatechange = function() { hAC.onXMLRPCHttpLoad() }
733 /*this.hXMLHttp.onreadystatechange = new Function( 'var sAC = "'+this.sObjName+'"; cAutocomplete.onXMLRPCHttpLoad( eval( sAC ) )' )*/
734 this.hXMLHttp.send( sRequest )
737 cAutocomplete.prototype.loadListArray = function()
739 var sURL = this.sListURL
740 var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
741 sStartWith = sStartWith.replace( /^\s/, '' )
742 sStartWith = sStartWith.replace( /\s$/, '' )
743 if( sURL.indexOf( '[S]' ) >= 0 )
745 sURL = sURL.replace( '[S]', sStartWith )
749 sURL += this.sActiveValue
751 this.hXMLHttp.open( 'GET', sURL, true )
754 this.hXMLHttp.onreadystatechange = function() { hAC.onXmlHttpLoad() }
755 this.hXMLHttp.send( null )
758 cAutocomplete.prototype.afterRemoteLoad = function()
760 var hInput = document.getElementById( this.sInputId )
762 var hArr = new Array()
763 var hTmpArray = this.hXMLHttp.responseText.split( '|' )
765 for( hKey in hTmpArray )
767 aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR )
768 if( aValueArr.length == 1 )
770 hArr[ hKey ] = hTmpArray[ hKey ]
774 hArr[ aValueArr[ 0 ] ] = hTmpArray[ hKey ].substr( hTmpArray[ hKey ].indexOf( cAutocomplete.CS_ARRAY_SEPARATOR ) + 1 )
778 hInput.className = ''
779 hInput.readonly = false
780 hInput.value = this.sActiveValue
781 this.setListArray( hArr )
784 cAutocomplete.prototype.afterRemoteLoadXMLRPC = function()
786 var hInput = document.getElementById( this.sInputId )
788 var hArr = new Array()
789 sResult = this.hXMLHttp.responseText
791 this.debug( "response: "+sResult.substring(70,190) )
793 sResult.replace('\n','');
794 sResult.replace('\r','');
796 var i = sResult.indexOf('<string>')
799 sResult = sResult.substring(i+8)
800 j = sResult.indexOf('</string>')
801 hArr[ hKey ] = sResult.substring(0, j)
802 // TODO: convert it from utf-8 to result charset and encoding
803 //this.debug( 'i:'+i+' j:'+j+' "'+hArr[ hKey ]+'"' )
804 /*if( hArr[ hKey ] == hArr[ hKey-1 ] )
807 sResult = sResult.substring(j+9)
808 i = sResult.indexOf('<string>')
811 hInput.className = ''
812 hInput.readonly = false
813 hInput.value = this.sActiveValue
814 this.setListArray( hArr )
819 cAutocomplete.prototype.prepareList = function( bFullList )
821 var hInput = document.getElementById( this.sInputId )
822 this.sActiveValue = hInput.value
824 // Check if this was invoked by a key that did not change the value
825 var sST = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
826 var sLST = this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint )
828 if( sLST != sST || bFullList || !this.bListDisplayed || this.bMatchSubstring )
830 if( this.bRemoteList )
832 hInput.className = 'search'
833 //hInput.readonly = true
834 // TODO: print please wait somewhere else
835 // hInput.value = 'please wait...'
836 // hInput.value = this.sListURL
837 this.bXMLRPC ? this.loadXMLRPCListArray() : this.loadListArray()
840 this.updateAndShowList( bFullList )
844 cAutocomplete.prototype.updateAndShowList = function( bFullList )
846 var hContainer = document.getElementById( this.sListId )
847 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
848 var hInput = document.getElementById( this.sInputId )
850 if( this.bListUpdated )
855 //stupid hack just for speed
856 var sST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) : this.sActiveValue
857 var sLST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint ) : this.sLastActiveValue
859 //nothing changed since last type - maybe only function keys were pressed
860 //this is the case when for example the down key was pressed
863 if( !this.bMatchSubstring )
868 this.filterOptions( bFullList )
870 if( this.nItemsDisplayed == 0 )
872 if( this.bForceCorrect )
874 var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, '' )
875 cAutocomplete.markInputRange( hInput, this.nLastMatchLength, aPos[0] )
879 this.sLastActiveValue = this.sActiveValue
881 if( this.nItemsDisplayed > 0 )
883 if( !bFullList || this.bMatchSubstring )
885 this.deselectOption()
887 if( this.bAutoComplete && this.nItemsDisplayed == 1 )
889 //test if we have a full match i.e. the user typed the entire value
890 var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
891 var sItemText = hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ].realText
892 if( sStartWith.toLowerCase() == sItemText.toLowerCase() )
894 this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] )
896 //and do not show the list
900 if( this.bAutoComplete && !bFullList )
902 this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] )
912 cAutocomplete.prototype.showList = function()
914 if( cAutocomplete.hListDisplayed )
916 cAutocomplete.hListDisplayed.clearList()
918 var hInput = document.getElementById( this.sInputId )
919 var nTop = cDomObject.getOffsetParam( hInput, 'offsetTop' )
920 var nLeft = cDomObject.getOffsetParam( hInput, 'offsetLeft' )
921 var hContainer = document.getElementById( this.sListId )
923 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
924 if( this.bHasButton )
926 hContainer.style.width = document.getElementById( this.sInputId ).parentNode.offsetWidth
930 hContainer.style.width = document.getElementById( this.sInputId ).offsetWidth
932 var nNumLines = ( this.nItemsDisplayed < cAutocomplete.CN_NUMBER_OF_LINES ) ? this.nItemsDisplayed : cAutocomplete.CN_NUMBER_OF_LINES;
933 hList.style.height = nNumLines * cAutocomplete.CN_LINE_HEIGHT + cAutocomplete.CN_HEIGHT_FIX + 'px'
935 hContainer.style.top = nTop + hInput.offsetHeight + cAutocomplete.CN_OFFSET_TOP + 'px'
936 hContainer.style.left = nLeft + cAutocomplete.CN_OFFSET_LEFT + 'px'
938 hContainer.style.display = 'none'
939 hContainer.style.visibility = 'visible'
940 hContainer.style.display = 'block'
942 cAutocomplete.hListDisplayed = this
943 this.bListDisplayed = true
946 cAutocomplete.prototype.binarySearch = function( sFilter )
949 var nHigh = this.aSearchData.length - 1
953 var nLen = sFilter.length
957 while ( nLow <= nHigh )
959 nMid = ( nLow + nHigh ) / 2
960 nTry = ( nMid < 1 ) ? 0 : parseInt( nMid )
962 sData = this.aSearchData[ nTry ].substr( 0, nLen )
964 if ( sData < sFilter )
969 if ( sData > sFilter )
974 if ( sData == sFilter )
983 if ( typeof ( nLastTry ) != "undefined" )
993 cAutocomplete.prototype.getStringForAutocompletion = function( sString, nPos )
995 if( sString == null || sString.length == 0 )
999 if( this.bMatchSubstring )
1001 var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
1002 nStartPos = nStartPos < 0 ? 0 : nStartPos
1003 var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
1004 nEndPos = nEndPos < 0 ? sString.length : nEndPos
1005 var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
1006 sStr = sStr.replace( /^(\,?)(\s*)(\S*)(\s*)(\,?)$/g, '$3' )
1015 cAutocomplete.prototype.insertString = function( sString, nPos, sInsert )
1017 if( this.bMatchSubstring )
1019 var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
1020 nStartPos = nStartPos < 0 ? 0 : nStartPos
1021 var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
1022 nEndPos = nEndPos < 0 ? sString.length : nEndPos
1023 var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
1024 sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert+'$4$5' )
1025 sStr = sString.substr( 0, nStartPos ) + sStr + sString.substr( nEndPos )
1034 cAutocomplete.prototype.getInsertPos = function( sString, nPos, sInsert )
1036 nPos = nPos == null ? 0 : nPos
1037 var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 )
1038 nStartPos = nStartPos < 0 ? 0 : nStartPos
1039 var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos )
1040 nEndPos = nEndPos < 0 ? sString.length : nEndPos
1041 var sStr = sString.substr( nStartPos, nEndPos - nStartPos )
1042 sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert )
1043 return [ nPos, nStartPos + sStr.length ]
1046 cAutocomplete.prototype.filterOptions = function( bShowAll )
1048 if( this.hActiveSelection && !bShowAll )
1050 this.hActiveSelection.className = ''
1052 if( typeof bShowAll == 'undefined' )
1057 var hInput = document.getElementById( this.sInputId )
1059 var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint )
1065 var hContainer = document.getElementById( this.sListId )
1066 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
1067 var nItemsLength = hList.childNodes.length
1068 var hLinkItem = null
1071 var hParent = hList.parentNode
1072 var hList = hList.parentNode.removeChild( hList )
1073 var hTItems = hList.childNodes
1075 this.nItemsDisplayed = 0
1077 if( sStartWith.length == 0 )
1079 for( var nI = 0; nI < nItemsLength; nI++ )
1081 if( this.formatOptions )
1083 hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
1085 hTItems[ nI ].style.display = 'block'
1088 nCount = nItemsLength
1090 if( nItemsLength > 0 )
1092 this.nFirstDisplayed = 0
1093 this.nLastDisplayed = nItemsLength - 1
1097 this.nFirstDisplayed = this.nLastDisplayed = -1
1100 //this.nLastMatchLength = 0
1101 var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith )
1102 this.nLastMatchLength = aPos[0]
1106 this.nFirstDisplayed = this.nLastDisplayed = -1
1107 sStartWith = sStartWith.toLowerCase()
1109 if( this.bSorted && this.bMatchBegin )
1111 var nStartAt = this.binarySearch( sStartWith )
1112 for( var nI = 0; nI < nItemsLength; nI++ )
1114 hTItems[ nI ].style.display = 'none'
1115 if( nI >= nStartAt && !bEnd )
1117 if( !bEnd && this.aSearchData[ nI ].indexOf( sStartWith ) != 0 )
1122 if( this.formatOptions )
1124 hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
1126 hTItems[ nI ].style.display = 'block'
1128 if( this.nFirstDisplayed < 0 )
1130 this.nFirstDisplayed = nI
1132 this.nLastDisplayed = nI
1138 for( var nI = 0; nI < nItemsLength; nI++ )
1140 hTItems[ nI ].style.display = 'none'
1141 if( ( this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) == 0 ) || ( !this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) >= 0 ) )
1143 if( this.formatOptions )
1145 hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI )
1147 hTItems[ nI ].style.display = 'block'
1149 if( this.nFirstDisplayed < 0 )
1151 this.nFirstDisplayed = nI
1153 this.nLastDisplayed = nI
1160 //this.nLastMatchLength = this.sActiveValue.length
1161 var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith )
1162 this.nLastMatchLength = aPos[0]
1165 hParent.appendChild( hList )
1166 this.nItemsDisplayed = nCount
1169 cAutocomplete.prototype.hideOptions = function()
1171 var hContainer = document.getElementById( this.sListId )
1172 hContainer.style.visibility = 'hidden'
1173 hContainer.style.display = 'none'
1174 this.hListDisplayed = null
1177 cAutocomplete.prototype.markAutocompletedValue = function()
1179 var hInput = document.getElementById( this.sInputId )
1180 var sValue = this.hActiveSelection.realText
1181 if( this.bMatchSubstring )
1183 var aPos = this.getInsertPos( this.sLastActiveValue, this.nInsertPoint, sValue )
1184 var nStartPos = aPos[ 0 ]
1185 var nEndPos = aPos[ 1 ]
1189 var nStartPos = this.nInsertPoint
1190 var nEndPos = sValue.length
1192 this.nStartAC = nStartPos
1193 this.nEndAC = nEndPos
1195 if( this.hMarkRangeTimeout != null )
1197 clearTimeout( this.hMarkRangeTimeout )
1199 this.hMarkRangeTimeout = setTimeout( function() {
1200 cAutocomplete.markInputRange2( hInput.id )
1202 , cAutocomplete.CN_MARK_TIMEOUT )
1203 //cAutocomplete.markInputRange( hInput, nStartPos, nEndPos )
1206 cAutocomplete.prototype.selectOptionByIndex = function( nOptionIndex )
1208 if( this.bListUpdated )
1213 var hContainer = document.getElementById( this.sListId )
1214 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
1215 var nItemsLength = hList.childNodes.length
1216 if( nOptionIndex >=0 && nOptionIndex < nItemsLength )
1218 this.selectOption( hList.childNodes[ nOptionIndex ].getElementsByTagName( 'A' )[ 0 ] )
1222 cAutocomplete.prototype.selectOptionByValue = function( sValue )
1224 if( this.bListUpdated )
1229 sValue = sValue.toLowerCase()
1231 var hContainer = document.getElementById( this.sListId )
1232 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
1233 var nItemsLength = hList.childNodes.length
1235 var nSelectedIndex = -1
1236 for( var nI = 0; nI < nItemsLength; nI++ )
1238 if( this.aSearchData[ nI ].indexOf( sValue ) == 0 )
1243 if( nSelectedIndex >=0 )
1245 this.selectOption( hList.childNodes[ nSelectedIndex ].getElementsByTagName( 'A' )[ 0 ] )
1249 cAutocomplete.prototype.selectOption = function( hNewOption )
1251 if( this.hActiveSelection )
1253 if( this.hActiveSelection == hNewOption )
1259 this.hActiveSelection.className = ''
1262 this.hActiveSelection = hNewOption
1263 var hInput = document.getElementById( this.sInputId )
1264 if( this.hActiveSelection != null )
1266 if( this.sHiddenInputId != null )
1268 if( this.bMatchSubstring )
1270 document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' )
1274 document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' )
1278 this.hActiveSelection.className = 'selected'
1279 if( this.bAutoComplete )
1281 hInput.value = this.insertString( this.sLastActiveValue, this.nInsertPoint, this.hActiveSelection.realText )
1282 this.bAutocompleted = true
1283 this.markAutocompletedValue()
1287 var aPos = this.getInsertPos( this.sLastActiveValue, this.nInsertPoint, this.hActiveSelection.realText )
1288 hInput.value = this.insertString( this.sActiveValue, this.nInsertPoint, this.hActiveSelection.realText )
1289 //cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint )
1290 cAutocomplete.setInputCaretPosition( hInput, aPos[ 1 ] )
1293 this.sActiveValue = hInput.value
1302 hInput.value = this.sActiveValue
1303 cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint )
1307 cAutocomplete.prototype.deselectOption = function( )
1309 if( this.hActiveSelection != null )
1311 this.hActiveSelection.className = ''
1312 this.hActiveSelection = null
1316 cAutocomplete.prototype.clearList = function()
1318 //this.deselectOption()
1320 this.bListDisplayed = false
1323 cAutocomplete.prototype.getPrevDisplayedItem = function( hItem )
1327 var hContainer = document.getElementById( this.sListId )
1328 hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.length - 1 )
1332 hItem = getPrevNodeSibling( hItem.parentNode )
1334 while( hItem != null )
1336 if( hItem.style.display == 'block' )
1340 hItem = hItem.previousSibling
1345 cAutocomplete.prototype.getNextDisplayedItem = function( hItem )
1349 var hContainer = document.getElementById( this.sListId )
1350 hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( 0 )
1354 hItem = getNextNodeSibling( hItem.parentNode )
1356 while( hItem != null )
1358 if( hItem.style.display == 'block' )
1362 hItem = hItem.nextSibling
1367 cAutocomplete.prototype.debug = function(s)
1370 var hInput = document.getElementById( this.sInputId )
1371 var hContainer = document.createElement( 'DIV' )
1372 hContainer.className = 'debug'
1373 hContainer.innerHTML = s
1374 var hDiv = hInput.form.parentNode
1375 /*if (hDiv.childNodes[1] && hDiv.childNodes[1].className == 'debug')
1376 hDiv.insertBefore( hContainer, hDiv.childNodes[1] )
1378 hDiv.appendChild( hContainer )
1383 cAutocomplete.onInputKeyDown = function ( hEvent )
1385 if( hEvent == null )
1387 hEvent = window.event
1389 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1390 var hAC = hElement.hAutocomplete
1391 var hContainer = document.getElementById( hAC.sListId )
1392 var hInput = document.getElementById( hAC.sInputId )
1393 var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ]
1394 var hEl = getParentByTagName( hElement, 'A' )
1395 if( hContainer != null && hAC.bListDisplayed )
1399 // The new active selection
1400 if( ( hEvent.keyCode == 13 ) || ( hEvent.keyCode == 27 ) )
1402 var bItemSelected = hEvent.keyCode == 13 ? true : false
1404 if (hAC.bDebug) { hAC.debug ("key "+hEvent.keyCode+" new active selection") }
1406 if( hEvent.keyCode == 38 )
1409 if (hAC.bDebug) { hAC.debug ("key "+hEvent.keyCode+" up") }
1410 hLINext = hAC.getPrevDisplayedItem( hAC.hActiveSelection )
1411 if( hLINext != null )
1413 hAC.selectOption( hLINext.childNodes.item(0) )
1414 if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES )
1416 if( hList.scrollTop < 5 && hLINext.offsetTop > hList.offsetHeight )
1418 hList.scrollTop = hList.scrollHeight - hList.offsetHeight
1420 if( hLINext.offsetTop - hList.scrollTop < 0 )
1422 hList.scrollTop -= hLINext.offsetHeight
1428 hAC.selectOption( null )
1431 else if ( hEvent.keyCode == 40 )
1434 if (hAC.bDebug) { hAC.debug ("key "+hEvent.keyCode+" down") }
1435 hLINext = hAC.getNextDisplayedItem( hAC.hActiveSelection )
1436 if( hLINext != null )
1438 hAC.selectOption( hLINext.childNodes.item(0) )
1439 if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES )
1441 if( hList.scrollTop > 0 && hList.scrollTop > hLINext.offsetTop )
1445 if( Math.abs( hLINext.offsetTop - hList.scrollTop - hList.offsetHeight ) < 5 )
1447 hList.scrollTop += hLINext.offsetHeight
1453 hAC.selectOption( null )
1459 hInput.form.bLocked = true
1460 //if (hAC.bDebug) { hAC.debug ("onInputKeyDown form blocked") }
1462 if ( hEvent.keyCode == 13 || hEvent.keyCode == 27 || hEvent.keyCode == 38 || hEvent.keyCode == 40 )
1464 if( hEvent.preventDefault )
1466 hEvent.preventDefault()
1468 if (hAC.bDebug) { hAC.debug ("no preventDefault return false") }
1470 if (hEvent.keyCode == 13) {
1471 /*if (hAC.bDebug) { hAC.debug ("Enter") }*/
1472 hEvent.cancelBubble = true
1473 hEvent.returnValue = true
1476 hEvent.cancelBubble = true
1477 hEvent.returnValue = false
1482 cAutocomplete.onInputKeyPress = function ( hEvent )
1484 if ( hEvent.keyCode == 13 || hEvent.keyCode == 38 || hEvent.keyCode == 40 )
1486 if( hEvent.preventDefault )
1488 hEvent.preventDefault()
1490 hEvent.cancelBubble = true
1491 hEvent.returnValue = false
1496 cAutocomplete.onInputKeyUp = function ( hEvent )
1498 if( hEvent == null )
1500 hEvent = window.event
1502 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1503 var hAC = hElement.hAutocomplete
1504 var hInput = document.getElementById( hAC.sInputId )
1505 //if we press the keys for up down enter or escape skip showing the list
1506 switch( hEvent.keyCode )
1508 case 8 : if( hAC.bAutoComplete && hAC.bAutocompleted )
1510 hAC.bAutocompleted = false
1515 case 40 : if( hAC.bListDisplayed )
1517 if( hEvent.preventDefault )
1519 hEvent.preventDefault()
1521 hEvent.cancelBubble = true
1522 hEvent.returnValue = false
1533 if( hEvent.keyCode < 48 )
1535 if( hEvent.preventDefault )
1537 hEvent.preventDefault()
1539 if (hEvent.keyCode == 13) {
1540 if (hAC.bDebug) { hAC.debug ("Enter KeyUp: returnValue = true") }
1541 hEvent.cancelBubble = true
1542 hEvent.returnValue = true
1546 if (hAC.bDebug) { hAC.debug ("keyUp: hEvent.returnValue = false") }
1547 hEvent.cancelBubble = true
1548 hEvent.returnValue = false
1554 if( hAC.hMarkRangeTimeout != null )
1556 clearTimeout( hAC.hMarkRangeTimeout )
1559 if( hAC.hShowTimeout )
1561 clearTimeout( hAC.hShowTimeout )
1562 hAC.hShowTimeout = null
1564 var nTimeout = hAC.bRemoteList ? cAutocomplete.CN_REMOTE_SHOW_TIMEOUT : cAutocomplete.CN_SHOW_TIMEOUT
1565 hAC.hShowTimeout = setTimeout( function(){ hAC.prepareList() }, nTimeout )
1566 if (hAC.bDebug) { hAC.debug ("setTimeout "+nTimeout) }
1569 cAutocomplete.onInputBlur = function( hEvent )
1571 if( hEvent == null )
1573 hEvent = window.event
1575 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1578 hElement.form.bLocked = false
1580 var hAC = hElement.hAutocomplete
1581 if( !hAC.hClearTimeout )
1583 hAC.hClearTimeout = setTimeout( function(){ hAC.clearList() }, cAutocomplete.CN_CLEAR_TIMEOUT )
1587 cAutocomplete.onInputFocus = function( hEvent )
1589 if( hEvent == null )
1591 hEvent = window.event
1593 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1594 var hAC = hElement.hAutocomplete
1595 if( hAC.hClearTimeout )
1597 clearTimeout( hAC.hClearTimeout )
1598 hAC.hClearTimeout = null
1602 cAutocomplete.saveCaretPosition = function( hEvent )
1604 if( hEvent == null )
1606 hEvent = window.event
1608 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1609 var hAC = hElement.hAutocomplete
1610 var hInput = document.getElementById( hAC.sInputId )
1612 //there is something weird about hitting up and down keys in a textarea
1613 if( hEvent.keyCode != 38 && hEvent.keyCode != 40 )
1615 hAC.nInsertPoint = cAutocomplete.getInputCaretPosition( hInput )
1619 cAutocomplete.getInputCaretPosition = function( hInput )
1621 if( typeof hInput.selectionStart != 'undefined' )
1623 if( hInput.selectionStart == hInput.selectionEnd )
1625 return hInput.selectionStart
1629 return hInput.selectionStart
1632 else if( hInput.createTextRange )
1634 var hSelRange = document.selection.createRange()
1635 if( hInput.tagName.toLowerCase() == 'textarea' )
1637 var hSelBefore = hSelRange.duplicate()
1638 var hSelAfter = hSelRange.duplicate()
1639 hSelRange.moveToElementText( hInput )
1640 hSelBefore.setEndPoint( 'StartToStart', hSelRange )
1641 return hSelBefore.text.length
1645 hSelRange.moveStart( 'character', -1*hInput.value.length )
1646 var nLen = hSelRange.text.length
1653 cAutocomplete.setInputCaretPosition = function( hInput, nPosition )
1655 if ( hInput.setSelectionRange )
1657 hInput.setSelectionRange( nPosition ,nPosition )
1659 else if ( hInput.createTextRange )
1661 var hRange = hInput.createTextRange()
1662 hRange.moveStart( 'character', nPosition )
1663 hRange.moveEnd( 'character', nPosition )
1664 hRange.collapse(true)
1669 cAutocomplete.markInputRange = function( hInput, nStartPos, nEndPos )
1671 if( hInput.setSelectionRange )
1674 hInput.setSelectionRange( nStartPos, nEndPos )
1676 else if( hInput.createTextRange )
1678 var hRange = hInput.createTextRange()
1679 hRange.collapse(true)
1680 hRange.moveStart( 'character', nStartPos )
1681 hRange.moveEnd( 'character', nEndPos - nStartPos )
1686 cAutocomplete.markInputRange2 = function( sInputId )
1688 var hInput = document.getElementById( sInputId )
1689 var nStartPos = hInput.hAutocomplete.nStartAC
1690 var nEndPos = hInput.hAutocomplete.nEndAC
1691 cAutocomplete.markInputRange( hInput, nStartPos, nEndPos )
1695 cAutocomplete.onListBlur = function( hEvent )
1697 if( hEvent == null )
1699 hEvent = window.event
1701 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1702 hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
1703 var hAC = hElement.hAutocomplete
1704 if( !hAC.hClearTimeout )
1706 hAC.hClearTimeout = setTimeout( function() { hAC.clearList() }, cAutocomplete.CN_CLEAR_TIMEOUT )
1710 cAutocomplete.onListFocus = function( hEvent )
1712 if( hEvent == null )
1714 hEvent = window.event
1716 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1717 hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
1718 var hAC = hElement.hAutocomplete
1719 if( hAC.hClearTimeout )
1721 clearTimeout( hAC.hClearTimeout )
1722 hAC.hClearTimeout = null
1726 cAutocomplete.onItemClick = function( hEvent )
1728 if( hEvent == null )
1730 hEvent = window.event
1732 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1733 var hContainer = getParentByProperty( hElement, 'className', 'autocomplete_holder' )
1734 var hEl = getParentByTagName( hElement, 'A' )
1735 if( hContainer != null )
1737 var hAC = hContainer.hAutocomplete
1738 hAC.selectOption( hEl )
1739 document.getElementById( hAC.sInputId ).focus()
1742 if( hEvent.preventDefault )
1744 hEvent.preventDefault()
1746 /*var hAC = hElement.hAutocomplete
1747 if (hAC.bDebug) { hAC.debug ("onItemClick") }*/
1748 hEvent.cancelBubble = true
1749 hEvent.returnValue = false
1753 cAutocomplete.onButtonClick = function ( hEvent )
1755 if( hEvent == null )
1757 hEvent = window.event
1759 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1760 var hAC = hElement.hAutocomplete
1761 var hInput = document.getElementById( hAC.sInputId )
1762 if( hInput.disabled )
1766 if (hAC.bDebug) { hAC.debug ("onButtonClick") }
1767 hAC.prepareList( true )
1768 var hInput = document.getElementById( hAC.sInputId )
1772 cAutocomplete.onFormSubmit = function ( hEvent )
1774 if( hEvent == null )
1776 hEvent = window.event
1778 var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget
1779 if( hElement.bLocked )
1781 var hAC = hElement.hAutocomplete
1782 if (hAC.bDebug) { hAC.debug ("onSubmit: hElement.bLocked") }
1783 hElement.bLocked = false
1784 hEvent.returnValue = false
1785 if( hEvent.preventDefault )
1787 hEvent.preventDefault()