Fixed full display
[pazpar2-moved-to-github.git] / www / demo / search.js
1 /* $Id: search.js,v 1.28 2007-01-16 15:02:35 quinn Exp $
2  * ---------------------------------------------------
3  * Javascript container
4  */
5
6 var xmlHttp
7 var xinitSession;
8 var xloadTargets;
9 var xsearch;
10 var xshow;
11 var xstat;
12 var xtermlist;
13 var xfetchDetails;
14 var session = false;
15 var targetsloaded = false;
16 var shown;
17 var searchtimer;
18 var showtimer;
19 var termtimer;
20 var stattimer;
21 var session_cells = Array('query', 'startrec', 'action_type');
22 var old_session = session_read();
23 var url_surveillence;
24 var recstoshow = 20;
25 var page_window = 5;  // Number of pages prior to and after the current page
26 var facet_list;
27 var cur_facet = 0;
28 var cur_sort = "relevance";
29 var searched = 0;
30 var cur_id = -1;
31 var cur_rec = 0;
32
33 function initialize ()
34 {
35     facet_list = get_available_facets();
36     start_session();
37     session_check();
38     set_sort();
39 }
40
41 function GetXmlHttpObject()
42
43     var objXMLHttp=null
44     if (window.XMLHttpRequest)
45       {
46       objXMLHttp=new XMLHttpRequest()
47       }
48     else if (window.ActiveXObject)
49       {
50       objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
51       }
52     return objXMLHttp
53
54
55 function SendXmlHttpObject(obj, url, handler)
56 {
57     obj.onreadystatechange=handler;
58     obj.open("GET", url);
59     obj.send(null);
60 }
61
62 function session_started()
63 {
64     if (xinitSession.readyState != 4)
65         return;
66     var xml = xinitSession.responseXML;
67     var sesid = xml.getElementsByTagName("session")[0].childNodes[0].nodeValue;
68     assign_text(document.getElementById("status"), 'Live');
69     session = sesid;
70     setTimeout(ping_session, 50000);
71 }
72
73 function start_session()
74 {
75     xinitSession = GetXmlHttpObject();
76     var url="search.pz2?";
77     url += "command=init";
78     xinitSession.onreadystatechange=session_started;
79     xinitSession.open("GET", url);
80     xinitSession.send(null);
81 }
82
83 function ping_session()
84 {
85     if (!session)
86         return;
87     var url = "search.pz2?command=ping&session=" + session;
88     SendXmlHttpObject(xpingSession = GetXmlHttpObject(), url, session_pinged);
89 }
90
91 function session_pinged()
92 {
93     if (xpingSession.readyState != 4)
94         return;
95     var xml = xpingSession.responseXML;
96     var error = xml.getElementsByTagName("error");
97     if (error[0])
98     {
99         var msg = error[0].childNodes[0].nodeValue;
100         alert(msg);
101         location = "?";
102         return;
103     }
104     setTimeout(ping_session, 50000);
105 }
106
107 function update_action (new_action) {
108     document.search.action_type.value = new_action;
109 }
110
111
112 function make_pager (hits, offset, max) {
113     var html = '';
114     var off;
115     var start_offset = offset - page_window * max;
116     var div_elem = document.createElement('div');
117     
118     div_elem.className = 'pages';
119
120     if (start_offset < 0) {
121         start_offset = 0;
122     }
123
124     for (off = start_offset;
125          off < hits && off < (start_offset + 2 * page_window * max); 
126          off += max) {
127         
128         var p = off / max + 1;
129         var page_elem = create_element('a', p);
130         var newline_node = document.createTextNode(' ');
131
132         if ((offset >= off) && (offset < (off + max))) {
133             page_elem.className = 'select';
134         }
135
136         page_elem.setAttribute('off', off);
137         page_elem.style.cursor = 'pointer';
138         page_elem.onclick = function () {
139             update_offset(this.getAttribute('off'));
140         };
141
142         div_elem.appendChild(page_elem);
143         div_elem.appendChild(newline_node);
144     }
145
146     return div_elem;
147 }
148
149
150 function update_offset (offset) {
151     clearTimeout(searchtimer);
152     document.search.startrec.value = offset;
153     update_action('page');
154     check_search();
155     update_history();
156     return false;
157 }
158
159
160 function create_element (name, cdata) {
161     var elem_node = document.createElement(name);
162     var text_node = document.createTextNode(cdata);
163     elem_node.appendChild(text_node);
164
165     return elem_node;
166 }
167
168
169 function clear_cell (cell) {
170     while (cell.hasChildNodes())
171         cell.removeChild(cell.firstChild);
172 }
173
174
175 function append_text(cell, text) {
176     text_node = document.createTextNode(text);
177     cell.appendChild(text_node);
178 }
179
180
181 function assign_text (cell, text) {
182     clear_cell(cell);
183     append_text(cell, text);
184 }
185
186 function set_sort_opt(n, opt, str)
187 {
188     var txt = document.createTextNode(str);
189     if (opt == cur_sort)
190         n.appendChild(txt);
191     else
192     {
193         var a = document.createElement('a');
194         a.appendChild(txt);
195         a.setAttribute('href', "");
196         a.setAttribute('onclick', "set_sort('" + opt + "'); return false");
197         n.appendChild(a);
198     }
199 }
200
201 function set_sort(sort)
202 {
203     if (sort && sort != cur_sort)
204     {
205         cur_sort = sort;
206         if (searched)
207             check_search();
208     }
209
210     var t = document.getElementById("sortselect");
211     clear_cell(t);
212     t.appendChild(document.createTextNode("Sort results by: "));
213     set_sort_opt(t, 'relevance', 'Relevance');
214     t.appendChild(document.createTextNode(" or "));
215     set_sort_opt(t, 'title:1', 'Title');
216 }
217
218 function displayname(name)
219 {
220     if (name == 'md-author')
221         return 'Author';
222     else if (name == 'md-subject')
223         return 'Subject';
224     else if (name == 'md-date')
225         return 'Date';
226     else if (name == 'md-isbn')
227         return 'ISBN';
228     else if (name == 'md-publisher')
229         return 'Publisher';
230     else
231         return name;
232 }
233
234 function paint_details(body, xml)
235 {
236     clear_cell(body);
237     //body.appendChild(document.createElement('br'));
238     var nodes = xml.childNodes[0].childNodes;
239     var i;
240     var table = document.createElement('table');
241     table.setAttribute('cellpadding', 2);
242     for (i = 0; i < nodes.length; i++)
243     {
244         if (nodes[i].nodeType != 1)
245             continue;
246         var name = nodes[i].nodeName;
247         if (name == 'recid' || name == 'md-title')
248             continue;
249         name = displayname(name);
250         if (!nodes[i].childNodes[0])
251                 continue;
252         var value = nodes[i].childNodes[0].nodeValue;
253         var lbl = create_element('b', name );
254         var lbln = document.createElement('td');
255         lbln.setAttribute('width', 70);
256         lbln.appendChild(lbl);
257         var val = create_element('td', value);
258         var tr = document.createElement('tr');
259         tr.appendChild(lbln);
260         tr.appendChild(val);
261         table.appendChild(tr);
262     }
263     body.appendChild(table);
264     body.style.display = 'inline';
265 }
266
267 function show_details()
268 {
269     if (xfetchDetails.readyState != 4)
270         return;
271     var xml = xfetchDetails.responseXML;
272     var error = xml.getElementsByTagName("error");
273     if (error[0])
274     {
275         var msg = error[0].childNodes[0].nodeValue;
276         alert(msg);
277         location = "?";
278         return;
279     }
280
281     // This is some ugly display code. Replace with your own ting o'beauty
282
283     var idn = xml.getElementsByTagName('recid');
284     if (!idn[0])
285         return;
286     var id = idn[0].childNodes[0].nodeValue;
287     cur_id = id;
288     cur_rec = xml;
289
290     var body = document.getElementById('rec_' + id);
291     if (!body)
292         return;
293     paint_details(body, xml);
294 }
295
296 function fetch_details(id)
297 {
298     cur_id = -1;
299     var nodes = document.getElementsByName('listrecord');
300     var i;
301     for (i = 0; i < nodes.length; i++)
302     {
303         var dets = nodes[i].getElementsByTagName('div');
304         if (dets[0])
305             dets[0].style.display = 'none';
306     }
307     if (id == cur_id)
308     {
309         cur_id = -1;
310         return;
311     }
312     if (!session)
313         return;
314     var url = "search.pz2?session=" + session +
315         "&command=record" +
316         "&id=" + id;
317     SendXmlHttpObject(xfetchDetails = GetXmlHttpObject(), url, show_details);
318 }
319
320 function show_records()
321 {
322     if (xshow.readyState != 4)
323         return;
324     var i;
325     var xml = xshow.responseXML;
326     var body = document.getElementById("body");
327     var hits = xml.getElementsByTagName("hit");
328
329     clear_cell(body);
330
331     if (!hits[0]) // We should never get here with blocking operations
332     {
333         assign_text(body, 'No records yet');
334         searchtimer = setTimeout(check_search, 250);
335     }
336     else
337     {
338         var total = Number(xml.getElementsByTagName('total')[0].childNodes[0].nodeValue);
339         var merged = Number(xml.getElementsByTagName('merged')[0].childNodes[0].nodeValue);
340         var start = Number(xml.getElementsByTagName('start')[0].childNodes[0].nodeValue);
341         var num = Number(xml.getElementsByTagName('num')[0].childNodes[0].nodeValue);
342         var clients = Number(xml.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue);
343         var pager = make_pager(merged, start,recstoshow);
344         var break_node1 = document.createElement('br');
345         var break_node2 = document.createElement('br');
346         var record_container = document.createElement('div');
347         var interval = create_element('div', 'Records : ' + (start + 1) +
348                                              ' to ' + (start + num) + ' of ' +
349                                              merged + ' (total hits: ' +
350                                              total + ')');
351         searched = 1;
352         interval.className = 'results';
353         record_container.className = 'records';
354
355         body.appendChild(pager);
356         body.appendChild(interval);
357         body.appendChild(break_node1);
358         body.appendChild(break_node2);
359         body.appendChild(record_container);
360
361         for (i = 0; i < hits.length; i++)
362         {
363             var tn = hits[i].getElementsByTagName("md-title");
364             var title = '';
365             var an = hits[i].getElementsByTagName("md-author");
366             var author = '';
367             var cn = hits[i].getElementsByTagName("count");
368             var count = 1;
369             var idn = hits[i].getElementsByTagName("recid");
370
371             if (tn[0]) {
372                 title = tn[0].childNodes[0].nodeValue;
373             } else {
374                 title = 'N/A';
375             }
376             if (an[0] && an[0].childNodes[0])
377                     author = an[0].childNodes[0].nodeValue;
378             if (cn[0])
379                 count = Number(cn[0].childNodes[0].nodeValue);
380             var id = idn[0].childNodes[0].nodeValue;
381             
382             var record_div = document.createElement('div');
383             record_div.className = 'record';
384             record_div.setAttribute('name', 'listrecord');
385
386             var record_cell = create_element('a', title);
387             record_cell.setAttribute('href', '#');
388             record_cell.setAttribute('onclick', 'fetch_details(' + id + '); return false');
389             record_div.appendChild(record_cell);
390             if (author)
391             {
392                 record_div.appendChild(document.createTextNode(', by '));
393                 record_div.appendChild(document.createTextNode(author));
394             }
395             if (count > 1)
396                 record_div.appendChild(document.createTextNode(
397                         ' (' + count + ')'));
398             var det_div = document.createElement('div');
399             if (id == cur_id)
400                 paint_details(det_div, cur_rec);
401             else
402                 det_div.style.display = 'none';
403             det_div.setAttribute('id', 'rec_' + id);
404             det_div.setAttribute('name', 'details');
405             record_div.appendChild(det_div);
406             record_container.appendChild(record_div);
407         }
408
409         shown++;
410         if (clients > 0)
411         {
412             if (shown < 5)
413                 searchtimer = setTimeout(check_search, 1000);
414             else
415                 searchtimer = setTimeout(check_search, 2000);
416         }
417     }
418     if (!termtimer)
419         termtimer = setTimeout(check_termlist, 500);
420 }
421
422 function check_search()
423 {
424     clearTimeout(searchtimer);
425     var url = "search.pz2?" +
426         "command=show" +
427         "&start=" + document.search.startrec.value +
428         "&num=" + recstoshow +
429         "&session=" + session +
430         "&sort=" + cur_sort +
431         "&block=1";
432     xshow = GetXmlHttpObject();
433     xshow.onreadystatechange=show_records;
434     xshow.open("GET", url);
435     xshow.send(null);
436 }
437
438
439 function refine_query (obj) {
440     var term = obj.getAttribute('term');
441     var cur_termlist = obj.getAttribute('facet');
442     var query_cell = document.getElementById('query');
443     
444     term = term.replace(/[\(\)]/g, '');
445     
446     if (cur_termlist == 'subject')
447         query_cell.value += ' and su=(' + term + ')';
448     else if (cur_termlist == 'author')
449         query_cell.value += ' and au=(' + term + ')';
450
451     start_search();
452 }
453
454
455
456 function show_termlist()
457 {
458     if (xtermlist.readyState != 4)
459         return;
460
461     var i;
462     var xml = xtermlist.responseXML;
463     var body = facet_list[cur_facet][1];
464     var facet_name = facet_list[cur_facet][0];
465     var hits = xml.getElementsByTagName("term");
466     var clients =
467         Number(xml.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue);
468
469     cur_facet++;
470
471     if (cur_facet >= facet_list.length)
472         cur_facet = 0;
473
474     if (!hits[0])
475     {
476         termtimer = setTimeout(check_termlist, 500);
477     }
478     else
479     {
480         clear_cell(body);
481         
482         for (i = 0; i < hits.length; i++)
483         {
484             var namen = hits[i].getElementsByTagName("name");
485             var freqn = hits[i].getElementsByTagName("frequency");
486             if (namen[0])
487                 var term = namen[0].childNodes[0].nodeValue;
488                 var freq = freqn[0].childNodes[0].nodeValue;
489                 var refine_cell = create_element('a', term + ' (' + freq + ')');
490                 refine_cell.setAttribute('href', '#');
491                 refine_cell.setAttribute('term', term);
492                 refine_cell.setAttribute('facet', facet_name);
493                 refine_cell.onclick = function () {
494                     refine_query(this);
495                     return false;
496                 };
497                 body.appendChild(refine_cell);
498         }
499
500         if (clients > 0)
501             termtimer = setTimeout(check_termlist, 1000);
502     }
503 }
504
505 function check_termlist()
506 {
507     var facet_name = facet_list[cur_facet][0];
508     var url = "search.pz2?" +
509         "command=termlist" +
510         "&session=" + session +
511         "&name=" + facet_name;
512     xtermlist = GetXmlHttpObject();
513     xtermlist.onreadystatechange=show_termlist;
514     xtermlist.open("GET", url);
515     xtermlist.send(null);
516 }
517
518 function show_stat()
519 {
520     if (xstat.readyState != 4)
521         return;
522     var i;
523     var xml = xstat.responseXML;
524     var body = document.getElementById("stat");
525     var nodes = xml.childNodes[0].childNodes;
526     var clients =
527         Number(xml.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue);
528     if (!nodes[0])
529     {
530         stattimer  = setTimeout(check_stat, 500);
531     }
532     else
533     {
534         assign_text(body, '(');
535         for (i = 0; i < nodes.length; i++)
536         {
537             if (nodes[i].nodeType != 1)
538                 continue;
539             var value = nodes[i].childNodes[0].nodeValue;
540             if (value == 0)
541                 continue;
542             var name = nodes[i].nodeName;
543             append_text(body, ' ' + name + '=' + value);
544         }
545
546         append_text(body, ')');
547         if (clients > 0)
548             stattimer = setTimeout(check_stat, 2000);
549     }
550 }
551
552 function check_stat()
553 {
554     var url = "search.pz2?" +
555         "command=stat" +
556         "&session=" + session;
557     xstat = GetXmlHttpObject();
558     xstat.onreadystatechange=show_stat;
559     xstat.open("GET", url);
560     xstat.send(null);
561 }
562
563 function search_started()
564 {
565     if (xsearch.readyState != 4)
566         return;
567     var xml = xsearch.responseXML;
568     var error = xml.getElementsByTagName("error");
569     if (error[0])
570     {
571         var msg = error[0].childNodes[0].nodeValue;
572         alert(msg);
573         return;
574     }
575     check_search();
576     stattimer = setTimeout(check_stat, 1000);
577 }
578
579 function start_search()
580 {
581     clearTimeout(termtimer);
582     termtimer = 0;
583     clearTimeout(searchtimer);
584     searchtimer = 0;
585     clearTimeout(stattimer);
586     stattimer = 0;
587     clearTimeout(showtimer);
588     showtimer = 0;
589     cur_id = -1;
590     var query = escape(document.getElementById('query').value);
591     var url = "search.pz2?" +
592         "command=search" +
593         "&session=" + session +
594         "&query=" + query;
595     xsearch = GetXmlHttpObject();
596     xsearch.onreadystatechange=search_started;
597     xsearch.open("GET", url);
598     xsearch.send(null);
599     clear_cell(document.getElementById("body"));
600     update_history();
601     shown = 0;
602     document.search.startrec.value = 0;
603 }
604
605 function session_encode ()
606 {
607     var i;
608     var session = '';
609
610     for (i = 0; i < session_cells.length; i++)
611     {
612         var name = session_cells[i];
613         var value = escape(document.getElementById(name).value);
614         session += '&' + name + '=' + value;
615     }
616
617     return session;
618 }
619
620
621 function session_restore (session)
622 {
623     var fields = session.split(/&/);
624     var i;
625
626     for (i = 1; i < fields.length; i++)
627     {
628         var pair = fields[i].split(/=/);
629         var key = pair.shift();
630         var value = pair.join('=');
631         var cell = document.getElementById(key);
632
633         cell.value = value;
634     }
635     
636 }
637
638
639 function session_read ()
640 {
641     var ses = window.location.hash.replace(/^#/, '');
642     return ses;
643 }
644
645
646 function session_store (new_value)
647 {
648     window.location.hash = '#' + new_value;
649 }
650
651
652 function update_history ()
653 {
654     var session = session_encode();
655     session_store(session);
656     old_session = session;
657 }
658
659
660 function session_check ()
661 {
662     var session = session_read();
663     var action = document.search.action_type.value;
664
665     clearInterval(url_surveillence);
666
667     if ( session != unescape(old_session) )
668     {
669         session_restore(session);
670
671         if (action == 'search') {
672             start_search();
673         } else if (action == 'page') {
674             check_search();
675         } else {
676             alert('Unregocnized action_type: ' + action);
677             return;
678         }
679     }
680     
681     url_surveillence = setInterval(session_check, 200);
682 }
683
684
685 function get_available_facets () {
686     var facet_container = document.getElementById('termlists');
687     var facet_cells = facet_container.childNodes;
688     var facets = Array();
689     var i;
690
691     for (i = 0; i < facet_cells.length; i++) {
692         var cell = facet_cells.item(i);
693
694         if (cell.className == 'facet') {
695             var facet_name = cell.id.replace(/^facet_([^_]+)_terms$/, "$1");
696             facets.push(Array(facet_name, cell));
697         }
698     }
699
700     return facets;
701 }
702
703
704 function get_facet_container (obj) {
705     return document.getElementById(obj.id + '_terms');
706 }
707
708
709 function toggle_facet (obj) {
710     var container = get_facet_container(obj);
711
712     if (obj.className == 'selected') {
713         obj.className = 'unselected';
714         container.style.display = 'inline';
715     } else {
716         obj.className = 'selected';
717         container.style.display = 'none';
718     }
719 }