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