/[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

Annotation of /trunk/bfilter.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide 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 dpavlin 1 /*
2     Fast filtering function using pre-sorted list elements
3     Dobrica Pavlinusic, dpavlin@rot13.org 2004-09-06
4 dpavlin 10 Matko Andjelinic, matko.andjelinic@gmail.com 2004-09-09 (contributed OO implementation)
5 dpavlin 1 */
6    
7 dpavlin 30 top.__bfilter_obj = new Array();
8 dpavlin 2
9 dpavlin 30
10 dpavlin 10 function BFilter(arr) {
11     this.id_cache = Array();
12     // total number of hits
13     this.hits = 0;
14 dpavlin 1
15 dpavlin 30 // 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 dpavlin 32 this.results_html = null;
21 dpavlin 28
22 dpavlin 30 // show results after 0.2s
23     this.timeout = 200;
24     this.timeout_handle = null;
25    
26 dpavlin 10 if (! arr) {
27     this.debug("ERROR: can't search empty array");
28     return;
29     }
30 dpavlin 1
31 dpavlin 10 this.arr = arr;
32     this.debug("index has "+this.arr.length+" parts");
33    
34     if (! arr.min_len) {
35 dpavlin 32 alert("ERROR: index structure problem");
36 dpavlin 10 return;
37 dpavlin 1 } else {
38 dpavlin 10 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 dpavlin 32 // show alert for non-existent elements?
46     this.show_alert = 1;
47    
48 dpavlin 10 }
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 dpavlin 30 var el = self.document.getElementById(id);
55 dpavlin 1 if (el) {
56 dpavlin 10 this.id_cache[id] = el;
57 dpavlin 1 return el;
58     } else {
59 dpavlin 32 if (! no_alert && this.show_alert) {
60     this.show_alert = confirm("can't find element id: "+id);
61 dpavlin 10 } else {
62     // don't look it up again
63     this.id_cache[id] = null;
64     }
65 dpavlin 1 }
66     }
67 dpavlin 22 return null;
68 dpavlin 1 }
69    
70    
71 dpavlin 32 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 dpavlin 1 }
84    
85 dpavlin 10 var el = this.element_id("status");
86 dpavlin 1 el.innerHTML = html+status+"\n";
87 dpavlin 32
88     return true;
89 dpavlin 1 }
90    
91 dpavlin 32 // 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 dpavlin 1
99 dpavlin 32 // 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 dpavlin 1
109 dpavlin 32 // this function is called when updating innerHTML with results
110     BFilter.prototype.show_results = function () {
111 dpavlin 10 var results_div = this.element_id("results");
112 dpavlin 32 if (this.results_html) {
113     results_div.innerHTML = '<ul>'+this.results_html+'</ul>';
114 dpavlin 1 }
115 dpavlin 32 return true;
116 dpavlin 1 }
117    
118 dpavlin 10 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 dpavlin 22 if (! debug_div) { return null; }
127 dpavlin 10
128 dpavlin 12 debug_div.innerHTML += html + "<br>\n";
129 dpavlin 22
130     return null;
131 dpavlin 10 }
132    
133    
134 dpavlin 2 // modified binary search to find first element with substring
135 dpavlin 30 BFilter.prototype.binarySearch = function (arr, user_filter) {
136     if (!arr || typeof (user_filter) == "undefined" || !arr.length) {
137 dpavlin 2 return null;
138     }
139     var low = 0;
140     var high = arr.length - 1;
141     var middlearr = parseInt(arr.length / 2);
142 dpavlin 32 this.debug("binarySearch: "+low+"-("+middlearr+")-"+high+" for "+user_filter);
143 dpavlin 2 var lastTry;
144     while (low <= high) {
145     var mid = (low + high) / 2;
146     var aTry = (mid < 1) ? 0 : parseInt(mid);
147    
148 dpavlin 30 var curr = arr[aTry][0].substr(0,user_filter.length).toLowerCase();
149 dpavlin 32 this.debug(low+"-"+high+", "+aTry+"="+curr+" last="+lastTry);
150 dpavlin 30 if (curr < user_filter) {
151 dpavlin 2 low = aTry + 1;
152     continue;
153     }
154 dpavlin 30 if (curr > user_filter) {
155 dpavlin 2 high = aTry - 1;
156     continue;
157     }
158 dpavlin 30 if (curr == user_filter) {
159 dpavlin 2 high = aTry - 1;
160     lastTry = aTry;
161     continue;
162     }
163     return aTry;
164     }
165 dpavlin 12 this.debug("lastTry="+lastTry);
166 dpavlin 1
167 dpavlin 2 if (typeof (lastTry) != "undefined") {
168     return lastTry;
169     } else {
170     return null;
171     }
172     }
173    
174 dpavlin 30 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 dpavlin 1
184 dpavlin 30 BFilter.prototype.show_filter = function (user_filter) {
185    
186 dpavlin 32 this.show_status("Showing entries with <em>"+user_filter+"</em>\n");
187    
188 dpavlin 30 if (this.timeout_handle) {
189     clearTimeout(this.timeout_handle);
190     this.timeout_handle = null;
191     this.debug("timeout cleared");
192     }
193    
194 dpavlin 32 this.clear_results();
195 dpavlin 10 this.hits = 0;
196 dpavlin 1
197 dpavlin 30 if (user_filter.length < this.min_len) {
198 dpavlin 10 this.show_status();
199 dpavlin 1 return;
200     }
201    
202 dpavlin 30 var user_filter_lc = user_filter.toLowerCase();
203 dpavlin 32
204     this.debug("filter: '"+user_filter_lc+"'");
205 dpavlin 1
206 dpavlin 30 var part = user_filter_lc.substr(0,this.min_len);
207 dpavlin 1
208     // no part found
209 dpavlin 10 if (! this.arr[part]) {
210 dpavlin 30 this.show_status(" for <em>"+user_filter+"</em><br>");
211 dpavlin 10 this.debug("no part "+part);
212 dpavlin 1 return;
213     }
214    
215     // start anim icon
216 dpavlin 32 //<img src=\"pie.gif\">&nbsp;Please wait, filtering...
217 dpavlin 1
218 dpavlin 22 var i;
219    
220 dpavlin 1 // full part? (optimization)
221 dpavlin 30 if (user_filter.length == this.min_len) {
222 dpavlin 22 for (i = 0; i < this.arr[part].length; i++) {
223 dpavlin 28 this.result(this.arr[part][i]);
224 dpavlin 10 this.hits++;
225 dpavlin 1 }
226 dpavlin 32 this.show_results();
227 dpavlin 1 } else {
228    
229 dpavlin 30 var from = this.binarySearch(this.arr[part], user_filter_lc);
230 dpavlin 1
231 dpavlin 2 if (from != null) {
232    
233 dpavlin 12 this.debug("loop "+from+" ... "+this.arr[part].length);
234 dpavlin 5
235 dpavlin 22 for(i = from ; i < this.arr[part].length ; i++) {
236 dpavlin 30 if (this.arr[part][i][0].substring(0,user_filter.length).toLowerCase() != user_filter_lc) {
237 dpavlin 10 this.debug("loop exit at "+i);
238 dpavlin 2 break;
239     }
240 dpavlin 28 this.result(this.arr[part][i]);
241 dpavlin 10 this.hits++;
242 dpavlin 1 }
243 dpavlin 5
244 dpavlin 32 this.show_results();
245 dpavlin 1 }
246    
247     }
248    
249 dpavlin 30 this.show_status(" for <em>"+user_filter+"</em>");
250 dpavlin 1
251     }
252    

  ViewVC Help
Powered by ViewVC 1.1.26