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