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

Annotation of /trunk2/out/js/search.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 534 - (hide 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 dpavlin 391 /**
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 dpavlin 534 ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY");
31 dpavlin 391
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 dpavlin 534 function Result(title, link, freq) {
43     this.title=title;
44     this.link=link;
45     this.frequency=Number(freq);
46 dpavlin 391 }
47    
48     // Function to merge (intersect) two result sets
49 dpavlin 534 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 dpavlin 391
56 dpavlin 534 var output=new Array();
57 dpavlin 391
58 dpavlin 534 // 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 dpavlin 391
69 dpavlin 534 results = output;
70 dpavlin 391 }
71    
72     /*
73     From David Flanagan's, _Javascript:_The Definitive_Guide_, pg. 294-5,
74 dpavlin 534 published by O'Reilly, 4th edition, 2002
75 dpavlin 391 */
76 dpavlin 496
77     var debug_div = null;
78    
79 dpavlin 534 function debug(msg) {
80 dpavlin 391
81 dpavlin 534 // return; // Disable debugging
82 dpavlin 391
83 dpavlin 534 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 dpavlin 391 }
96    
97     // Convert a number into a base 62 alphanumeric number string
98 dpavlin 534 function convert(num) {
99     var base = conversion.length;
100     var pow = 1;
101     var pos = 0;
102     var out = "";
103 dpavlin 391
104 dpavlin 534 if (num == 0) return "0";
105 dpavlin 391
106 dpavlin 534 while (num > 0) {
107     pos = num % base;
108     out = conversion.charAt(pos) + out;
109     num = Math.floor(num/base);
110     pow *= base;
111     }
112 dpavlin 391
113 dpavlin 534 return out;
114 dpavlin 391 }
115    
116 dpavlin 534 function watchdog() {
117     debug ("TIMEOUT!");
118     watchdog_callback(new Array());
119 dpavlin 391 }
120    
121 dpavlin 469 var xmldoc;
122    
123 dpavlin 391 // 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 dpavlin 534 function loadXML(url, handler, data, result_handler) {
128     debug("loadXML("+url+","+data+")");
129 dpavlin 391
130 dpavlin 534 // Timeout operation in 10 seconds
131     watchdog_callback = result_handler;
132     watchdog_id=setTimeout("watchdog()", 20000);
133 dpavlin 391
134 dpavlin 534 debug("setTimeout = "+watchdog_id);
135 dpavlin 391
136 dpavlin 534 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 dpavlin 391
142 dpavlin 534 // Specify what should happen when it finishes loading
143     xmldoc.onload = function() { handler(xmldoc, url, data, result_handler); }
144 dpavlin 391
145 dpavlin 534 //xmldoc.onerror = docError;
146     //xmldoc.addEventListener("load",docError,false);
147 dpavlin 496
148 dpavlin 534 // 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 dpavlin 496
177 dpavlin 534 // set timeout to re-check if iframe is loaded
178     window.iframe_timeout = window.setInterval('iframe_xml_loaded();',100);
179 dpavlin 391
180 dpavlin 534 // 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 dpavlin 391 }
203    
204 dpavlin 496 function iframe_xml_loaded() {
205 dpavlin 534 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 dpavlin 496 clearTimeout(window.iframe_timeout);
210 dpavlin 534 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 dpavlin 496 }
216    
217 dpavlin 534 var data = new Array();
218 dpavlin 391
219 dpavlin 534 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 dpavlin 391
230 dpavlin 534 function loadData(xmldoc, url, pos, result_handler) {
231 dpavlin 391
232 dpavlin 534 clearTimeout(watchdog_id);
233     debug("clearTimeout = "+watchdog_id);
234 dpavlin 391
235 dpavlin 534 debug ("loadData("+url+","+pos+")");
236 dpavlin 391
237 dpavlin 534 // Get all entries
238     var entries = xmldoc.getElementsByTagName("e");
239 dpavlin 391
240 dpavlin 534 if (entries.length > pos) {
241     // Get the links associated with this query
242     var links = entries[pos].getElementsByTagName("l");
243 dpavlin 391
244 dpavlin 534 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 dpavlin 391 }
261    
262 dpavlin 534
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 dpavlin 391 }
271    
272 dpavlin 534 // 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 dpavlin 391
281 dpavlin 534 debug("traverseTree("+xmldoc+","+url+","+query+")");
282 dpavlin 391
283 dpavlin 534 var keys = xmldoc.getElementsByTagName("k");
284     var i;
285 dpavlin 391
286 dpavlin 534 // 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 dpavlin 391 }
373    
374 dpavlin 534 function doSearch(index_name,query, result_func) {
375 dpavlin 391
376 dpavlin 534 //alert("doSearch("+index_name+","+query+")");
377     var pos=query.search(/[\s\+]/);
378     if (index_name) index_path = index_name+'/';
379 dpavlin 391
380 dpavlin 534 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 dpavlin 391 }

  ViewVC Help
Powered by ViewVC 1.1.26