issue111, first try of auto completion for tag search box
authorAndreas Unterkircher <unki@netshadow.at>
Thu, 27 Mar 2008 21:59:06 +0000 (22:59 +0100)
committerAndreas Unterkircher <unki@netshadow.at>
Thu, 27 Mar 2008 21:59:06 +0000 (22:59 +0100)
Signed-off-by: Andreas Unterkircher <unki@netshadow.at>
30 files changed:
autocomplete/css/SyntaxHighlighter.css [new file with mode: 0644]
autocomplete/css/dropdown.css [new file with mode: 0644]
autocomplete/css/page.css [new file with mode: 0644]
autocomplete/css/tabsexamples.css [new file with mode: 0644]
autocomplete/i/al.png [new file with mode: 0644]
autocomplete/i/ar.png [new file with mode: 0644]
autocomplete/i/arrowdown.gif [new file with mode: 0644]
autocomplete/i/blbg.png [new file with mode: 0644]
autocomplete/i/code.png [new file with mode: 0644]
autocomplete/i/conf.gif [new file with mode: 0644]
autocomplete/i/ial.png [new file with mode: 0644]
autocomplete/i/iar.png [new file with mode: 0644]
autocomplete/i/leftb.png [new file with mode: 0644]
autocomplete/i/rightb.png [new file with mode: 0644]
autocomplete/js/acdropdown.js [new file with mode: 0644]
autocomplete/js/getobject2.js [new file with mode: 0644]
autocomplete/js/ieselect.js [new file with mode: 0644]
autocomplete/js/modomevent3.js [new file with mode: 0644]
autocomplete/js/modomext.js [new file with mode: 0644]
autocomplete/js/modomt.js [new file with mode: 0644]
autocomplete/js/shBrushJScript.js [new file with mode: 0644]
autocomplete/js/shBrushXml.js [new file with mode: 0644]
autocomplete/js/shCore.js [new file with mode: 0644]
autocomplete/js/tabs2.js [new file with mode: 0644]
autocomplete/js/xmlextras.js [new file with mode: 0644]
autocomplete/license.txt [new file with mode: 0644]
phpfspot.class.php
rpc.php
themes/default/templates/header.tpl
themes/default/templates/search.tpl

