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