From: Andreas Unterkircher Date: Thu, 27 Mar 2008 21:59:06 +0000 (+0100) Subject: issue111, first try of auto completion for tag search box X-Git-Url: https://git.nubati.net/cgi-bin/gitweb.cgi?p=phpfspot.git;a=commitdiff_plain;h=af0be8f9546fb5dec947be33e465bb6d9e85d0a7 issue111, first try of auto completion for tag search box Signed-off-by: Andreas Unterkircher --- diff --git a/autocomplete/css/SyntaxHighlighter.css b/autocomplete/css/SyntaxHighlighter.css new file mode 100644 index 0000000..d76aee9 --- /dev/null +++ b/autocomplete/css/SyntaxHighlighter.css @@ -0,0 +1,166 @@ + +/* Main style for the table */ + +.dp-highlighter { + width: 100%; + overflow: auto; + line-height: 100% !important; + margin: 18px 0px 18px 0px; +} + +.dp-highlighter table { + width: 100%; + margin: 2px 0px 2px 0px; + border-collapse: collapse; + border-bottom: 2px solid #eee; + background-color: #fff; +} + +.dp-highlighter td +{ + font-family: Courier New; + font-size: 11px; +} + +/* Styles for the tools */ + +.dp-highlighter .tools-corner { + background-color: #eee; + font-size: 9px; +} + +.dp-highlighter .tools { + background-color: #eee; + padding: 3px 8px 3px 0px; + border-bottom: 1px solid gray; + font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif; + color: silver; +} + +.dp-highlighter .tools a { + font-size: 9px; + color: gray; + text-decoration: none; +} + +.dp-highlighter .tools a:hover { + color: red; + text-decoration: underline; +} + +/* Gutter with line number */ + +.dp-highlighter .gutter { + padding-right: 5px; + padding-left: 10px; + width: 5px; + background-color: #eee; + border-right: 1px solid gray; + color: gray; + text-align: right; + vertical-align: top; +} + +/* Single line style */ + +.dp-highlighter .line { + padding-left: 10px; + border-bottom: 1px solid #F7F7F7; + white-space:nowrap; +} + +/* About dialog styles */ + +.dp-about { + background-color: #fff; + margin: 0px; +} + +.dp-about table { + width: 100%; + height: 100%; + font-size: 11px; + font-family: Tahoma, Verdana, Arial, sans-serif !important; +} + +.dp-about td { + padding: 10px; + vertical-align: top; +} + +.dp-about .copy { + border-bottom: 1px solid #ACA899; + height: 95%; +} + +.dp-about .title { + color: red; + font-weight: bold; +} + +.dp-about .para { + margin-bottom: 4px; +} + +.dp-about .footer { + background-color: #ECEADB; + border-top: 1px solid #fff; + text-align: right; +} + +.dp-about .close { + font-size: 11px; + font-family: Tahoma, Verdana, Arial, sans-serif !important; + background-color: #ECEADB; + width: 60px; + height: 22px; +} + +/* Language specific styles */ + +.dp-c {} +.dp-c .comment { color: green; } +.dp-c .string { color: blue; } +.dp-c .preprocessor { color: gray; } +.dp-c .keyword { color: blue; } +.dp-c .vars { color: #d00; } + +.dp-vb {} +.dp-vb .comment { color: green; } +.dp-vb .string { color: blue; } +.dp-vb .preprocessor { color: gray; } +.dp-vb .keyword { color: blue; } + +.dp-sql {} +.dp-sql .comment { color: green; } +.dp-sql .string { color: red; } +.dp-sql .keyword { color: blue; } +.dp-sql .func { color: #ff1493; } +.dp-sql .op { color: #808080; } + +.dp-xml {} +.dp-xml .cdata { color: #ff1493; } +.dp-xml .comments { color: green; } +.dp-xml .tag { color: blue; } +.dp-xml .tag-name { color: black; font-weight: bold; } +.dp-xml .attribute { color: red; } +.dp-xml .attribute-value { color: blue; } + +.dp-delphi {} +.dp-delphi .comment { color: #008200; font-style: italic; } +.dp-delphi .string { color: blue; } +.dp-delphi .number { color: blue; } +.dp-delphi .directive { color: #008284; } +.dp-delphi .keyword { font-weight: bold; color: navy; } +.dp-delphi .vars { color: #000; } + +.dp-py {} +.dp-py .comment { color: green; } +.dp-py .string { color: red; } +.dp-py .docstring { color: brown; } +.dp-py .keyword { color: blue; font-weight: bold;} +.dp-py .builtins { color: #ff1493; } +.dp-py .magicmethods { color: #808080; } +.dp-py .exceptions { color: brown; } +.dp-py .types { color: brown; font-style: italic; } +.dp-py .commonlibs { color: #8A2BE2; font-style: italic; } diff --git a/autocomplete/css/dropdown.css b/autocomplete/css/dropdown.css new file mode 100644 index 0000000..8fae480 --- /dev/null +++ b/autocomplete/css/dropdown.css @@ -0,0 +1,180 @@ +div.acinputContainer +{ + position: relative; + float: left; + clear: none; + width: 240px; + height: 20px; + margin:0px; + padding: 0px; + border-width: 1px; + border-style: solid; +/* border-color: buttonshadow buttonhighlight buttonhighlight buttonshadow;*/ + border-color: #aaa #eee #eee #aaa; + background-color: buttonface; + overflow: show; + white-space: nowrap; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +div.acinputContainer input +{ + position: relative; + float: left; + clear: none; + /*width: 220px;*/ + border-width: 1px; + margin:0px; + padding: 0px; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +/* this is set when the input is 'working' i.e. remote loading is in process */ +div.acinputContainer input.search +{ + background-color: #b41b00; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +div.acinputContainer input.button +{ + position: relative; + float: left; + clear: none; + font-size: 2px; + top: 0px; + left: 1px; + width:18px; + height: 100%; + border-width: 1px; + background-image:url( ../i/arrowdown.gif ); + background-repeat: no-repeat; + background-position: 2px 2px; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +input.dropdown +{ + width: 160px; + border: 1px solid #AAAAAA; + border-color: #888 #aaa #aaa #888; + margin-bottom: 2px; + -moz-box-sizing : border-box; +} + +div.autocomplete_holder +{ + position: absolute; + visibility: hidden; + display: none; + background-color: #fff; + background-image: url( ../i/bg.gif ); + -moz-box-sizing : border-box; +} + +div.autocomplete_firstborder +{ + border-width: 1px; + border-style: solid; + border-color: buttonshadow buttonhighlight buttonhighlight buttonshadow; + padding: 0px; + -moz-box-sizing : border-box; +} + +div.autocomplete_secondborder +{ + border-style: none; + padding: 2px; + -moz-box-sizing : border-box; +} + +ul.autocomplete +{ + width : 100%; + height : 95px; + overflow-y : auto; + overflow : -moz-scrollbars-vertical; + + font : menu; + + margin : 0px; + margin-left : 0px; + padding-left : 0px; + text-indent : 0px; + + list-style-type : none; + vertical-align : middle; + + background-repeat : no-repeat; + -moz-box-sizing : border-box; +} + +ul.autocomplete li a, ul.autocomplete li a:hover, +ul.autocomplete li a.selected, ul.autocomplete li a:hover.selected +{ + display : block; + width : 100%; + padding : 2px; + text-decoration : none; + color : #333; + border : 1px solid #fff; + -moz-box-sizing : border-box; + + margin-left : -14px; + voice-family : "\"}\""; + voice-family : inherit; + margin-left : 0px; +} + +ul.autocomplete li +{ + padding : 0px; + paddnig-left : 5px; + background-position : 2px 0px; + background-repeat : no-repeat; + + line-height : 13px; + vertical-align : top; + margin : 0px; + /*border-style : none;*/ + -moz-box-sizing : border-box; +} + +ul.autocomplete li a +{ +} + +ul.autocomplete li a:hover +{ + color: highlighttext; + background-color: highlight; + border-color: #e0e0e0; +} + +ul.autocomplete li a.selected +{ + border : 1px solid #444; + /* + background-color : #fcbdb6; + color : #fff; + */ + background-color : #0d94df; + color : #fff; + + background-color: #f00; + background-image: url( ../i/conf.gif ); + background-position: center right; + background-repeat: no-repeat; +} + +ul.autocomplete li a:hover.selected +{ + border : 1px solid #e0e0e0; + color : white; + background-color : #f00; + background-image: none; +} diff --git a/autocomplete/css/page.css b/autocomplete/css/page.css new file mode 100644 index 0000000..ca2a2cd --- /dev/null +++ b/autocomplete/css/page.css @@ -0,0 +1,37 @@ +.pages +{ + font-family: verdana; + font-size: 12px; + color: #111; + padding: 5px; +} + +.pages div.holder +{ + width: 100%; + padding: 15px; + background: #fff; + border: 1px solid #666; + border-color: #111 #eee #eee #111; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +.pages div.code +{ + display: none; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +.pages a.codeToggle +{ + height: 28px; + line-height: 28px; + padding-left: 30px; + margin-top: 10px; + margin-bottom: 10px; + display: block; + background: url(../i/code.png) no-repeat; + -moz-box-sizing: border-box; +} diff --git a/autocomplete/css/tabsexamples.css b/autocomplete/css/tabsexamples.css new file mode 100644 index 0000000..08f1539 --- /dev/null +++ b/autocomplete/css/tabsexamples.css @@ -0,0 +1,107 @@ +/* CSS Document */ +body +{ + background-color: #fff; +} + +.pages +{ + position: relative; + float: none; + clear: both; + width: 100%; + display: none; + padding: 3px; + border: 1px solid #560702; + border-top-width: 0px; + background-color: #F4783C; + -moz-box-sizing: border-box; +} + +span.hilite +{ + color: #00f; + background-color: #eee; +} + +#navcontainer +{ + position: relative; + float: left; + width: 100%; + border-bottom: 1px solid #7ABBDA; + -moz-box-sizing: border-box; +} + +ul.navlist +{ + position: relative; + top: 1px; + display: block; + float: left; + clear: both; + + margin-top: 0px; + margin-left: 0px; + margin-bottom: 0px; + padding-left: 9px; + padding-bottom: 0px; + + font: 10px Verdana, sans-serif; + list-style-type: none; + -moz-box-sizing: border-box; +} + +ul.navlist li +{ + display: block; + float: left; + margin: 0; + padding: 0; + padding-right: 5px; + width: auto; + height: 23px; + line-height: 23px; + font-weight: bold; + background-image: url(../i/iar.png); + background-position: center right; + background-repeat: no-repeat; + -moz-box-sizing: border-box; +} + +ul.navlist li.tabactive +{ + background-image: url(../i/ar.png); +} + +ul.navlist li a, ul.navlist li a:link +{ + color: #FFB098; + text-decoration: none; + padding: 0px 5px 0px 11px; + display: block; + background-image: url(../i/ial.png); + background-repeat: no-repeat; + background-position: 0px center; +} + +ul.navlist li a:hover +{ + color: #FFE5DD; + cursor: pointer; + background-image: url(../i/ial.png); + background-repeat: no-repeat; + background-position: 0px center; +} + +ul.navlist li.tabactive a, ul.navlist li.tabactive a:link +{ + color: #F8FFC8; + cursor: default; + background-image: url(../i/al.png); +} + +ul.navlist li.tabactive a:hover +{ + background-image: url(../i/al.png); +} diff --git a/autocomplete/i/al.png b/autocomplete/i/al.png new file mode 100644 index 0000000..0638ce2 Binary files /dev/null and b/autocomplete/i/al.png differ diff --git a/autocomplete/i/ar.png b/autocomplete/i/ar.png new file mode 100644 index 0000000..45efa4e Binary files /dev/null and b/autocomplete/i/ar.png differ diff --git a/autocomplete/i/arrowdown.gif b/autocomplete/i/arrowdown.gif new file mode 100644 index 0000000..b06803e Binary files /dev/null and b/autocomplete/i/arrowdown.gif differ diff --git a/autocomplete/i/blbg.png b/autocomplete/i/blbg.png new file mode 100644 index 0000000..84f03e9 Binary files /dev/null and b/autocomplete/i/blbg.png differ diff --git a/autocomplete/i/code.png b/autocomplete/i/code.png new file mode 100644 index 0000000..eb4a98c Binary files /dev/null and b/autocomplete/i/code.png differ diff --git a/autocomplete/i/conf.gif b/autocomplete/i/conf.gif new file mode 100644 index 0000000..ebbfdb6 Binary files /dev/null and b/autocomplete/i/conf.gif differ diff --git a/autocomplete/i/ial.png b/autocomplete/i/ial.png new file mode 100644 index 0000000..d075b6c Binary files /dev/null and b/autocomplete/i/ial.png differ diff --git a/autocomplete/i/iar.png b/autocomplete/i/iar.png new file mode 100644 index 0000000..e7282d8 Binary files /dev/null and b/autocomplete/i/iar.png differ diff --git a/autocomplete/i/leftb.png b/autocomplete/i/leftb.png new file mode 100644 index 0000000..75ab711 Binary files /dev/null and b/autocomplete/i/leftb.png differ diff --git a/autocomplete/i/rightb.png b/autocomplete/i/rightb.png new file mode 100644 index 0000000..776af75 Binary files /dev/null and b/autocomplete/i/rightb.png differ diff --git a/autocomplete/js/acdropdown.js b/autocomplete/js/acdropdown.js new file mode 100644 index 0000000..c5ad240 --- /dev/null +++ b/autocomplete/js/acdropdown.js @@ -0,0 +1,1622 @@ +// +// This script was created +// by Mircho Mirev +// mo /mo@momche.net/ +// Copyright (c) 2004-2005 Mircho Mirev +// +// :: feel free to use it BUT +// :: if you want to use this code PLEASE send me a note +// :: and please keep this disclaimer intact +// + +function cAutocomplete( sInputId ) +{ + this.init( sInputId ) +} + +cAutocomplete.CS_NAME = 'Autocomplete component' +cAutocomplete.CS_OBJ_NAME = 'AC_COMPONENT' +cAutocomplete.CS_LIST_PREFIX = 'ACL_' +cAutocomplete.CS_BUTTON_PREFIX = 'ACB_' +cAutocomplete.CS_INPUT_PREFIX = 'AC_' +cAutocomplete.CS_HIDDEN_INPUT_PREFIX = 'ACH_' +cAutocomplete.CS_INPUT_CLASSNAME = 'dropdown' + +cAutocomplete.CB_AUTOINIT = true + +cAutocomplete.CB_AUTOCOMPLETE = false + +cAutocomplete.CB_FORCECORRECT = false + +//the separator when autocompleting multiple values +cAutocomplete.CB_MATCHSUBSTRING = false +cAutocomplete.CS_SEPARATOR = ',' + +//the separator of associative arrays +cAutocomplete.CS_ARRAY_SEPARATOR = ',' + +//match the input string only against the begining of the strings +//or anywhere in the string +cAutocomplete.CB_MATCHSTRINGBEGIN = true + +cAutocomplete.CN_OFFSET_TOP = 2 +cAutocomplete.CN_OFFSET_LEFT = -1 + +cAutocomplete.CN_LINE_HEIGHT = 19 +cAutocomplete.CN_NUMBER_OF_LINES = 10 +cAutocomplete.CN_HEIGHT_FIX = 2 + +cAutocomplete.CN_CLEAR_TIMEOUT = 300 +cAutocomplete.CN_SHOW_TIMEOUT = 400 +cAutocomplete.CN_REMOTE_SHOW_TIMEOUT = 1000 +cAutocomplete.CN_MARK_TIMEOUT = 400 + +cAutocomplete.hListDisplayed = null +cAutocomplete.nCount = 0 + +cAutocomplete.autoInit = function() +{ + var nI = 0 + var hACE = null + var sLangAtt + + for( nI = 0; nI < document.getElementsByTagName( 'INPUT' ).length; nI++ ) + { + if( document.getElementsByTagName( 'INPUT' )[ nI ].type.toLowerCase() == 'text' ) + { + sLangAtt = document.getElementsByTagName( 'INPUT' )[ nI ].getAttribute( 'acdropdown' ) + if( sLangAtt != null && sLangAtt.length > 0 ) + { + if( document.getElementsByTagName( 'INPUT' )[ nI ].id == null || document.getElementsByTagName( 'INPUT' )[ nI ].id.length == 0 ) + { + document.getElementsByTagName( 'INPUT' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount + } + hACE = new cAutocomplete( document.getElementsByTagName( 'INPUT' )[ nI ].id ) + } + } + } + + var nTALength = document.getElementsByTagName( 'TEXTAREA' ).length + for( nI = 0; nI < nTALength; nI++ ) + { + sLangAtt = document.getElementsByTagName( 'TEXTAREA' )[ nI ].getAttribute( 'acdropdown' ) + if( sLangAtt != null && sLangAtt.length > 0 ) + { + if( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id == null || document.getElementsByTagName( 'TEXTAREA' )[ nI ].id.length == 0 ) + { + document.getElementsByTagName( 'TEXTAREA' )[ nI ].id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount + } + hACE = new cAutocomplete( document.getElementsByTagName( 'TEXTAREA' )[ nI ].id ) + } + } + + + var nSelectsLength = document.getElementsByTagName( 'SELECT' ).length + var aSelect = null + for( nI = 0; nI < nSelectsLength; nI++ ) + { + aSelect = document.getElementsByTagName( 'SELECT' )[ nI ] + sLangAtt = aSelect.getAttribute( 'acdropdown' ) + if( sLangAtt != null && sLangAtt.length > 0 ) + { + if( aSelect.id == null || aSelect.id.length == 0 ) + { + aSelect.id = cAutocomplete.CS_OBJ_NAME + cAutocomplete.nCount + } + hACE = new cAutocomplete( aSelect.id ) + nSelectsLength-- + nI-- + } + } +} + +if( cAutocomplete.CB_AUTOINIT ) +{ + if( window.attachEvent ) + { + window.attachEvent( 'onload', cAutocomplete.autoInit ) + } + else if( window.addEventListener ) + { + window.addEventListener( 'load', cAutocomplete.autoInit, false ) + } +} + +cAutocomplete.prototype.init = function( sInputId ) +{ + this.sInputId = sInputId + this.sListId = cAutocomplete.CS_LIST_PREFIX + sInputId + + this.sObjName = cAutocomplete.CS_OBJ_NAME + '_obj_' + (cAutocomplete.nCount++) + this.hObj = this.sObjName + + this.hActiveSelection = null + this.nSelectedItemIdx = -1 + + //the value of the input before the list is displayed + this.sLastActiveValue = '' + this.sActiveValue = '' + this.bListDisplayed = false + this.nItemsDisplayed = 0 + + //if I transform a select option or the supplied array is associative I create a hidden input + //with the name of the original input and replace the original input's name + this.bAssociative = false + this.sHiddenInputId = null + this.bHasButton = false + + //the actual data + this.aData = null + //the search array object + this.aSearchData = new Array() + this.bSorted = false + + //the length of the last matched typed string + this.nLastMatchLength = 0 + + this.bForceCorrect = cAutocomplete.CB_FORCECORRECT + var sForceCorrect = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_forcecorrect' ) + if( sForceCorrect != null && sForceCorrect.length > 0 ) + { + this.bForceCorrect = eval( sForceCorrect ) + } + + //match a only from the beginning or anywhere in the values + this.bMatchBegin = cAutocomplete.CB_MATCHSTRINGBEGIN + var sMatchBegin = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchbegin' ) + if( sMatchBegin != null && sMatchBegin.length > 0 ) + { + this.bMatchBegin = eval( sMatchBegin ) + } + //match substrings separated by cAutocomplete.CS_SEPARATOR + this.bMatchSubstring = cAutocomplete.CB_MATCHSUBSTRING + var sMatchSubstring = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_matchsubstring' ) + if( sMatchSubstring != null && sMatchSubstring.length > 0 ) + { + this.bMatchSubstring = true + } + + //autocomplete with the first option from the list + this.bAutoComplete = cAutocomplete.CB_AUTOCOMPLETE + this.bAutocompleted = false + var sAutoComplete = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_complete' ) + if( sAutoComplete != null && sAutoComplete.length > 0 ) + { + this.bAutoComplete = eval( sAutoComplete ) + } + //format function + this.formatOptions = null + var sFormatFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_format' ) + if( sFormatFunction != null && sFormatFunction.length > 0 ) + { + this.formatOptions = eval( sFormatFunction ) + } + //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 + //clicking on it with the mouse + this.onSelect = null + var sOnSelectFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_onselect' ) + if( sOnSelectFunction != null && sOnSelectFunction.length > 0 ) + { + this.onSelect = eval( sOnSelectFunction ) + } + + //onchange callback function - get called when a new option is selected by clicking on it or by pressing enter + //almost the same as onselect, but will get activated on + /* + this.onChange = null + var sOnSelectFunction = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_onselect' ) + if( sOnSelectFunction != null && sOnSelectFunction.length > 0 ) + { + this.onSelect = eval( sOnSelectFunction ) + } + */ + + //I assume that we always have the associative type + //you can turn it off only with the autocomplete_assoc=false attribute + this.bAssociative = true + var sAssociative = document.getElementById( this.sInputId ).getAttribute( 'autocomplete_assoc' ) + if( sAssociative != null && sAssociative.length > 0 ) + { + if( sAssociative == 'false' ) + { + this.bAssociative = false + } + } + + //if we have remote list then we postpone the list creation + if( this.getListArrayType() != 'url' ) + { + this.bRemoteList = false + } + else + { + this.bRemoteList = true + this.sListURL = this.getListURL() + this.hXMLHttp = XmlHttp.create() + } + this.initListArray() + this.initListContainer() + //this.createList() + this.initInput() + + eval( this.hObj + '= this' ) +} + +cAutocomplete.prototype.initInput = function() +{ + var hInput = document.getElementById( this.sInputId ) + hInput.hAutocomplete = this + var hContainer = document.getElementById( this.sListId ) + hContainer.hAutocomplete = this + + //any element ( and it's children ) with display:none have offset values of 0 ( in mozilla ) + var nWidth = hInput.offsetWidth + if( !nWidth || nWidth == 0 ) + { + //any element ( and it's children ) with display:none have offset values of 0 ( in mozilla ) + var hOWInput = hInput.cloneNode( true ) + hOWInput.style.position = 'absolute' + hOWInput.style.top = '-1000px' + document.body.appendChild( hOWInput ) + var nWidth = hOWInput.offsetWidth + document.body.removeChild( hOWInput ) + } + + var sInputName = hInput.name + var hForm = hInput.form + var bHasButton = false + var sHiddenValue = hInput.value + var sValue = hInput.type.toLowerCase() == 'text' ? hInput.value : '' + + var sHasButton = hInput.getAttribute( 'autocomplete_button' ) + if( sHasButton != null && sHasButton.length > 0 ) + { + bHasButton = true + } + + //if it is a select - I unconditionally add a button + if( hInput.type.toLowerCase() == 'select-one' ) + { + bHasButton = true + if( hInput.selectedIndex >= 0 ) + { + sHiddenValue = hInput.options[ hInput.selectedIndex ].value + sValue = hInput.options[ hInput.selectedIndex ].text + } + } + + //this is the case when the control is a transformed select or the list supplied is of the type - key,value not only values + if( hForm ) + { + var hHiddenInput = document.createElement( 'INPUT' ) + hHiddenInput.id = cAutocomplete.CS_HIDDEN_INPUT_PREFIX + this.sInputId + hHiddenInput.type = 'hidden' + hForm.appendChild( hHiddenInput ) + + if( this.bAssociative ) + { + hHiddenInput.name = sInputName + hInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName + } + else + { + hHiddenInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName + } + + hHiddenInput.value = sHiddenValue + this.sHiddenInputId = hHiddenInput.id + } + + if( bHasButton ) + { + this.bHasButton = true + + var hInputContainer = document.createElement( 'DIV' ) + hInputContainer.className = 'acinputContainer' + hInputContainer.style.width = nWidth + + var hInputButton = document.createElement( 'INPUT' ) + hInputButton.id = cAutocomplete.CS_BUTTON_PREFIX + this.sInputId + hInputButton.type = 'button' + hInputButton.className = 'button' + hInputButton.tabIndex = hInput.tabIndex + 1 + hInputButton.hAutocomplete = this + + var hNewInput = document.createElement( 'INPUT' ) + if( this.bAssociative ) + { + hNewInput.name = cAutocomplete.CS_INPUT_PREFIX + sInputName + } + else + { + hNewInput.name = sInputName + } + + hNewInput.type = 'text' + hNewInput.value = sValue + hNewInput.style.width = nWidth-22 + hNewInput.className = cAutocomplete.CS_INPUT_CLASSNAME + hNewInput.tabIndex = hInput.tabIndex + hNewInput.hAutocomplete = this + + hInputContainer.appendChild( hNewInput ) + hInputContainer.appendChild( hInputButton ) + + hInput.parentNode.replaceChild( hInputContainer, hInput ) + + hNewInput.id = this.sInputId + hInput = hNewInput + } + + if( hInput.attachEvent ) + { + hInput.attachEvent( 'onkeyup', cAutocomplete.onInputKeyUp ) + hInput.attachEvent( 'onkeyup', cAutocomplete.saveCaretPosition ) + hInput.attachEvent( 'onkeydown', cAutocomplete.onInputKeyDown ) + hInput.attachEvent( 'onblur', cAutocomplete.onInputBlur ) + hInput.attachEvent( 'onfocus', cAutocomplete.onInputFocus ) + + if( hInputButton ) + { + hInputButton.attachEvent( 'onclick', cAutocomplete.onButtonClick ) + } + } + else if( hInput.addEventListener ) + { + hInput.addEventListener( 'keyup', cAutocomplete.onInputKeyUp, false ) + hInput.addEventListener( 'keyup', cAutocomplete.saveCaretPosition, false ) + hInput.addEventListener( 'keydown', cAutocomplete.onInputKeyDown, false ) + hInput.addEventListener( 'keypress', cAutocomplete.onInputKeyPress, false ) + hInput.addEventListener( 'blur', cAutocomplete.onInputBlur, false ) + hInput.addEventListener( 'focus', cAutocomplete.onInputFocus, false ) + + if( hInputButton ) + { + hInputButton.addEventListener( 'click', cAutocomplete.onButtonClick, false ) + } + } + + //I don't need the standard autocomplete + hInput.setAttribute( 'autocomplete', 'OFF' ) + + if( hForm ) + { + if( hForm.attachEvent ) + { + hForm.attachEvent( 'onsubmit', cAutocomplete.onFormSubmit ) + } + else if( hForm.addEventListener ) + { + hForm.addEventListener( 'submit', cAutocomplete.onFormSubmit, false ) + } + } +} + +cAutocomplete.prototype.initListContainer = function() +{ + var hInput = document.getElementById( this.sInputId ) + var hContainer = document.createElement( 'DIV' ) + hContainer.className = 'autocomplete_holder' + hContainer.id = this.sListId + hContainer.style.zIndex = 10000 + cAutocomplete.nCount + hContainer.hAutocomplete = this + + var hFirstBorder = document.createElement( 'DIV' ) + hFirstBorder.className = 'autocomplete_firstborder' + var hSecondBorder = document.createElement( 'DIV' ) + hSecondBorder.className = 'autocomplete_secondborder' + + var hList = document.createElement( 'UL' ) + hList.className = 'autocomplete' + + hSecondBorder.appendChild( hList ) + hFirstBorder.appendChild( hSecondBorder ) + hContainer.appendChild( hFirstBorder ) + document.body.appendChild( hContainer ) + + if( hContainer.attachEvent ) + { + hContainer.attachEvent( 'onblur', cAutocomplete.onListBlur ) + hContainer.attachEvent( 'onfocus', cAutocomplete.onListFocus ) + } + else if( hInput.addEventListener ) + { + hContainer.addEventListener( 'blur', cAutocomplete.onListBlur, false ) + hContainer.addEventListener( 'focus', cAutocomplete.onListFocus, false ) + } + + + if( hContainer.attachEvent ) + { + hContainer.attachEvent( 'onclick', cAutocomplete.onItemClick ) + } + else if( hContainer.addEventListener ) + { + hContainer.addEventListener( 'click', cAutocomplete.onItemClick, false ) + } +} + +cAutocomplete.prototype.createList = function() +{ + var hInput = document.getElementById( this.sInputId ) + var hContainer = document.getElementById( this.sListId ) + var hList = hContainer.getElementsByTagName( 'UL' )[0] + if( hList ) + { + hList = hList.parentNode.removeChild( hList ) + while( hList.hasChildNodes() ) + { + hList.removeChild( hList.childNodes[ 0 ] ) + } + } + + var hListItem = null + var hListItemLink = null + var hArrKey = null + var sArrEl = null + + var hArr = this.aData + var nI = 0 + var sRealText + for( hArrKey in hArr ) + { + sArrEl = hArr[ hArrKey ] + hListItem = document.createElement( 'LI' ) + hListItemLink = document.createElement( 'A' ) + hListItemLink.setAttribute( 'itemvalue', hArrKey ) + + /* so you can attach data to the element */ + /* it's a hack but seems to work */ + if(sArrEl.split) { + var sArrData = sArrEl.split( cAutocomplete.CS_ARRAY_SEPARATOR ) + if( sArrData.length > 1 ) + { + this.aData[ hArrKey ] = sArrData[ 0 ] + hListItemLink.setAttribute( 'itemdata', sArrEl.substring( sArrEl.indexOf( cAutocomplete.CS_ARRAY_SEPARATOR ) + 1 ) ) + sRealText = sArrData[ 0 ] + } + else + { + sRealText = sArrEl + } + /* end of attach data to the element */ + + hListItemLink.href = '#' + hListItemLink.appendChild( document.createTextNode( sRealText ) ) + hListItemLink.realText = sRealText + if( nI == this.nSelectedItemIdx ) + { + this.hActiveSelection = hListItemLink + this.hActiveSelection.className = 'selected' + } + hListItem.appendChild( hListItemLink ) + hList.appendChild( hListItem ) + this.aSearchData[ nI++ ] = sRealText.toLowerCase() + } + } + var hSecondBorder = hContainer.firstChild.firstChild + hSecondBorder.appendChild( hList ) + this.bListUpdated = false +} + +/* list array functions */ + +cAutocomplete.prototype.initListArray = function() +{ + var hInput = document.getElementById( this.sInputId ) + var hArr = null + + if( hInput.type.toLowerCase() == 'select-one' ) + { + hArr = new Object() + for( var nI = 0; nI < hInput.options.length; nI++ ) + { + hArrKey = hInput.options.item( nI ).value + sArrEl = hInput.options.item( nI ).text + hArr[ hArrKey ] = sArrEl + if( hInput.options.item( nI ).selected ) + { + this.nSelectedItemIdx = nI + } + } + } + else + { + var sAA = hInput.getAttribute( 'autocomplete_list' ) + var sAAS = hInput.getAttribute( 'autocomplete_list_sort' ) + + var sArrayType = this.getListArrayType() + + switch( sArrayType ) + { + case 'array' : hArr = eval( sAA.substring( 6 ) ) + break + + case 'list' : hArr = new Array() + var hTmpArray = sAA.substring( 5 ).split( '|' ) + var aValueArr + for( hKey in hTmpArray ) + { + aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR ) + if( aValueArr.length == 1 ) + { + hArr[ hKey ] = hTmpArray[ hKey ] + this.bAssociative = false + } + else + { + hArr[ aValueArr[ 0 ] ] = aValueArr[ 1 ] + } + } + break + } + if( sAAS != null && eval( sAAS ) ) + { + this.bSorted = true + this.aData = hArr.sort() + hArr = hArr.sort() + } + } + this.setArray( hArr ) +} + +cAutocomplete.prototype.setArray = function( sArray ) +{ + if( typeof sArray == 'string' ) + { + this.aData = eval( sArray ) + } + else + { + this.aData = sArray + } + this.bListUpdated = true +} + +//use this function to change the list of autocomplete values to a new one +//supply as an argument the name as a literal of an JS array object +//well things changed - you can supply an actual array too +cAutocomplete.prototype.setListArray = function( sArray ) +{ + this.setArray( sArray ) + this.updateAndShowList() +} + +cAutocomplete.prototype.getListArrayType = function() +{ + var hInput = document.getElementById( this.sInputId ) + var sAA = hInput.getAttribute( 'autocomplete_list' ) + if( sAA != null && sAA.length > 0 ) + { + if( sAA.indexOf( 'array:' ) >= 0 ) + { + return 'array' + } + else if( sAA.indexOf( 'list:' ) >= 0 ) + { + return 'list' + } + else if( sAA.indexOf( 'url:' ) >= 0 ) + { + return 'url' + } + } +} + +cAutocomplete.prototype.getListURL = function() +{ + var hInput = document.getElementById( this.sInputId ) + var sAA = hInput.getAttribute( 'autocomplete_list' ) + if( sAA != null && sAA.length > 0 ) + { + if( sAA.indexOf( 'url:' ) >= 0 ) + { + return sAA.substring( 4 ) + } + } +} + +cAutocomplete.prototype.setListURL = function( sURL ) +{ + this.sListURL = sURL; +} + +cAutocomplete.prototype.onXmlHttpLoad = function() +{ + if( this.hXMLHttp.readyState == 4 ) + { + var hError = this.hXMLHttp.parseError + if( hError && hError.errorCode != 0 ) + { + alert( hError.reason ) + } + else + { + this.afterRemoteLoad() + } + } +} + +cAutocomplete.prototype.loadListArray = function() +{ + var sURL = this.sListURL + var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) + sStartWith = sStartWith.replace( /^\s/, '' ) + sStartWith = sStartWith.replace( /\s$/, '' ) + if( sURL.indexOf( '[S]' ) >= 0 ) + { + sURL = sURL.replace( '[S]', sStartWith ) + } + else + { + sURL += this.sActiveValue + } + this.hXMLHttp.open( 'GET', sURL, true ) + + var hAC = this + this.hXMLHttp.onreadystatechange = function() { hAC.onXmlHttpLoad() } + this.hXMLHttp.send( null ) +} + +cAutocomplete.prototype.afterRemoteLoad = function() +{ + var hInput = document.getElementById( this.sInputId ) + + var hArr = new Array() + var hTmpArray = this.hXMLHttp.responseText.split( '|' ) + var aValueArr + for( hKey in hTmpArray ) + { + if(hTmpArray[ hKey ].split) { + aValueArr = hTmpArray[ hKey ].split( cAutocomplete.CS_ARRAY_SEPARATOR ) + if( aValueArr.length == 1 ) + { + hArr[ hKey ] = hTmpArray[ hKey ] + } + else + { + hArr[ aValueArr[ 0 ] ] = hTmpArray[ hKey ].substr( hTmpArray[ hKey ].indexOf( cAutocomplete.CS_ARRAY_SEPARATOR ) + 1 ) + } + } + } + + hInput.className = '' + hInput.readonly = false + hInput.value = this.sActiveValue + this.setListArray( hArr ) +} + +/**/ + +cAutocomplete.prototype.prepareList = function( bFullList ) +{ + var hInput = document.getElementById( this.sInputId ) + this.sActiveValue = hInput.value + if( this.bRemoteList ) + { + hInput.readonly = true + } + + //check if this was invoked by a key that did not change the value + var sST = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) + var sLST = this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint ) + + if( sLST != sST || bFullList || !this.bListDisplayed || this.bMatchSubstring ) + { + if( this.bRemoteList ) + { + hInput.className = 'search' + hInput.value = 'please wait...' + this.loadListArray() + return + } + this.updateAndShowList( bFullList ) + } +} + +cAutocomplete.prototype.updateAndShowList = function( bFullList ) +{ + var hContainer = document.getElementById( this.sListId ) + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + var hInput = document.getElementById( this.sInputId ) + + if( this.bListUpdated ) + { + this.createList() + } + + //stupid hack just for speed + var sST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) : this.sActiveValue + var sLST = this.bMatchSubstring ? this.getStringForAutocompletion( this.sLastActiveValue, this.nInsertPoint ) : this.sLastActiveValue + + //nothing changed since last type - maybe only function keys were pressed + //this is the case when for example the down key was pressed + if( sST == sLST ) + { + if( !this.bMatchSubstring ) + { + bFullList = true + } + } + this.filterOptions( bFullList ) + + if( this.nItemsDisplayed == 0 ) + { + if( this.bForceCorrect ) + { + var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, '' ) + cAutocomplete.markInputRange( hInput, this.nLastMatchLength, aPos[0] ) + } + } + + this.sLastActiveValue = this.sActiveValue + + if( this.nItemsDisplayed > 0 ) + { + if( !bFullList || this.bMatchSubstring ) + { + this.deselectOption() + } + if( this.bAutoComplete && this.nItemsDisplayed == 1 ) + { + //test if we have a full match i.e. the user typed the entire value + var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) + var sItemText = hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ].realText + if( sStartWith.toLowerCase() == sItemText.toLowerCase() ) + { + this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] ) + this.hideOptions() + //and do not show the list + return + } + } + if( this.bAutoComplete && !bFullList ) + { + this.selectOption( hList.getElementsByTagName( 'LI' )[ this.nFirstDisplayed ].getElementsByTagName( 'A' )[ 0 ] ) + } + this.showList() + } + else + { + this.clearList() + } +} + +cAutocomplete.prototype.showList = function() +{ + if( cAutocomplete.hListDisplayed ) + { + cAutocomplete.hListDisplayed.clearList() + } + var hInput = document.getElementById( this.sInputId ) + var nTop = cDomObject.getOffsetParam( hInput, 'offsetTop' ) + var nLeft = cDomObject.getOffsetParam( hInput, 'offsetLeft' ) + var hContainer = document.getElementById( this.sListId ) + + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + if( this.bHasButton ) + { + hContainer.style.width = document.getElementById( this.sInputId ).parentNode.offsetWidth + } + else + { + hContainer.style.width = document.getElementById( this.sInputId ).offsetWidth + } + var nNumLines = ( this.nItemsDisplayed < cAutocomplete.CN_NUMBER_OF_LINES ) ? this.nItemsDisplayed : cAutocomplete.CN_NUMBER_OF_LINES; + hList.style.height = nNumLines * cAutocomplete.CN_LINE_HEIGHT + cAutocomplete.CN_HEIGHT_FIX + 'px' + + hContainer.style.top = nTop + hInput.offsetHeight + cAutocomplete.CN_OFFSET_TOP + 'px' + hContainer.style.left = nLeft + cAutocomplete.CN_OFFSET_LEFT + 'px' + + hContainer.style.display = 'none' + hContainer.style.visibility = 'visible' + hContainer.style.display = 'block' + + cAutocomplete.hListDisplayed = this + this.bListDisplayed = true +} + +cAutocomplete.prototype.binarySearch = function( sFilter ) +{ + var nLow = 0 + var nHigh = this.aSearchData.length - 1 + var nMid + var nTry, nLastTry + var sData + var nLen = sFilter.length + + var lastTry + + while ( nLow <= nHigh ) + { + nMid = ( nLow + nHigh ) / 2 + nTry = ( nMid < 1 ) ? 0 : parseInt( nMid ) + + sData = this.aSearchData[ nTry ].substr( 0, nLen ) + + if ( sData < sFilter ) + { + nLow = nTry + 1 + continue + } + if ( sData > sFilter ) + { + nHigh = nTry - 1 + continue + } + if ( sData == sFilter ) + { + nHigh = nTry - 1 + nLastTry = nTry + continue + } + return nTry + } + + if ( typeof ( nLastTry ) != "undefined" ) + { + return nLastTry + } + else + { + return null + } +} + +cAutocomplete.prototype.getStringForAutocompletion = function( sString, nPos ) +{ + if( sString == null || sString.length == 0 ) + { + return '' + } + if( this.bMatchSubstring ) + { + var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 ) + nStartPos = nStartPos < 0 ? 0 : nStartPos + var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos ) + nEndPos = nEndPos < 0 ? sString.length : nEndPos + var sStr = sString.substr( nStartPos, nEndPos - nStartPos ) + sStr = sStr.replace( /^(\,?)(\s*)(\S*)(\s*)(\,?)$/g, '$3' ) + return sStr + } + else + { + return sString + } +} + +cAutocomplete.prototype.insertString = function( sString, nPos, sInsert ) +{ + if( this.bMatchSubstring ) + { + var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 ) + nStartPos = nStartPos < 0 ? 0 : nStartPos + var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos ) + nEndPos = nEndPos < 0 ? sString.length : nEndPos + var sStr = sString.substr( nStartPos, nEndPos - nStartPos ) + sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert+'$4$5' ) + sStr = sString.substr( 0, nStartPos ) + sStr + sString.substr( nEndPos ) + return sStr + } + else + { + return sInsert + } +} + +cAutocomplete.prototype.getInsertPos = function( sString, nPos, sInsert ) +{ + nPos = nPos == null ? 0 : nPos + var nStartPos = sString.lastIndexOf( cAutocomplete.CS_SEPARATOR, nPos - 1 ) + nStartPos = nStartPos < 0 ? 0 : nStartPos + var nEndPos = sString.indexOf( cAutocomplete.CS_SEPARATOR, nPos ) + nEndPos = nEndPos < 0 ? sString.length : nEndPos + var sStr = sString.substr( nStartPos, nEndPos - nStartPos ) + sStr = sStr.replace( /^(\,?)(\s*)(\S?[\S\s]*\S?)(\s*)(\,?)$/g, '$1$2'+sInsert ) + return [ nPos, nStartPos + sStr.length ] +} + +cAutocomplete.prototype.filterOptions = function( bShowAll ) +{ + if( this.hActiveSelection && !bShowAll ) + { + this.hActiveSelection.className = '' + } + if( typeof bShowAll == 'undefined' ) + { + bShowAll = false + } + + var hInput = document.getElementById( this.sInputId ) + + var sStartWith = this.getStringForAutocompletion( this.sActiveValue, this.nInsertPoint ) + if( bShowAll ) + { + sStartWith = '' + } + + var hContainer = document.getElementById( this.sListId ) + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + var nItemsLength = hList.childNodes.length + var hLinkItem = null + var nCount = 0 + + var hParent = hList.parentNode + var hList = hList.parentNode.removeChild( hList ) + var hTItems = hList.childNodes + + this.nItemsDisplayed = 0 + + if( sStartWith.length == 0 ) + { + for( var nI = 0; nI < nItemsLength; nI++ ) + { + if( this.formatOptions ) + { + hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI ) + } + hTItems[ nI ].style.display = 'block' + } + + nCount = nItemsLength + + if( nItemsLength > 0 ) + { + this.nFirstDisplayed = 0 + this.nLastDisplayed = nItemsLength - 1 + } + else + { + this.nFirstDisplayed = this.nLastDisplayed = -1 + } + + //this.nLastMatchLength = 0 + var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith ) + this.nLastMatchLength = aPos[0] + } + else + { + this.nFirstDisplayed = this.nLastDisplayed = -1 + sStartWith = sStartWith.toLowerCase() + var bEnd = false + if( this.bSorted && this.bMatchBegin ) + { + var nStartAt = this.binarySearch( sStartWith ) + for( var nI = 0; nI < nItemsLength; nI++ ) + { + hTItems[ nI ].style.display = 'none' + if( nI >= nStartAt && !bEnd ) + { + if( !bEnd && this.aSearchData[ nI ].indexOf( sStartWith ) != 0 ) + { + bEnd = true + continue + } + if( this.formatOptions ) + { + hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI ) + } + hTItems[ nI ].style.display = 'block' + nCount++ + if( this.nFirstDisplayed < 0 ) + { + this.nFirstDisplayed = nI + } + this.nLastDisplayed = nI + } + } + } + else + { + for( var nI = 0; nI < nItemsLength; nI++ ) + { + hTItems[ nI ].style.display = 'none' + if( ( this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) == 0 ) || ( !this.bMatchBegin && this.aSearchData[ nI ].indexOf( sStartWith ) >= 0 ) ) + { + if( this.formatOptions ) + { + hTItems[ nI ].childNodes[0].innerHTML = this.formatOptions( hTItems[ nI ].childNodes[0].realText, nI ) + } + hTItems[ nI ].style.display = 'block' + nCount++ + if( this.nFirstDisplayed < 0 ) + { + this.nFirstDisplayed = nI + } + this.nLastDisplayed = nI + } + } + } + + if( nCount > 0 ) + { + //this.nLastMatchLength = this.sActiveValue.length + var aPos = this.getInsertPos( this.sActiveValue, this.nInsertPoint, sStartWith ) + this.nLastMatchLength = aPos[0] + } + } + hParent.appendChild( hList ) + this.nItemsDisplayed = nCount +} + +cAutocomplete.prototype.hideOptions = function() +{ + var hContainer = document.getElementById( this.sListId ) + hContainer.style.visibility = 'hidden' + hContainer.style.display = 'none' + cAutocomplete.hListDisplayed = null +} + +cAutocomplete.prototype.markAutocompletedValue = function() +{ + var hInput = document.getElementById( this.sInputId ) + var sValue = this.hActiveSelection.realText + if( this.bMatchSubstring ) + { + var aPos = this.getInsertPos( this.sLastActiveValue, this.nInsertPoint, sValue ) + var nStartPos = aPos[ 0 ] + var nEndPos = aPos[ 1 ] + } + else + { + var nStartPos = this.nInsertPoint + var nEndPos = sValue.length + } + this.nStartAC = nStartPos + this.nEndAC = nEndPos + + if( this.hMarkRangeTimeout != null ) + { + clearTimeout( this.hMarkRangeTimeout ) + } + this.hMarkRangeTimeout = setTimeout( function() { + cAutocomplete.markInputRange2( hInput.id ) + } + , cAutocomplete.CN_MARK_TIMEOUT ) + //cAutocomplete.markInputRange( hInput, nStartPos, nEndPos ) +} + +cAutocomplete.prototype.selectOptionByIndex = function( nOptionIndex ) +{ + if( this.bListUpdated ) + { + this.createList() + } + + var hContainer = document.getElementById( this.sListId ) + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + var nItemsLength = hList.childNodes.length + if( nOptionIndex >=0 && nOptionIndex < nItemsLength ) + { + this.selectOption( hList.childNodes[ nOptionIndex ].getElementsByTagName( 'A' )[ 0 ] ) + } +} + +cAutocomplete.prototype.selectOptionByValue = function( sValue ) +{ + if( this.bListUpdated ) + { + this.createList() + } + + sValue = sValue.toLowerCase() + + var hContainer = document.getElementById( this.sListId ) + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + var nItemsLength = hList.childNodes.length + + var nSelectedIndex = -1 + for( var nI = 0; nI < nItemsLength; nI++ ) + { + if( this.aSearchData[ nI ].indexOf( sValue ) == 0 ) + { + nSelectedIndex = nI + } + } + if( nSelectedIndex >=0 ) + { + this.selectOption( hList.childNodes[ nSelectedIndex ].getElementsByTagName( 'A' )[ 0 ] ) + } +} + +cAutocomplete.prototype.selectOption = function( hNewOption ) +{ + if( this.hActiveSelection ) + { + if( this.hActiveSelection == hNewOption ) + { + return + } + else + { + this.hActiveSelection.className = '' + } + } + this.hActiveSelection = hNewOption + var hInput = document.getElementById( this.sInputId ) + if( this.hActiveSelection != null ) + { + if( this.sHiddenInputId != null ) + { + if( this.bMatchSubstring ) + { + document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' ) + } + else + { + document.getElementById( this.sHiddenInputId ).value = this.hActiveSelection.getAttribute( 'itemvalue' ) + } + } + + this.hActiveSelection.className = 'selected' + if( this.bAutoComplete ) + { + hInput.value = this.insertString( this.sLastActiveValue, this.nInsertPoint, this.hActiveSelection.realText ) + this.bAutocompleted = true + this.markAutocompletedValue() + } + else + { + var aPos = this.getInsertPos( this.sLastActiveValue, this.nInsertPoint, this.hActiveSelection.realText ) + hInput.value = this.insertString( this.sActiveValue, this.nInsertPoint, this.hActiveSelection.realText ) + //cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint ) + cAutocomplete.setInputCaretPosition( hInput, aPos[ 1 ] ) + } + + this.sActiveValue = hInput.value + + if( this.onSelect ) + { + this.onSelect() + } + } + else + { + hInput.value = this.sActiveValue + cAutocomplete.setInputCaretPosition( hInput, this.nInsertPoint ) + } +} + +cAutocomplete.prototype.deselectOption = function( ) +{ + if( this.hActiveSelection != null ) + { + this.hActiveSelection.className = '' + this.hActiveSelection = null + } +} + +cAutocomplete.prototype.clearList = function() +{ + //this.deselectOption() + this.hideOptions() + this.bListDisplayed = false +} + +cAutocomplete.prototype.getPrevDisplayedItem = function( hItem ) +{ + if( hItem == null ) + { + var hContainer = document.getElementById( this.sListId ) + hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.length - 1 ) + } + else + { + hItem = getPrevNodeSibling( hItem.parentNode ) + } + while( hItem != null ) + { + if( hItem.style.display == 'block' ) + { + return hItem + } + hItem = hItem.previousSibling + } + return null +} + +cAutocomplete.prototype.getNextDisplayedItem = function( hItem ) +{ + if( hItem == null ) + { + var hContainer = document.getElementById( this.sListId ) + hItem = hContainer.getElementsByTagName( 'UL' )[ 0 ].childNodes.item( 0 ) + } + else + { + hItem = getNextNodeSibling( hItem.parentNode ) + } + while( hItem != null ) + { + if( hItem.style.display == 'block' ) + { + return hItem + } + hItem = hItem.nextSibling + } + return null +} + +cAutocomplete.onInputKeyDown = function ( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hAC = hElement.hAutocomplete + var hContainer = document.getElementById( hAC.sListId ) + var hInput = document.getElementById( hAC.sInputId ) + var hList = hContainer.getElementsByTagName( 'UL' )[ 0 ] + var hEl = getParentByTagName( hElement, 'A' ) + if( hContainer != null && hAC.bListDisplayed ) + { + var hLI = null + var hLINext = null + //the new active selection + if( ( hEvent.keyCode == 13 ) || ( hEvent.keyCode == 27 ) ) + { + var bItemSelected = hEvent.keyCode == 13 ? true : false + hAC.clearList() + } + if( hEvent.keyCode == 38 ) + { + //up key pressed + hLINext = hAC.getPrevDisplayedItem( hAC.hActiveSelection ) + if( hLINext != null ) + { + hAC.selectOption( hLINext.childNodes.item(0) ) + if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES ) + { + if( hList.scrollTop < 5 && hLINext.offsetTop > hList.offsetHeight ) + { + hList.scrollTop = hList.scrollHeight - hList.offsetHeight + } + if( hLINext.offsetTop - hList.scrollTop < 0 ) + { + hList.scrollTop -= hLINext.offsetHeight + } + } + } + else + { + hAC.selectOption( null ) + } + } + else if ( hEvent.keyCode == 40 ) + { + //down key pressed + hLINext = hAC.getNextDisplayedItem( hAC.hActiveSelection ) + if( hLINext != null ) + { + hAC.selectOption( hLINext.childNodes.item(0) ) + if( hAC.nItemsDisplayed > cAutocomplete.CN_NUMBER_OF_LINES ) + { + if( hList.scrollTop > 0 && hList.scrollTop > hLINext.offsetTop ) + { + hList.scrollTop = 0 + } + if( Math.abs( hLINext.offsetTop - hList.scrollTop - hList.offsetHeight ) < 5 ) + { + hList.scrollTop += hLINext.offsetHeight + } + } + } + else + { + hAC.selectOption( null ) + } + } + } + if( hInput.form ) + { + hInput.form.bLocked = true + } + if ( hEvent.keyCode == 13 || hEvent.keyCode == 27 || hEvent.keyCode == 38 || hEvent.keyCode == 40 ) + { + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + hEvent.cancelBubble = true + hEvent.returnValue = false + return false + } +} + +cAutocomplete.onInputKeyPress = function ( hEvent ) +{ + if ( hEvent.keyCode == 13 || hEvent.keyCode == 38 || hEvent.keyCode == 40 ) + { + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + hEvent.cancelBubble = true + hEvent.returnValue = false + return false + } +} + +cAutocomplete.onInputKeyUp = function ( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hAC = hElement.hAutocomplete + var hInput = document.getElementById( hAC.sInputId ) + //if we press the keys for up down enter or escape skip showing the list + switch( hEvent.keyCode ) + { + case 8 : if( hAC.bAutoComplete && hAC.bAutocompleted ) + { + hAC.bAutocompleted = false + return false + } + break + case 38 : + case 40 : if( hAC.bListDisplayed ) + { + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + hEvent.cancelBubble = true + hEvent.returnValue = false + return false + } + break + case 13 : + case 32 : + case 46 : + //case 37 : + //case 39 : + case 35 : + case 36 : break; + default : if( hEvent.keyCode < 48 ) + { + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + hEvent.cancelBubble = true + hEvent.returnValue = false + return false + } + break + } + + if( hAC.hMarkRangeTimeout != null ) + { + clearTimeout( hAC.hMarkRangeTimeout ) + } + + if( hAC.hShowTimeout ) + { + clearTimeout( hAC.hShowTimeout ) + hAC.hShowTimeout = null + } + var nTimeout = hAC.bRemoteList ? cAutocomplete.CN_REMOTE_SHOW_TIMEOUT : cAutocomplete.CN_SHOW_TIMEOUT + hAC.hShowTimeout = setTimeout( function(){ hAC.prepareList() }, nTimeout ) +} + +cAutocomplete.onInputBlur = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + if( hElement.form ) + { + hElement.form.bLocked = false + } + var hAC = hElement.hAutocomplete + if( !hAC.hClearTimeout ) + { + hAC.hClearTimeout = setTimeout( function(){ hAC.clearList() }, cAutocomplete.CN_CLEAR_TIMEOUT ) + } +} + +cAutocomplete.onInputFocus = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hAC = hElement.hAutocomplete + if( hAC.hClearTimeout ) + { + clearTimeout( hAC.hClearTimeout ) + hAC.hClearTimeout = null + } +} + +cAutocomplete.saveCaretPosition = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hAC = hElement.hAutocomplete + var hInput = document.getElementById( hAC.sInputId ) + + //there is something weird about hitting up and down keys in a textarea + if( hEvent.keyCode != 38 && hEvent.keyCode != 40 ) + { + hAC.nInsertPoint = cAutocomplete.getInputCaretPosition( hInput ) + } +} + +cAutocomplete.getInputCaretPosition = function( hInput ) +{ + if( typeof hInput.selectionStart != 'undefined' ) + { + if( hInput.selectionStart == hInput.selectionEnd ) + { + return hInput.selectionStart + } + else + { + return hInput.selectionStart + } + } + else if( hInput.createTextRange ) + { + var hSelRange = document.selection.createRange() + if( hInput.tagName.toLowerCase() == 'textarea' ) + { + var hSelBefore = hSelRange.duplicate() + var hSelAfter = hSelRange.duplicate() + hSelRange.moveToElementText( hInput ) + hSelBefore.setEndPoint( 'StartToStart', hSelRange ) + return hSelBefore.text.length + } + else + { + hSelRange.moveStart( 'character', -1*hInput.value.length ) + var nLen = hSelRange.text.length + return nLen + } + } + return null +} + +cAutocomplete.setInputCaretPosition = function( hInput, nPosition ) +{ + if ( hInput.setSelectionRange ) + { + hInput.setSelectionRange( nPosition ,nPosition ) + } + else if ( hInput.createTextRange ) + { + var hRange = hInput.createTextRange() + hRange.moveStart( 'character', nPosition ) + hRange.moveEnd( 'character', nPosition ) + hRange.collapse(true) + hRange.select() + } +} + +cAutocomplete.markInputRange = function( hInput, nStartPos, nEndPos ) +{ + if( hInput.setSelectionRange ) + { + hInput.focus() + hInput.setSelectionRange( nStartPos, nEndPos ) + } + else if( hInput.createTextRange ) + { + var hRange = hInput.createTextRange() + hRange.collapse(true) + hRange.moveStart( 'character', nStartPos ) + hRange.moveEnd( 'character', nEndPos - nStartPos ) + hRange.select() + } +} + +cAutocomplete.markInputRange2 = function( sInputId ) +{ + var hInput = document.getElementById( sInputId ) + var nStartPos = hInput.hAutocomplete.nStartAC + var nEndPos = hInput.hAutocomplete.nEndAC + cAutocomplete.markInputRange( hInput, nStartPos, nEndPos ) +} + + +cAutocomplete.onListBlur = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' ) + var hAC = hElement.hAutocomplete + if( !hAC.hClearTimeout ) + { + hAC.hClearTimeout = setTimeout( function() { hAC.clearList() }, cAutocomplete.CN_CLEAR_TIMEOUT ) + } +} + +cAutocomplete.onListFocus = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + hElement = getParentByProperty( hElement, 'className', 'autocomplete_holder' ) + var hAC = hElement.hAutocomplete + if( hAC.hClearTimeout ) + { + clearTimeout( hAC.hClearTimeout ) + hAC.hClearTimeout = null + } +} + +cAutocomplete.onItemClick = function( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hContainer = getParentByProperty( hElement, 'className', 'autocomplete_holder' ) + var hEl = getParentByTagName( hElement, 'A' ) + if( hContainer != null ) + { + var hAC = hContainer.hAutocomplete + hAC.selectOption( hEl ) + document.getElementById( hAC.sInputId ).focus() + hAC.clearList() + } + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + hEvent.cancelBubble = true + hEvent.returnValue = false + return false +} + +cAutocomplete.onButtonClick = function ( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + var hAC = hElement.hAutocomplete + var hInput = document.getElementById( hAC.sInputId ) + if( hInput.disabled ) + { + return + } + hAC.prepareList( true ) + var hInput = document.getElementById( hAC.sInputId ) + hInput.focus() +} + +cAutocomplete.onFormSubmit = function ( hEvent ) +{ + if( hEvent == null ) + { + hEvent = window.event + } + var hElement = ( hEvent.srcElement ) ? hEvent.srcElement : hEvent.originalTarget + if( hElement.bLocked ) + { + hElement.bLocked = false + hEvent.returnValue = false + if( hEvent.preventDefault ) + { + hEvent.preventDefault() + } + return false + } +} diff --git a/autocomplete/js/getobject2.js b/autocomplete/js/getobject2.js new file mode 100644 index 0000000..d8125c5 --- /dev/null +++ b/autocomplete/js/getobject2.js @@ -0,0 +1,126 @@ +//misc objects +//a simple encapsulation object +//used to query widths and heights + +function cDomObject( sId ) +{ + if( bw.dom || bw.ie ) + { + this.hElement = document.getElementById( sId ) + this.hStyle = this.hElement.style + } +} + +cDomObject.prototype.getWidth = function( ) +{ + return cDomObject.getWidth( this.hElement ) +} + +cDomObject.getWidth = function( hElement ) +{ + if( hElement.currentStyle ) + { + var nWidth = parseInt( hElement.currentStyle.width ) + if( isNaN( nWidth ) ) + { + return parseInt( hElement.offsetWidth ) + } + else + { + return nWidth + } + } + else + { + return parseInt( hElement.offsetWidth ) + } +} + +cDomObject.prototype.getHeight = function( ) +{ + return cDomObject.getHeight( this.hElement ) +} + +cDomObject.getHeight = function( hElement ) +{ + if( hElement.currentStyle ) + { + var nHeight = parseInt( hElement.currentStyle.height ) + if( isNaN( nHeight ) ) + { + return parseInt( hElement.offsetHeight ) + } + else + { + return nHeight + } + } + else + { + return parseInt( hElement.offsetHeight ) + } +} + +cDomObject.prototype.getLeft = function() +{ + return cDomObject.getLeft( this.hElement ) +} + +cDomObject.getLeft = function( hElement ) +{ + return parseInt( hElement.offsetLeft ) +} + +cDomObject.prototype.getTop = function( ) +{ + return cDomObject.getTop( this.hElement ) +} + +cDomObject.getTop = function( hElement ) +{ + return parseInt( hElement.offsetTop ) +} + + +// used to get the absolute position of an relativeli position element +// by accumulating the offset parameters +// example +// cDomObject.getOffsetParam( hElement,'offsetLeft' ) + +cDomObject.getOffsetParam = function( hElement, sParam, hLimitParent ) +{ + var nRes = 0 + if( hLimitParent == null ) + { + hLimitParent = document.body.parentElement + } + while( hElement != hLimitParent ) + { + nRes += eval( 'hElement.' + sParam ) + if( !hElement.offsetParent ) { break } + hElement = hElement.offsetParent + } + return nRes +} + + +// used to get the absolute position of an relativeli position element +// by accumulating the scroll offset parameters +// example +// cDomObject.getScrollOffset( hElement,'Left' ) + +cDomObject.getScrollOffset = function( hElement, sParam, hLimitParent ) +{ + nRes = 0 + if( hLimitParent == null ) + { + hLimitParent = document.body.parentElement + } + while( hElement != hLimitParent ) + { + nRes += eval( 'hElement.scroll' + sParam ) + if( !hElement.offsetParent ) { break } + hElement = hElement.parentNode + } + return nRes +} \ No newline at end of file diff --git a/autocomplete/js/ieselect.js b/autocomplete/js/ieselect.js new file mode 100644 index 0000000..1715580 --- /dev/null +++ b/autocomplete/js/ieselect.js @@ -0,0 +1,85 @@ +function Property(name, value) { + this.name = name; + this.value = value; +} + +var defaultSelectProps = new Array(); + +defaultSelectProps[defaultSelectProps.length] = new Property("VariousPropertyBits", "726624571"); +defaultSelectProps[defaultSelectProps.length] = new Property("DisplayStyle", "7"); +defaultSelectProps[defaultSelectProps.length] = new Property("FontName", "Arial"); +defaultSelectProps[defaultSelectProps.length] = new Property("FontHeight", "200"); +defaultSelectProps[defaultSelectProps.length] = new Property("ShowDropButtonWhen", "2"); +defaultSelectProps[defaultSelectProps.length] = new Property("FontHeight", "200"); +defaultSelectProps[defaultSelectProps.length] = new Property("ScrollBars", "0"); + +function replaceIESelect(id, selectProps) { + if (selectProps==null) selectProps = defaultSelectProps; + if (document.all&&document.getElementById) { + var sel = document.getElementById(id); + var parent = sel.parentNode; + + var obj = document.createElement("object"); + var paramSuccess = true; + + try { + for (var j in selectProps) { + var param = document.createElement("param"); + param.setAttribute("name", selectProps[j].name); + param.setAttribute("value", selectProps[j].value); + obj.appendChild(param); + } + } catch(er) { + paramSuccess = false; + } + + with (obj) { + setAttribute("classid","clsid:8BD21D30-EC42-11CE-9E0D-00AA006002F3"); + setAttribute("id", "comp_" + sel.name); + setAttribute("width", sel.offsetWidth); + setAttribute("height", sel.offsetHeight); + if (!paramSuccess) Style=2; + } + + var input = document.createElement("input"); + with (input) { + setAttribute("id", sel.name); + setAttribute("name", sel.name); + setAttribute("type", "hidden"); + setAttribute("value", obj.name); + } + + obj.options = new Array(); + + for (var j=0; j 0 ) + { + if( aAttributeData[ 3 ] == '=' ) + { + if( aAttributeData[ 2 ] == '' ) + { + if( sAttribute == aAttributeData[4] ) + { + hInitFunction( hGroup[ nI ] ) + } + } + else + { + switch( aAttributeData[ 2 ] ) + { + case '^' : if( sAttribute.indexOf( aAttributeData[ 4 ] ) == 0 ) + { + hInitFunction( hGroup[ nI ] ) + } + break + case '$' : if( sAttribute.lastIndexOf( aAttributeData[ 4 ] ) == sAttribute.length - aAttributeData[ 4 ].length ) + { + hInitFunction( hGroup[ nI ] ) + } + break + case '*' : if( sAttribute.indexOf( aAttributeData[ 4 ] ) >= 0 ) + { + hInitFunction( hGroup[ nI ] ) + } + break + } + } + } + else + { + hInitFunction( hGroup[ nI ] ) + } + } + } + } + //we have the new implementation - css3 style selectors, so return + return + } + } + + + hSelectorRegEx = /([a-z0-9_]*)([\.#@]?)([a-z0-9_=~]*)/i + hAttributeRegEx = /([a-z0-9_]*)([=~])?([a-z0-9_]*)/i + aSelectorData = hSelectorRegEx.exec( sSelector ) + + if( aSelectorData[ 1 ] != '' ) + { + var hGroup = hParent.getElementsByTagName( aSelectorData[ 1 ] ) + for( nI = 0; nI < hGroup.length; nI ++ ) + { + hGroup[ nI ].markExt = true + } + for( nI = 0; nI < hGroup.length; nI ++ ) + { + if( !hGroup[ nI ].markExt ) + { + continue + } + else + { + hGroup[ nI ].markExt = false + } + if( aSelectorData[ 2 ] != '' ) + { + switch( aSelectorData[ 2 ] ) + { + case '.' : if( hGroup[ nI ].className == aSelectorData[ 3 ] ) + { + hInitFunction( hGroup[ nI ] ) + } + break + + case '#' : if( hGroup[ nI ].id == aSelectorData[ 3 ] ) + { + hInitFunction( hGroup[ nI ] ) + } + break + + case '@' : aAttributeData = hAttributeRegEx.exec( aSelectorData[ 3 ] ) + sAttribute = hGroup[ nI ].getAttribute( aAttributeData[ 1 ] ) + if( sAttribute != null && sAttribute.length > 0 ) + { + if( aAttributeData[ 3 ] != '' ) + { + if( aAttributeData[ 2 ] == '=' ) + { + if( sAttribute == aAttributeData[ 3 ] ) + { + hInitFunction( hGroup[ nI ] ) + } + } + else /* the case is like ~ */ + { + if( sAttribute.indexOf( aAttributeData[ 3 ] ) >= 0 ) + { + hInitFunction( hGroup[ nI ] ) + } + } + } + else + { + hInitFunction( hGroup[ nI ] ) + } + } + break + } + } + } + } + +} + +cDomExtensionManager.initialize = function() +{ + var hDomExtension = null + var aSelectors + + for( var nKey in cDomExtensionManager.aExtensions ) + { + aSelectors = cDomExtensionManager.aExtensions[ nKey ].aSelectors + for( var nKey2 in aSelectors ) + { + cDomExtensionManager.initSelector( cDomExtensionManager.aExtensions[ nKey ].hParent, aSelectors[ nKey2 ], cDomExtensionManager.aExtensions[ nKey ].hInitFunction ) + } + } +} + +if( window.addEventListener ) +{ + window.addEventListener( 'load', cDomExtensionManager.initialize, false ) +} +else if( window.attachEvent ) +{ + window.attachEvent( 'onload', cDomExtensionManager.initialize ) +} diff --git a/autocomplete/js/modomt.js b/autocomplete/js/modomt.js new file mode 100644 index 0000000..2987ae8 --- /dev/null +++ b/autocomplete/js/modomt.js @@ -0,0 +1,259 @@ +// +// This script was created +// by Mircho Mirev +// mo /mo@momche.net/ +// +// :: feel free to use it BUT +// :: if you want to use this code PLEASE send me a note +// :: and please keep this disclaimer intact +// + +if ( document.ELEMENT_NODE == null ) +{ + document.ELEMENT_NODE = 1 + document.TEXT_NODE = 3 +} + + +function getSubNodeByName( hNode, sNodeName ) +{ + if( hNode != null ) + { + var nNc = 0 + var nC = 0 + var hNodeChildren = hNode.childNodes + var hCNode = null + while( nC < hNodeChildren.length ) + { + hCNode = hNodeChildren.item( nC++ ) + if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) ) + { + return hCNode + } + } + } + return null +} + +function getPrevNodeSibling( hNode ) +{ + if( hNode != null ) + { + do { + hNode = hNode.previousSibling + } while( hNode != null && hNode.nodeType != 1 ) + return hNode + } +} + +function getNextNodeSibling( hNode ) +{ + if( hNode != null ) + { + do { + hNode = hNode.nextSibling + } while( hNode != null && hNode.nodeType != 1 ) + return hNode + } +} + +function getLastSubNodeByName( hNode, sNodeName ) +{ + if( hNode != null ) + { + var nNc = 0 + var nC = 0 + var hNodeChildren = hNode.childNodes + var hCNode = null + var nLength = hNodeChildren.length - 1 + while( nLength >=0 ) + { + hCNode = hNodeChildren.item( nLength ) + if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) ) + { + return hCNode + } + nLength-- + } + } + return null +} + +function getSubNodeByProperty( hNode, sProperty, sPropValue ) +{ + if( hNode != null ) + { + var nNc = 0 + var nC = 0 + var hNodeChildren = hNode.childNodes + var hCNode = null + var sAttribute + var hProp + sPropValue = sPropValue.toLowerCase() + while( nC < hNodeChildren.length ) + { + hCNode = hNodeChildren.item( nC++ ) + if( hCNode.nodeType == document.ELEMENT_NODE ) + { + hProp = eval( 'hCNode.'+sProperty ) + if( typeof( sPropValue ) != 'undefined' ) + { + if( hProp.toLowerCase() == sPropValue ) + { + return hCNode + } + } + else + { + return hCNode + } + } + nNc++ + } + } + return null +} + +function findAttribute( hNode, sAtt ) +{ + sAtt = sAtt.toLowerCase() + for( var nI = 0; nI < hNode.attributes.length; nI++ ) + { + if( hNode.attributes.item( nI ).nodeName.toLowerCase() == sAtt ) + { + return hNode.attributes.item( nI ).nodeValue + } + } + return null +} + +function getSubNodeByAttribute( hNode, sAtt, sAttValue ) +{ + if( hNode != null ) + { + var nNc = 0 + var nC = 0 + var hNodeChildren = hNode.childNodes + var hCNode = null + var sAttribute + sAttValue = sAttValue.toLowerCase() + while( nC < hNodeChildren.length ) + { + hCNode = hNodeChildren.item( nC++ ) + if( hCNode.nodeType == document.ELEMENT_NODE ) + { + sAttribute = hCNode.getAttribute( sAtt ) + if( sAttribute && sAttribute.toLowerCase() == sAttValue ) + return hCNode + } + nNc++ + } + } + return null +} + +function getLastSubNodeByAttribute( hNode, sAtt, sAttValue ) +{ + if( hNode != null ) + { + var nNc = 0 + var nC = 0 + var hNodeChildren = hNode.childNodes + var hCNode = null + var nLength = hNodeChildren.length - 1 + while( nLength >= 0 ) + { + hCNode = hNodeChildren.item( nLength ) + if( hCNode.nodeType == document.ELEMENT_NODE ) + { + sAttribute = hCNode.getAttribute( sAtt ) + if( sAttribute && sAttribute.toLowerCase() == sAttValue ) + return hCNode + } + nLength-- + } + } + return null +} + +function getParentByTagName( hNode, sParentTagName ) +{ + while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) ) + { + if( hNode.tagName == sParentTagName ) + { + return hNode + } + hNode = hNode.parentNode + } + return null +} + +function getParentByAttribute( hNode, sAtt, sAttValue ) +{ + while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) ) + { + //opera strangely returns non null result sometimes + var sAttr = hNode.getAttribute( sAtt ) + if( sAttr != null && sAttr.toString().length > 0 ) + { + if( sAttValue !== null ) + { + if( sAttr == sAttValue ) + { + return hNode + } + } + else + { + return hNode + } + } + hNode = hNode.parentNode + } + return null +} + +function getParentByProperty( hNode, sProperty, sPropValue ) +{ + while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) ) + { + //opera strangely returns non null result sometimes + var hProp = eval( 'hNode.'+sProperty ) + if( hProp != null && hProp.toString().length > 0 ) + { + if( sPropValue !== null ) + { + if( hProp == sPropValue ) + { + return hNode + } + } + else + { + return hNode + } + } + hNode = hNode.parentNode + } + return null +} + + +function getNodeText( hNode ) +{ + if( hNode == null ) + { + return '' + } + var sRes + if( hNode.hasChildNodes() ) + { + sRes = hNode.childNodes.item(0).nodeValue + } + else + { + sRes = hNode.text + } + return sRes +} \ No newline at end of file diff --git a/autocomplete/js/shBrushJScript.js b/autocomplete/js/shBrushJScript.js new file mode 100644 index 0000000..e61a767 --- /dev/null +++ b/autocomplete/js/shBrushJScript.js @@ -0,0 +1,22 @@ +dp.sh.Brushes.JScript = function() +{ + var keywords = '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'; + + this.regexList = [ + { regex: new RegExp('//.*$', 'gm'), css: 'comment' }, // one line comments + { regex: new RegExp('/\\*[\\s\\S]*?\\*/', 'g'), css: 'comment' }, // multiline comments + { regex: new RegExp('"(?:\\.|[^\\""])*"', 'g'), css: 'string' }, // double quoted strings + { regex: new RegExp('\'(?:\\.|[^\\\'\'])*\'', 'g'), css: 'string' }, // single quoted strings + { regex: new RegExp('^\\s*#.*', 'gm'), css: 'preprocessor' }, // preprocessor tags like #region and #endregion + { regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword' } // keywords + ]; + + this.CssClass = 'dp-c'; +} + +dp.sh.Brushes.JScript.prototype = new dp.sh.Highlighter(); +dp.sh.Brushes.JScript.Aliases = ['js', 'jscript', 'javascript']; diff --git a/autocomplete/js/shBrushXml.js b/autocomplete/js/shBrushXml.js new file mode 100644 index 0000000..941ad57 --- /dev/null +++ b/autocomplete/js/shBrushXml.js @@ -0,0 +1,61 @@ +dp.sh.Brushes.Xml = function() +{ + this.CssClass = 'dp-xml'; +} + +dp.sh.Brushes.Xml.prototype = new dp.sh.Highlighter(); +dp.sh.Brushes.Xml.Aliases = ['xml', 'xhtml', 'xslt', 'html', 'xhtml']; + +dp.sh.Brushes.Xml.prototype.ProcessRegexList = function() +{ + function push(array, value) + { + array[array.length] = value; + } + + /* If only there was a way to get index of a group within a match, the whole XML + could be matched with the expression looking something like that: + + () + | () + | (<)*(\w+)*\s*(\w+)\s*=\s*(".*?"|'.*?'|\w+)(/*>)* + | () + */ + var index = 0; + var match = null; + var regex = null; + + // Match CDATA in the following format + // <\!\[[\w\s]*?\[(.|\s)*?\]\]> + this.GetMatches(new RegExp('<\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\]>', 'gm'), 'cdata'); + + // Match comments + // + this.GetMatches(new RegExp('', 'gm'), 'comments'); + + // Match attributes and their values + // (\w+)\s*=\s*(".*?"|\'.*?\'|\w+)* + regex = new RegExp('([\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*', 'gm'); + while((match = regex.exec(this.code)) != null) + { + push(this.matches, new dp.sh.Match(match[1], match.index, 'attribute')); + + // if xml is invalid and attribute has no property value, ignore it + if(match[2] != undefined) + { + push(this.matches, new dp.sh.Match(match[2], match.index + match[0].indexOf(match[2]), 'attribute-value')); + } + } + + // Match opening and closing tag brackets + // + this.GetMatches(new RegExp('', 'gm'), 'tag'); + + // Match tag names + // + * + * + * + * + * + * + ** + * History: + * 1.1.0 - March 23rd, 2005 + * - split brushes into separate files + * - now works in Safari + * - added missing strings to PHP matches + * + * 1.0.4 - February 2nd, 2005 + * - added Delphi & Python + * - multi-line comments fixed + * - language name can be set through w3c valid 'class' attribute + * - HighlightAll(name, [showGutter], [showTools]) + * + * 1.0.3 - December 31th, 2004 (added PHP & SQL) + * 1.0.2 - December 28th, 2004 (refactoring with namespaces) + * 1.0.1 - December 14th, 2004 + * 1.0.0 - November 13th, 2004 + */ + +// create namespaces +var dp = { + sh : // dp.sh + { + Utils : {}, // dp.sh.Utils + Brushes : {} // dp.sh.Brushes + } +}; + +dp.sh.Config = { + Version : '1.1.0', + About : 'About...
dp.SyntaxHighlighter
Version: {V}
©2004-2005 Dream Projections Inc. All right reserved.
' +}; + +dp.SyntaxHighlighter = dp.sh; + + + +// opens a new windows and puts the original unformatted source code inside. +dp.sh.Utils.ViewSource = function(sender) +{ + var code = sender.parentNode.originalCode; + var wnd = window.open('', '_blank', 'width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=1'); + + code = code.replace(/' + code + ''); + wnd.document.close(); +} + +// copies the original source code in to the clipboard (IE only) +dp.sh.Utils.ToClipboard = function(sender) +{ + var code = sender.parentNode.originalCode; + + // This works only for IE. There's a way to make it work with Mozilla as well, + // but it requires security settings changed on the client, which isn't by + // default, so 99% of users won't have it working anyways. + if(window.clipboardData) + { + window.clipboardData.setData('text', code); + + alert('The code is in your clipboard now.'); + } +} + +// creates an invisible iframe, puts the original source code inside and prints it +dp.sh.Utils.PrintSource = function(sender) +{ + var td = sender.parentNode; + var code = td.processedCode; + var iframe = document.createElement('IFRAME'); + var doc = null; + var wnd = + + // this hides the iframe + iframe.style.cssText = 'position:absolute; width:0px; height:0px; left:-5px; top:-5px;'; + + td.appendChild(iframe); + + doc = iframe.contentWindow.document; + code = code.replace(/' + code + ''); + doc.close(); + + iframe.contentWindow.focus(); + iframe.contentWindow.print(); + + td.removeChild(iframe); +} + +dp.sh.Utils.About = function() +{ + var wnd = window.open('', '_blank', 'dialog, width=320, height=150'); + var doc = wnd.document; + + var styles = document.getElementsByTagName('style'); + var links = document.getElementsByTagName('link'); + + doc.write(dp.sh.Config.About.replace('{V}', dp.sh.Config.Version)); + + // copy over ALL the styles from the parent page + for(var i = 0; i < styles.length; i++) + doc.write(''); + + for(var i = 0; i < links.length; i++) + if(links[i].rel.toLowerCase() == 'stylesheet') + doc.write(''); + + doc.close(); + wnd.focus(); +} + + + + + +// creates a new match object +dp.sh.Match = function(value, index, css) +{ + this.value = value; + this.index = index; + this.length = value.length; + this.css = css; +} + + + + + +dp.sh.Highlighter = function() +{ + this.addGutter = true; + this.addControls = true; + this.tabsToSpaces = true; +} + +// static callback for the match sorting +dp.sh.Highlighter.SortCallback = function(m1, m2) +{ + // sort matches by index first + if(m1.index < m2.index) + return -1; + else if(m1.index > m2.index) + return 1; + else + { + // if index is the same, sort by length + if(m1.length < m2.length) + return -1; + else if(m1.length > m2.length) + return 1; + } + return 0; +} + +// gets a list of all matches for a given regular expression +dp.sh.Highlighter.prototype.GetMatches = function(regex, css) +{ + var index = 0; + var match = null; + + while((match = regex.exec(this.code)) != null) + { + this.matches[this.matches.length] = new dp.sh.Match(match[0], match.index, css); + } +} + +dp.sh.Highlighter.prototype.AddBit = function(str, css) +{ + var span = document.createElement('span'); + + str = str.replace(/&/g, '&'); + str = str.replace(/ /g, ' '); + str = str.replace(/'); + + // when adding a piece of code, check to see if it has line breaks in it + // and if it does, wrap individual line breaks with span tags + if(css != null) + { + var regex = new RegExp('
', 'gi'); + + if(regex.test(str)) + { + var lines = str.split(' 
'); + + str = ''; + + for(var i = 0; i < lines.length; i++) + { + span = document.createElement('SPAN'); + span.className = css; + span.innerHTML = lines[i]; + + this.div.appendChild(span); + + // don't add a
for the last line + if(i + 1 < lines.length) + { + this.div.appendChild(document.createElement('BR')); + } + } + } + else + { + span.className = css; + span.innerHTML = str; + this.div.appendChild(span); + } + } + else + { + span.innerHTML = str; + this.div.appendChild(span); + } +} + +// checks if one match is inside another +dp.sh.Highlighter.prototype.IsInside = function(match) +{ + if(match == null || match.length == 0) + { + return; + } + + for(var i = 0; i < this.matches.length; i++) + { + var c = this.matches[i]; + + if(c == null) + { + continue; + } + + if((match.index > c.index) && (match.index <= c.index + c.length)) + { + return true; + } + } + + return false; +} + +dp.sh.Highlighter.prototype.ProcessRegexList = function() +{ + for(var i = 0; i < this.regexList.length; i++) + { + this.GetMatches(this.regexList[i].regex, this.regexList[i].css); + } +} + +dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code) +{ + var lines = code.split('\n'); + var result = ''; + var tabSize = 4; + var tab = '\t'; + + // This function inserts specified amount of spaces in the string + // where a tab is while removing that given tab. + function InsertSpaces(line, pos, count) + { + var left = line.substr(0, pos); + var right = line.substr(pos + 1, line.length); // pos + 1 will get rid of the tab + var spaces = ''; + + for(var i = 0; i < count; i++) + { + spaces += ' '; + } + + return left + spaces + right; + } + + // This function process one line for 'smart tabs' + function ProcessLine(line, tabSize) + { + if(line.indexOf(tab) == -1) + { + return line; + } + + var pos = 0; + + while((pos = line.indexOf(tab)) != -1) + { + // This is pretty much all there is to the 'smart tabs' logic. + // Based on the position within the line and size of a tab, + // calculate the amount of spaces we need to insert. + var spaces = tabSize - pos % tabSize; + + line = InsertSpaces(line, pos, spaces); + } + + return line; + } + + // Go through all the lines and do the 'smart tabs' magic. + for(var i = 0; i < lines.length; i++) + { + var line = lines[i]; + result += ProcessLine(line, tabSize) + '\n'; + } + + return result; +} + +dp.sh.Highlighter.prototype.SwitchToTable = function() +{ + // Safari fix: for some reason lowercase
isn't getting picked up, even though 'i' is set + var lines = this.div.innerHTML.split(/
/gi); + var row = null; + var cell = null; + var html = ''; + var pipe = ' | '; + + // creates an anchor to a utility + function UtilHref(util, text) + { + return '' + text + ''; + } + + row = this.table.insertRow(-1); + + if(this.addGutter == true) + { + cell = row.insertCell(-1); + cell.className = 'tools-corner'; + } + + if(this.addControls == true) + { + cell = row.insertCell(-1); + + cell.originalCode = this.originalCode; + cell.processedCode = this.code; + + cell.className = 'tools'; + cell.innerHTML = UtilHref('ViewSource', 'view plain') + pipe + UtilHref('PrintSource', 'print'); + + if(window.clipboardData) + { + cell.innerHTML += pipe + UtilHref('ToClipboard', 'copy to clipboard'); + } + + cell.innerHTML += pipe + UtilHref('About', '?'); + } + + for(var i = 0; i < lines.length - 1; i++) + { + row = this.table.insertRow(-1); + + if(this.addGutter == true) + { + cell = row.insertCell(-1); + cell.className = 'gutter'; + cell.innerHTML = i + 1; + } + + cell = row.insertCell(-1); + cell.className = 'line'; + cell.innerHTML = lines[i]; + } + + this.div.innerHTML = ''; +} + +dp.sh.Highlighter.prototype.Highlight = function(code) +{ + // This function strips all new lines and spaces + // from the beging and end of the string . + function Trim(str) + { + var begining = new RegExp('^[\\s\\n]', 'g'); + var end = new RegExp('[\\s\\n]$', 'g'); + + while(begining.test(str)) + { + str = str.substr(1); + } + + while(end.test(str)) + { + str = str.substr(0, str.length - 1); + } + + return str; + } + + // This function returns a portions of the string + // from pos1 to pos2 inclusive. + function Copy(string, pos1, pos2) + { + return string.substr(pos1, pos2 - pos1); + } + + var pos = 0; + + this.originalCode = code; + this.code = Trim(code); + this.div = document.createElement('DIV'); + this.table = document.createElement('TABLE'); + this.matches = new Array(); + + if(this.CssClass != null) + { + this.table.className = this.CssClass; + } + + // replace tabs with spaces + if(this.tabsToSpaces == true) + { + this.code = this.ProcessSmartTabs(this.code); + } + + this.table.border = 0; + this.table.cellSpacing = 0; + this.table.cellPadding = 0; + + this.ProcessRegexList(); + + // if no matches found, do nothing + if(this.matches.length == 0) + { + return; + } + + // sort the matches + this.matches = this.matches.sort(dp.sh.Highlighter.SortCallback); + + // The following loop checks to see if any of the matches are inside + // of other matches. This process would get rid of highligting strings + // inside comments, keywords inside strings and so on. + for(var i = 0; i < this.matches.length; i++) + { + if(this.IsInside(this.matches[i])) + { + this.matches[i] = null; + } + } + + // Finally, go through the final list of matches and pull the all + // together adding everything in between that isn't a match. + for(var i = 0; i < this.matches.length; i++) + { + var match = this.matches[i]; + + if(match == null || match.length == 0) + { + continue; + } + + this.AddBit(Copy(this.code, pos, match.index), null); + this.AddBit(match.value, match.css); + + pos = match.index + match.length; + } + + this.AddBit(this.code.substr(pos), null); + + this.SwitchToTable(); +} + +dp.sh.Highlighter.prototype.GetKeywords = function(str) +{ + return '\\b' + str.replace(/ /g, '\\b|\\b') + '\\b'; +} + +// highlightes all elements identified by name and gets source code from specified property +dp.sh.HighlightAll = function(name, showGutter /* optional */, showControls /* optional */) +{ + var elements = document.getElementsByName(name); + var highlighter = null; + var registered = new Object(); + var propertyName = 'value'; + + function FindValue() + { + var a = arguments; + + for(var i = 0; i < a.length; i++) + if(a[i] != null && ((typeof(a[i]) == 'string' && a[i] != '') || (typeof(a[i]) == 'object' && a[i].value != ''))) + return a[i]; + + return null; + } + + if(elements == null) + { + return; + } + + // if showGutter isn't set, default to TRUE + if(showGutter == null) + { + showGutter = true; + } + + // if showControls isn't set, default to TRUE + if(showControls == null) + { + showControls = true; + } + + // register all brushes + for(var brush in dp.sh.Brushes) + { + var aliases = dp.sh.Brushes[brush].Aliases; + + if(aliases == null) + { + continue; + } + + for(var i = 0; i < aliases.length; i++) + { + registered[aliases[i]] = brush; + } + } + + for(var i = 0; i < elements.length; i++) + { + var element = elements[i]; + var language = FindValue(element.attributes['class'], element.className, element.attributes['language'], element.language); + + if(language == null) + continue; + + if(language.value) + language = language.value; + + language = (language + '').toLowerCase(); + + if(registered[language] == null) + { + continue; + } + + // instantiate a brush + highlighter = new dp.sh.Brushes[registered[language]](); + + // hide the original element + element.style.display = 'none'; + + highlighter.addGutter = showGutter; + highlighter.addControls = showControls; + highlighter.Highlight(element[propertyName]); + + // place the result table inside a div + var div = document.createElement('DIV'); + + div.className = 'dp-highlighter'; + div.appendChild(highlighter.table); + + element.parentNode.insertBefore(div, element); + } +} diff --git a/autocomplete/js/tabs2.js b/autocomplete/js/tabs2.js new file mode 100644 index 0000000..9d196c8 --- /dev/null +++ b/autocomplete/js/tabs2.js @@ -0,0 +1,124 @@ +/* +* mo's Tabs script +* +* mo@momche.net +* please keep this disclaimer and send me a message if you intend to use the script +*/ +cMoTabs = new Object() + +cMoTabs.getTabGroup = function( hElement ) +{ + return getParentByTagName( hElement, 'UL' ) +} + +cMoTabs.getTabElement = function( hElement ) +{ + if( hElement == null ) + { + return null + } + try + { + if( typeof hElement.tagName == 'undefined' ) return null + } + catch( hException ) + { + return null + } + return getParentByProperty( hElement, 'className', 'tab' ) +} + + +cMoTabs.setActiveTabElement = function( hTabElement ) +{ + if( hTabElement == null ) + { + return + } + hTabElement.className = 'tabactive' + var hView = document.getElementById( hTabElement.getAttribute( 'tabview' ) ) + if( hView ) + { + hView.style.display = 'block' + } +} + +cMoTabs.setInactiveTabElement = function( hTabElement ) +{ + if( hTabElement == null ) + { + return + } + hTabElement.className = 'tab' + var hView = document.getElementById( hTabElement.getAttribute( 'tabview' ) ) + if( hView ) + { + hView.style.display = 'none' + } +} + +cMoTabs.doTab = function( e ) +{ + cDomEvent.init( e ) + var hTabElement = null + + if( e.type.indexOf( 'keypress' ) > -1 ) + { + if( e.keyCode != 13 ) + { + return + } + } + + hTabElement = cMoTabs.getTabElement( cDomEvent.target ) + + if ( hTabElement != null ) + { + //var hLink = getSubNodeByName( hTabElement, 'a' ) + //hLink.blur() + var hGroup = cMoTabs.getTabGroup( hTabElement ) + if( hGroup.hAcvtiveElm == null ) + { + var hActiveTab = getSubNodeByProperty( hTabElement.parentNode, 'className', 'tabactive' ) + } + else + { + var hActiveTab = hGroup.hAcvtiveElm + } + if( hActiveTab == hTabElement ) + { + } + else + { + cMoTabs.setInactiveTabElement( hActiveTab ) + cMoTabs.setActiveTabElement( hTabElement ) + hGroup.hAcvtiveElm = hTabElement + } + } + return true +} + +cMoTabs.doTabClick = function( e ) +{ + cDomEvent.init( e ) + if( e.preventDefault ) + { + e.preventDefault() + } + e.cancelBubble = false + e.returnValue = false + return false +} + +cMoTabs.init = function( hListItem ) +{ + var hLink = getSubNodeByName( hListItem, 'a' ) + cDomEvent.addEvent( hLink, 'activate', cMoTabs.doTab, false ) + cDomEvent.addEvent( hLink, 'focus', cMoTabs.doTab, false ) + cDomEvent.addEvent( hLink, 'mousedown', cMoTabs.doTab, false ) + cDomEvent.addEvent( hLink, 'keypress', cMoTabs.doTab, false ) + cDomEvent.addEvent( hLink, 'click', cMoTabs.doTabClick, false ) +} + + +cDomExtensionManager.register( new cDomExtension( document, [ "li[tabview]" ], cMoTabs.init ) ) diff --git a/autocomplete/js/xmlextras.js b/autocomplete/js/xmlextras.js new file mode 100644 index 0000000..0c3cec0 --- /dev/null +++ b/autocomplete/js/xmlextras.js @@ -0,0 +1,149 @@ +// { /if } + { if ! $use_autocomplete } + + + + + + + + + + { /if } diff --git a/themes/default/templates/search.tpl b/themes/default/templates/search.tpl index 10800e1..e6baaa9 100644 --- a/themes/default/templates/search.tpl +++ b/themes/default/templates/search.tpl @@ -7,7 +7,11 @@ Tag: + { if ! $use_autocomplete } + + { else } + { /if }