]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/Util.js
Serials batch receive: usability improvements
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / Util.js
1 /* ---------------------------------------------------------------------------
2  * Copyright (C) 2008  Georgia Public Library Service
3  * Bill Erickson <erickson@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * ---------------------------------------------------------------------------
15  */
16
17
18 /**
19  * General purpose, static utility functions
20  */
21
22 if(!dojo._hasResource["openils.Util"]) {
23     dojo._hasResource["openils.Util"] = true;
24     dojo.provide("openils.Util");
25     dojo.require("dojo.date.locale");
26     dojo.require("dojo.date.stamp");
27     dojo.require('openils.Event');
28     dojo.declare('openils.Util', null, {});
29
30
31     openils.Util.timeStampRegexp =
32         /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\+-]\d{2})(\d{2})$/;
33
34     openils.Util.timeStampAsDateObj = function(s) {
35         if (s.constructor.name == "Date") return s;
36         return dojo.date.stamp.fromISOString(
37             s.replace(openils.Util.timeStampRegexp, "$1:$2")
38         );
39     }
40
41     /**
42      * Returns a locale-appropriate representation of a timestamp when the
43      * timestamp (first argument) is actually a string as provided by
44      * fieldmapper objects.
45      * The second argument is an optional argument that will be provided
46      * as the second argument to dojo.date.locale.format()
47      */
48     openils.Util.timeStamp = function(s, opts) {
49         if (typeof(opts) == "undefined") opts = {};
50
51         return dojo.date.locale.format(
52             openils.Util.timeStampAsDateObj(s), opts
53         );
54     };
55
56     /**
57      * Wrapper for dojo.addOnLoad that verifies a valid login session is active
58      * before adding the function to the onload set
59      */
60     openils.Util.addOnLoad = function(func, noSes) {
61         if(func) {
62             if(!noSes) {
63                 dojo.require('openils.User');
64                 if(!openils.User.authtoken) 
65                     return;
66             }
67             console.log("adding onload " + func.name);
68             dojo.addOnLoad(func);
69         }
70     };
71
72     /**
73      * Returns true if the provided array contains the specified value
74      */
75     openils.Util.arrayContains = function(arr, val) {
76         for(var i = 0; arr && i < arr.length; i++) {
77             if(arr[i] == val)
78                 return true;
79         }
80         return false;
81     };
82
83     /**
84      * Given a HTML select object, returns the currently selected value
85      */
86     openils.Util.selectorValue = function(sel) {
87         if(!sel) return null;
88         var idx = sel.selectedIndex;
89         if(idx < 0) return null;
90         var o = sel.options[idx];
91         var v = o.value; 
92         if(v == null) v = o.innerHTML;
93         return v;
94     }
95
96     /**
97      * Returns the character code of the provided (or current window) event
98      */
99     openils.Util.getCharCode = function(evt) {
100         evt = (evt) ? evt : ((window.event) ? event : null); 
101         if(evt) {
102             return (evt.charCode ? evt.charCode : 
103                 ((evt.which) ? evt.which : evt.keyCode ));
104         } else { return -1; }
105     }
106
107
108     /**
109      * Registers a handler for when the Enter key is pressed while 
110      * the provided DOM node has focus.
111      */
112     openils.Util.registerEnterHandler = function(domNode, func) {
113             if(!(domNode && func)) return;
114             domNode.onkeydown = function(evt) {
115             var code = openils.Util.getCharCode(evt);
116             if(code == 13 || code == 3) 
117                 func();
118         }
119         }
120
121
122     /**
123      * Parses opensrf response objects to see if they contain 
124      * data and/or an ILS event.  This only calls request.recv()
125      * once, so in a streaming context, it's necessary to loop on
126      * this method. 
127      * @param r The OpenSRF Request object
128      * @param eventOK If true, any found events will be returned as responses.  
129      * If false, they will be treated as error conditions and their content will
130      * be alerted if openils.Util.alertEvent is set to true.  Also, if eventOk is
131      * false, the response content will be null when an event is encountered.
132      * @param isList If true, assume the response will be a list of data and
133      * check the 1st item in the list for event-ness instead of the list itself.
134      */
135     openils.Util.alertEvent = true;
136     openils.Util.readResponse = function(r, eventOk, isList) {
137         var msg = r.recv();
138         if(msg == null) return msg;
139         var val = msg.content();
140         var testval = val;
141         if(isList && dojo.isArray(val))
142             testval = val[0];
143         if(e = openils.Event.parse(testval)) {
144             if(eventOk) return e;
145             console.log(e.toString());
146             if(openils.Util.alertEvent)
147                 alert(e);
148             return null;
149         }
150         return val;
151     };
152
153
154     /**
155      * Given a DOM node, adds the provided class to the node 
156      */
157     openils.Util.addCSSClass = function(node, cls) {
158         if(!(node && cls)) return; 
159         var className = node.className;
160
161         if(!className) {
162             node.className = cls;
163             return;
164         }
165
166         var classList = className.split(/\s+/);
167         var newName = '';
168             
169         for (var i = 0; i < classList.length; i++) {
170             if(classList[i] == cls) return;
171             if(classList[i] != null)
172                 newName += classList[i] + " ";
173         }
174
175         newName += cls;
176         node.className = newName;
177     },
178
179     /**
180      * Given a DOM node, removes the provided class from the CSS class 
181      * name list.
182      */
183     openils.Util.removeCSSClass = function(node, cls) {
184         if(!(node && cls && node.className)) return;
185         var classList = node.className.split(/\s+/);
186         var className = '';
187         for(var i = 0; i < classList.length; i++) {
188             if (typeof(cls) == "object") { /* assume regex */
189                 if (!cls.test(classList[i])) {
190                     if(i == 0)
191                         className = classList[i];
192                     else
193                         className += ' ' + classList[i];
194                 }
195             } else {
196                 if (classList[i] != cls) {
197                     if(i == 0)
198                         className = classList[i];
199                     else
200                         className += ' ' + classList[i];
201                 }
202             }
203         }
204         node.className = className;
205     }
206
207     openils.Util.objectSort = function(list, field) {
208         if(dojo.isArray(list)) {
209             if(!field) field = 'id';
210             return list.sort(
211                 function(a, b) {
212                     if(a[field]() > b[field]()) return 1;
213                     return -1;
214                 }
215             );
216         }
217         return [];
218     };
219
220     openils.Util.isTrue = function(val) {
221         return (val && val != '0' && !(val+'').match(/^f$/i));
222     };
223
224     /**
225      * Turns a list into a mapped object.
226      * @param list The list
227      * @param pkey The field to use as the map key 
228      * @param isFunc If true, the map key field is an accessor function 
229      * that will return the value of the map key
230      */
231     openils.Util.mapList = function(list, pkey, isFunc) {
232         if(!(list && pkey)) 
233             return null;
234         var map = {};
235         for(var i in list) {
236             if(isFunc)
237                 map[list[i][pkey]()] = list[i];
238             else
239                 map[list[i][pkey]] = list[i];
240         }
241         return map;
242     };
243
244     /**
245      * Assume a space-separated interval string, with optional comma
246      * E.g. "1 year, 2 days"  "3 days 6 hours"
247      */
248     openils.Util.intervalToSeconds = function(interval) {
249         var d = new Date();
250         var start = d.getTime();
251         var parts = interval.split(' ');
252         for(var i = 0; i < parts.length; i += 2)  {
253             var type = parts[i+1].replace(/s?,?$/,'');
254             switch(type) {
255                 case 'mon': // postgres
256                     type = 'month'; // dojo
257                     break;
258                 // add more as necessary
259             }
260
261             d = dojo.date.add(d, type, Number(parts[i]));
262         }
263         return Number((d.getTime() - start) / 1000);
264     };
265
266     openils.Util.hide = function(node) {
267         if(typeof node == 'string')
268             node = dojo.byId(node);
269         dojo.style(node, 'display', 'none');
270         dojo.style(node, 'visibility', 'hidden');
271     };
272
273     openils.Util.show = function(node, displayType) {
274         if(typeof node == 'string')
275             node = dojo.byId(node);
276         displayType = displayType || 'block';
277         dojo.style(node, 'display', displayType);
278         dojo.style(node, 'visibility', 'visible');
279     };
280
281     /** Toggles the display using show/hide, depending on the current value for CSS 'display' */
282     openils.Util.toggle = function(node, displayType) {
283         if(typeof node == 'string')
284             node = dojo.byId(node);
285         if(dojo.style(node, 'display') == 'none')
286             openils.Util.show(node, displayType);
287         else
288             openils.Util.hide(node);
289     };
290
291     openils.Util.appendClear = function(node, child) {
292         if(typeof node == 'string')
293             node = dojo.byId(node);
294         while(node.childNodes[0])
295             node.removeChild(node.childNodes[0]);
296         node.appendChild(child);
297     };
298
299     /**
300      * Plays a sound file via URL.  Only works with browsers
301      * that support HTML 5 <audio> element.  E.g. Firefox 3.5
302      */
303     openils.Util.playAudioUrl = function(urlString) {
304         if(!urlString) return;
305         var audio = document.createElement('audio');
306         audio.setAttribute('src', urlString);
307         audio.setAttribute('autoplay', 'true');
308         document.body.appendChild(audio);
309         document.body.removeChild(audio);
310     }
311
312     /**
313      * Return the properties of an object as a list. Saves typing.
314      */
315     openils.Util.objectProperties = function(obj) {
316         var K = [];
317         for (var k in obj) K.push(k);
318         return K;
319     }
320
321     openils.Util.uniqueElements = function(L) {
322         var o = {};
323         for (var k in L) o[L[k]] = true;
324         return openils.Util.objectProperties(o);
325     }
326
327     openils.Util.uniqueObjects = function(list, field) {
328         var sorted = openils.Util.objectSort(list, field);
329         var results = [];
330         for (var i = 0; i < sorted.length; i++) {
331             if (!i || (sorted[i][field]() != sorted[i-1][field]()))
332                 results.push(sorted[i]);
333         }
334         return results;
335     };
336
337     /**
338      * Highlight instances of each pattern in the given DOM node
339      * Inspired by the jquery plugin
340      * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
341      */
342     openils.Util.hilightNode = function(node, patterns, args) {
343
344         args = args ||{};
345         var hclass = args.classname || 'oils-highlight';
346
347         function _hilightNode(node, pat) {
348
349             if(node.nodeType == 3) { 
350
351                 pat = pat.toUpperCase();
352                 var text = node.data.toUpperCase();
353                 var pos = -1;
354
355                 // find each instance of pat in the current node
356                 while( (pos =  text.indexOf(pat, pos + 1)) >= 0 ) {
357
358                     var wrapper = dojo.create('span', {className : hclass});
359                     var midnode = node.splitText(pos);
360                     midnode.splitText(pat.length);
361                     wrapper.appendChild(midnode.cloneNode(true));
362                     midnode.parentNode.replaceChild(wrapper, midnode);
363                 }
364
365             } else if(node.nodeType == 1 && node.childNodes[0]) {
366
367                 // not a text node?  have you checked the children?
368                 dojo.forEach(
369                     node.childNodes,
370                     function(child) { _hilightNode(child, pat); }
371                 );
372             }
373         }
374
375         // descend the tree for each pattern, since nodes are changed during highlighting
376         dojo.forEach(patterns, function(pat) { _hilightNode(node, pat); });
377     };
378
379
380     /**
381      * Takes a chunk of HTML, inserts it into a new window, prints the window, 
382      * then closes the windw.  To provide ample printer queueing time, automatically
383      * wait a short time before closing the window after calling .print().  The amount
384      * of time to wait is based on the size of the data to be printed.
385      * @param html The HTML string
386      * @param callback Optional post-printing callback
387      */
388     openils.Util.printHtmlString = function(html, callback) {
389
390         var win = window.open('', 'Print Window', 'resizable,width=800,height=600,scrollbars=1'); 
391
392         // force the new window to the background
393         win.blur(); 
394         window.focus(); 
395
396         win.document.body.innerHTML = html;
397         win.print();
398
399         setTimeout(
400             function() { 
401                 win.close();
402                 if(callback)
403                     callback();
404             },
405             // 1k == 1 second pause, max 10 seconds
406             Math.min(html.length, 10000)
407         );
408     };
409
410 }
411