/[webpac]/trunk2/out/js/search.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 /trunk2/out/js/search.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 534 - (show annotations)
Sat Oct 23 18:18:11 2004 UTC (19 years, 6 months ago) by dpavlin
File MIME type: application/javascript
File size: 10739 byte(s)
jsFind: re-ident whole source code, first try at implementing wildcard
search (non-working one)

1 /**
2 search.js searchs an XML index to HTML files.
3
4 A part of the jsfind project (http://projects.elucidsoft.net/jsfind)
5 Copyright (C) 2003 Shawn Garbett
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 Contact Info:
22 Shawn Garbett <Shawn@eLucidSoft.net>
23 http://www.elucidsoft.net
24 4037 General Bate Drive
25 Nashville, TN 37204
26 */
27
28 // Constants
29 var conversion = new String
30 ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY");
31
32 // State variables
33 var query_left = "";
34 var search_err = "";
35 var results = null;
36 var index_path = "";
37
38 var watchdog_id = 0;
39 var watchdog_callback = null;
40
41 // Object to hold search results
42 function Result(title, link, freq) {
43 this.title=title;
44 this.link=link;
45 this.frequency=Number(freq);
46 }
47
48 // Function to merge (intersect) two result sets
49 function intersect_results(data) {
50 // If there are no stored results, then these are the results
51 if (! results) {
52 results = data;
53 return;
54 }
55
56 var output=new Array();
57
58 // There are existing results, to do an intersect...
59 for (var i=0; i<results.length; i++) {
60 for (var j=0; j<data.length; j++) {
61 if (data[j].title == results[i].title) {
62 results[i].frequency += data[j].frequency;
63 output.push(results[i]);
64 break;
65 }
66 }
67 }
68
69 results = output;
70 }
71
72 /*
73 From David Flanagan's, _Javascript:_The Definitive_Guide_, pg. 294-5,
74 published by O'Reilly, 4th edition, 2002
75 */
76
77 var debug_div = null;
78
79 function debug(msg) {
80
81 // return; // Disable debugging
82
83 if (! debug_div) debug_div = document.getElementById('debug');
84
85 // this will create debug div if it doesn't exist.
86 if (! debug_div) {
87 debug_div = document.createElement('div');
88 if (document.body) document.body.appendChild(debug_div);
89 else debug_div = null;
90 }
91 if (debug_div) {
92 debug_div.appendChild(document.createTextNode(msg));
93 debug_div.appendChild(document.createElement("br"));
94 }
95 }
96
97 // Convert a number into a base 62 alphanumeric number string
98 function convert(num) {
99 var base = conversion.length;
100 var pow = 1;
101 var pos = 0;
102 var out = "";
103
104 if (num == 0) return "0";
105
106 while (num > 0) {
107 pos = num % base;
108 out = conversion.charAt(pos) + out;
109 num = Math.floor(num/base);
110 pow *= base;
111 }
112
113 return out;
114 }
115
116 function watchdog() {
117 debug ("TIMEOUT!");
118 watchdog_callback(new Array());
119 }
120
121 var xmldoc;
122
123 // This function loads the XML document from the specified URL, and when
124 // it is fully loaded, passes that document and the url to the specified
125 // handler function. This function works with any XML document
126
127 function loadXML(url, handler, data, result_handler) {
128 debug("loadXML("+url+","+data+")");
129
130 // Timeout operation in 10 seconds
131 watchdog_callback = result_handler;
132 watchdog_id=setTimeout("watchdog()", 20000);
133
134 debug("setTimeout = "+watchdog_id);
135
136 try {
137 // Use the standard DOM Level 2 technique, if it is supported
138 if (document.implementation && document.implementation.createDocument) {
139 // Create a new Document object
140 xmldoc = document.implementation.createDocument("", "", null);
141
142 // Specify what should happen when it finishes loading
143 xmldoc.onload = function() { handler(xmldoc, url, data, result_handler); }
144
145 //xmldoc.onerror = docError;
146 //xmldoc.addEventListener("load",docError,false);
147
148 // And tell it what URL to load
149 xmldoc.load(url);
150 return true;
151 }
152 // Otherwise use Microsoft's proprietary API for Internet Explorer
153 // Something about not following standards once again
154 else if (window.ActiveXObject) {
155 xmldoc = new ActiveXObject("Microsoft.XMLDOM"); // Create doc.
156 if (! xmldoc) xmldoc = new ActiveXObject("MSXML2.DOMDocument"); // Create doc.
157 // Specify onload
158 xmldoc.onreadystatechange = function() {
159 if (xmldoc.readyState == 4) handler(xmldoc, url, data, result_handler);
160 }
161 xmldoc.load(url); // Start loading!
162 return true;
163 }
164 // else fallback on usage of iframes to load xml (Opera 7.53 without Java and maybe old Mac browsers)
165 else {
166 debug("using iframe xml loader - experimental and slow");
167 if (! window.xml_iframe) {
168 debug("creating iframe");
169 window.xml_iframe = document.createElement('div');
170 window.xml_iframe.innerHTML = '<iframe src="'+url+'" name="xml_iframe" height="0" width="0" style="display: none;"></iframe>';
171 document.body.appendChild(window.xml_iframe);
172 } else {
173 debug("loading xml in existing iframe");
174 window.frames.xml_iframe.window.document.location.href = url;
175 }
176
177 // set timeout to re-check if iframe is loaded
178 window.iframe_timeout = window.setInterval('iframe_xml_loaded();',100);
179
180 // save some data for iframe_xml_loaded()
181 window.xml_handler = handler;
182 window.xml_url = url;
183 window.xml_data = data;
184 window.xml_result_handler = result_handler;
185 return true;
186 }
187
188 clearTimeout(watchdog_id);
189 debug("Browser incompatilibity: can't request XML document by one of supported methods");
190 return false;
191 }
192
193 catch(ex) {
194 clearTimeout(watchdog_id);
195 debug("clearTimeout = "+watchdog_id);
196 debug ("CAUGHT EXCEPTION!");
197 result_handler(new Array());
198 return false;
199 }
200
201 return true;
202 }
203
204 function iframe_xml_loaded() {
205 debug("iframe_xmldoc_loaded");
206 if (! window.frames['xml_iframe']) return;
207 var xml = eval('window.frames.xml_iframe.window.document');
208 if (xml) {
209 clearTimeout(window.iframe_timeout);
210 debug("calling handler with ("+window.xml_url+","+window.xml_data+",...)");
211 window.xml_handler(window.frames.xml_iframe.window.document, window.xml_url, window.xml_data, window.xml_result_handler);
212 } else {
213 debug("can't eval iframe with xml");
214 }
215 }
216
217 var data = new Array();
218
219 function loadData_intersect(xmldoc, url, pos, result_handler) {
220 data = new Array();
221 if (loadData(xmldoc, url, pos, result_handler)) {
222 intersect_results(data);
223 search_query_left(result_handler);
224 } else {
225 debug("INTERNAL ERROR, Inconsistent index");
226 search_err="INTERNAL ERROR, Inconsistent index";
227 }
228 }
229
230 function loadData(xmldoc, url, pos, result_handler) {
231
232 clearTimeout(watchdog_id);
233 debug("clearTimeout = "+watchdog_id);
234
235 debug ("loadData("+url+","+pos+")");
236
237 // Get all entries
238 var entries = xmldoc.getElementsByTagName("e");
239
240 if (entries.length > pos) {
241 // Get the links associated with this query
242 var links = entries[pos].getElementsByTagName("l");
243
244 debug("loaded "+links.length+" links");
245
246 // Dynamically append results to output
247 var ret = false;
248 for(i=0; i<links.length; i++) {
249 data.push(new Result(
250 links[i].getAttribute("t"),
251 links[i].firstChild.data,
252 links[i].getAttribute("f"))
253 );
254 ret = true;
255 }
256 return ret;
257 } else {
258 debug("ERROR: seek to "+pos+" with only "+entries.length+" elements");
259 }
260 }
261
262
263 function search_query_left(result_handler) {
264 if (query_left.length > 0) {
265 doSearch(index_path, query_left, result_handler);
266 } else {
267 results.sort(sortResults);
268 result_handler(results);
269 }
270 }
271
272 // you may override this function to sort by something else
273 function sortResults(a, b) {
274 return a.frequency - b.frequency;
275 }
276
277 function traverseTree(xmldoc, url, query, result_handler) {
278 clearTimeout(watchdog_id);
279 debug("clearTimeout = "+watchdog_id);
280
281 debug("traverseTree("+xmldoc+","+url+","+query+")");
282
283 var keys = xmldoc.getElementsByTagName("k");
284 var i;
285
286 // support for wildcard
287 var qlen = query.length;
288 var wildcard = false;
289 var query_full = query;
290 if (query.charAt(qlen-1) == '*') {
291 wildcard = true;
292 query = query.substr(0,--qlen);
293 debug("using wildcard "+query+"*");
294 }
295
296 for(i = 0; i < keys.length; i++) {
297 var key = keys[i].firstChild.data;
298
299 if (wildcard) {
300 key = key.substr(0,qlen);
301 debug("wildcard key "+key+"*");
302 }
303
304 debug("traverseTree: "+key+"=="+query);
305
306 if (key != '' && key != null) {
307 // Case where current key is greater than query, descend
308 if (key > query) {
309 if (key != '' && key != null) {
310 if (! loadXML(url.replace(".xml","/"+convert(i)+".xml"), traverseTree,query_full,result_handler)) {
311 debug("Unable to locate key "+query);
312 result_handler(new Array());
313 }
314 // make sure of garbage collection
315 xmldoc=null;
316 return;
317 }
318 }
319 // Found it!
320 else if (key==query) {
321 if (wildcard) {
322 data = new Array();
323 while (xmldoc && keys[i].firstChild.data.substr(0,qlen) == query) {
324 var url2 = url;
325 if (loadXML(url2.replace(/(\w+\.xml)/, "_$1"), loadData, i, result_handler)) {
326 // add loaded data to results
327 if (! results) {
328 results = data;
329 debug("wildcard loop: "+i+" created "+data.length+" results");
330 } else {
331 for (var j=0; j<data.length; j++) {
332 results.push(data[j]);
333 }
334 debug("wildcard loop: "+i+" added "+j+" results");
335 }
336
337 } else {
338 // this will break out of loop
339 xmldoc = null;
340 debug("wildcard loop stop at "+i);
341 }
342 i++;
343 }
344 debug("wildcard results: "+results.length);
345 search_query_left(result_handler);
346 return;
347 } else {
348 // exact match
349 if (! loadXML(url.replace(/(\w+\.xml)/, "_$1"), loadData_intersect, i, result_handler)) {
350 debug("ERROR: Unable to locate data "+query);
351 result_handler(new Array());
352 }
353 // make sure of garbage collection
354 xmldoc=null;
355 return;
356 }
357 } // key < query
358 } // if key
359 } // for
360
361 // Look past the end...
362 if (wildcard) query += '*';
363
364 if (keys.length == 0 || !loadXML(url.replace(".xml","/"+convert(i)+".xml"), traverseTree,query,result_handler)) {
365 debug("Unable to locate key "+query);
366 result_handler(new Array());
367 }
368
369 // make sure of garbage collection
370 xmldoc=null;
371 return;
372 }
373
374 function doSearch(index_name,query, result_func) {
375
376 //alert("doSearch("+index_name+","+query+")");
377 var pos=query.search(/[\s\+]/);
378 if (index_name) index_path = index_name+'/';
379
380 if (pos < 0) {
381 query_left = "";
382 } else {
383 query_left = query.slice(pos+1);
384 query = query.slice(0,pos);
385 }
386
387 if (! loadXML(index_path+"0.xml", traverseTree, query.toLowerCase(), result_func)) {
388 debug("ERROR: Couldn't find main index 0.xml");
389 search_err = "INTERNAL ERROR: Unable to load main index 0.xml";
390 }
391 }

  ViewVC Help
Powered by ViewVC 1.1.26