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