9fb9412073b7a19d9aab5173c76044feb0efd275
[pazpar2-moved-to-github.git] / www / masterkey / js / client.js
1 /*
2 ** $Id: client.js,v 1.22 2007-04-30 14:28:09 quinn Exp $
3 ** MasterKey - pazpar2's javascript client .
4 */
5
6 /* start with creating pz2 object and passing it event handlers*/
7 var my_paz = new pz2({ 
8                     "onshow": my_onshow,
9                     //"showtime": 1000,
10                     //"onstat": my_onstat,
11                     "onterm": my_onterm,
12                     "termlist": "xtargets,subject,author,date",
13                     //"onbytarget": my_onbytarget,
14                     "onrecord": my_onrecord,
15                     "errorhandler": my_errorhandler
16                     });
17
18 /* some state variable */
19 var currentSort = 'relevance';
20 var currentResultsPerPage = 20;
21 var currentPage = 0;
22 var curQuery = new pzQuery();
23
24 var currentDetailedId = null;
25 var currentDetailedData = null;
26
27 var termStartup = true;
28 var advancedOn = false;
29
30 var showBriefLocations = false;
31
32 /* wait until the DOM is ready and register basic handlers */
33 $(document).ready( function() { 
34                     document.search.onsubmit = onFormSubmitEventHandler;
35
36                     document.search.query.value = '';
37                     document.search.title.value = '';
38                     document.search.author.value = '';
39                     document.search.subject.value = '';
40                     document.search.date.value = '';
41                     
42                     $('#advanced').click(toggleAdvanced);
43
44                     $('#sort').change(function(){ 
45                         currentSort = this.value;
46                         currentPage = 0;
47                         my_paz.show(0, currentResultsPerPage, currentSort);
48                     });
49                     
50                     $('#perpage').change(function(){ 
51                         currentResultsPerPage = this.value;
52                         currentPage = 0;
53                         my_paz.show(0, currentResultsPerPage, currentSort);
54                     });
55 } );
56
57 /* search button event handler */
58 function onFormSubmitEventHandler() {
59     loadQueryFromForm();
60     curQuery.clearFilter();
61     fireSearch();
62     drawBreadcrumb();
63     $('div.motd').empty();
64     $('div.content').show();
65     $("div.leftbar").show();
66     return false;
67 }
68
69 /*
70 *********************************************************************************
71 ** pz2 Event Handlers ***********************************************************
72 *********************************************************************************
73 */
74 function my_errorhandler(err)
75 {
76     switch (err.message) 
77     {
78         case 'QUERY': alert("Your query was not understood. Please rephrase."); break;
79         default: alert(err.message);
80     }
81 }
82
83 /*
84 ** data.hits["md-title"], data.hits["md-author"], data.hits.recid, data.hits.count
85 ** data.activeclients, data.merged, data.total, data.start, data.num 
86 */
87 function my_onshow(data)
88 {
89     var recsBody = $('div.records');
90     recsBody.empty();
91     
92     for (var i = 0; i < data.hits.length; i++) {
93         var title = data.hits[i]["md-title"] || 'N/A';
94         var author = data.hits[i]["md-author"] || '';
95         var id = data.hits[i].recid;
96         var count = data.hits[i].count || 1;
97         
98         var recBody = $('<div class="record" id="rec_'+id+'"></div>');
99         var aTitle = $('<a class="recTitle">'+title+'</a>').appendTo(recBody);
100         aTitle.click(function(){
101                         var clickedId = this.parentNode.id.split('_')[1];
102                         if(currentDetailedId == clickedId){
103                             $(this.parentNode.lastChild).remove();
104                             currentDetailedId = null;
105                             return;
106                         } else if (currentDetailedId != null) {
107                             $('#rec_'+currentDetailedId).children('.detail').remove();
108                         }
109                         currentDetailedId = clickedId;
110                         my_paz.record(currentDetailedId);
111                         });
112         
113         if( author ) {
114             recBody.append('<i> by </i>');
115             $('<a name="author" class="recAuthor">'+author+'</a>\n').click(function(){ 
116                             refine("authoronly", this.firstChild.nodeValue) }).appendTo(recBody);
117         }
118
119         if( currentDetailedId == id ) {
120             var detailBox = $('<div class="detail"></div>').appendTo(recBody);
121             drawDetailedRec(detailBox);
122         }
123
124         if (showBriefLocations) {
125             var location = data.hits[i]['location'];
126             var l;
127             var list = '';
128             for (l in location) {
129                 if (list)
130                     list += ', ';
131                 list += location[l].name;
132             }
133             recBody.append('<span> ('+list+')</span>');
134         }
135         else {
136             if( count > 1 ) {
137                 recBody.append('<span> ('+count+')</span>');
138             }
139         }
140
141         recsBody.append('<div class="resultNum">'+(currentPage*currentResultsPerPage+i+1)+'.</a>');
142         recsBody.append(recBody);
143     }
144     drawPager(data.merged, data.total);    
145 }
146
147 /*
148 ** data.activeclients, data.hits, data.records, data.clients, data.searching
149 */
150 function my_onstat(data){}
151
152 /*
153 ** data[listname]: name, freq, [id]
154 */
155 function my_onterm(data)
156 {
157     if(termStartup)
158     {
159         var termLists = $("#termlists");
160         
161         for(var key in data){
162             if (key == "activeclients")
163                 continue;
164             var listName = key;
165             var listClass = "unselected";
166
167             if (key == "xtargets"){
168                 listName = "resource";
169                 listClass = "selected";
170             }
171
172             var termList = $('<div class="termlist" id="term_'+key+'"/>').appendTo(termLists);
173             var termTitle = $('<div class="termTitle"><a class="'+listClass+'">'+listName+'</a></div>').appendTo(termList);
174             termTitle.click(function(){
175                                 if( this.firstChild.className == "selected" ){
176                                     this.firstChild.className = "unselected";
177                                     $(this.nextSibling).hide();
178                                 } else {
179                                     this.firstChild.className = "selected";
180                                     $(this.nextSibling).show();
181                                 }
182                             });
183
184             listEntries = $('<div class="termEntries"></div>');
185             if (key != "xtargets") listEntries.hide();
186             listEntries.appendTo(termList);
187
188             for(var i = 0; i < data[key].length; i++)
189             {
190                 if (key == "xtargets"){
191                     var listItem = $('<a class="sub" name="xtarget" value="'+data[key][i].id+'">'+data[key][i].name +'<span> ('+data[key][i].freq+')</span>'+'</a>');
192                     listItem.click(function(){ 
193                         refine(this.name, this.attributes[0].nodeValue, this.firstChild.nodeValue) });
194                     listItem.appendTo(listEntries);
195                 } else {
196                     var listItem = $('<a class="sub" name="'+key+'">'+data[key][i].name
197                             +'<span> ('+data[key][i].freq+')</span>'+'</a>');
198                     listItem.click(function(){ refine(this.name, this.firstChild.nodeValue) });
199                     listItem.appendTo(listEntries);
200                 }
201             }        
202             $('<hr/>').appendTo(termLists);
203         }
204         termStartup = false;
205     } 
206     else 
207     {
208         for(var key in data){
209             if (key == "activeclients")
210                 continue;
211             var listEntries = $('#term_'+key).children('.termEntries');
212             if( data[key].length ) listEntries.empty();
213
214             for(var i = 0; i < data[key].length; i++){
215                 if (key == "xtargets"){
216                     var listItem = $('<a class="sub" name="xtarget" value="'+data[key][i].id+'">'+data[key][i].name+'<span> ('+data[key][i].freq+')</span>'+'</a>').click(function(){ 
217                                     refine(this.name, this.attributes[0].nodeValue, this.firstChild.nodeValue) });
218                     listItem.appendTo(listEntries);
219                 } else {
220                     var listItem = $('<a class="sub" name="'+key+'">'+data[key][i].name
221                                 +'<span> ('+data[key][i].freq+')</span>'+'</a>').click(function(){ 
222                                                                         refine(this.name, this.firstChild.nodeValue) });
223                     listItem.appendTo(listEntries);
224                 }
225             }         
226         }
227     }
228 }
229
230 /*
231 ** data["md-title"], data["md-date"], data["md-author"], data["md-subject"], data["location"][0].name
232 */
233 function my_onrecord(data)
234 {
235     currentDetailedData = data;
236     drawDetailedRec();
237 }
238
239 /*
240 ** data[i].id, data[i].hits, data[i].diagnostic, data[i].records, data[i].state
241 */
242 function my_onbytarget(data){}
243
244 /*
245 *********************************************************************************
246 ** HELPER FUNCTIONS *************************************************************
247 *********************************************************************************
248 */
249 function fireSearch()
250 {
251     $('div.showing').empty().text('No records to show.');
252     $('div.pages').empty().html('&nbsp;');
253     $('div.records').empty();
254     currentDetailedId = null;
255     if( !curQuery.totalLength() )
256         return false;
257     my_paz.search(curQuery.toCCL(), currentResultsPerPage, currentSort, curQuery.getFilterString() );
258 }
259
260 function toggleAdvanced()
261 {
262     if(advancedOn){
263         $("div.advanced").hide();
264         $("div.search").height(73);
265         advancedOn = false;
266         $("#advanced").text("Advanced search");
267     } else {
268         $("div.search").height(173);
269         $("div.advanced").show();
270         advancedOn = true;
271         $("#advanced").text("Simple search");
272         loadFormFieldsFromQuery();
273     }
274 }
275
276 function drawDetailedRec(detailBox)
277 {
278     if( detailBox == undefined )
279         detailBox = $('<div class="detail"></div>').appendTo($('#rec_'+currentDetailedId));
280     
281     var detailTable = $('<table></table>');
282     var recLocation = currentDetailedData["location"];
283
284     var hdtarget;
285     if( recLocation ) {
286         hdtarget = $('<tr><td class="item" align="right">Available at:&nbsp;</td></tr>');
287         detailTable.append(hdtarget);
288
289         for(var i=0; i < recLocation.length; i++)
290         {
291             if (!hdtarget)
292                 hdtarget = $('<tr><td class="item">&nbsp;</td></tr>').appendTo(detailTable);
293             var url = recLocation[i]["md-url"];
294             var description = recLocation[i]["md-description"];
295             var date = recLocation[i]["md-date"];
296             var citation = recLocation[i]["md-citation"];
297             hdtarget.append('<td><b>'+recLocation[i].name+'</b></td>');
298             if (date)
299                 detailTable.append($('<tr><td align="right">Date:&nbsp;</td><td>'+date+'</td></tr>'));
300             if (citation)
301                 detailTable.append($('<tr><td align="right" valign="top">Citation:&nbsp;</td><td>'+citation+'</td></tr>'));
302             if (description)
303                 detailTable.append($('<tr><td>&nbsp</td><td>'+description+'</td></tr>'));
304             if (url) {
305                 var tline = $('<tr><td>&nbsp;</td></tr>');
306                 var td = $('<td></td>').appendTo(tline);
307                 var tlink = $('<a>Go to resource</a>');
308                 tlink.attr('href', url);;
309                 tlink.attr('target', '_blank');
310                 tlink.appendTo(td);
311                 detailTable.append(tline);
312             }
313             hdtarget = undefined;
314         }
315     }
316
317     detailTable.appendTo(detailBox);
318 }
319
320 function refine(field, value, opt)
321 {
322     switch(field) {
323         case "authoronly":  curQuery.reset(); curQuery.addTerm('au', value); break;
324         case "author":  curQuery.addTerm('au', value); break;
325         case "title":   curQuery.addTerm('ti', value); break;
326         case "date":    curQuery.addTerm('date', value); break;
327         case "subject": curQuery.addTerm('su', value); break;
328         case "xtarget": curQuery.setFilter(opt, value); break;
329     }
330
331     if(advancedOn)
332         loadFormFieldsFromQuery();
333
334     currentPage = 0;
335     drawBreadcrumb();
336     fireSearch();
337 }
338
339 function loadQueryFromForm()
340 {
341     curQuery.reset();
342     curQuery.simpleQuery = document.search.query.value;
343
344     if( advancedOn )
345     {
346         curQuery.addTermsFromList(document.search.author.value, 'au');
347         curQuery.addTermsFromList(document.search.title.value, 'ti');
348         curQuery.addTermsFromList(document.search.date.value, 'date');
349         curQuery.addTermsFromList(document.search.subject.value, 'su');
350     }
351 }
352
353 function loadFormFieldsFromQuery()
354 {
355     document.search.author.value = '';
356     document.search.title.value = '';
357     document.search.date.value = '';
358     document.search.subject.value = '';
359
360     for(var i = 0; i < curQuery.numTerms; i++)
361     {
362         switch( curQuery.getTermFieldByIdx(i) )
363         {
364             case "au": document.search.author.value += curQuery.getTermValueByIdx(i) + '; '; break;
365             case "ti": document.search.title.value += curQuery.getTermValueByIdx(i) + '; '; break;
366             case "date": document.search.date.value += curQuery.getTermValueByIdx(i) + '; '; break;
367             case "su": document.search.subject.value += curQuery.getTermValueByIdx(i) + '; '; break;
368         }
369     }
370 }
371
372 function drawPager(max, hits)
373 {
374     var firstOnPage = currentPage * currentResultsPerPage + 1;
375     var lastOnPage = (firstOnPage + currentResultsPerPage - 1) < max ? (firstOnPage + currentResultsPerPage - 1) : max;
376
377     var results = $('div.showing');
378     results.empty();
379     results.append('Displaying: <b>'+firstOnPage+'</b> to <b>'+lastOnPage+
380                             '</b> of <b>'+max+'</b> (total hits: '+hits+')');
381     var pager = $('div.pages');
382     pager.empty();
383     
384     if ( currentPage > 0 ){
385         $('<a class="previous_active">Previous</a>').click(function() { my_paz.showPrev(1); currentPage--; }).appendTo(pager.eq(0));
386         $('<a class="previous_active">Previous</a>').click(function() { my_paz.showPrev(1); currentPage--; }).appendTo(pager.eq(1));
387     }
388     else
389         pager.append('<a class="previous_inactive">Previous</a>');
390
391     var numPages = Math.ceil(max / currentResultsPerPage);
392
393     var start = ( currentPage - 5 > 0 ? currentPage - 5 : 1 );
394     var stop =  ( start + 12 < numPages ? start + 12 : numPages );
395
396     if (start > 1) $('<span>... </span>').appendTo(pager);
397     
398     for(var i = start; i <= stop; i++)
399     {
400         if( i == (currentPage + 1) ){
401            $('<a class="select">'+i+'</a>').appendTo(pager);
402            continue;
403         }
404         var pageLink = $('<a class="page">'+i+'</a>');
405         var plClone = pageLink.clone();
406
407         pageLink.click(function() { 
408             my_paz.showPage(this.firstChild.nodeValue - 1);
409             currentPage = (this.firstChild.nodeValue - 1);
410             });
411
412         plClone.click(function() { 
413             my_paz.showPage(this.firstChild.nodeValue - 1);
414             currentPage = (this.firstChild.nodeValue - 1);
415             });
416
417         //nasty hack
418         pager.eq(0).append(pageLink);
419         pager.eq(1).append(plClone);
420     }
421
422     if (stop < numPages) $('<span> ...</span>').appendTo(pager);
423
424     if ( currentPage < (numPages-1) ){
425         $('<a class="next_active">Next</a>').click(function() { my_paz.showNext(1); currentPage++; }).appendTo(pager.eq(0));
426         $('<a class="next_active">Next</a>').click(function() { my_paz.showNext(1); currentPage++; }).appendTo(pager.eq(1));
427     }
428     else
429         pager.append('<a class="next_inactive">Next</a>');
430 }
431
432 function drawBreadcrumb()
433 {
434     var bc = $("#breadcrumb");
435     bc.empty();
436     
437     if(curQuery.filterNums) $('<strong id="filter"><a>'+curQuery.getFilterName(0)+'</a>: </strong>').click(function() {
438                                 curQuery.removeFilter(0);
439                                 refine();
440                                 }).appendTo(bc);
441
442     bc.append('<span>'+curQuery.simpleQuery+'</span>');
443
444     for(var i = 0; i < curQuery.numTerms; i++){
445         bc.append('<strong> + </strong>');
446         var bcLink = $('<a id="pos_'+i+'">'+curQuery.getTermValueByIdx(i)+'</a>').click(function() { 
447                                             curQuery.removeTermByIdx(this.id.split('_')[1]);
448                                             refine(); 
449                                             });
450         bc.append(bcLink);
451     }
452 }