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