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