diff --git a/autocomplete/css/SyntaxHighlighter.css b/autocomplete/css/SyntaxHighlighter.css
new file mode 100644 (file)
index 0000000..d76aee9
--- /dev/null
@@ -0,0 +1,166 @@
+\r
+/* Main style for the table */\r
+\r
+.dp-highlighter {\r
+       width: 100%;\r
+       overflow: auto;\r
+       line-height: 100% !important;\r
+       margin: 18px 0px 18px 0px;\r
+}\r
+\r
+.dp-highlighter table {\r
+       width: 100%;\r
+       margin: 2px 0px 2px 0px;\r
+       border-collapse: collapse;\r
+       border-bottom: 2px solid #eee;\r
+       background-color: #fff;\r
+}\r
+\r
+.dp-highlighter td \r
+{\r
+       font-family: Courier New;\r
+       font-size: 11px;\r
+}\r
+\r
+/* Styles for the tools */\r
+\r
+.dp-highlighter .tools-corner {\r
+       background-color: #eee;\r
+       font-size: 9px;\r
+}\r
+\r
+.dp-highlighter .tools {\r
+       background-color: #eee;\r
+       padding: 3px 8px 3px 0px;\r
+       border-bottom: 1px solid gray;\r
+       font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif;\r
+       color: silver;\r
+}\r
+\r
+.dp-highlighter .tools a {\r
+       font-size: 9px;\r
+       color: gray;\r
+       text-decoration: none;\r
+}\r
+\r
+.dp-highlighter .tools a:hover {\r
+       color: red;\r
+       text-decoration: underline;\r
+}\r
+\r
+/* Gutter with line number */\r
+\r
+.dp-highlighter .gutter {\r
+       padding-right: 5px; \r
+       padding-left: 10px; \r
+       width: 5px;\r
+       background-color: #eee; \r
+       border-right: 1px solid gray; \r
+       color: gray;\r
+       text-align: right;\r
+       vertical-align: top;\r
+}\r
+\r
+/* Single line style */\r
+\r
+.dp-highlighter .line {\r
+       padding-left: 10px;\r
+       border-bottom: 1px solid #F7F7F7;\r
+       white-space:nowrap;\r
+}\r
+\r
+/* About dialog styles */\r
+\r
+.dp-about {\r
+       background-color: #fff;\r
+       margin: 0px;\r
+}\r
+\r
+.dp-about table {\r
+       width: 100%;\r
+       height: 100%;\r
+       font-size: 11px;\r
+       font-family: Tahoma, Verdana, Arial, sans-serif !important;\r
+}\r
+\r
+.dp-about td {\r
+       padding: 10px;\r
+       vertical-align: top;\r
+}\r
+\r
+.dp-about .copy {\r
+       border-bottom: 1px solid #ACA899;\r
+       height: 95%;\r
+}\r
+\r
+.dp-about .title {\r
+       color: red;\r
+       font-weight: bold;\r
+}\r
+\r
+.dp-about .para {\r
+       margin-bottom: 4px;\r
+}\r
+\r
+.dp-about .footer {\r
+       background-color: #ECEADB;\r
+       border-top: 1px solid #fff;\r
+       text-align: right;\r
+}\r
+\r
+.dp-about .close {\r
+       font-size: 11px;\r
+       font-family: Tahoma, Verdana, Arial, sans-serif !important;\r
+       background-color: #ECEADB;\r
+       width: 60px;\r
+       height: 22px;\r
+}\r
+\r
+/* Language specific styles */\r
+\r
+.dp-c {}\r
+.dp-c .comment { color: green; }\r
+.dp-c .string { color: blue; }\r
+.dp-c .preprocessor { color: gray; }\r
+.dp-c .keyword { color: blue; }\r
+.dp-c .vars { color: #d00; }\r
+\r
+.dp-vb {}\r
+.dp-vb .comment { color: green; }\r
+.dp-vb .string { color: blue; }\r
+.dp-vb .preprocessor { color: gray; }\r
+.dp-vb .keyword { color: blue; }\r
+\r
+.dp-sql {}\r
+.dp-sql .comment { color: green; }\r
+.dp-sql .string { color: red; }\r
+.dp-sql .keyword { color: blue; }\r
+.dp-sql .func { color: #ff1493; }\r
+.dp-sql .op { color: #808080; }\r
+\r
+.dp-xml {}\r
+.dp-xml .cdata { color: #ff1493; }\r
+.dp-xml .comments { color: green; }\r
+.dp-xml .tag { color: blue; }\r
+.dp-xml .tag-name { color: black; font-weight: bold; }\r
+.dp-xml .attribute { color: red; }\r
+.dp-xml .attribute-value { color: blue; }\r
+\r
+.dp-delphi {}\r
+.dp-delphi .comment { color: #008200; font-style: italic; }\r
+.dp-delphi .string { color: blue; }\r
+.dp-delphi .number { color: blue; }\r
+.dp-delphi .directive { color: #008284; }\r
+.dp-delphi .keyword { font-weight: bold; color: navy; }\r
+.dp-delphi .vars { color: #000; }\r
+\r
+.dp-py {}\r
+.dp-py .comment { color: green; }\r
+.dp-py .string { color: red; }\r
+.dp-py .docstring { color: brown; }\r
+.dp-py .keyword { color: blue; font-weight: bold;}\r
+.dp-py .builtins { color: #ff1493; }\r
+.dp-py .magicmethods { color: #808080; }\r
+.dp-py .exceptions { color: brown; }\r
+.dp-py .types { color: brown; font-style: italic; }\r
+.dp-py .commonlibs { color: #8A2BE2; font-style: italic; }\r
diff --git a/autocomplete/css/dropdown.css b/autocomplete/css/dropdown.css
new file mode 100644 (file)
index 0000000..8fae480
--- /dev/null
@@ -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 (file)
index 0000000..ca2a2cd
--- /dev/null
@@ -0,0 +1,37 @@
+.pages\r
+{\r
+       font-family: verdana;\r
+       font-size: 12px;\r
+       color: #111;\r
+       padding: 5px;\r
+}\r
+\r
+.pages div.holder\r
+{\r
+       width: 100%;\r
+       padding: 15px;\r
+       background: #fff;\r
+       border: 1px solid #666;\r
+       border-color: #111 #eee #eee #111;\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+}\r
+\r
+.pages div.code\r
+{\r
+       display: none;\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+}\r
+\r
+.pages a.codeToggle\r
+{\r
+       height: 28px;\r
+       line-height: 28px;\r
+       padding-left: 30px;\r
+       margin-top: 10px;\r
+       margin-bottom: 10px;\r
+       display: block;\r
+       background: url(../i/code.png) no-repeat;\r
+       -moz-box-sizing: border-box;\r
+}\r
diff --git a/autocomplete/css/tabsexamples.css b/autocomplete/css/tabsexamples.css
new file mode 100644 (file)
index 0000000..08f1539
--- /dev/null
@@ -0,0 +1,107 @@
+/* CSS Document */\r
+body\r
+{\r
+       background-color: #fff;\r
+}\r
+\r
+.pages\r
+{\r
+       position: relative;\r
+       float: none;\r
+       clear: both;\r
+       width: 100%;\r
+    display: none;\r
+    padding: 3px;\r
+    border: 1px solid #560702;\r
+    border-top-width: 0px;\r
+    background-color: #F4783C;\r
+    -moz-box-sizing: border-box;\r
+}\r
+\r
+span.hilite\r
+{\r
+       color: #00f;\r
+       background-color: #eee;\r
+}\r
+\r
+#navcontainer\r
+{\r
+       position: relative;\r
+       float: left;\r
+       width: 100%;\r
+    border-bottom: 1px solid #7ABBDA;\r
+    -moz-box-sizing: border-box;\r
+}\r
+\r
+ul.navlist\r
+{\r
+       position: relative;\r
+       top: 1px;\r
+       display: block;\r
+       float: left;\r
+       clear: both;\r
+\r
+       margin-top: 0px;        \r
+       margin-left: 0px;\r
+       margin-bottom: 0px;\r
+       padding-left: 9px;\r
+       padding-bottom: 0px;\r
+\r
+       font: 10px Verdana, sans-serif;\r
+       list-style-type: none;\r
+    -moz-box-sizing: border-box;\r
+}\r
+\r
+ul.navlist li\r
+{\r
+       display: block;\r
+       float: left;\r
+       margin: 0;\r
+       padding: 0;\r
+       padding-right: 5px;\r
+       width: auto;\r
+       height: 23px;\r
+       line-height: 23px;\r
+       font-weight: bold;\r
+       background-image: url(../i/iar.png);\r
+       background-position: center right;\r
+       background-repeat: no-repeat;\r
+    -moz-box-sizing: border-box;       \r
+}\r
+\r
+ul.navlist li.tabactive\r
+{\r
+       background-image: url(../i/ar.png);\r
+}\r
+\r
+ul.navlist li a, ul.navlist li a:link\r
+{\r
+       color: #FFB098;\r
+       text-decoration: none;\r
+       padding: 0px 5px 0px 11px;\r
+       display: block;\r
+       background-image: url(../i/ial.png);\r
+       background-repeat: no-repeat;\r
+       background-position: 0px center;\r
+}\r
+\r
+ul.navlist li a:hover\r
+{\r
+       color: #FFE5DD;\r
+       cursor: pointer;\r
+       background-image: url(../i/ial.png);\r
+       background-repeat: no-repeat;\r
+       background-position: 0px center;\r
+}\r
+\r
+ul.navlist li.tabactive a, ul.navlist li.tabactive a:link\r
+{\r
+       color: #F8FFC8;\r
+       cursor: default;\r
+       background-image: url(../i/al.png);\r
+}\r
+\r
+ul.navlist li.tabactive a:hover\r
+{\r
+       background-image: url(../i/al.png);\r
+}\r
diff --git a/autocomplete/i/al.png b/autocomplete/i/al.png
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..c5ad240
--- /dev/null
@@ -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 (file)
index 0000000..d8125c5
--- /dev/null
@@ -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 (file)
index 0000000..1715580
--- /dev/null
@@ -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<sel.options.length; j++) {
+                       obj.options[sel.options[j].text] = sel.options[j].value;
+               }
+               
+               obj.input = input;
+               obj.input.value = obj.options[obj.value];
+               
+               for (var j in obj.options) {
+                       obj.additem(j);
+               }
+               
+               selText = sel.options[sel.selectedIndex].text;
+               
+               parent.replaceChild(obj, sel);
+               parent.appendChild(input);
+               
+               obj.value = selText;
+               obj.style.position = "relative";
+               obj.style.top = "0.3em";
+               obj.style.zIndex = "-1";
+       }
+}
+
+function replaceAllIESelects() {
+       if (document.getElementById) {
+               var sels = document.getElementsByTagName("SELECT");
+               for( var nI = 0; nI < sels.length; nI++ )
+               {
+                       replaceIESelect(sels[nI].id);
+               }
+       }
+}
diff --git a/autocomplete/js/modomevent3.js b/autocomplete/js/modomevent3.js
new file mode 100644 (file)
index 0000000..7a548b3
--- /dev/null
@@ -0,0 +1,189 @@
+//
+//  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
+//
+
+//define the cEvent object
+cDomEvent = {
+       e               : null,
+       type    : '',
+       button  : 0,
+       key             : 0,
+       x               : 0,
+       y               : 0,
+       pagex   : 0,
+       pagey   : 0,
+       target  : null,
+       from    : null,
+       to              : null
+}
+
+cDomEvent.init = function( e )
+{
+       if( window.event ) e = window.event
+       this.e = e
+       this.type = e.type
+       this.button = ( e.which ) ? e.which : e.button
+       this.key = ( e.which ) ? e.which : e.keyCode
+       this.target = ( e.srcElement ) ? e.srcElement : e.originalTarget
+       this.currentTarget = ( e.currentTarget ) ? e.currentTarget : e.srcElement
+       this.from = ( e.originalTarget ) ? e.originalTarget : ( e.fromElement ) ? e.fromElement : null
+       this.to  = ( e.currentTarget ) ? e.currentTarget : ( e.toElement ) ? e.toElement : null
+       this.x = ( e.layerX ) ? e.layerX : ( e.offsetX ) ? e.offsetX : null
+       this.y = ( e.layerY ) ? e.layerY : ( e.offsetY ) ? e.offsetY : null
+       this.screenX = e.screenX
+       this.screenY = e.screenY
+       this.pageX = ( e.pageX ) ? e.pageX : e.x + document.body.scrollLeft
+       this.pageY = ( e.pageY ) ? e.pageY : e.y + document.body.scrollTop
+}
+
+cDomEvent.getEvent = function( e )
+{
+       if( window.event ) e = window.event
+       return  {
+                               e: e,
+                               type: e.type,
+                               button: ( e.which ) ? e.which : e.button,
+                               key: ( e.which ) ? e.which : e.keyCode,
+                               target: ( e.srcElement ) ? e.srcElement : e.originalTarget,
+                               currentTarget: ( e.currentTarget ) ? e.currentTarget : e.srcElement,
+                               from: ( e.originalTarget ) ? e.originalTarget : ( e.fromElement ) ? e.fromElement : null,
+                               to: ( e.currentTarget ) ? e.currentTarget : ( e.toElement ) ? e.toElement : null,
+                               x: ( e.layerX ) ? e.layerX : ( e.offsetX ) ? e.offsetX : null,
+                               y: ( e.layerY ) ? e.layerY : ( e.offsetY ) ? e.offsetY : null,
+                               screenX: e.screenX,
+                               screenY: e.screenY,
+                               pageX: ( e.pageX ) ? e.pageX : ( e.clientX + ( document.documentElement.scrollLeft || document.body.scrollLeft ) ),
+                               pageY: ( e.pageY ) ? e.pageY : ( e.clientY + ( document.documentElement.scrollTop || document.body.scrollTop ) )
+                       }
+}
+
+cDomEvent.cancelEvent = function( e )
+{
+       if( e.preventDefault )
+       {
+               e.preventDefault()
+       }
+       e.returnValue = false
+       e.cancelBubble = true
+       return false
+}
+
+cDomEvent.addEvent = function( hElement, sEvent, handler, bCapture )
+{
+       if( hElement.addEventListener )
+       {
+               hElement.addEventListener( sEvent, handler, bCapture )
+               return true
+       }
+       else if( hElement.attachEvent )
+       {
+               return hElement.attachEvent( 'on'+sEvent, handler )
+       }
+       else if( document.all || hElement.captureEvents )
+       {
+               if( hElement.captureEvents ) eval( 'hElement.captureEvents( Event.'+sEvent.toUpperCase()+' )' )
+               eval( 'hElement.on'+sEvent+' = '+handler )
+       }
+       else
+       {
+               alert('Not implemented yet!')
+       }
+}
+
+cDomEvent.encapsulateEvent = function( hHandler )
+{
+       return function ( hEvent )
+       {
+               hEvent = cDomEvent.getEvent( hEvent )
+               hHandler.call( hEvent.target, hEvent.e )
+       }
+}
+
+cDomEvent.addEvent2 = function( hElement, sEvent, handler, bCapture )
+{
+       if( hElement )
+       {
+               if( hElement.addEventListener )
+               {
+                       hElement.addEventListener( sEvent, cDomEvent.encapsulateEvent( handler ), bCapture )
+                       return true
+               }
+               else if( hElement.attachEvent )
+               {
+                       return hElement.attachEvent( 'on'+sEvent, cDomEvent.encapsulateEvent( handler ) )
+               }
+               else
+               {
+                       alert('Not implemented yet!')
+               }
+       }
+       else
+       {
+               //alert( 'wrong' )
+       }
+}
+
+cDomEvent.addCustomEvent2 = function( hElement, sEvent, handler )
+{
+       if( hElement )
+       {
+               hElement[ sEvent ] = handler
+       }
+       else
+       {
+               //alert( 'wrong' )
+       }
+}
+
+cDomEvent.removeEvent = function( hElement, sEvent, handler, bCapture )
+{
+       if( hElement.addEventListener )
+       {
+               hElement.removeEventListener( sEvent, handler, bCapture )
+               return true
+       }
+       else if( hElement.attachEvent )
+       {
+               return hElement.detachEvent( 'on'+sEvent, handler )
+       }
+       else if( document.all || hElement.captureEvents )
+       {
+               eval( 'hElement.on'+sEvent+' = null' )
+       }
+       else
+       {
+               alert('Not implemented yet!')
+       }
+}
+
+
+//Mouse button mapper object
+function MouseButton()
+{
+       if( document.layers )
+       {
+               this.left = 1
+               this.middle = 2
+               this.right = 3
+       }
+       else if( document.all )
+       {
+               this.left = 1
+               this.middle = 4
+               this.right = 2
+       }
+       else //hopefully this is mozilla case
+       {
+               this.left = 0
+               this.middle = 1
+               this.right = 2
+       }
+}
+
+var MB = new MouseButton()
\ No newline at end of file
diff --git a/autocomplete/js/modomext.js b/autocomplete/js/modomext.js
new file mode 100644 (file)
index 0000000..f914292
--- /dev/null
@@ -0,0 +1,219 @@
+//\r
+//  This script was created\r
+//  by Mircho Mirev\r
+//  mo /mo@momche.net/\r
+//\r
+//     :: feel free to use it BUT\r
+//     :: if you want to use this code PLEASE send me a note\r
+//     :: and please keep this disclaimer intact\r
+//\r
+\r
+//     This in fact is a simple dom iterator\r
+//     requires: mobrowser.js\r
+\r
+function cDomExtension( hParent, aSelectors, hInitFunction )\r
+{\r
+       this.hParent = hParent\r
+       this.aSelectors = aSelectors\r
+       this.hInitFunction = hInitFunction\r
+}\r
+\r
+cDomExtensionManager = \r
+{\r
+       aExtensions : new Array()\r
+}\r
+\r
+cDomExtensionManager.register = function( hDomExtension )\r
+{\r
+       cDomExtensionManager.aExtensions.push( hDomExtension )\r
+}\r
+\r
+cDomExtensionManager.initSelector = function( hParent, sSelector, hInitFunction )\r
+{\r
+       var hSelectorRegEx\r
+       var hAttributeRegEx\r
+       var aSelectorData\r
+       var aAttributeData\r
+       var sAttribute \r
+\r
+       hSelectorRegEx = /([a-z0-9_]*)\[?([^\]]*)\]?/i\r
+       hAttributeRegEx = /([a-z0-9_]*)([\*\^\$]?)(=?)(([a-z0-9_=]*))/i\r
+\r
+       if( hSelectorRegEx.test( sSelector ) && !/[@#\.]/.test( sSelector ) )\r
+       {\r
+               aSelectorData = hSelectorRegEx.exec( sSelector )\r
+               if( aSelectorData[ 1 ] != '' )\r
+               {\r
+                       hGroup  = hParent.getElementsByTagName( aSelectorData[ 1 ].toLowerCase() )\r
+                       for( nI = 0; nI < hGroup.length; nI ++ )\r
+                       {\r
+                               hGroup[ nI ].markExt = true\r
+                       }\r
+                       for( nI = 0; nI < hGroup.length; nI ++ )\r
+                       {\r
+                               if( !hGroup[ nI ].markExt )\r
+                               {\r
+                                       continue\r
+                               }\r
+                               else\r
+                               {\r
+                                       hGroup[ nI ].markExt = false\r
+                               }\r
+                               if( aSelectorData[ 2 ] == '' )\r
+                               {\r
+                                       if( hGroup[ nI ].tagName.toLowerCase() == aSelectorData[ 1 ].toLowerCase()  )\r
+                                       {\r
+                                               hInitFunction( hGroup[ nI ] )\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       aAttributeData = hAttributeRegEx.exec( aSelectorData[ 2 ] )\r
+                                       if( aAttributeData[ 1 ] == 'class' )\r
+                                       {\r
+                                               sAttribute = hGroup[ nI ].className\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               sAttribute = hGroup[ nI ].getAttribute( aAttributeData[ 1 ] )\r
+                                       }\r
+                                       if( sAttribute != null && sAttribute.length > 0 )\r
+                                       {\r
+                                               if( aAttributeData[ 3 ] == '=' )\r
+                                               {\r
+                                                       if( aAttributeData[ 2 ] == '' )\r
+                                                       {\r
+                                                               if( sAttribute == aAttributeData[4] )\r
+                                                               {\r
+                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               switch( aAttributeData[ 2 ] )\r
+                                                               {\r
+                                                                       case '^' :      if( sAttribute.indexOf( aAttributeData[ 4 ] ) == 0 )\r
+                                                                                               {\r
+                                                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                                                               }\r
+                                                                                               break\r
+                                                                       case '$' :      if( sAttribute.lastIndexOf( aAttributeData[ 4 ] ) == sAttribute.length - aAttributeData[ 4 ].length )\r
+                                                                                               {\r
+                                                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                                                               }\r
+                                                                                               break\r
+                                                                       case '*' :      if( sAttribute.indexOf( aAttributeData[ 4 ] ) >= 0 )\r
+                                                                                               {\r
+                                                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                                                               }\r
+                                                                                               break\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       hInitFunction( hGroup[ nI ] )\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       //we have the new implementation - css3 style selectors, so return\r
+                       return\r
+               }\r
+       }\r
+\r
+\r
+       hSelectorRegEx = /([a-z0-9_]*)([\.#@]?)([a-z0-9_=~]*)/i\r
+       hAttributeRegEx = /([a-z0-9_]*)([=~])?([a-z0-9_]*)/i\r
+       aSelectorData = hSelectorRegEx.exec( sSelector )\r
+       \r
+       if( aSelectorData[ 1 ] != '' )\r
+       {\r
+               var hGroup  = hParent.getElementsByTagName( aSelectorData[ 1 ] )\r
+               for( nI = 0; nI < hGroup.length; nI ++ )\r
+               {\r
+                       hGroup[ nI ].markExt = true\r
+               }\r
+               for( nI = 0; nI < hGroup.length; nI ++ )\r
+               {\r
+                       if( !hGroup[ nI ].markExt )\r
+                       {\r
+                               continue\r
+                       }\r
+                       else\r
+                       {\r
+                               hGroup[ nI ].markExt = false\r
+                       }\r
+                       if( aSelectorData[ 2 ] != '' )\r
+                       {\r
+                               switch( aSelectorData[ 2 ] )\r
+                               {\r
+                                       case '.' :      if( hGroup[ nI ].className == aSelectorData[ 3 ] )\r
+                                                               {\r
+                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                               }\r
+                                                               break\r
+                                                               \r
+                                       case '#' :      if( hGroup[ nI ].id == aSelectorData[ 3 ] )\r
+                                                               {\r
+                                                                       hInitFunction( hGroup[ nI ] )\r
+                                                               }\r
+                                                               break\r
+                                                               \r
+                                       case '@' :      aAttributeData = hAttributeRegEx.exec( aSelectorData[ 3 ] )\r
+                                                               sAttribute = hGroup[ nI ].getAttribute( aAttributeData[ 1 ] )\r
+                                                               if(  sAttribute != null && sAttribute.length > 0  )\r
+                                                               {                                       \r
+                                                                       if( aAttributeData[ 3 ] != '' )\r
+                                                                       {\r
+                                                                               if( aAttributeData[ 2 ] == '=' )\r
+                                                                               {\r
+                                                                                       if( sAttribute == aAttributeData[ 3 ] )\r
+                                                                                       {\r
+                                                                                               hInitFunction( hGroup[ nI ] )\r
+                                                                                       }\r
+                                                                               }\r
+                                                                               else /* the case is like ~ */\r
+                                                                               {\r
+                                                                                       if( sAttribute.indexOf( aAttributeData[ 3 ] ) >= 0 )\r
+                                                                                       {\r
+                                                                                               hInitFunction( hGroup[ nI ] )\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       }\r
+                                                                       else\r
+                                                                       {\r
+                                                                               hInitFunction( hGroup[ nI ] )\r
+                                                                       }\r
+                                                               }\r
+                                                               break\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+}\r
+\r
+cDomExtensionManager.initialize = function()\r
+{\r
+       var hDomExtension = null\r
+       var aSelectors\r
+       \r
+       for( var nKey in cDomExtensionManager.aExtensions )\r
+       {\r
+               aSelectors = cDomExtensionManager.aExtensions[ nKey ].aSelectors\r
+               for( var nKey2 in aSelectors )\r
+               {\r
+                       cDomExtensionManager.initSelector( cDomExtensionManager.aExtensions[ nKey ].hParent, aSelectors[ nKey2 ], cDomExtensionManager.aExtensions[ nKey ].hInitFunction )\r
+               }\r
+       }\r
+}\r
+\r
+if( window.addEventListener )\r
+{\r
+       window.addEventListener( 'load', cDomExtensionManager.initialize, false )\r
+}\r
+else if( window.attachEvent )\r
+{\r
+       window.attachEvent( 'onload', cDomExtensionManager.initialize )\r
+}\r
diff --git a/autocomplete/js/modomt.js b/autocomplete/js/modomt.js
new file mode 100644 (file)
index 0000000..2987ae8
--- /dev/null
@@ -0,0 +1,259 @@
+//\r
+//  This script was created\r
+//  by Mircho Mirev\r
+//  mo /mo@momche.net/\r
+//\r
+//     :: feel free to use it BUT\r
+//     :: if you want to use this code PLEASE send me a note\r
+//     :: and please keep this disclaimer intact\r
+//\r
+\r
+if ( document.ELEMENT_NODE == null )\r
+{\r
+       document.ELEMENT_NODE = 1\r
+       document.TEXT_NODE = 3\r
+}\r
+\r
+\r
+function getSubNodeByName( hNode, sNodeName )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               var nNc = 0\r
+               var nC  = 0\r
+               var hNodeChildren = hNode.childNodes\r
+               var hCNode = null\r
+               while( nC < hNodeChildren.length )\r
+               {\r
+                       hCNode = hNodeChildren.item( nC++ )\r
+                       if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) )\r
+                       {\r
+                               return hCNode\r
+                       }\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function getPrevNodeSibling( hNode )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               do {\r
+                       hNode = hNode.previousSibling\r
+               } while( hNode != null && hNode.nodeType != 1 )\r
+               return hNode\r
+       }\r
+}\r
+\r
+function getNextNodeSibling( hNode )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               do {\r
+                       hNode = hNode.nextSibling\r
+               } while( hNode != null && hNode.nodeType != 1 )\r
+               return hNode\r
+       }\r
+}\r
+\r
+function getLastSubNodeByName( hNode, sNodeName )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               var nNc = 0\r
+               var nC  = 0\r
+               var hNodeChildren = hNode.childNodes\r
+               var hCNode = null\r
+               var nLength = hNodeChildren.length - 1\r
+               while( nLength >=0  )\r
+               {\r
+                       hCNode = hNodeChildren.item( nLength )\r
+                       if( ( hCNode.nodeType == 1 ) && ( hCNode.nodeName.toLowerCase() == sNodeName ) )\r
+                       {\r
+                               return hCNode\r
+                       }\r
+                       nLength--\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function getSubNodeByProperty( hNode, sProperty, sPropValue )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               var nNc = 0\r
+               var nC  = 0\r
+               var hNodeChildren = hNode.childNodes\r
+               var hCNode = null\r
+               var sAttribute\r
+               var hProp \r
+               sPropValue = sPropValue.toLowerCase()\r
+               while( nC < hNodeChildren.length )\r
+               {\r
+                       hCNode = hNodeChildren.item( nC++ )\r
+                       if( hCNode.nodeType == document.ELEMENT_NODE )\r
+                       {\r
+                               hProp = eval( 'hCNode.'+sProperty )\r
+                               if( typeof( sPropValue ) != 'undefined' )\r
+                               {\r
+                                       if( hProp.toLowerCase() == sPropValue )\r
+                                       {\r
+                                               return hCNode\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       return hCNode\r
+                               }\r
+                       }\r
+                       nNc++\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function findAttribute( hNode, sAtt )\r
+{\r
+       sAtt = sAtt.toLowerCase()\r
+       for( var nI = 0; nI < hNode.attributes.length; nI++ )\r
+       {\r
+               if( hNode.attributes.item( nI ).nodeName.toLowerCase() == sAtt )\r
+               {\r
+                       return hNode.attributes.item( nI ).nodeValue\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function getSubNodeByAttribute( hNode, sAtt, sAttValue )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               var nNc = 0\r
+               var nC  = 0\r
+               var hNodeChildren = hNode.childNodes\r
+               var hCNode = null\r
+               var sAttribute\r
+               sAttValue = sAttValue.toLowerCase()\r
+               while( nC < hNodeChildren.length )\r
+               {\r
+                       hCNode = hNodeChildren.item( nC++ )\r
+                       if( hCNode.nodeType == document.ELEMENT_NODE )\r
+                       {\r
+                               sAttribute = hCNode.getAttribute( sAtt )\r
+                               if( sAttribute && sAttribute.toLowerCase() == sAttValue )\r
+                               return hCNode\r
+                       }\r
+                       nNc++\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function getLastSubNodeByAttribute( hNode, sAtt, sAttValue )\r
+{\r
+       if( hNode != null )\r
+       {\r
+               var nNc = 0\r
+               var nC  = 0\r
+               var hNodeChildren = hNode.childNodes\r
+               var hCNode = null\r
+               var nLength = hNodeChildren.length - 1\r
+               while( nLength >= 0 )\r
+               {\r
+                       hCNode = hNodeChildren.item( nLength )\r
+                       if( hCNode.nodeType == document.ELEMENT_NODE )\r
+                       {\r
+                               sAttribute = hCNode.getAttribute( sAtt )\r
+                               if( sAttribute && sAttribute.toLowerCase() == sAttValue )\r
+                               return hCNode\r
+                       }\r
+                       nLength--\r
+               }\r
+       }\r
+       return null\r
+}\r
+\r
+function getParentByTagName( hNode, sParentTagName )\r
+{\r
+       while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )\r
+       {\r
+               if( hNode.tagName == sParentTagName )\r
+               {\r
+                       return hNode\r
+               }\r
+               hNode = hNode.parentNode\r
+       }\r
+       return null\r
+}\r
+\r
+function getParentByAttribute( hNode, sAtt, sAttValue )\r
+{\r
+       while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )\r
+       {\r
+               //opera strangely returns non null result sometimes\r
+               var sAttr = hNode.getAttribute( sAtt )\r
+               if( sAttr != null && sAttr.toString().length > 0 )\r
+               {       \r
+                       if( sAttValue !== null )\r
+                       {\r
+                               if( sAttr == sAttValue )\r
+                               {\r
+                                       return hNode\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               return hNode\r
+                       }\r
+               }\r
+               hNode = hNode.parentNode\r
+       }\r
+       return null\r
+}\r
+\r
+function getParentByProperty( hNode, sProperty, sPropValue )\r
+{\r
+       while( ( hNode.tagName ) && !( /(body|html)/i.test( hNode.tagName ) ) )\r
+       {\r
+               //opera strangely returns non null result sometimes\r
+               var hProp = eval( 'hNode.'+sProperty )\r
+               if( hProp != null && hProp.toString().length > 0 )\r
+               {       \r
+                       if( sPropValue !== null )\r
+                       {\r
+                               if( hProp == sPropValue )\r
+                               {\r
+                                       return hNode\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               return hNode\r
+                       }\r
+               }\r
+               hNode = hNode.parentNode\r
+       }\r
+       return null\r
+}\r
+\r
+\r
+function getNodeText( hNode )\r
+{\r
+       if( hNode == null )\r
+       {\r
+               return ''\r
+       }\r
+       var sRes\r
+       if( hNode.hasChildNodes() )\r
+       {\r
+               sRes = hNode.childNodes.item(0).nodeValue\r
+       }\r
+       else\r
+       {\r
+               sRes = hNode.text\r
+       }\r
+       return sRes\r
+}
\ No newline at end of file
diff --git a/autocomplete/js/shBrushJScript.js b/autocomplete/js/shBrushJScript.js
new file mode 100644 (file)
index 0000000..e61a767
--- /dev/null
@@ -0,0 +1,22 @@
+dp.sh.Brushes.JScript = function()\r
+{\r
+       var keywords =  'abstract boolean break byte case catch char class const continue debugger ' +\r
+                                       'default delete do double else enum export extends false final finally float ' +\r
+                                       'for function goto if implements import in instanceof int interface long native ' +\r
+                                       'new null package private protected public return short static super switch ' +\r
+                                       'synchronized this throw throws transient true try typeof var void volatile while with';\r
+\r
+       this.regexList = [\r
+               { regex: new RegExp('//.*$', 'gm'),                                                     css: 'comment' },                       // one line comments\r
+               { regex: new RegExp('/\\*[\\s\\S]*?\\*/', 'g'),                         css: 'comment' },                       // multiline comments\r
+               { regex: new RegExp('"(?:\\.|[^\\""])*"', 'g'),                         css: 'string' },                        // double quoted strings\r
+               { regex: new RegExp('\'(?:\\.|[^\\\'\'])*\'', 'g'),                     css: 'string' },                        // single quoted strings\r
+               { regex: new RegExp('^\\s*#.*', 'gm'),                                          css: 'preprocessor' },          // preprocessor tags like #region and #endregion\r
+               { regex: new RegExp(this.GetKeywords(keywords), 'gm'),          css: 'keyword' }                        // keywords\r
+               ];\r
+\r
+       this.CssClass = 'dp-c';\r
+}\r
+\r
+dp.sh.Brushes.JScript.prototype        = new dp.sh.Highlighter();\r
+dp.sh.Brushes.JScript.Aliases  = ['js', 'jscript', 'javascript'];\r
diff --git a/autocomplete/js/shBrushXml.js b/autocomplete/js/shBrushXml.js
new file mode 100644 (file)
index 0000000..941ad57
--- /dev/null
@@ -0,0 +1,61 @@
+dp.sh.Brushes.Xml = function()\r
+{\r
+       this.CssClass = 'dp-xml';\r
+}\r
+\r
+dp.sh.Brushes.Xml.prototype    = new dp.sh.Highlighter();\r
+dp.sh.Brushes.Xml.Aliases      = ['xml', 'xhtml', 'xslt', 'html', 'xhtml'];\r
+\r
+dp.sh.Brushes.Xml.prototype.ProcessRegexList = function()\r
+{\r
+       function push(array, value)\r
+       {\r
+               array[array.length] = value;\r
+       }\r
+       \r
+       /* If only there was a way to get index of a group within a match, the whole XML\r
+          could be matched with the expression looking something like that:\r
+       \r
+          (<!\[CDATA\[\s*.*\s*\]\]>)\r
+          | (<!--\s*.*\s*?-->)\r
+          | (<)*(\w+)*\s*(\w+)\s*=\s*(".*?"|'.*?'|\w+)(/*>)*\r
+          | (</?)(.*?)(/?>)\r
+       */\r
+       var index       = 0;\r
+       var match       = null;\r
+       var regex       = null;\r
+\r
+       // Match CDATA in the following format <![ ... [ ... ]]>\r
+       // <\!\[[\w\s]*?\[(.|\s)*?\]\]>\r
+       this.GetMatches(new RegExp('<\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\]>', 'gm'), 'cdata');\r
+       \r
+       // Match comments\r
+       // <!--\s*.*\s*?-->\r
+       this.GetMatches(new RegExp('<!--\\s*.*\\s*?-->', 'gm'), 'comments');\r
+\r
+       // Match attributes and their values\r
+       // (\w+)\s*=\s*(".*?"|\'.*?\'|\w+)*\r
+       regex = new RegExp('([\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*', 'gm');\r
+       while((match = regex.exec(this.code)) != null)\r
+       {\r
+               push(this.matches, new dp.sh.Match(match[1], match.index, 'attribute'));\r
+       \r
+               // if xml is invalid and attribute has no property value, ignore it     \r
+               if(match[2] != undefined)\r
+               {\r
+                       push(this.matches, new dp.sh.Match(match[2], match.index + match[0].indexOf(match[2]), 'attribute-value'));\r
+               }\r
+       }\r
+\r
+       // Match opening and closing tag brackets\r
+       // </*\?*(?!\!)|/*\?*>\r
+       this.GetMatches(new RegExp('</*\\?*(?!\\!)|/*\\?*>', 'gm'), 'tag');\r
+\r
+       // Match tag names\r
+       // </*\?*\s*(\w+)\r
+       regex = new RegExp('</*\\?*\\s*([\\w-\.]+)', 'gm');\r
+       while((match = regex.exec(this.code)) != null)\r
+       {\r
+               push(this.matches, new dp.sh.Match(match[1], match.index + match[0].indexOf(match[1]), 'tag-name'));\r
+       }\r
+}\r
diff --git a/autocomplete/js/shCore.js b/autocomplete/js/shCore.js
new file mode 100644 (file)
index 0000000..e53e02c
--- /dev/null
@@ -0,0 +1,589 @@
+/**\r
+ * Code Syntax Highlighter. Version 1.1.0\r
+ * Copyright (C) 2004 Dream Projections Inc.\r
+ * \r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ *\r
+ **\r
+ * Usage example:\r
+ *\r
+ * <script src="shCore.js" language="javascript"></script>\r
+ * <script src="shBrushXml.js" language="javascript"></script>\r
+ *\r
+ * <textarea name="code" language="html">\r
+ * <img src="myimage.gif" border="0">\r
+ * </textarea>\r
+ *\r
+ * <script>dp.SyntaxHighlighter.HighlightAll('code', 'value');</script>\r
+ *\r
+ **\r
+ * History:\r
+ * 1.1.0 - March 23rd, 2005\r
+ *    - split brushes into separate files\r
+ *    - now works in Safari\r
+ *    - added missing strings to PHP matches\r
+ *\r
+ * 1.0.4 - February 2nd, 2005\r
+ *    - added Delphi & Python\r
+ *    - multi-line comments fixed\r
+ *    - language name can be set through w3c valid 'class' attribute\r
+ *    - HighlightAll(name, [showGutter], [showTools])\r
+ *\r
+ * 1.0.3 - December 31th, 2004 (added PHP & SQL)\r
+ * 1.0.2 - December 28th, 2004 (refactoring with namespaces)\r
+ * 1.0.1 - December 14th, 2004\r
+ * 1.0.0 - November 13th, 2004\r
+ */\r
+\r
+// create namespaces\r
+var dp = {\r
+       sh :                                            // dp.sh\r
+       {\r
+                       Utils   : {},           // dp.sh.Utils\r
+                       Brushes : {}            // dp.sh.Brushes\r
+       }\r
+};\r
+\r
+dp.sh.Config = {\r
+       Version : '1.1.0',\r
+       About   : '<html><head><title>About...</title></head><body class="dp-about"><table cellspacing="0"><tr><td class="copy"><div class="para title">dp.SyntaxHighlighter</div><div class="para">Version: {V}</div><div class="para"><a href="http://www.dreamprojections.com/sh/?ref=about" target="_blank">http://www.dreamprojections.com/SyntaxHighlighter</a></div>&copy;2004-2005 Dream Projections Inc. All right reserved.</td></tr><tr><td class="footer"><input type="button" class="close" value="OK" onClick="window.close()"/></td></tr></table></body></html>'\r
+};\r
+\r
+dp.SyntaxHighlighter = dp.sh;\r
+\r
+\r
+\r
+// opens a new windows and puts the original unformatted source code inside.\r
+dp.sh.Utils.ViewSource = function(sender)\r
+{\r
+       var code = sender.parentNode.originalCode;\r
+       var wnd = window.open('', '_blank', 'width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=1');\r
+       \r
+       code = code.replace(/</g, '&lt;');\r
+       \r
+       wnd.document.write('<pre>' + code + '</pre>');\r
+       wnd.document.close();\r
+}\r
+\r
+// copies the original source code in to the clipboard (IE only)\r
+dp.sh.Utils.ToClipboard = function(sender)\r
+{\r
+       var code = sender.parentNode.originalCode;\r
+       \r
+       // This works only for IE. There's a way to make it work with Mozilla as well,\r
+       // but it requires security settings changed on the client, which isn't by\r
+       // default, so 99% of users won't have it working anyways.\r
+       if(window.clipboardData)\r
+       {\r
+               window.clipboardData.setData('text', code);\r
+               \r
+               alert('The code is in your clipboard now.');\r
+       }\r
+}\r
+\r
+// creates an invisible iframe, puts the original source code inside and prints it\r
+dp.sh.Utils.PrintSource = function(sender)\r
+{\r
+       var td          = sender.parentNode;\r
+       var code        = td.processedCode;\r
+       var iframe      = document.createElement('IFRAME');\r
+       var doc         = null;\r
+       var wnd         = \r
+\r
+       // this hides the iframe\r
+       iframe.style.cssText = 'position:absolute; width:0px; height:0px; left:-5px; top:-5px;';\r
+       \r
+       td.appendChild(iframe);\r
+       \r
+       doc             = iframe.contentWindow.document;\r
+       code    = code.replace(/</g, '&lt;');\r
+       \r
+       doc.open();\r
+       doc.write('<pre>' + code + '</pre>');\r
+       doc.close();\r
+       \r
+       iframe.contentWindow.focus();\r
+       iframe.contentWindow.print();\r
+       \r
+       td.removeChild(iframe);\r
+}\r
+\r
+dp.sh.Utils.About = function()\r
+{\r
+       var wnd = window.open('', '_blank', 'dialog, width=320, height=150');\r
+       var doc = wnd.document;\r
+       \r
+       var styles      = document.getElementsByTagName('style');\r
+       var links       = document.getElementsByTagName('link');\r
+       \r
+       doc.write(dp.sh.Config.About.replace('{V}', dp.sh.Config.Version));\r
+       \r
+       // copy over ALL the styles from the parent page\r
+       for(var i = 0; i < styles.length; i++)\r
+               doc.write('<style>' + styles[i].innerHTML + '</style>');\r
+\r
+       for(var i = 0; i < links.length; i++)\r
+               if(links[i].rel.toLowerCase() == 'stylesheet')\r
+                       doc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');\r
+       \r
+       doc.close();\r
+       wnd.focus();\r
+}\r
+\r
+\r
+\r
+\r
+\r
+// creates a new match object\r
+dp.sh.Match = function(value, index, css)\r
+{\r
+       this.value              = value;\r
+       this.index              = index;\r
+       this.length             = value.length;\r
+       this.css                = css;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+dp.sh.Highlighter = function()\r
+{\r
+       this.addGutter          = true;\r
+       this.addControls        = true;\r
+       this.tabsToSpaces       = true;\r
+}\r
+\r
+// static callback for the match sorting\r
+dp.sh.Highlighter.SortCallback = function(m1, m2)\r
+{\r
+       // sort matches by index first\r
+       if(m1.index < m2.index)\r
+               return -1;\r
+       else if(m1.index > m2.index)\r
+               return 1;\r
+       else\r
+       {\r
+               // if index is the same, sort by length\r
+               if(m1.length < m2.length)\r
+                       return -1;\r
+               else if(m1.length > m2.length)\r
+                       return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+// gets a list of all matches for a given regular expression\r
+dp.sh.Highlighter.prototype.GetMatches = function(regex, css)\r
+{\r
+       var index = 0;\r
+       var match = null;\r
+\r
+       while((match = regex.exec(this.code)) != null)\r
+       {\r
+               this.matches[this.matches.length] = new dp.sh.Match(match[0], match.index, css);\r
+       }\r
+}\r
+\r
+dp.sh.Highlighter.prototype.AddBit = function(str, css)\r
+{\r
+       var span = document.createElement('span');\r
+       \r
+       str = str.replace(/&/g, '&amp;');\r
+       str = str.replace(/ /g, '&nbsp;');\r
+       str = str.replace(/</g, '&lt;');\r
+       str = str.replace(/\n/gm, '&nbsp;<br>');\r
+\r
+       // when adding a piece of code, check to see if it has line breaks in it \r
+       // and if it does, wrap individual line breaks with span tags\r
+       if(css != null)\r
+       {\r
+               var regex = new RegExp('<br>', 'gi');\r
+               \r
+               if(regex.test(str))\r
+               {\r
+                       var lines = str.split('&nbsp;<br>');\r
+                       \r
+                       str = '';\r
+                       \r
+                       for(var i = 0; i < lines.length; i++)\r
+                       {\r
+                               span                    = document.createElement('SPAN');\r
+                               span.className  = css;\r
+                               span.innerHTML  = lines[i];\r
+                               \r
+                               this.div.appendChild(span);\r
+                               \r
+                               // don't add a <BR> for the last line\r
+                               if(i + 1 < lines.length)\r
+                               {\r
+                                       this.div.appendChild(document.createElement('BR'));\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       span.className = css;\r
+                       span.innerHTML = str;\r
+                       this.div.appendChild(span);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               span.innerHTML = str;\r
+               this.div.appendChild(span);\r
+       }\r
+}\r
+\r
+// checks if one match is inside another\r
+dp.sh.Highlighter.prototype.IsInside = function(match)\r
+{\r
+       if(match == null || match.length == 0)\r
+       {\r
+               return;\r
+       }\r
+       \r
+       for(var i = 0; i < this.matches.length; i++)\r
+       {\r
+               var c = this.matches[i];\r
+               \r
+               if(c == null)\r
+               {\r
+                       continue;\r
+               }\r
+               \r
+               if((match.index > c.index) && (match.index <= c.index + c.length))\r
+               {\r
+                       return true;\r
+               }\r
+       }\r
+       \r
+       return false;\r
+}\r
+\r
+dp.sh.Highlighter.prototype.ProcessRegexList = function()\r
+{\r
+       for(var i = 0; i < this.regexList.length; i++)\r
+       {\r
+               this.GetMatches(this.regexList[i].regex, this.regexList[i].css);\r
+       }\r
+}\r
+\r
+dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code)\r
+{\r
+       var lines       = code.split('\n');\r
+       var result      = '';\r
+       var tabSize     = 4;\r
+       var tab         = '\t';\r
+\r
+       // This function inserts specified amount of spaces in the string\r
+       // where a tab is while removing that given tab. \r
+       function InsertSpaces(line, pos, count)\r
+       {\r
+               var left        = line.substr(0, pos);\r
+               var right       = line.substr(pos + 1, line.length);    // pos + 1 will get rid of the tab\r
+               var spaces      = '';\r
+               \r
+               for(var i = 0; i < count; i++)\r
+               {\r
+                       spaces += ' ';\r
+               }\r
+               \r
+               return left + spaces + right;\r
+       }\r
+\r
+       // This function process one line for 'smart tabs'\r
+       function ProcessLine(line, tabSize)\r
+       {\r
+               if(line.indexOf(tab) == -1)\r
+               {\r
+                       return line;\r
+               }\r
+\r
+               var pos = 0;\r
+\r
+               while((pos = line.indexOf(tab)) != -1)\r
+               {\r
+                       // This is pretty much all there is to the 'smart tabs' logic.\r
+                       // Based on the position within the line and size of a tab, \r
+                       // calculate the amount of spaces we need to insert.\r
+                       var spaces = tabSize - pos % tabSize;\r
+                       \r
+                       line = InsertSpaces(line, pos, spaces);\r
+               }\r
+               \r
+               return line;\r
+       }\r
+\r
+       // Go through all the lines and do the 'smart tabs' magic.\r
+       for(var i = 0; i < lines.length; i++)\r
+       {\r
+               var line = lines[i];\r
+               result += ProcessLine(line, tabSize) + '\n';\r
+       }\r
+       \r
+       return result;\r
+}\r
+\r
+dp.sh.Highlighter.prototype.SwitchToTable = function()\r
+{\r
+       // Safari fix: for some reason lowercase <br> isn't getting picked up, even though 'i' is set\r
+       var lines       = this.div.innerHTML.split(/<BR>/gi);\r
+       var row         = null;\r
+       var cell        = null;\r
+       var html        = '';\r
+       var pipe        = ' | ';\r
+\r
+       // creates an anchor to a utility\r
+       function UtilHref(util, text)\r
+       {\r
+               return '<a href="#" onclick="dp.sh.Utils.' + util + '(this); return false;">' + text + '</a>';\r
+       }\r
+       \r
+       row = this.table.insertRow(-1);\r
+       \r
+       if(this.addGutter == true)\r
+       {\r
+               cell                    = row.insertCell(-1);\r
+               cell.className  = 'tools-corner';\r
+       }\r
+\r
+       if(this.addControls == true)\r
+       {\r
+               cell                    = row.insertCell(-1);\r
+               \r
+               cell.originalCode       = this.originalCode;\r
+               cell.processedCode      = this.code;\r
+               \r
+               cell.className          = 'tools';\r
+               cell.innerHTML          = UtilHref('ViewSource', 'view plain') + pipe + UtilHref('PrintSource', 'print');\r
+               \r
+               if(window.clipboardData)\r
+               {\r
+                       cell.innerHTML += pipe + UtilHref('ToClipboard', 'copy to clipboard');\r
+               }\r
+               \r
+               cell.innerHTML += pipe + UtilHref('About', '?');\r
+       }\r
+\r
+       for(var i = 0; i < lines.length - 1; i++)\r
+       {\r
+               row = this.table.insertRow(-1);\r
+               \r
+               if(this.addGutter == true)\r
+               {\r
+                       cell                    = row.insertCell(-1);\r
+                       cell.className  = 'gutter';\r
+                       cell.innerHTML  = i + 1;\r
+               }\r
+\r
+               cell                    = row.insertCell(-1);\r
+               cell.className  = 'line';\r
+               cell.innerHTML  = lines[i];\r
+       }\r
+       \r
+       this.div.innerHTML      = '';\r
+}\r
+\r
+dp.sh.Highlighter.prototype.Highlight = function(code)\r
+{\r
+       // This function strips all new lines and spaces\r
+       // from the beging and end of the string .\r
+       function Trim(str)\r
+       {\r
+               var begining    = new RegExp('^[\\s\\n]', 'g');\r
+               var end                 = new RegExp('[\\s\\n]$', 'g');\r
+\r
+               while(begining.test(str))\r
+               {\r
+                       str = str.substr(1);\r
+               }\r
+\r
+               while(end.test(str))\r
+               {\r
+                       str = str.substr(0, str.length - 1);\r
+               }\r
+               \r
+               return str;\r
+       }\r
+       \r
+       // This function returns a portions of the string \r
+       // from pos1 to pos2 inclusive.\r
+       function Copy(string, pos1, pos2)\r
+       {\r
+               return string.substr(pos1, pos2 - pos1);\r
+       }\r
+\r
+       var pos = 0;\r
+       \r
+       this.originalCode       = code;\r
+       this.code                       = Trim(code);\r
+       this.div                        = document.createElement('DIV');\r
+       this.table                      = document.createElement('TABLE');\r
+       this.matches            = new Array();\r
+       \r
+       if(this.CssClass != null)\r
+       {\r
+               this.table.className = this.CssClass;\r
+       }\r
+\r
+       // replace tabs with spaces\r
+       if(this.tabsToSpaces == true)\r
+       {\r
+               this.code = this.ProcessSmartTabs(this.code);\r
+       }\r
+\r
+       this.table.border               = 0;\r
+       this.table.cellSpacing  = 0;\r
+       this.table.cellPadding  = 0;\r
+\r
+       this.ProcessRegexList();        \r
+\r
+       // if no matches found, do nothing\r
+       if(this.matches.length == 0)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // sort the matches\r
+       this.matches = this.matches.sort(dp.sh.Highlighter.SortCallback);\r
+\r
+       // The following loop checks to see if any of the matches are inside\r
+       // of other matches. This process would get rid of highligting strings\r
+       // inside comments, keywords inside strings and so on.\r
+       for(var i = 0; i < this.matches.length; i++)\r
+       {\r
+               if(this.IsInside(this.matches[i]))\r
+               {\r
+                       this.matches[i] = null;\r
+               }\r
+       }\r
+\r
+       // Finally, go through the final list of matches and pull the all\r
+       // together adding everything in between that isn't a match.\r
+       for(var i = 0; i < this.matches.length; i++)\r
+       {\r
+               var match = this.matches[i];\r
+\r
+               if(match == null || match.length == 0)\r
+               {\r
+                       continue;\r
+               }\r
+               \r
+               this.AddBit(Copy(this.code, pos, match.index), null);\r
+               this.AddBit(match.value, match.css);\r
+               \r
+               pos = match.index + match.length;\r
+       }\r
+       \r
+       this.AddBit(this.code.substr(pos), null);\r
+\r
+       this.SwitchToTable();   \r
+}\r
+\r
+dp.sh.Highlighter.prototype.GetKeywords = function(str) \r
+{\r
+       return '\\b' + str.replace(/ /g, '\\b|\\b') + '\\b';\r
+}\r
+\r
+// highlightes all elements identified by name and gets source code from specified property\r
+dp.sh.HighlightAll = function(name, showGutter /* optional */, showControls /* optional */)\r
+{\r
+       var elements            = document.getElementsByName(name);\r
+       var highlighter         = null;\r
+       var registered          = new Object();\r
+       var propertyName        = 'value';\r
+       \r
+       function FindValue()\r
+       {\r
+               var a = arguments;\r
+               \r
+               for(var i = 0; i < a.length; i++)\r
+                       if(a[i] != null && ((typeof(a[i]) == 'string' && a[i] != '') || (typeof(a[i]) == 'object' && a[i].value != '')))\r
+                               return a[i];\r
+               \r
+               return null;\r
+       }\r
+       \r
+       if(elements == null)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // if showGutter isn't set, default to TRUE\r
+       if(showGutter == null)\r
+       {\r
+               showGutter = true;\r
+       }\r
+       \r
+       // if showControls isn't set, default to TRUE\r
+       if(showControls == null)\r
+       {\r
+               showControls = true;\r
+       }\r
+\r
+       // register all brushes\r
+       for(var brush in dp.sh.Brushes)\r
+       {\r
+               var aliases = dp.sh.Brushes[brush].Aliases;\r
+               \r
+               if(aliases == null)\r
+               {\r
+                       continue;\r
+               }\r
+               \r
+               for(var i = 0; i < aliases.length; i++)\r
+               {\r
+                       registered[aliases[i]] = brush;\r
+               }\r
+       }\r
+\r
+       for(var i = 0; i < elements.length; i++)\r
+       {\r
+               var element             = elements[i];\r
+               var language    = FindValue(element.attributes['class'], element.className, element.attributes['language'], element.language);\r
+               \r
+               if(language == null)\r
+                       continue;\r
+               \r
+               if(language.value)\r
+                       language = language.value;\r
+\r
+               language = (language + '').toLowerCase();\r
+               \r
+               if(registered[language] == null)\r
+               {\r
+                       continue;\r
+               }\r
+               \r
+               // instantiate a brush\r
+               highlighter = new dp.sh.Brushes[registered[language]]();\r
+               \r
+               // hide the original element\r
+               element.style.display = 'none';\r
+\r
+               highlighter.addGutter   = showGutter;\r
+               highlighter.addControls = showControls;\r
+               highlighter.Highlight(element[propertyName]);\r
+\r
+               // place the result table inside a div\r
+               var div = document.createElement('DIV');\r
+               \r
+               div.className = 'dp-highlighter';\r
+               div.appendChild(highlighter.table);\r
+\r
+               element.parentNode.insertBefore(div, element);          \r
+       }       \r
+}\r
diff --git a/autocomplete/js/tabs2.js b/autocomplete/js/tabs2.js
new file mode 100644 (file)
index 0000000..9d196c8
--- /dev/null
@@ -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 (file)
index 0000000..0c3cec0
--- /dev/null
@@ -0,0 +1,149 @@
+//<script>\r
+//////////////////\r
+// Helper Stuff //\r
+//////////////////\r
+\r
+// used to find the Automation server name\r
+function getDomDocumentPrefix() {\r
+       if (getDomDocumentPrefix.prefix)\r
+               return getDomDocumentPrefix.prefix;\r
+       \r
+       var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];\r
+       var o;\r
+       for (var i = 0; i < prefixes.length; i++) {\r
+               try {\r
+                       // try to create the objects\r
+                       o = new ActiveXObject(prefixes[i] + ".DomDocument");\r
+                       return getDomDocumentPrefix.prefix = prefixes[i];\r
+               }\r
+               catch (ex) {};\r
+       }\r
+       \r
+       throw new Error("Could not find an installed XML parser");\r
+}\r
+\r
+function getXmlHttpPrefix() {\r
+       if (getXmlHttpPrefix.prefix)\r
+               return getXmlHttpPrefix.prefix;\r
+       \r
+       var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];\r
+       var o;\r
+       for (var i = 0; i < prefixes.length; i++) {\r
+               try {\r
+                       // try to create the objects\r
+                       o = new ActiveXObject(prefixes[i] + ".XmlHttp");\r
+                       return getXmlHttpPrefix.prefix = prefixes[i];\r
+               }\r
+               catch (ex) {};\r
+       }\r
+       \r
+       throw new Error("Could not find an installed XML parser");\r
+}\r
+\r
+//////////////////////////\r
+// Start the Real stuff //\r
+//////////////////////////\r
+\r
+\r
+// XmlHttp factory\r
+function XmlHttp() {}\r
+\r
+XmlHttp.create = function () {\r
+       try {\r
+               if (window.XMLHttpRequest) {\r
+                       var req = new XMLHttpRequest();\r
+                       \r
+                       // some versions of Moz do not support the readyState property\r
+                       // and the onreadystate event so we patch it!\r
+                       if (req.readyState == null) {\r
+                               req.readyState = 1;\r
+                               req.addEventListener("load", function () {\r
+                                       req.readyState = 4;\r
+                                       if (typeof req.onreadystatechange == "function")\r
+                                               req.onreadystatechange();\r
+                               }, false);\r
+                       }\r
+                       \r
+                       return req;\r
+               }\r
+               if (window.ActiveXObject) {\r
+                       return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");\r
+               }\r
+       }\r
+       catch (ex) {}\r
+       // fell through\r
+       throw new Error("Your browser does not support XmlHttp objects");\r
+};\r
+\r
+// XmlDocument factory\r
+function XmlDocument() {}\r
+\r
+XmlDocument.create = function () {\r
+       try {\r
+               // DOM2\r
+               if (document.implementation && document.implementation.createDocument) {\r
+                       var doc = document.implementation.createDocument("", "", null);\r
+                       \r
+                       // some versions of Moz do not support the readyState property\r
+                       // and the onreadystate event so we patch it!\r
+                       if (doc.readyState == null) {\r
+                               doc.readyState = 1;\r
+                               doc.addEventListener("load", function () {\r
+                                       doc.readyState = 4;\r
+                                       if (typeof doc.onreadystatechange == "function")\r
+                                               doc.onreadystatechange();\r
+                               }, false);\r
+                       }\r
+                       \r
+                       return doc;\r
+               }\r
+               if (window.ActiveXObject)\r
+                       return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");\r
+       }\r
+       catch (ex) {}\r
+       throw new Error("Your browser does not support XmlDocument objects");\r
+};\r
+\r
+// Create the loadXML method and xml getter for Mozilla\r
+if (window.DOMParser &&\r
+       window.XMLSerializer &&\r
+       window.Node && Node.prototype && Node.prototype.__defineGetter__) {\r
+\r
+       // XMLDocument did not extend the Document interface in some versions\r
+       // of Mozilla. Extend both!\r
+       //XMLDocument.prototype.loadXML = \r
+       Document.prototype.loadXML = function (s) {\r
+               \r
+               // parse the string to a new doc        \r
+               var doc2 = (new DOMParser()).parseFromString(s, "text/xml");\r
+               \r
+               // remove all initial children\r
+               while (this.hasChildNodes())\r
+                       this.removeChild(this.lastChild);\r
+                       \r
+               // insert and import nodes\r
+               for (var i = 0; i < doc2.childNodes.length; i++) {\r
+                       this.appendChild(this.importNode(doc2.childNodes[i], true));\r
+               }\r
+       };\r
+       \r
+       \r
+       /*\r
+        * xml getter\r
+        *\r
+        * This serializes the DOM tree to an XML String\r
+        *\r
+        * Usage: var sXml = oNode.xml\r
+        *\r
+        */\r
+       // XMLDocument did not extend the Document interface in some versions\r
+       // of Mozilla. Extend both!\r
+       /*\r
+       XMLDocument.prototype.__defineGetter__("xml", function () {\r
+               return (new XMLSerializer()).serializeToString(this);\r
+       });\r
+       */\r
+       Document.prototype.__defineGetter__("xml", function () {\r
+               return (new XMLSerializer()).serializeToString(this);\r
+       });\r
+}
\ No newline at end of file
diff --git a/autocomplete/license.txt b/autocomplete/license.txt
new file mode 100644 (file)
index 0000000..277b47a
--- /dev/null
@@ -0,0 +1,10 @@
+Copyright (c) 2004-2005, Mircho Mirev\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r
+\r
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r
+    * Neither the name of Mircho Mirev nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
index 7e7d4dd8ff6ad0ac067d13c54b15408459a4eb2f..9c1126dc4a7479a44d2348ec609a5420bbe3861e 100644 (file)
@@ -689,6 +689,45 @@ class PHPFSPOT {
 
    } // resetTags()
 
+   /**
+    * returns the value for the autocomplet tag-search
+    */
+   public function get_xml_tag_list()
+   {
+      if(!isset($_GET['search']) || !is_string($_GET['search']))
+         $_GET['search'] = '';
+      
+      if(!isset($_GET['length']) || !is_numeric($_GET['length']))
+         $_GET['length'] = 5;
+         
+         
+      /* retrive tags from database */
+      $this->get_tags();
+
+      $matched_tags = Array();
+
+      foreach($this->avail_tags as $tag)
+      {
+         if(!empty($_GET['search']) &&
+            preg_match("/". $_GET['search'] ."/i", $this->tags[$tag]) &&
+            count($matched_tags) < $_GET['length']) {
+
+            array_push($matched_tags, $this->tags[$tag] .",". $this->tags[$tag]);
+         }
+
+         /* if we have collected enough items, break out */
+         if(count($matched_tags) >= $_GET['length'])
+            break;
+      }
+
+      if(empty($matched_tags))
+         return;
+
+      return implode('|', $matched_tags);
+
+   } // get_xml_tag_list()
+
+
    /**
     * reset single photo
     *
diff --git a/rpc.php b/rpc.php
index f850dad42e8d61306861f85639965bfe274b0942..786bc7d56103b28e0fd44b58c43ad52d491735d5 100644 (file)
--- a/rpc.php
+++ b/rpc.php
@@ -58,6 +58,10 @@ class PHPFSPOT_RPC {
             }
             break;
    
+         case 'getxmltaglist':
+            print $fspot->get_xml_tag_list();
+            break;
+
          case 'show_available_tags':
             print $fspot->getAvailableTags();
             break;
index c233bb341a6ce0e54c13cbba88ca3de6ef8b6d36..f98705a59741ead4c4a07fc9468e5c85969a7219 100644 (file)
   <script type="text/javascript" src="lightbox2/js/lightbox.js"></script>
   <link rel="stylesheet" href="lightbox2/css/lightbox.css" type="text/css" media="screen" />
   { /if }
+  { if ! $use_autocomplete }
+  <link rel="stylesheet" href="autocomplete/css/dropdown.css" type="text/css" media="screen" />
+  <script src="autocomplete/js/modomevent3.js"></script>
+  <script src="autocomplete/js/modomt.js"></script>
+  <script src="autocomplete/js/modomext.js"></script>
+  <script src="autocomplete/js/getobject2.js"></script>
+  <script src="autocomplete/js/xmlextras.js"></script>
+  <script src="autocomplete/js/acdropdown.js"></script>
+  <script src="autocomplete/js/ieselect.js"></script>
+  <script language="javascript" src="autocomplete/js/shCore.js" ></script>
+  { /if }
  </head>                                                                                                      
index 10800e1441e34342eb2b519b3099ce5ecf8a83ed..e6baaa92a4e87f9f704f3632a7e472dae4207ee8 100644 (file)
@@ -7,7 +7,11 @@
  <tr>
   <td>Tag:</td>
   <td>
+   { if ! $use_autocomplete }
+   <input type="text" name="searchfor_tag" value="{$searchfor_tag}" size="15" acdropdown="true" autocomplete_list="url:rpc.php?action=getxmltaglist&amp;search=[S]&amp;length=10" />
+   { else }
    <input type="text" name="searchfor_tag" value="{$searchfor_tag}" size="15" />
+   { /if }
   </td>
   <td>
    <input type="image" class="submit" src="resources/doit.png" alt="start search" title="start search" onclick="click(this);" />