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