/[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 32 - (show annotations)
Sat Sep 25 22:13:13 2004 UTC (19 years, 7 months ago) by dpavlin
File MIME type: application/javascript
File size: 5724 byte(s)
once again, API changes: now there are following fuctions
for generating results:

- reset_results (clear results list)
- result (add one result)
- show_results (called after all results)
- filter (filter entries, with timeout)
- show_filter (filter entries, without timeout)

Hopefully, this is last major change in API

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

  ViewVC Help
Powered by ViewVC 1.1.26