/[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 560 - (hide annotations)
Sat Oct 30 23:04:37 2004 UTC (19 years, 6 months ago) by dpavlin
File MIME type: application/javascript
File size: 10149 byte(s)
removed upper case letters from encoding of index nodes (to support Windows
which is case-insensitive), added support for filters into TT templates,
changed crovoc symbol to #C# in data

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 560 ("0123456789abcdefghijklmnopqrstuvwxyz");
31 dpavlin 391
32     // State variables
33     var query_left = "";
34     var search_err = "";
35     var results = null;
36     var index_path = "";
37    
38 dpavlin 535 // wildcard data about found keys URLs and position
39     var wildcard_url_pos = new Array();
40    
41 dpavlin 391 var watchdog_id = 0;
42     var watchdog_callback = null;
43    
44     // Object to hold search results
45 dpavlin 534 function Result(title, link, freq) {
46     this.title=title;
47     this.link=link;
48     this.frequency=Number(freq);
49 dpavlin 391 }
50    
51     // Function to merge (intersect) two result sets
52 dpavlin 534 function intersect_results(data) {
53     // If there are no stored results, then these are the results
54     if (! results) {
55     results = data;
56     return;
57     }
58 dpavlin 391
59 dpavlin 534 var output=new Array();
60 dpavlin 391
61 dpavlin 534 // There are existing results, to do an intersect...
62     for (var i=0; i<results.length; i++) {
63     for (var j=0; j<data.length; j++) {
64     if (data[j].title == results[i].title) {
65     results[i].frequency += data[j].frequency;
66     output.push(results[i]);
67     break;
68     }
69     }
70     }
71 dpavlin 391
72 dpavlin 534 results = output;
73 dpavlin 391 }
74    
75 dpavlin 496 var debug_div = null;
76    
77 dpavlin 534 function debug(msg) {
78 dpavlin 391
79 dpavlin 534 // return; // Disable debugging
80 dpavlin 391
81 dpavlin 534 if (! debug_div) debug_div = document.getElementById('debug');
82    
83     // this will create debug div if it doesn't exist.
84     if (! debug_div) {
85     debug_div = document.createElement('div');
86     if (document.body) document.body.appendChild(debug_div);
87     else debug_div = null;
88     }
89     if (debug_div) {
90     debug_div.appendChild(document.createTextNode(msg));
91     debug_div.appendChild(document.createElement("br"));
92     }
93 dpavlin 391 }
94    
95 dpavlin 560 // Convert a number into a base x alphanumeric number string
96 dpavlin 534 function convert(num) {
97     var base = conversion.length;
98     var pow = 1;
99     var pos = 0;
100     var out = "";
101 dpavlin 391
102 dpavlin 534 if (num == 0) return "0";
103 dpavlin 391
104 dpavlin 534 while (num > 0) {
105     pos = num % base;
106     out = conversion.charAt(pos) + out;
107     num = Math.floor(num/base);
108     pow *= base;
109     }
110 dpavlin 391
111 dpavlin 534 return out;
112 dpavlin 391 }
113    
114 dpavlin 534 function watchdog() {
115     debug ("TIMEOUT!");
116     watchdog_callback(new Array());
117 dpavlin 391 }
118    
119 dpavlin 469 var xmldoc;
120    
121 dpavlin 391 // This function loads the XML document from the specified URL, and when
122     // it is fully loaded, passes that document and the url to the specified
123     // handler function. This function works with any XML document
124    
125 dpavlin 534 function loadXML(url, handler, data, result_handler) {
126     debug("loadXML("+url+","+data+")");
127 dpavlin 391
128 dpavlin 534 // Timeout operation in 10 seconds
129     watchdog_callback = result_handler;
130     watchdog_id=setTimeout("watchdog()", 20000);
131 dpavlin 391
132 dpavlin 535 //debug("setTimeout = "+watchdog_id);
133 dpavlin 391
134 dpavlin 534 try {
135     // Use the standard DOM Level 2 technique, if it is supported
136     if (document.implementation && document.implementation.createDocument) {
137     // Create a new Document object
138     xmldoc = document.implementation.createDocument("", "", null);
139 dpavlin 391
140 dpavlin 534 // Specify what should happen when it finishes loading
141     xmldoc.onload = function() { handler(xmldoc, url, data, result_handler); }
142 dpavlin 391
143 dpavlin 534 //xmldoc.onerror = docError;
144     //xmldoc.addEventListener("load",docError,false);
145 dpavlin 496
146 dpavlin 534 // And tell it what URL to load
147     xmldoc.load(url);
148     return true;
149     }
150     // Otherwise use Microsoft's proprietary API for Internet Explorer
151     // Something about not following standards once again
152     else if (window.ActiveXObject) {
153     xmldoc = new ActiveXObject("Microsoft.XMLDOM"); // Create doc.
154     if (! xmldoc) xmldoc = new ActiveXObject("MSXML2.DOMDocument"); // Create doc.
155     // Specify onload
156     xmldoc.onreadystatechange = function() {
157     if (xmldoc.readyState == 4) handler(xmldoc, url, data, result_handler);
158     }
159     xmldoc.load(url); // Start loading!
160     return true;
161     }
162     // else fallback on usage of iframes to load xml (Opera 7.53 without Java and maybe old Mac browsers)
163     else {
164     debug("using iframe xml loader - experimental and slow");
165     if (! window.xml_iframe) {
166     debug("creating iframe");
167     window.xml_iframe = document.createElement('div');
168     window.xml_iframe.innerHTML = '<iframe src="'+url+'" name="xml_iframe" height="0" width="0" style="display: none;"></iframe>';
169     document.body.appendChild(window.xml_iframe);
170     } else {
171     debug("loading xml in existing iframe");
172     window.frames.xml_iframe.window.document.location.href = url;
173     }
174 dpavlin 496
175 dpavlin 534 // set timeout to re-check if iframe is loaded
176     window.iframe_timeout = window.setInterval('iframe_xml_loaded();',100);
177 dpavlin 391
178 dpavlin 534 // save some data for iframe_xml_loaded()
179     window.xml_handler = handler;
180     window.xml_url = url;
181     window.xml_data = data;
182     window.xml_result_handler = result_handler;
183     return true;
184     }
185    
186     clearTimeout(watchdog_id);
187     debug("Browser incompatilibity: can't request XML document by one of supported methods");
188     return false;
189     }
190    
191     catch(ex) {
192     clearTimeout(watchdog_id);
193 dpavlin 535 //debug("clearTimeout = "+watchdog_id);
194 dpavlin 534 debug ("CAUGHT EXCEPTION!");
195     result_handler(new Array());
196     return false;
197     }
198    
199     return true;
200 dpavlin 391 }
201    
202 dpavlin 496 function iframe_xml_loaded() {
203 dpavlin 534 debug("iframe_xmldoc_loaded");
204     if (! window.frames['xml_iframe']) return;
205     var xml = eval('window.frames.xml_iframe.window.document');
206     if (xml) {
207 dpavlin 496 clearTimeout(window.iframe_timeout);
208 dpavlin 534 debug("calling handler with ("+window.xml_url+","+window.xml_data+",...)");
209     window.xml_handler(window.frames.xml_iframe.window.document, window.xml_url, window.xml_data, window.xml_result_handler);
210     } else {
211     debug("can't eval iframe with xml");
212     }
213 dpavlin 496 }
214    
215 dpavlin 534 var data = new Array();
216 dpavlin 391
217 dpavlin 534 function loadData_intersect(xmldoc, url, pos, result_handler) {
218     data = new Array();
219 dpavlin 535 if (loadData(xmldoc, url, pos)) {
220 dpavlin 534 intersect_results(data);
221     search_query_left(result_handler);
222     } else {
223     debug("INTERNAL ERROR, Inconsistent index");
224     search_err="INTERNAL ERROR, Inconsistent index";
225     }
226     }
227 dpavlin 391
228 dpavlin 535 function loadData(xmldoc, url, pos) {
229 dpavlin 391
230 dpavlin 534 clearTimeout(watchdog_id);
231 dpavlin 535 //debug("clearTimeout = "+watchdog_id);
232 dpavlin 391
233 dpavlin 534 debug ("loadData("+url+","+pos+")");
234 dpavlin 391
235 dpavlin 534 // Get all entries
236     var entries = xmldoc.getElementsByTagName("e");
237 dpavlin 391
238 dpavlin 534 if (entries.length > pos) {
239     // Get the links associated with this query
240     var links = entries[pos].getElementsByTagName("l");
241 dpavlin 391
242 dpavlin 534 debug("loaded "+links.length+" links");
243    
244     // Dynamically append results to output
245     var ret = false;
246     for(i=0; i<links.length; i++) {
247     data.push(new Result(
248     links[i].getAttribute("t"),
249     links[i].firstChild.data,
250     links[i].getAttribute("f"))
251     );
252     ret = true;
253     }
254     return ret;
255     } else {
256     debug("ERROR: seek to "+pos+" with only "+entries.length+" elements");
257     }
258 dpavlin 391 }
259    
260 dpavlin 534
261     function search_query_left(result_handler) {
262     if (query_left.length > 0) {
263     doSearch(index_path, query_left, result_handler);
264     } else {
265     results.sort(sortResults);
266     result_handler(results);
267     }
268 dpavlin 391 }
269    
270 dpavlin 534 // you may override this function to sort by something else
271     function sortResults(a, b) {
272     return a.frequency - b.frequency;
273     }
274    
275 dpavlin 535 function end_traverseTree(wildcard,query,result_handler) {
276     if (! wildcard) {
277     debug("Unable to locate key "+query);
278     result_handler(new Array());
279     } else {
280     debug("wildcard "+query+" produced "+(wildcard_url_pos.length / 2)+" results: "+wildcard_url_pos.join(" "));
281     }
282    
283     }
284    
285 dpavlin 534 function traverseTree(xmldoc, url, query, result_handler) {
286     clearTimeout(watchdog_id);
287 dpavlin 535 //debug("clearTimeout = "+watchdog_id);
288 dpavlin 391
289 dpavlin 534 debug("traverseTree("+xmldoc+","+url+","+query+")");
290 dpavlin 391
291 dpavlin 534 var keys = xmldoc.getElementsByTagName("k");
292     var i;
293 dpavlin 391
294 dpavlin 534 // support for wildcard
295     var qlen = query.length;
296     var wildcard = false;
297     var query_full = query;
298     if (query.charAt(qlen-1) == '*') {
299     wildcard = true;
300     query = query.substr(0,--qlen);
301     debug("using wildcard "+query+"*");
302     }
303    
304     for(i = 0; i < keys.length; i++) {
305     var key = keys[i].firstChild.data;
306    
307 dpavlin 535 if (wildcard) key = key.substr(0,qlen);
308 dpavlin 534
309 dpavlin 535 debug("? "+key+" -- "+query);
310 dpavlin 534
311     if (key != '' && key != null) {
312     // Case where current key is greater than query, descend
313     if (key > query) {
314 dpavlin 535 if (! loadXML(url.replace(".xml","/"+convert(i)+".xml"), traverseTree, query_full, result_handler)) {
315     end_traverseTree(wildcard, query_full, result_handler);
316 dpavlin 534 }
317 dpavlin 535 // make sure of garbage collection
318     xmldoc=null;
319     return;
320 dpavlin 534 }
321     // Found it!
322     else if (key==query) {
323     if (wildcard) {
324 dpavlin 535 wildcard_url_pos.push(url.replace(/(\w+\.xml)/, "_$1"));
325     wildcard_url_pos.push(i);
326     debug("+"+i+": "+keys[i].firstChild.data);
327 dpavlin 534 } else {
328     // exact match
329     if (! loadXML(url.replace(/(\w+\.xml)/, "_$1"), loadData_intersect, i, result_handler)) {
330 dpavlin 535 debug("ERROR: Unable to locate data "+query_full);
331 dpavlin 534 result_handler(new Array());
332     }
333     // make sure of garbage collection
334     xmldoc=null;
335     return;
336     }
337     } // key < query
338     } // if key
339     } // for
340    
341     // Look past the end...
342 dpavlin 535 if (keys.length == 0 || !loadXML(url.replace(".xml","/"+convert(i)+".xml"), traverseTree, query_full, result_handler)) {
343     end_traverseTree(wildcard, query_full, result_handler);
344 dpavlin 534 }
345    
346     // make sure of garbage collection
347     xmldoc=null;
348     return;
349 dpavlin 391 }
350    
351 dpavlin 534 function doSearch(index_name,query, result_func) {
352 dpavlin 391
353 dpavlin 534 //alert("doSearch("+index_name+","+query+")");
354     var pos=query.search(/[\s\+]/);
355     if (index_name) index_path = index_name+'/';
356 dpavlin 391
357 dpavlin 534 if (pos < 0) {
358     query_left = "";
359     } else {
360     query_left = query.slice(pos+1);
361     query = query.slice(0,pos);
362     }
363    
364     if (! loadXML(index_path+"0.xml", traverseTree, query.toLowerCase(), result_func)) {
365     debug("ERROR: Couldn't find main index 0.xml");
366     search_err = "INTERNAL ERROR: Unable to load main index 0.xml";
367     }
368 dpavlin 391 }

  ViewVC Help
Powered by ViewVC 1.1.26