7f83e3c03900053246b208036e617887fa45ffb2
[mkdru-moved-to-drupal.org.git] / mkdru.client.js
1 // Set up namespace and some state.
2 var mkdru = {
3   // Settings to pass to pz2.js
4   useSessions: Drupal.settings.mkdru.use_sessions === '1',
5   //   showResponseType: 'json',
6   // Variables
7   active: false,
8   pz2: null,
9   totalRec: 0,
10   pagerRange: 6,
11   pazpar2Path: Drupal.settings.mkdru.pz2_path,
12   // Facets
13   facets: {
14     source: {
15       pz2Name: 'xtargets',
16       max: Drupal.settings.mkdru.source_max
17     },
18     subject: {
19       pz2Name: 'subject',
20       max: Drupal.settings.mkdru.subject_max
21     },
22     author: {
23       pz2Name: 'author',
24       max: Drupal.settings.mkdru.author_max
25     }
26   },
27   // State
28   defaultState: {
29     page: 1,
30     perpage: 20,
31     sort: 'relevance',
32     filter: null,
33     query:'',
34     recid:null
35   },
36   state: {},
37   realm: ''
38 };
39
40
41
42 // Wrapper for jQuery
43 (function ($) {
44
45 // So we can use jQuery BBQ with Drupal 6 and its 1.2.6 jQuery
46 if (!$.isArray) $.isArray = function(obj) {
47   return Object.prototype.toString.call(obj) === "[object Array]";
48 };
49
50 // BBQ has no handy way to remove params without changing the hash.
51 // This takes an object to add and an array of keys to delete.
52 mkdru.hashAddDelMany = function (add, del) {
53   var newHash = $.deparam.fragment();
54   if (typeof(add) === 'object')
55     $.extend(newHash, add);
56   if ($.isArray(del))
57     for (var i=0; i < del.length; i++)
58       if (newHash[del[i]] !== 'undefined')
59         delete newHash[del[i]];
60   return $.param.fragment("#", newHash);
61 }
62
63 // It's sometimes cumbersome that object literals can't take variable keys.
64 mkdru.hashAddDelOne = function (key, value, del) {
65   var toAdd;
66   var toDel;
67   if (key && value) {
68     var toAdd = {};
69     toAdd[key] = value;
70   }
71   if (del) {
72     var toDel = [];
73     toDel.push(del);
74   }
75   return mkdru.hashAddDelMany(toAdd, toDel);
76 }
77
78
79
80 // pz2.js event handlers:
81 mkdru.pz2Init = function () {
82   if (mkdru.state.query) {
83     mkdru.search();
84   }
85   mkdru.pz2.stat();
86   //mkdru.pz2.bytarget();
87 };
88
89 mkdru.pz2Show = function (data) {
90   mkdru.totalRec = data.merged;
91   $('.mkdru-pager').html(mkdru.generatePager());
92   $('.mkdru-counts').html(Drupal.theme('mkdruCounts', data.start + 1,
93                                       data.num, data.merged, data.total));
94   var html = "";
95   for (var i = 0; i < data.hits.length; i++) {
96     html += Drupal.theme('mkdruResult', data.hits[i], 
97       i + 1 + mkdru.state.perpage * (mkdru.state.page - 1),
98       "#" + $.param.fragment($.param.fragment(
99         window.location.href, {recid: data.hits[i].recid})) + "\n"
100     );
101   }
102   $('.mkdru-result-list').html(html);
103   if (mkdru.state.recid) {
104     mkdru.pz2.record(mkdru.state.recid);
105   }
106   else {
107     $('.mkdru-results').show();
108   }
109 };
110
111 mkdru.pz2Status = function (data) {
112   $('.mkdru-status').html(Drupal.theme('mkdruStatus', data.activeclients, data.clients));
113 };
114
115 mkdru.pz2Term = function (data) {
116   for (var facet in mkdru.facets) {
117     // facet is limited
118     if (mkdru.state['limit_' + facet]) {
119       $('.mkdru-facet-' + facet).html(Drupal.theme('mkdruFacetLimit',
120                                  data[mkdru.facets[facet].pz2Name][0],
121                                  mkdru.hashAddDelOne(null, null, 'limit_' + facet)));
122     } else {
123       $('.mkdru-facet-' + facet).html(Drupal.theme('mkdruFacet',
124                                  data[mkdru.facets[facet].pz2Name],
125                                  facet, mkdru.facets[facet].max));
126     }
127   }
128 };
129
130 mkdru.pz2ByTarget = function (data) {
131   
132 };
133
134 mkdru.pz2Record = function (data) {
135   clearTimeout(mkdru.pz2.showTimer);
136   $('.mkdru-results').hide();
137   $('.mkdru-detail').html(Drupal.theme('mkdruDetail', data,
138                                        mkdru.hashAddDelOne(null, null, 'recid')));
139   $('.mkdru-detail').show();
140   clearTimeout(mkdru.pz2.recordTimer);
141 };
142
143
144
145 // State and URL handling 
146
147 // populate state from an object and fill in the blanks with defaults
148 mkdru.stateFromObject = function (obj) {
149   mkdru.state = $.extend({}, mkdru.defaultState);
150   for (var key in mkdru.defaultState)
151     if (typeof(obj[key]) != "undefined")
152       mkdru.state[key] = obj[key];
153 };
154
155 // populate state from current window's hash string
156 mkdru.stateFromHash = function () {
157   mkdru.stateFromObject($.deparam.fragment());
158 };
159
160 // set current window's hash string from state
161 mkdru.hashFromState = function () {
162   // only include non-default settings in the URL
163   var alteredState = {};
164   for (var key in mkdru.defaultState) {
165     if (mkdru.state[key] != mkdru.defaultState[key]) {
166       alteredState[key] = mkdru.state[key];
167     }
168   }
169   $.bbq.pushState(alteredState, 2);
170 };
171
172 // update mkdru_form theme's ui to match state
173 mkdru.uiFromState = function () {
174   for (var key in mkdru.state) {
175     switch(key) {
176     case 'query':
177       $('.mkdru-search input:text').attr('value', mkdru.state[key]);
178       break;
179     case 'perpage':
180       $('.mkdru-perpage').attr('value', mkdru.state[key]);
181       break;
182     case 'sort':
183       $('.mkdru-sort').attr('value', mkdru.state[key]);
184       break;
185     }
186   }
187 };
188
189 mkdru.hashChange = function () {
190   mkdru.stateFromHash();
191   // Request for details
192   if (mkdru.state.recid) {
193     mkdru.pz2.record(mkdru.state.recid);
194   }
195   // Other internal link
196   else {
197     // may need to run search again to limit targets
198     for (key in mkdru.state) {
199       if (key.substring(0,5) === 'limit') {
200         mkdru.search();
201         break;
202       }
203     }
204     mkdru.pz2.showPage(mkdru.state.page-1);
205     $('.mkdru-detail').hide();
206     $('.mkdru-results').show();
207   }
208 };
209
210
211
212 //form submit handler
213 mkdru.submitQuery = function () {
214   // new query, back to defaults (shallow copy)
215   mkdru.state = $.extend({}, mkdru.defaultState);
216   mkdru.state.query = $('.mkdru-search input:text').attr('value');
217   mkdru.pollDropDowns();
218   mkdru.hashFromState();
219   mkdru.search();
220   mkdru.active = true;
221   return false;
222 };
223
224 //criteria drop-down (perpage, sort) handler
225 mkdru.submitCriteria = function () {
226   mkdru.pollDropDowns();
227   //search is not ON, do nothing
228   if (!mkdru.active) return false;
229   // pages mean different things now
230   mkdru.state.page = 1;
231   mkdru.hashFromState();
232   mkdru.pz2.show(0, mkdru.state.perpage, mkdru.state.sort);
233   return false;
234 }
235
236 mkdru.search = function () {
237   var filter = null;
238   var query = mkdru.state.query;
239
240   // facet limit implementation
241   if (mkdru.state.limit_source) {
242     filter = 'pz:id=' + mkdru.state.limit_source;
243   }
244   if (mkdru.state.limit_subject) {
245     query += ' and su="' + mkdru.state.limit_subject + '"';
246   }
247   if (mkdru.state.limit_author) {
248     query += ' and au="' + mkdru.state.limit_author + '"';
249   }
250   mkdru.pz2.search(query, mkdru.state.perpage, mkdru.state.sort, filter);
251   //inform others that the search is ON
252   mkdru.active = true;
253 };
254
255 mkdru.pollDropDowns = function () {
256   mkdru.state.perpage = $('.mkdru-perpage').attr('value');
257   mkdru.state.sort = $('.mkdru-sort').attr('value');
258 };
259
260 mkdru.generatePager = function () {
261  // make sure page param is a number, otherwise pageing frwd will be broken
262   if (typeof mkdru.state.page == "string") {
263     mkdru.state.page = Number(mkdru.state.page);
264   }
265   var total = Math.ceil(mkdru.totalRec / mkdru.state.perpage);
266   var first = (mkdru.state.page - mkdru.pagerRange > 0)
267       ? mkdru.state.page - mkdru.pagerRange : 1;
268   var last = first + 2 * mkdru.pagerRange < total
269       ? first + 2 * mkdru.pagerRange : total;  
270   var prev = null;
271   var next = null;
272   var pages = [];
273
274   if ((mkdru.state.page - 1) >= first) {
275     prev = "#" + $.param.fragment($.param.fragment(
276                window.location.href, {page: mkdru.state.page - 1}))
277   }
278   if ((mkdru.state.page + 1) <= total) {
279     next = "#" + $.param.fragment($.param.fragment(
280                window.location.href, {page: mkdru.state.page + 1}))
281   }
282
283   for (var i = first; i <= last; i++) {
284     pages.push("#" + $.param.fragment($.param.fragment(
285                window.location.href, {page: i})));
286   }
287
288   return Drupal.theme('mkdruPager', pages, first, mkdru.state.page,
289                       total, prev, next);
290 };
291
292
293
294 // wait until the DOM is ready, bind events
295 // and instantiate pz2 library
296 $(document).ready(function () {
297   $(window).bind( 'hashchange', mkdru.hashChange);
298   $('.mkdru-search').bind('submit', mkdru.submitQuery);
299   $('.mkdru-search input:text').attr('value', '');
300   $('.mkdru-perpage').bind('change', mkdru.submitCriteria);
301   $('.mkdru-sort').bind('change', mkdru.submitCriteria);
302
303   // generate termlist for pz2.js and populate facet limit state
304   var termlist = [];
305   for (var key in mkdru.facets) {
306     termlist.push(mkdru.facets[key].pz2Name);
307     mkdru.defaultState['limit_' + key] = null;
308   }
309
310   mkdru.pz2 = new pz2( { "onshow": mkdru.pz2Show,
311               "showtime": 500, //each timer (show, stat, term, bytarget) can be specified this way
312               "pazpar2path": mkdru.pazpar2Path,
313               "oninit": mkdru.pz2Init,
314               "onstat": mkdru.pz2Status,
315               "onterm": mkdru.pz2Term,
316               "termlist": termlist.join(','),
317               "onbytarget": mkdru.pz2ByTarget,
318               "usesessions" : mkdru.useSessions,
319               "showResponseType": mkdru.showResponseType,
320               "onrecord": mkdru.pz2Record,
321               "autoInit": false } );
322
323   // initialise state to hash string or defaults
324   mkdru.stateFromHash();
325   // and update UI to match
326   mkdru.uiFromState();
327
328   // ting thing
329   if (typeof(Drupal.settings.mkdru.query) !== "undefined") {
330     mkdru.state.query = Drupal.settings.mkdru.query
331   }
332   
333   //not running against SP? init, otherwise authenticate
334   if (mkdru.useSessions) {
335     mkdru.pz2.init();
336   } else {
337     //runnin against SP
338     var user = Drupal.settings.mkdru.sp_user;
339     var pass = Drupal.settings.mkdru.sp_pass;
340     var params = {};
341     params['command'] = 'auth';
342     if (user && pass) {
343       params['action'] = 'login';
344       params['username'] = user;
345       params['password'] = pass;
346     } else {
347       params['action'] = 'ipauth';
348     }
349     var authReq = new pzHttpRequest(mkdru.pazpar2Path, 
350       function (err) {
351         alert("Authentication against metasearch gateway failed: " +err);
352       }
353     );
354     authReq.get(params,
355       function (data) {
356         var s = data.getElementsByTagName('status');
357         if (s.length && Element_getTextContent(s[0]) == "OK") {
358           mkdru.realm = data.getElementsByTagName('realm');
359           mkdru.pz2Init();
360         } else {
361           alert("Malformed response when authenticating against the metasearch"
362             + " gateway");
363         }
364       }
365     );
366   }
367 });
368 })(jQuery);