84e98933a07c3cafb3eb37b12ae4f86027e37145
[pazpar2-moved-to-github.git] / www / pz2_js / pz2.js
1 //since explorer is flawed
2 if (!window['Node']) {
3     window.Node = new Object();
4     Node.ELEMENT_NODE = 1;
5     Node.ATTRIBUTE_NODE = 2;
6     Node.TEXT_NODE = 3;
7     Node.CDATA_SECTION_NODE = 4;
8     Node.ENTITY_REFERENCE_NODE = 5;
9     Node.ENTITY_NODE = 6;
10     Node.PROCESSING_INSTRUCTION_NODE = 7;
11     Node.COMMENT_NODE = 8;
12     Node.DOCUMENT_NODE = 9;
13     Node.DOCUMENT_TYPE_NODE = 10;
14     Node.DOCUMENT_FRAGMENT_NODE = 11;
15     Node.NOTATION_NODE = 12;
16 }
17 // check for jQuery
18 if(typeof window.jQuery == "undefined"){
19     throw new Error("pz2.js requires jQuery library");
20 }
21 // prevent execution of more than once
22 if(typeof window.pz2 == "undefined") {
23 window.undefined = window.undefined;
24
25 var pz2 = function(paramArray) {
26     //for convenience
27     __myself = this;
28
29     // at least one callback required
30     if ( !paramArray )
31         throw new Error("An array with parameters has to be suplied when instantiating a class");   
32     
33     // function callbacks
34     __myself.statCallback = paramArray.onstat || null;
35     __myself.showCallback = paramArray.onshow || null;
36     __myself.termlistCallback = paramArray.onterm || null;
37     __myself.recordCallback = paramArray.onrecord || null;
38     __myself.bytargetCallback = paramArray.onbytarget || null;
39
40     // termlist keys
41     __myself.termKeys = paramArray.termlist || "subject";
42     
43     // some configurational stuff
44     __myself.pz2String = "search.pz2";
45     __myself.keepAlive = 50000;
46
47     __myself.sessionID = null;
48     __myself.initStatusOK = false;
49     __myself.pingStatusOK = false;
50     __myself.searchStatusOK = false;
51
52     if ( paramArray.keepAlive < __myself.keepAlive )
53         __myself.keepAlive = paramArray.keepAlive;
54
55     // for sorting
56     __myself.currentSort = "relevance";
57     // where are we?
58     __myself.currentStart = 0;
59     __myself.currentNum = 20;
60
61     // last full record retrieved
62     __myself.currRecID = null;
63     // current query
64     __myself.currQuery = null;
65
66     //timers
67     __myself.statTime = paramArray.stattime || 2000;
68     __myself.statTimer = null;
69     __myself.termTime = paramArray.termtime || 2000;
70     __myself.termTimer = null;
71     __myself.showTime = paramArray.showtime || 2000;
72     __myself.showTimer = null;
73     __myself.bytargetTime = paramArray.bytargettime || 1000;
74     __myself.bytargetTimer = null;
75
76     // active clients, updated by stat and show
77     // might be an issue since bytarget will poll accordingly
78     __myself.activeClients = 1;
79
80     // error handling
81     $(document).ajaxError( 
82     function (request, settings, exception) {
83         if ( settings.responseXML && settings.responseXML.getElementsByTagName("error") )
84             throw new Error( settings.responseXML.getElementsByTagName("error")[0].childNodes[0].nodeValue);
85     });
86     
87     // auto init session?
88     if (paramArray.autoInit !== false)
89         __myself.init(__myself.keepAlive);
90 };
91 pz2.prototype = {
92     init: function(keepAlive) 
93     {
94         if ( keepAlive < __myself.keepAlive )
95             __myself.keepAlive = keepAlive;  
96         
97         $.get( __myself.pz2String,
98             { "command": "init" },
99             function(data) {
100                 if ( data.getElementsByTagName("status")[0].childNodes[0].nodeValue == "OK" ) {
101                     __myself.initStatusOK = true;
102                     __myself.sessionID = data.getElementsByTagName("session")[0].childNodes[0].nodeValue;
103                     setTimeout(__myself.ping, __myself.keepAlive);
104                 }
105                 else
106                     // if it gets here the http return code was 200 (pz2 errors are 417)
107                     // but the response was invalid, it should never occur
108                     setTimeout("__myself.init()", 1000);
109             }
110         );
111     },
112     // no need to ping explicitly
113     ping: function() 
114     {
115         if( !__myself.initStatusOK )
116             return;
117             // session is not initialized code here
118
119         $.get( __myself.pz2String,
120             { "command": "ping", "session": __myself.sessionID },
121             function(data) {
122                 if ( data.getElementsByTagName("status")[0].childNodes[0].nodeValue == "OK" ) {
123                     __myself.pingStatusOK = true;
124                     setTimeout("__myself.ping()", __myself.keepAlive);
125                 }
126                 else
127                     // if it gets here the http return code was 200 (pz2 errors are 417)
128                     // but the response was invalid, it should never occur
129                     setTimeout("__myself.ping()", 1000);
130             }
131         );
132     },
133     search: function(query, num, sort, filter)
134     {
135         clearTimeout(__myself.statTimer);
136         clearTimeout(__myself.showTimer);
137         clearTimeout(__myself.termTimer);
138         clearTimeout(__myself.bytargetTimer);
139
140         if( !__myself.initStatusOK )
141             return;
142         
143         if( query !== undefined )
144             __myself.currQuery = query;
145         else
146             throw new Error("You need to supply query to the search command");
147
148         if( filter !== undefined )
149             var searchParams = { "command": "search", "session": __myself.sessionID, "query": __myself.currQuery, "filter": filter };
150         else
151             var searchParams = { "command": "search", "session": __myself.sessionID, "query": __myself.currQuery };
152
153         $.get( __myself.pz2String,
154             searchParams,
155             function(data) {
156                 if ( data.getElementsByTagName("status")[0].childNodes[0].nodeValue == "OK" ) {
157                     __myself.searchStatusOK = true;
158                     //piggyback search
159                     __myself.show(0, num, sort);
160                     if ( __myself.statCallback )
161                         __myself.statTimer = setTimeout("__myself.stat()", __myself.statTime / 2);
162                     if ( __myself.termlistCallback )
163                         __myself.termlist();
164                         //__myself.termTimer = setTimeout("__myself.termlist()", __myself.termTime / 2);
165                     if ( __myself.bytargetCallback )
166                         __myself.bytargetTimer = setTimeout("__myself.bytarget()", __myself.bytargetTime / 2);
167                 }
168                 else
169                     // if it gets here the http return code was 200 (pz2 errors are 417)
170                     // but the response was invalid, it should never occur
171                     setTimeout("__myself.search(__myself.currQuery)", 1000);
172             }
173         );
174     },
175     stat: function()
176     {
177         if( !__myself.searchStatusOK )
178             return;
179         // if called explicitly takes precedence
180         clearTimeout(__myself.statTimer);
181
182         $.get( __myself.pz2String,
183             { "command": "stat", "session": __myself.sessionID },
184             function(data) {
185                 if ( data.getElementsByTagName("stat") ) {
186                     var activeClients = Number( data.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue );
187                     __myself.activeClients = activeClients;
188                     var stat = {
189                     "activeclients": activeClients,
190                     "hits": Number( data.getElementsByTagName("hits")[0].childNodes[0].nodeValue ),
191                     "records": Number( data.getElementsByTagName("records")[0].childNodes[0].nodeValue ),
192                     "clients": Number( data.getElementsByTagName("clients")[0].childNodes[0].nodeValue ),
193                     "initializing": Number( data.getElementsByTagName("initializing")[0].childNodes[0].nodeValue ),
194                     "searching": Number( data.getElementsByTagName("searching")[0].childNodes[0].nodeValue ),
195                     "presenting": Number( data.getElementsByTagName("presenting")[0].childNodes[0].nodeValue ),
196                     "idle": Number( data.getElementsByTagName("idle")[0].childNodes[0].nodeValue ),
197                     "failed": Number( data.getElementsByTagName("failed")[0].childNodes[0].nodeValue ),
198                     "error": Number( data.getElementsByTagName("error")[0].childNodes[0].nodeValue )
199                     };
200                     __myself.statCallback(stat);
201                     if (activeClients > 0)
202                         __myself.statTimer = setTimeout("__myself.stat()", __myself.statTime); 
203                 }
204                 else
205                     // if it gets here the http return code was 200 (pz2 errors are 417)
206                     // but the response was invalid, it should never occur
207                     __myself.statTimer = setTimeout("__myself.stat()", __myself.statTime / 4);
208             }
209         );
210     },
211     show: function(start, num, sort)
212     {
213         if( !__myself.searchStatusOK )
214             return;
215         // if called explicitly takes precedence
216         clearTimeout(__myself.showTimer);
217         
218         if( sort !== undefined )
219             __myself.currentSort = sort;
220         if( start !== undefined )
221             __myself.currentStart = Number( start );
222         if( num !== undefined )
223             __myself.currentNum = Number( num );
224         
225         $.get( __myself.pz2String,
226             { "command": "show", "session": __myself.sessionID, "start": __myself.currentStart,
227               "num": __myself.currentNum, "sort": __myself.currentSort, "block": 1 },
228             function(data) {
229                 if ( data.getElementsByTagName("status")[0].childNodes[0].nodeValue == "OK" ) {
230                     // first parse the status data send along with records
231                     // this is strictly bound to the format
232                     var activeClients = Number( data.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue );
233                     var show = {
234                     "activeclients": activeClients,
235                     "merged": Number( data.getElementsByTagName("merged")[0].childNodes[0].nodeValue ),
236                     "total": Number( data.getElementsByTagName("total")[0].childNodes[0].nodeValue ),
237                     "start": Number( data.getElementsByTagName("start")[0].childNodes[0].nodeValue ),
238                     "num": Number( data.getElementsByTagName("num")[0].childNodes[0].nodeValue ),
239                     "hits": []
240                     };
241                     // parse all the first-level nodes for all <hit> tags
242                     var hits = data.getElementsByTagName("hit");
243                     var hit = new Array();
244                     for (i = 0; i < hits.length; i++) {
245                         show.hits[i] = new Array();
246                         for ( j = 0; j < hits[i].childNodes.length; j++) {
247                             if ( hits[i].childNodes[j].nodeType == Node.ELEMENT_NODE ) {
248                                 var nodeName = hits[i].childNodes[j].nodeName;
249                                 var nodeText = hits[i].childNodes[j].firstChild.nodeValue;
250                                 show.hits[i][nodeName] = nodeText;
251                             }
252                         }
253                     }
254                     __myself.showCallback(show);
255                     if (activeClients > 0)
256                         __myself.showTimer = setTimeout("__myself.show()", __myself.showTime);
257                 }
258                 else
259                     // if it gets here the http return code was 200 (pz2 errors are 417)
260                     // but the response was invalid, it should never occur
261                     __myself.showTimer = setTimeout("__myself.show()", __myself.showTime / 4);
262             }
263         );
264     },
265     record: function(id)
266     {
267         if( !__myself.searchStatusOK )
268             return;
269
270         if( id !== undefined )
271             __myself.currRecID = id;
272
273         $.get( __myself.pz2String,
274             { "command": "record", "session": __myself.sessionID, "id": __myself.currRecID },
275             function(data) {
276                 var recordNode;
277                 var record = new Array();
278                 if ( recordNode = data.getElementsByTagName("record")[0] ) {
279                     for ( i = 0; i < recordNode.childNodes.length; i++) {
280                         if ( recordNode.childNodes[i].nodeType == Node.ELEMENT_NODE ) {
281                             var nodeName = recordNode.childNodes[i].nodeName;
282                             var nodeText = recordNode.childNodes[i].firstChild.nodeValue;
283                             record[nodeName] = nodeText;                            
284                         }
285                     }
286                     // the location is hard coded
287                     var locationNodes = recordNode.getElementsByTagName("location");
288                     record["location"] = new Array();
289                     for ( i = 0; i < locationNodes.length; i++ ) {
290                         record["location"][i] = {
291                             "id": locationNodes[i].getAttribute("id"),
292                             "name": locationNodes[i].getAttribute("name")
293                         };
294                         for ( j = 0; j < locationNodes[i].childNodes.length; j++) {
295                             if ( locationNodes[i].childNodes[j].nodeType == Node.ELEMENT_NODE ) {
296                                 var nodeName = locationNodes[i].childNodes[j].nodeName;
297                                 var nodeText = locationNodes[i].childNodes[j].firstChild.nodeValue;
298                                 record["location"][i][nodeName] = nodeText;                            
299                             }
300                         }
301                     }
302                     __myself.recordCallback(record);
303                 }
304                 else
305                     // if it gets here the http return code was 200 (pz2 errors are 417)
306                     // but the response was invalid, it should never occur
307                     setTimeout("__myself.record(__myself.currRecID)", 1000);
308             }
309         );
310     },
311     termlist: function()
312     {
313         if( !__myself.searchStatusOK )
314             return;
315         // if called explicitly takes precedence
316         clearTimeout(__myself.termTimer);
317
318         $.get( __myself.pz2String,
319             { "command": "termlist", "session": __myself.sessionID, "name": __myself.termKeys },
320             function(data) {
321                 if ( data.getElementsByTagName("termlist") ) {
322                     var termList = { "activeclients": Number( data.getElementsByTagName("activeclients")[0].childNodes[0].nodeValue ) };
323                     var termLists = data.getElementsByTagName("list");
324                     //for each termlist
325                     for (i = 0; i < termLists.length; i++) {
326                         var listName = termLists[i].getAttribute('name');
327                         termList[listName] = new Array();
328                         var terms = termLists[i].getElementsByTagName('term');
329                         //for each term in the list
330                         for (j = 0; j < terms.length; j++) { 
331                             var term = {
332                                 "name": terms[j].getElementsByTagName("name")[0].childNodes[0].nodeValue,
333                                 "freq": terms[j].getElementsByTagName("frequency")[0].childNodes[0].nodeValue
334                             };
335
336                             var termIdNode = terms[j].getElementsByTagName("id");
337                             if(terms[j].getElementsByTagName("id").length)
338                                 term["id"] = termIdNode[0].childNodes[0].nodeValue;
339
340                             termList[listName][j] = term;
341                         }
342                     }
343                     __myself.termlistCallback(termList);
344                     if (termList["activeclients"] > 0)
345                         __myself.termTimer = setTimeout("__myself.termlist()", __myself.termTime); 
346                 }
347                 else
348                     // if it gets here the http return code was 200 (pz2 errors are 417)
349                     // but the response was invalid, it should never occur
350                     __myself.termTimer = setTimeout("__myself.termlist()", __myself.termTime / 4); 
351             }
352         );
353
354     },
355     bytarget: function()
356     {
357         if( !__myself.searchStatusOK )
358             return;
359         // if called explicitly takes precedence
360         clearTimeout(__myself.bytargetTimer);
361
362         $.get( __myself.pz2String,
363             { "command": "bytarget", "session": __myself.sessionID },
364             function(data) {
365                 if ( data.getElementsByTagName("status")[0].childNodes[0].nodeValue == "OK" ) {
366                     var targetNodes = data.getElementsByTagName("target");
367                     var bytarget = new Array();
368                     for ( i = 0; i < targetNodes.length; i++) {
369                         bytarget[i] = new Array();
370                         for( j = 0; j < targetNodes[i].childNodes.length; j++ ) {
371                             if ( targetNodes[i].childNodes[j].nodeType == Node.ELEMENT_NODE ) {
372                                 var nodeName = targetNodes[i].childNodes[j].nodeName;
373                                 var nodeText = targetNodes[i].childNodes[j].firstChild.nodeValue;
374                                 bytarget[i][nodeName] = nodeText;
375                             }
376                         }
377                     }
378                     __myself.bytargetCallback(bytarget);
379                     if ( __myself.activeClients > 0 )
380                         __myself.bytargetTimer = setTimeout("__myself.bytarget()", __myself.bytargetTime);
381                 }
382                 else
383                     // if it gets here the http return code was 200 (pz2 errors are 417)
384                     // but the response was invalid, it should never occur
385                     __myself.bytargetTimer = setTimeout("__myself.bytarget()", __myself.bytargetTime / 4);
386             }
387         );
388     },
389     // just for testing, probably shouldn't be here
390     showNext: function(page)
391     {
392         var step = page || 1;
393         __myself.show( ( step * __myself.currentNum ) + __myself.currentStart );     
394     },
395     showPrev: function(page)
396     {
397         if (__myself.currentStart == 0 )
398             return false;
399         var step = page || 1;
400         var newStart = __myself.currentStart - (step * __myself.currentNum );
401         __myself.show( newStart > 0 ? newStart : 0 );
402     },
403     showPage: function(pageNum)
404     {
405         //var page = pageNum || 1;
406         __myself.show(pageNum * __myself.currentNum);
407     }
408 };
409 }