/[bfilter]/trunk/bfilter.js
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/bfilter.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (show annotations)
Fri Sep 24 16:58:08 2004 UTC (19 years, 7 months ago) by dpavlin
File MIME type: application/javascript
File size: 5481 byte(s)
implemented timeout to start filtering (by default 200ms)

1 /*
2 Fast filtering function using pre-sorted list elements
3 Dobrica Pavlinusic, dpavlin@rot13.org 2004-09-06
4 Matko Andjelinic, matko.andjelinic@gmail.com 2004-09-09 (contributed OO implementation)
5 */
6
7 top.__bfilter_obj = new Array();
8
9
10 function BFilter(arr) {
11 this.id_cache = Array();
12 // total number of hits
13 this.hits = 0;
14
15 // store reference to this object for later (YAK)
16 this.obj_count = top.__bfilter_obj.length;
17 top.__bfilter_obj[this.obj_count] = this;
18
19 // clear results html
20 this.results_html = '';
21
22 // show results after 0.2s
23 this.timeout = 200;
24 this.timeout_handle = null;
25
26 // this function is called for each result
27 this.result = function (arr) {
28 this.results_html += '<li><a href="'+arr[1]+'">'+
29 (this.hits % 2 == 0 ? '<span style="background: #e0e0e0;">' : '') +
30 arr[0] +
31 (this.hits % 2 == 0 ? '</span>' : '') +
32 '</a></li>';
33 return true;
34 }
35
36 // this function is called when updating innerHTML with results
37 this.display = function () {
38 if (this.results_html) {
39 return '<ul>'+this.results_html+'</ul>';
40 } else {
41 return null;
42 }
43 }
44
45
46 if (! arr) {
47 this.debug("ERROR: can't search empty array");
48 return;
49 }
50
51 this.arr = arr;
52 this.debug("index has "+this.arr.length+" parts");
53
54 if (! arr.min_len) {
55 this.results("ERROR: index structure problem");
56 return;
57 } else {
58 this.min_len = arr.min_len;
59 }
60
61 this.debug("index part has "+this.min_len+" parts");
62
63 this.show_status();
64
65 }
66
67 BFilter.prototype.element_id = function (id,no_alert) {
68 if (this.id_cache[id]) {
69 return this.id_cache[id];
70 } else {
71 var el = self.document.getElementById(id);
72 if (el) {
73 this.id_cache[id] = el;
74 return el;
75 } else {
76 if (! no_alert) {
77 alert("can't find element id: "+id);
78 } else {
79 // don't look it up again
80 this.id_cache[id] = null;
81 }
82 }
83 }
84 return null;
85 }
86
87
88 BFilter.prototype.show_status = function (status) {
89 var html;
90 if (this.hits > 0) {
91 html = "shown "+this.hits+" entries";
92 } else {
93 html = "no results";
94 }
95 if (! status) {
96 html = "Enter "+this.min_len+" letter"+(this.min_len == 1 ? '' : 's')+" to filter entries";
97 status = "";
98 }
99
100 var el = this.element_id("status");
101 el.innerHTML = html+status+"\n";
102 }
103
104 BFilter.prototype.results = function (html,clean) {
105
106 if (! html) { html = ""; }
107
108 // results_div.style.cursor = 'wait'; // 'auto'
109 var results_div = this.element_id("results");
110 if (clean) {
111 results_div.innerHTML = html;
112 this.results_html = '';
113 } else {
114 html = this.display();
115 if (html) results_div.innerHTML += html;
116 }
117 }
118
119
120 BFilter.prototype.debug = function (html) {
121
122 //return;
123
124 // check if debugging is on
125 if (! html) { return 1; }
126
127 var debug_div = this.element_id("debug",1);
128 if (! debug_div) { return null; }
129
130 debug_div.innerHTML += html + "<br>\n";
131
132 return null;
133 }
134
135
136 // modified binary search to find first element with substring
137 BFilter.prototype.binarySearch = function (arr, user_filter) {
138 if (!arr || typeof (user_filter) == "undefined" || !arr.length) {
139 return null;
140 }
141 var low = 0;
142 var high = arr.length - 1;
143 var middlearr = parseInt(arr.length / 2);
144 var lastTry;
145 while (low <= high) {
146 var mid = (low + high) / 2;
147 var aTry = (mid < 1) ? 0 : parseInt(mid);
148
149 var curr = arr[aTry][0].substr(0,user_filter.length).toLowerCase();
150 this.debug("low="+low+" high="+high+" lastTry="+lastTry+" "+aTry+": "+curr);
151 if (curr < user_filter) {
152 low = aTry + 1;
153 continue;
154 }
155 if (curr > user_filter) {
156 high = aTry - 1;
157 continue;
158 }
159 if (curr == user_filter) {
160 high = aTry - 1;
161 lastTry = aTry;
162 continue;
163 }
164 return aTry;
165 }
166 this.debug("lastTry="+lastTry);
167
168 if (typeof (lastTry) != "undefined") {
169 return lastTry;
170 } else {
171 return null;
172 }
173 }
174
175 BFilter.prototype.filter = function (user_filter) {
176 this.debug("set timeout for "+this.obj_count+" to "+this.timeout);
177 if (this.timeout_handle) {
178 clearTimeout(this.timeout_handle);
179 this.timeout_handle = null;
180 }
181 this.timeout_handle=setTimeout("top.__bfilter_obj["+this.obj_count+"].show_filter('"+user_filter.replace(/'/,"\\'")+"');", this.timeout);
182 return true;
183 }
184
185 BFilter.prototype.show_filter = function (user_filter) {
186
187 if (this.timeout_handle) {
188 clearTimeout(this.timeout_handle);
189 this.timeout_handle = null;
190 this.debug("timeout cleared");
191 }
192
193 this.results('',1);
194 this.hits = 0;
195
196 if (user_filter.length < this.min_len) {
197 this.show_status();
198 return;
199 }
200
201 this.debug("filter: '"+user_filter+"'");
202
203 var user_filter_lc = user_filter.toLowerCase();
204
205 var part = user_filter_lc.substr(0,this.min_len);
206
207 // no part found
208 if (! this.arr[part]) {
209 this.show_status(" for <em>"+user_filter+"</em><br>");
210 this.debug("no part "+part);
211 return;
212 }
213
214 // start anim icon
215 //results("<img src=\"pie.gif\">&nbsp;Please wait, filtering...\n",1);
216
217 var i;
218
219 // full part? (optimization)
220 if (user_filter.length == this.min_len) {
221 for (i = 0; i < this.arr[part].length; i++) {
222 this.result(this.arr[part][i]);
223 this.hits++;
224 }
225 this.results();
226 } else {
227
228 var from = this.binarySearch(this.arr[part], user_filter_lc);
229
230 if (from != null) {
231
232 this.debug("loop "+from+" ... "+this.arr[part].length);
233
234 for(i = from ; i < this.arr[part].length ; i++) {
235 if (this.arr[part][i][0].substring(0,user_filter.length).toLowerCase() != user_filter_lc) {
236 this.debug("loop exit at "+i);
237 break;
238 }
239 this.result(this.arr[part][i]);
240 this.hits++;
241 }
242
243 this.results();
244 }
245
246 }
247
248 this.show_status(" for <em>"+user_filter+"</em>");
249
250 }
251

  ViewVC Help
Powered by ViewVC 1.1.26