1 /* ---------------------------------------------------------------------------
2 * Copyright (C) 2008 Georgia Public Library Service
3 * Bill Erickson <erickson@esilibrary.com>
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.
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 * ---------------------------------------------------------------------------
19 * General purpose, static utility functions
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, {});
31 openils.Util.timeStampRegexp =
32 /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\+-]\d{2})(\d{2})$/;
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")
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()
48 openils.Util.timeStamp = function(s, opts) {
49 if (typeof(opts) == "undefined") opts = {};
51 return dojo.date.locale.format(
52 openils.Util.timeStampAsDateObj(s), opts
57 * Wrapper for dojo.addOnLoad that verifies a valid login session is active
58 * before adding the function to the onload set
60 openils.Util.addOnLoad = function(func, noSes) {
63 dojo.require('openils.User');
64 if(!openils.User.authtoken)
67 console.log("adding onload " + func.name);
73 * Returns true if the provided array contains the specified value
75 openils.Util.arrayContains = function(arr, val) {
76 for(var i = 0; arr && i < arr.length; i++) {
84 * Given a HTML select object, returns the currently selected value
86 openils.Util.selectorValue = function(sel) {
88 var idx = sel.selectedIndex;
89 if(idx < 0) return null;
90 var o = sel.options[idx];
92 if(v == null) v = o.innerHTML;
97 * Returns the character code of the provided (or current window) event
99 openils.Util.getCharCode = function(evt) {
100 evt = (evt) ? evt : ((window.event) ? event : null);
102 return (evt.charCode ? evt.charCode :
103 ((evt.which) ? evt.which : evt.keyCode ));
104 } else { return -1; }
109 * Registers a handler for when the Enter key is pressed while
110 * the provided DOM node has focus.
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)
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
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.
135 openils.Util.alertEvent = true;
136 openils.Util.readResponse = function(r, eventOk, isList) {
138 if(msg == null) return msg;
139 var val = msg.content();
141 if(isList && dojo.isArray(val))
143 if(e = openils.Event.parse(testval)) {
144 if(eventOk) return e;
145 console.log(e.toString());
146 if(openils.Util.alertEvent)
155 * Given a DOM node, adds the provided class to the node
157 openils.Util.addCSSClass = function(node, cls) {
158 if(!(node && cls)) return;
159 var className = node.className;
162 node.className = cls;
166 var classList = className.split(/\s+/);
169 for (var i = 0; i < classList.length; i++) {
170 if(classList[i] == cls) return;
171 if(classList[i] != null)
172 newName += classList[i] + " ";
176 node.className = newName;
180 * Given a DOM node, removes the provided class from the CSS class
183 openils.Util.removeCSSClass = function(node, cls) {
184 if(!(node && cls && node.className)) return;
185 var classList = node.className.split(/\s+/);
187 for(var i = 0; i < classList.length; i++) {
188 if (typeof(cls) == "object") { /* assume regex */
189 if (!cls.test(classList[i])) {
191 className = classList[i];
193 className += ' ' + classList[i];
196 if (classList[i] != cls) {
198 className = classList[i];
200 className += ' ' + classList[i];
204 node.className = className;
207 openils.Util.objectSort = function(list, field) {
208 if(dojo.isArray(list)) {
209 if(!field) field = 'id';
212 if(a[field]() > b[field]()) return 1;
220 openils.Util.isTrue = function(val) {
221 return (val && val != '0' && !(val+'').match(/^f$/i));
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
231 openils.Util.mapList = function(list, pkey, isFunc) {
237 map[list[i][pkey]()] = list[i];
239 map[list[i][pkey]] = list[i];
245 * Assume a space-separated interval string, with optional comma
246 * E.g. "1 year, 2 days" "3 days 6 hours"
248 openils.Util.intervalToSeconds = function(interval) {
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?,?$/,'');
255 case 'mon': // postgres
256 type = 'month'; // dojo
258 // add more as necessary
261 d = dojo.date.add(d, type, Number(parts[i]));
263 return Number((d.getTime() - start) / 1000);
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');
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');
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);
288 openils.Util.hide(node);
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);
300 * Plays a sound file via URL. Only works with browsers
301 * that support HTML 5 <audio> element. E.g. Firefox 3.5
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);
313 * Return the properties of an object as a list. Saves typing.
315 openils.Util.objectProperties = function(obj) {
317 for (var k in obj) K.push(k);
321 openils.Util.uniqueElements = function(L) {
323 for (var k in L) o[L[k]] = true;
324 return openils.Util.objectProperties(o);
328 * Highlight instances of each pattern in the given DOM node
329 * Inspired by the jquery plugin
330 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
332 openils.Util.hilightNode = function(node, patterns, args) {
335 var hclass = args.classname || 'oils-highlight';
337 function _hilightNode(node, pat) {
339 if(node.nodeType == 3) {
341 pat = pat.toUpperCase();
342 var text = node.data.toUpperCase();
345 // find each instance of pat in the current node
346 while( (pos = text.indexOf(pat, pos + 1)) >= 0 ) {
348 var wrapper = dojo.create('span', {className : hclass});
349 var midnode = node.splitText(pos);
350 midnode.splitText(pat.length);
351 wrapper.appendChild(midnode.cloneNode(true));
352 midnode.parentNode.replaceChild(wrapper, midnode);
355 } else if(node.nodeType == 1 && node.childNodes[0]) {
357 // not a text node? have you checked the children?
360 function(child) { _hilightNode(child, pat); }
365 // descend the tree for each pattern, since nodes are changed during highlighting
366 dojo.forEach(patterns, function(pat) { _hilightNode(node, pat); });
371 * Takes a chunk of HTML, inserts it into a new window, prints the window,
372 * then closes the windw. To provide ample printer queueing time, automatically
373 * wait a short time before closing the window after calling .print(). The amount
374 * of time to wait is based on the size of the data to be printed.
375 * @param html The HTML string
376 * @param callback Optional post-printing callback
378 openils.Util.printHtmlString = function(html, callback) {
380 var win = window.open('', 'Print Window', 'resizable,width=800,height=600,scrollbars=1');
382 // force the new window to the background
386 win.document.body.innerHTML = html;
395 // 1k == 1 second pause, max 10 seconds
396 Math.min(html.length, 10000)