PageSourceSearch

https://anvh.com/dwr/util.js

js anvh.com collected 2026-10-07 14:11:01 UTC 48,421 bytes, 1,526 lines download raw bytes

1/*
2 * Copyright 2005 Joe Walker
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Declare an object to which we can add real functions.
19 */
20if (window['dojo']) dojo.provide('dwr.util');
21if (typeof window['dwr'] == 'undefined') window.dwr = {};
22if (typeof dwr['util'] == 'undefined') dwr.util = {};
23//if (typeof window['DWRUtil'] == 'undefined') window.DWRUtil = dwr.util;
24
25/** @private The flag we use to decide if we should escape html */
26dwr.util._escapeHtml = true;
27
28/**
29 * Set the global escapeHtml flag
30 */
31dwr.util.setEscapeHtml = function(escapeHtml) {
32  dwr.util._escapeHtml = escapeHtml;
33};
34
35/** @private Work out from an options list and global settings if we should be esccaping */
36dwr.util._shouldEscapeHtml = function(options) {
37  if (options && options.escapeHtml != null) {
38    return options.escapeHtml;
39  }
40  return dwr.util._escapeHtml;
41};
42
43/**
44 * Return a string with &, < and > replaced with their entities
45 * @see TODO
46 */
47dwr.util.escapeHtml = function(original) {
48  return original.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#039;');
49};
50
51/**
52 * Replace common XML entities with characters (see dwr.util.escapeHtml())
53 * @see TODO
54 */
55dwr.util.unescapeHtml = function(original) {
56  return original.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&#039;/g,"'").replace(/&amp;/g,'&');
57};
58
59/**
60 * Replace characters dangerous for XSS reasons with visually similar characters
61 * @see TODO
62 */
63dwr.util.replaceXmlCharacters = function(original) {
64  original = original.replace("&", "+");
65  original = original.replace("<", "\u2039");
66  original = original.replace(">", "\u203A");
67  original = original.replace("\'", "\u2018");
68  original = original.replace("\"", "\u201C");
69  return original;
70};
71
72/**
73 * Return true iff the input string contains any XSS dangerous characters
74 * @see TODO
75 */
76dwr.util.containsXssRiskyCharacters = function(original) {
77  return (original.indexOf('&') != -1
78    || original.indexOf('<') != -1
79    || original.indexOf('>') != -1
80    || original.indexOf('\'') != -1
81    || original.indexOf('\"') != -1);
82};
83
84/**
85 * Enables you to react to return being pressed in an input
86 * @see http://getahead.org/dwr/browser/util/selectrange
87 */
88dwr.util.onReturn = function(event, action) {
89  if (!event) event = window.event;
90  if (event && event.keyCode && event.keyCode == 13) action();
91};
92
93/**
94 * Select a specific range in a text box. Useful for 'google suggest' type functions.
95 * @see http://getahead.org/dwr/browser/util/selectrange
96 */
97dwr.util.selectRange = function(ele, start, end) {
98  ele = dwr.util._getElementById(ele, "selectRange()");
99  if (ele == null) return;
100  if (ele.setSelectionRange) {
101    ele.setSelectionRange(start, end);
102  }
103  else if (ele.createTextRange) {
104    var range = ele.createTextRange();
105    range.moveStart("character", start);
106    range.moveEnd("character", end - ele.value.length);
107    range.select();
108  }
109  ele.focus();
110};
111
112/**
113 * Find the element in the current HTML document with the given id or ids
114 * @see http://getahead.org/dwr/browser/util/$
115 */
116dwr.util.byId = function() {
117  var elems = [];
118  for (var i = 0; i < arguments.length; i++) {
119    var idOrElem = arguments[i];
120    var elem;
121    if (typeof idOrElem == 'string') {
122      var elem = document.getElementById(idOrElem);
123      // Workaround for IE and Opera that may return element based on name
124      // (note use of elem.attributes.id.value due to IE bug for elem.getAttribute) 
125      if (document.all && elem && elem.attributes.id.value != idOrElem) {
126        elem = null;
127        var maybeElems = document.all[idOrElem];
128        if (maybeElems.tagName) maybeElems = [maybeElems];
129        for (var j = 0; j < maybeElems.length; j++) {
130          if (maybeElems[j].attributes.id.value == idOrElem) {
131            elem = maybeElems[j];
132            break;
133          }
134        }
135      }
136    }
137    else {
138      elem = idOrElem;
139    }
140    if (arguments.length == 1) {
141      return elem;
142    }
143    elems.push(elem);
144  }
145  return elems;
146}
147
148/**
149 * Alias $ to dwr.util.byId
150 * @see http://getahead.org/dwr/browser/util/$
151 */
152if (window['$'] == null) {
153  window['$'] = dwr.util.byId;
154}
155
156/**
157 * This function pretty-prints simple data or whole object graphs, f ex as an aid in debugging.
158 * @see http://getahead.org/dwr/browser/util/todescriptivestring
159 */
160dwr.util.toDescriptiveString = function(data, showLevels, options) {
161  if (showLevels === undefined) showLevels = 1;
162  var opt = {};
163  if (dwr.util._isObject(options)) opt = options;
164  var defaultoptions = {
165    escapeHtml:false,
166    baseIndent: "",
167    childIndent: "\u00A0\u00A0",
168    lineTerminator: "\n",
169    oneLineMaxItems: 5,
170    shortStringMaxLength: 13,
171    propertyNameMaxLength: 30 
172  };
173  for (var p in defaultoptions) {
174    if (!(p in opt)) {
175      opt[p] = defaultoptions[p];
176    }
177  }
178
179  var skipDomProperties = {
180    document:true, ownerDocument:true,
181    all:true,
182    parentElement:true, parentNode:true, offsetParent:true,
183    children:true, firstChild:true, lastChild:true,
184    previousSibling:true, nextSibling:true,
185    innerHTML:true, outerHTML:true,
186    innerText:true, outerText:true, textContent:true,
187    attributes:true,
188    style:true, currentStyle:true, runtimeStyle:true,
189    parentTextEdit:true
190  };
191  
192  function recursive(data, showLevels, indentDepth, options) {
193    var reply = "";
194    try {
195      // string
196      if (dwr.util._isString(data)) {
197        var str = data;
198        if (showLevels == 0 && str.length > options.shortStringMaxLength)
199          str = str.substring(0, options.shortStringMaxLength-3) + "...";
200        if (options.escapeHtml) {
201          // Do the escape separately for every line as escapeHtml() on some 
202          // browsers (IE) will strip line breaks and we want to preserve them
203          var lines = str.split("\n");
204          for (var i = 0; i < lines.length; i++) lines[i] = dwr.util.escapeHtml(lines[i]);
205          str = lines.join("\n");
206        }
207        if (showLevels == 0) { // Short format
208          str = str.replace(/\n|\r|\t/g, function(ch) {
209            switch (ch) {
210              case "\n": return "\\n";
211              case "\r": return "";
212              case "\t": return "\\t";
213            }
214          });
215        }
216        else { // Long format
217          str = str.replace(/\n|\r|\t/g, function(ch) {
218            switch (ch) {
219              case "\n": return options.lineTerminator + indent(indentDepth+1, options);
220              case "\r": return "";
221              case "\t": return "\\t";
222            }
223          });
224        }
225        reply = '"' + str + '"';
226      }
227      
228      // function
229      else if (dwr.util._isFunction(data)) {
230        reply = "function";
231      }
232    
233      // Array
234      else if (dwr.util._isArrayLike(data)) {
235        if (showLevels == 0) { // Short format (don't show items)
236          if (data.length > 0)
237            reply = "[...]";
238          else
239            reply = "[]";
240        }
241        else { // Long format (show items)
242          var strarr = [];
243          strarr.push("[");
244          var count = 0;
245          for (var i = 0; i < data.length; i++) {
246            if (!(i in data) && data != "[object NodeList]") continue;
247            var itemvalue = data[i];
248            if (count > 0) strarr.push(", ");
249            if (showLevels == 1) { // One-line format
250              if (count == options.oneLineMaxItems) {
251                strarr.push("...");
252                break;
253              }
254            }
255            else { // Multi-line format
256              strarr.push(options.lineTerminator + indent(indentDepth+1, options));
257            }
258            if (i != count) {
259              strarr.push(i);
260              strarr.push(":");
261            }
262            strarr.push(recursive(itemvalue, showLevels-1, indentDepth+1, options));
263            count++;
264          }
265          if (showLevels > 1) strarr.push(options.lineTerminator + indent(indentDepth, options));
266          strarr.push("]");
267          reply = strarr.join("");
268        }
269      }
270      
271      // Objects except Date
272      else if (dwr.util._isObject(data) && !dwr.util._isDate(data)) {
273        if (showLevels == 0) { // Short format (don't show properties)
274          reply = dwr.util._detailedTypeOf(data);
275        }
276        else { // Long format (show properties)
277          var strarr = [];
278          if (dwr.util._detailedTypeOf(data) != "Object") {
279            strarr.push(dwr.util._detailedTypeOf(data));
280            if (typeof data.valueOf() != "object") {
281              strarr.push(":");
282              strarr.push(recursive(data.valueOf(), 1, indentDepth, options));
283            }
284            strarr.push(" ");
285          }
286          strarr.push("{");
287          var isDomObject = dwr.util._isHTMLElement(data); 
288          var count = 0;
289          for (var prop in data) {
290            var propvalue = data[prop];
291            if (isDomObject) {
292              if (!propvalue) continue;
293              if (typeof propvalue == "function") continue;
294              if (skipDomProperties[prop]) continue;
295              if (prop.toUpperCase() == prop) continue;
296            }
297            if (count > 0) strarr.push(", ");
298            if (showLevels == 1) { // One-line format
299              if (count == options.oneLineMaxItems) {
300                strarr.push("...");
301                break;
302              }
303            }
304            else { // Multi-line format
305              strarr.push(options.lineTerminator + indent(indentDepth+1, options));
306            }
307            strarr.push(prop.length > options.propertyNameMaxLength ? prop.substring(0, options.propertyNameMaxLength-3) + "..." : prop);
308            strarr.push(":");
309            strarr.push(recursive(propvalue, showLevels-1, indentDepth+1, options));
310            count++;
311          }
312          if (showLevels > 1 && count > 0) strarr.push(options.lineTerminator + indent(indentDepth, options));
313          strarr.push("}");
314          reply = strarr.join("");
315        }
316      }
317  
318      // undefined, null, number, boolean, Date
319      else {
320        reply = "" + data;
321      }
322  
323      return reply;
324    }
325    catch(err) {
326      return (err.message ? err.message : ""+err);
327    }
328  }
329
330  function indent(count, options) {
331    var strarr = [];
332    strarr.push(options.baseIndent);
333    for (var i=0; i<count; i++) {
334      strarr.push(options.childIndent);
335    }
336    return strarr.join("");
337  };
338  
339  return recursive(data, showLevels, 0, opt);
340};
341
342/**
343 * Setup a GMail style loading message.
344 * @see http://getahead.org/dwr/browser/util/useloadingmessage
345 */
346dwr.util.useLoadingMessage = function(message) {
347  var loadingMessage;
348  if (message) loadingMessage = message;
349  else loadingMessage = "Loading";
350  dwr.engine.setPreHook(function() {
351    var disabledZone = dwr.util.byId('disabledZone');
352    if (!disabledZone) {
353      disabledZone = document.createElement('div');
354      disabledZone.setAttribute('id', 'disabledZone');
355      disabledZone.style.position = "absolute";
356      disabledZone.style.zIndex = "1000";
357      disabledZone.style.left = "0px";
358      disabledZone.style.top = "0px";
359      disabledZone.style.width = "100%";
360      disabledZone.style.height = "100%";
361      // IE need a background color to block click. Use an invisible background.
362      if (window.ActiveXObject) {
363        disabledZone.style.background = "white";
364        disabledZone.style.filter = "alpha(opacity=0)";
365      }
366      document.body.appendChild(disabledZone);
367      var messageZone = document.createElement('div');
368      messageZone.setAttribute('id', 'messageZone');
369      messageZone.style.position = "absolute";
370      messageZone.style.top = "0px";
371      messageZone.style.right = "0px";
372      messageZone.style.background = "red";
373      messageZone.style.color = "white";
374      messageZone.style.fontFamily = "Arial,Helvetica,sans-serif";
375      messageZone.style.padding = "4px";
376      document.body.appendChild(messageZone);
377      var text = document.createTextNode(loadingMessage);
378      messageZone.appendChild(text);
379      dwr.util._disabledZoneUseCount = 1;
380    }
381    else {
382      dwr.util.byId('messageZone').innerHTML = loadingMessage;
383      disabledZone.style.visibility = 'visible';
384      dwr.util._disabledZoneUseCount++;
385      dwr.util.byId('messageZone').style.visibility = 'visible';
386    }
387  });
388  dwr.engine.setPostHook(function() {
389    dwr.util._disabledZoneUseCount--;
390    if (dwr.util._disabledZoneUseCount == 0) {
391      dwr.util.byId('disabledZone').style.visibility = 'hidden';
392      dwr.util.byId('messageZone').style.visibility = 'hidden';
393    }
394  });
395};
396
397/**
398 * Set a global highlight handler
399 */
400dwr.util.setHighlightHandler = function(handler) {
401  dwr.util._highlightHandler = handler;
402};
403
404/**
405 * An example highlight handler
406 */
407dwr.util.yellowFadeHighlightHandler = function(ele) {
408  dwr.util._yellowFadeProcess(ele, 0);
409};
410dwr.util._yellowFadeSteps = [ "d0", "b0", "a0", "90", "98", "a0", "a8", "b0", "b8", "c0", "c8", "d0", "d8", "e0", "e8", "f0", "f8" ];
411dwr.util._yellowFadeProcess = function(ele, colorIndex) {
412  ele = dwr.util.byId(ele);
413  if (colorIndex < dwr.util._yellowFadeSteps.length) {
414    ele.style.backgroundColor = "#ffff" + dwr.util._yellowFadeSteps[colorIndex];
415    setTimeout("dwr.util._yellowFadeProcess('" + ele.id + "'," + (colorIndex + 1) + ")", 200);
416  }
417  else {
418    ele.style.backgroundColor = "transparent";
419  }
420};
421
422/**
423 * An example highlight handler
424 */
425dwr.util.borderFadeHighlightHandler = function(ele) {
426  ele.style.borderWidth = "2px";
427  ele.style.borderStyle = "solid";
428  dwr.util._borderFadeProcess(ele, 0);
429};
430dwr.util._borderFadeSteps = [ "d0", "b0", "a0", "90", "98", "a0", "a8", "b0", "b8", "c0", "c8", "d0", "d8", "e0", "e8", "f0", "f8" ];
431dwr.util._borderFadeProcess = function(ele, colorIndex) {
432  ele = dwr.util.byId(ele);
433  if (colorIndex < dwr.util._borderFadeSteps.length) {
434    ele.style.borderColor = "#ff" + dwr.util._borderFadeSteps[colorIndex] + dwr.util._borderFadeSteps[colorIndex];
435    setTimeout("dwr.util._borderFadeProcess('" + ele.id + "'," + (colorIndex + 1) + ")", 200);
436  }
437  else {
438    ele.style.backgroundColor = "transparent";
439  }
440};
441
442/**
443 * A focus highlight handler
444 */
445dwr.util.focusHighlightHandler = function(ele) {
446  try {
447    ele.focus();
448  }
449  catch (ex) { /* ignore */ }
450};
451
452/** @private the current global highlight style */
453dwr.util._highlightHandler = null;
454
455/**
456 * Highlight that an element has changed
457 */
458dwr.util.highlight = function(ele, options) {
459  if (options && options.highlightHandler) {
460    options.highlightHandler(dwr.util.byId(ele));
461  }
462  else if (dwr.util._highlightHandler != null) {
463    dwr.util._highlightHandler(dwr.util.byId(ele));
464  }
465};
466
467/**
468 * Set the value an HTML element to the specified value.
469 * @see http://getahead.org/dwr/browser/util/setvalue
470 */
471dwr.util.setValue = function(ele, val, options) {
472  if (val == null) val = "";
473  if (options == null) options = {};
474
475  var orig = ele;
476  ele = dwr.util.byId(ele); // Returns null if argument is a name, even on IE
477  var nodes = null;
478  if (ele == null) {
479    // Now it is time to look by name
480    nodes = document.getElementsByName(orig);
481    if (nodes.length >= 1) ele = nodes.item(0);
482  }
483
484  if (ele == null) {
485    dwr.util._debug("setValue() can't find an element with id/name: " + orig + ".");
486    return;
487  }
488
489  // All paths now lead to some update so we highlight a change
490  dwr.util.highlight(ele, options);
491
492  if (dwr.util._isHTMLElement(ele, "select")) {
493    if (ele.type == "select-multiple" && dwr.util._isArray(val)) dwr.util._selectListItems(ele, val);
494    else dwr.util._selectListItem(ele, val);
495    return;
496  }
497
498  if (dwr.util._isHTMLElement(ele, "input")) {
499    if (ele.type == "radio" || ele.type == "checkbox") {
500      if (nodes && nodes.length >= 1) {
501        for (var i = 0; i < nodes.length; i++) {
502          var node = nodes.item(i);
503          if (node.type != ele.type) continue;
504          if (dwr.util._isArray(val)) {
505            node.checked = false;
506            for (var j = 0; j < val.length; j++)
507              if (val[j] == node.value) node.checked = true;
508          }
509          else {
510            node.checked = (node.value == val);
511          }
512        }
513      }
514      else {
515        ele.checked = (val == true);
516      }
517    }
518    else ele.value = val;
519
520    return;
521  }
522
523  if (dwr.util._isHTMLElement(ele, "textarea")) {
524    ele.value = val;
525    return;
526  }
527
528  if (dwr.util._isHTMLElement(ele, "img")) {
529    ele.src = val;
530    return;
531  }
532
533  // If the value to be set is a DOM object then we try importing the node
534  // rather than serializing it out
535  if (val.nodeType) {
536    if (val.nodeType == 9 /*Node.DOCUMENT_NODE*/) val = val.documentElement;
537    val = dwr.util._importNode(ele.ownerDocument, val, true);
538    ele.appendChild(val);
539    return;
540  }
541
542  // Fall back to innerHTML and friends
543  if (dwr.util._shouldEscapeHtml(options)) {
544    if ("textContent" in ele) ele.textContent = val.toString();
545    else if ("innerText" in ele) ele.innerText = val.toString();
546    else ele.innerHTML = dwr.util.escapeHtml(val.toString());
547  }
548  else {
549    ele.innerHTML = val;
550  }
551};
552
553/**
554 * @private Find multiple items in a select list and select them. Used by setValue()
555 * @param ele The select list item
556 * @param val The array of values to select
557 */
558dwr.util._selectListItems = function(ele, val) {
559  // We deal with select list elements by selecting the matching option
560  // Begin by searching through the values
561  var found  = 0;
562  var i;
563  var j;
564  for (i = 0; i < ele.options.length; i++) {
565    ele.options[i].selected = false;
566    for (j = 0; j < val.length; j++) {
567      if (ele.options[i].value == val[j]) {
568        ele.options[i].selected = true;
569        found++;
570      }
571    }
572  }
573  // If that fails then try searching through the visible text
574  if (found == val.length) return;
575
576  for (i = 0; i < ele.options.length; i++) {
577    for (j = 0; j < val.length; j++) {
578      if (ele.options[i].text == val[j]) {
579        ele.options[i].selected = true;
580      }
581    }
582  }
583};
584
585/**
586 * @private Find an item in a select list and select it. Used by setValue()
587 * @param ele The select list item
588 * @param val The value to select
589 */
590dwr.util._selectListItem = function(ele, val) {
591  // We deal with select list elements by selecting the matching option
592  // Begin by searching through the values
593  var found = false;
594  var i;
595  for (i = 0; i < ele.options.length; i++) {
596    if (ele.options[i].value == val) {
597      ele.options[i].selected = true;
598      found = true;
599    }
600    else {
601      ele.options[i].selected = false;
602    }
603  }
604
605  // If that fails then try searching through the visible text
606  if (found) return;
607
608  for (i = 0; i < ele.options.length; i++) {
609    ele.options[i].selected = (ele.options[i].text == val);
610  }
611};
612
613/**
614 * Read the current value for a given HTML element.
615 * @see http://getahead.org/dwr/browser/util/getvalue
616 */
617dwr.util.getValue = function(ele, options) {
618  if (options == null) options = {};
619  var orig = ele;
620  ele = dwr.util.byId(ele); // Returns null if argument is a name, even on IE
621  var nodes = null;
622  if (ele == null) {
623    // Now it is time to look by name
624    nodes = document.getElementsByName(orig);
625    if (nodes.length >= 1) ele = nodes.item(0);
626  }
627  if (ele == null) {
628    dwr.util._debug("getValue() can't find an element with id/name: " + orig + ".");
629    return "";
630  }
631
632  if (dwr.util._isHTMLElement(ele, "select")) {
633    // Using "type" property instead of "multiple" as "type" is an official 
634    // client-side property since JS 1.1
635    if (ele.type == "select-multiple") {
636      var reply = new Array();
637      for (var i = 0; i < ele.options.length; i++) {
638        var item = ele.options[i];
639        if (item.selected) {
640          var valueAttr = item.getAttributeNode("value");
641          if (valueAttr && valueAttr.specified) {
642            reply.push(item.value);
643          }
644          else {
645            reply.push(item.text);
646          }
647        }
648      }
649      return reply;
650    }
651    else {
652      var sel = ele.selectedIndex;
653      if (sel != -1) {
654        var item = ele.options[sel];
655        var valueAttr = item.getAttributeNode("value");
656        if (valueAttr && valueAttr.specified) {
657          return item.value;
658        }
659        return item.text;
660      }
661      else {
662        return "";
663      }
664    }
665  }
666
667  if (dwr.util._isHTMLElement(ele, "input")) {
668    if (ele.type == "radio") {
669      if (nodes && nodes.length >= 1) {
670        for (var i = 0; i < nodes.length; i++) {
671          var node = nodes.item(i);
672          if (node.type == ele.type) {
673            if (node.checked) return node.value;
674          }
675        }
676      }
677      return ele.checked;
678    }
679    if (ele.type == "checkbox") {
680      if (nodes && nodes.length >= 1) {
681        var reply = [];
682        for (var i = 0; i < nodes.length; i++) {
683          var node = nodes.item(i);
684          if (node.type == ele.type) {
685            if (node.checked) reply.push(node.value);
686          }
687        }
688        return reply;
689      }
690      return ele.checked;
691    }
692    if (ele.type == "file") {
693      return ele;
694    }
695    return ele.value;
696  }
697
698  if (dwr.util._isHTMLElement(ele, "textarea")) {
699    return ele.value;
700  }
701
702  if (dwr.util._shouldEscapeHtml(options)) {
703    if (ele.textContent) return ele.textContent;
704    else if (ele.innerText) return ele.innerText;
705  }
706  return ele.innerHTML;
707};
708
709/**
710 * getText() is like getValue() except that it reads the text (and not the value) from select elements
711 * @see http://getahead.org/dwr/browser/util/gettext
712 */
713dwr.util.getText = function(ele) {
714  ele = dwr.util._getElementById(ele, "getText()");
715  if (ele == null) return null;
716  if (!dwr.util._isHTMLElement(ele, "select")) {
717    dwr.util._debug("getText() can only be used with select elements. Attempt to use: " + dwr.util._detailedTypeOf(ele) + " from  id: " + orig + ".");
718    return "";
719  }
720
721  // This is a bit of a scam because it assumes single select
722  // but I'm not sure how we should treat multi-select.
723  var sel = ele.selectedIndex;
724  if (sel != -1) {
725    return ele.options[sel].text;
726  }
727  else {
728    return "";
729  }
730};
731
732/**
733 * Given a map, or a recursive structure consisting of arrays and maps, call 
734 * setValue() for all leaf entries and use intermediate levels to form nested
735 * element ids.
736 * @see http://getahead.org/dwr/browser/util/setvalues
737 */
738dwr.util.setValues = function(data, options) {
739  var prefix = "";
740  var depth = 100;
741  if (options && options.prefix) prefix = options.prefix;
742  if (options && options.idPrefix) prefix = options.idPrefix;
743  if (options && "depth" in options) depth = options.depth;
744  dwr.util._setValuesRecursive(data, prefix, depth, options);
745};
746
747/**
748 * @private Recursive helper for setValues()
749 */
750dwr.util._setValuesRecursive = function(data, idpath, depth, options) {
751  if (depth == 0) return;
752  // Array containing objects -> add "[n]" to prefix and make recursive call
753  // for each item object
754  if (dwr.util._isArray(data) && data.length > 0 && dwr.util._isObject(data[0])) {
755    for (var i = 0; i < data.length; i++) {
756      dwr.util._setValuesRecursive(data[i], idpath+"["+i+"]", depth-1, options);
757    }
758  }
759  // Object (not array) -> handle nested object properties
760  else if (dwr.util._isObject(data) && !dwr.util._isArray(data)) {
761    for (var prop in data) {
762      var subidpath = idpath ? idpath+"."+prop : prop;
763      // Object (not array), or array containing objects -> call ourselves recursively
764      if (dwr.util._isObject(data[prop]) && !dwr.util._isArray(data[prop]) && !dwr.util._isDate(data[prop]) 
765          || dwr.util._isArray(data[prop]) && data[prop].length > 0 && dwr.util._isObject(data[prop][0])) {
766        dwr.util._setValuesRecursive(data[prop], subidpath, depth-1, options);
767      }
768      // Functions -> skip
769      else if (typeof data[prop] == "function") {
770        // NOP
771      }
772      // Only simple values left (or array of simple values, or empty array)
773      // -> call setValue()
774      else {
775        // Are there any elements with that id or name
776        if (dwr.util.byId(subidpath) != null || document.getElementsByName(subidpath).length >= 1) {
777          dwr.util.setValue(subidpath, data[prop], options);
778        }
779      }
780    }
781  }
782};
783
784/**
785 * Given a map, or a recursive structure consisting of arrays and maps, call 
786 * getValue() for all leaf entries and use intermediate levels to form nested
787 * element ids.
788 * Given a string or element that refers to a form, create an object from the 
789 * elements of the form.
790 * @see http://getahead.org/dwr/browser/util/getvalues
791 */
792dwr.util.getValues = function(data, options) {
793  if (typeof data == "string" || dwr.util._isHTMLElement(data)) {
794    return dwr.util.getFormValues(data);
795  }
796  else {
797    var prefix = "";
798    var depth = 100;
799    if (options != null && options.prefix) prefix = options.prefix;
800    if (options != null && options.idPrefix) prefix = options.idPrefix;
801    if (options != null && "depth" in options) depth = options.depth;
802    dwr.util._getValuesRecursive(data, prefix, depth, options);
803    return data;
804  }
805};
806
807/**
808 * Given a string or element that refers to a form, create an object from the 
809 * elements of the form.
810 * @see http://getahead.org/dwr/browser/util/getvalues
811 */
812dwr.util.getFormValues = function(eleOrNameOrId) {
813  var ele = null;
814  if (typeof eleOrNameOrId == "string") {
815    ele = document.forms[eleOrNameOrId]; // arg is name
816    if (ele == null) ele = dwr.util.byId(eleOrNameOrId); // arg is id
817  }
818  else if (dwr.util._isHTMLElement(eleOrNameOrId)) {
819    ele = eleOrNameOrId; // arg is element
820  }
821  if (ele != null) {
822    if (ele.elements == null) {
823      alert("getFormValues() requires an object or reference to a form element.");
824      return null;
825    }
826    var reply = {};
827    var name;
828    var value;
829    for (var i = 0; i < ele.elements.length; i++) {
830      if (ele[i].type in {button:0,submit:0,reset:0,image:0,file:0}) continue;
831      if (ele[i].name) {
832        name = ele[i].name;
833        value = dwr.util.getValue(name);
834      }
835      else {
836        if (ele[i].id) name = ele[i].id;
837        else name = "element" + i;
838        value = dwr.util.getValue(ele[i]);
839      }
840      reply[name] = value;
841    }
842    return reply;
843  }
844};
845
846/**
847 * @private Recursive helper for getValues().
848 */
849dwr.util._getValuesRecursive = function(data, idpath, depth, options) {
850  if (depth == 0) return;
851  // Array containing objects -> add "[n]" to idpath and make recursive call
852  // for each item object
853  if (dwr.util._isArray(data) && data.length > 0 && dwr.util._isObject(data[0])) {
854    for (var i = 0; i < data.length; i++) {
855      dwr.util._getValuesRecursive(data[i], idpath+"["+i+"]", depth-1, options);
856    }
857  }
858  // Object (not array) -> handle nested object properties
859  else if (dwr.util._isObject(data) && !dwr.util._isArray(data)) {
860    for (var prop in data) {
861      var subidpath = idpath ? idpath+"."+prop : prop;
862      // Object, or array containing objects -> call ourselves recursively
863      if (dwr.util._isObject(data[prop]) && !dwr.util._isArray(data[prop])
864          || dwr.util._isArray(data[prop]) && data[prop].length > 0 && dwr.util._isObject(data[prop][0])) {
865        dwr.util._getValuesRecursive(data[prop], subidpath, depth-1, options);
866      }
867      // Functions -> skip
868      else if (typeof data[prop] == "function") {
869        // NOP
870      }
871      // Only simple values left (or array of simple values, or empty array)
872      // -> call getValue()
873      else {
874        // Are there any elements with that id or name
875        if (dwr.util.byId(subidpath) != null || document.getElementsByName(subidpath).length >= 1) {
876          data[prop] = dwr.util.getValue(subidpath);
877        }
878      }
879    }
880  }
881};
882
883/**
884 * Add options to a list from an array or map.
885 * @see http://getahead.org/dwr/browser/lists
886 */
887dwr.util.addOptions = function(ele, data/*, options*/) {
888  ele = dwr.util._getElementById(ele, "addOptions()");
889  if (ele == null) return;
890  var useOptions = dwr.util._isHTMLElement(ele, "select");
891  var useLi = dwr.util._isHTMLElement(ele, ["ul", "ol"]);
892  if (!useOptions && !useLi) {
893    dwr.util._debug("addOptions() can only be used with select/ul/ol elements. Attempt to use: " + dwr.util._detailedTypeOf(ele));
894    return;
895  }
896  if (data == null) return;
897  
898  var argcount = arguments.length;
899  var options = {};
900  var lastarg = arguments[argcount - 1]; 
901  if (argcount > 2 && dwr.util._isObject(lastarg)) {
902    options = lastarg;
903    argcount--;
904  }
905  var arg3 = null; if (argcount >= 3) arg3 = arguments[2];
906  var arg4 = null; if (argcount >= 4) arg4 = arguments[3];
907  if (!options.optionCreator && useOptions) options.optionCreator = dwr.util._defaultOptionCreator;
908  if (!options.optionCreator && useLi) options.optionCreator = dwr.util._defaultListItemCreator;
909  options.document = ele.ownerDocument;
910
911  var text, value, li;
912  if (dwr.util._isArray(data)) {
913    // Loop through the data that we do have
914    for (var i = 0; i < data.length; i++) {
915      options.data = data[i];
916      options.text = null;
917      options.value = null;
918      if (useOptions) {
919        if (arg3 != null) {
920          if (arg4 != null) {
921            options.text = dwr.util._getValueFrom(data[i], arg4);
922            options.value = dwr.util._getValueFrom(data[i], arg3);
923          }
924          else options.text = options.value = dwr.util._getValueFrom(data[i], arg3);
925        }
926        else options.text = options.value = dwr.util._getValueFrom(data[i]);
927
928        if (options.text != null || options.value) {
929          var opt = options.optionCreator(options);
930          opt.text = options.text;
931          opt.value = options.value;
932          ele.options[ele.options.length] = opt;
933        }
934      }
935      else {
936        options.value = dwr.util._getValueFrom(data[i], arg3);
937        if (options.value != null) {
938          li = options.optionCreator(options);
939          if (dwr.util._shouldEscapeHtml(options)) {
940            options.value = dwr.util.escapeHtml(options.value);
941          }
942          li.innerHTML = options.value;
943          ele.appendChild(li);
944        }
945      }
946    }
947  }
948  else if (arg4 != null) {
949    if (!useOptions) {
950      alert("dwr.util.addOptions can only create select lists from objects.");
951      return;
952    }
953    for (var prop in data) {
954      options.data = data[prop];
955      options.value = dwr.util._getValueFrom(data[prop], arg3);
956      options.text = dwr.util._getValueFrom(data[prop], arg4);
957
958      if (options.text != null || options.value) {
959        var opt = options.optionCreator(options);
960        opt.text = options.text;
961        opt.value = options.value;
962        ele.options[ele.options.length] = opt;
963      }
964    }
965  }
966  else {
967    if (!useOptions) {
968      dwr.util._debug("dwr.util.addOptions can only create select lists from objects.");
969      return;
970    }
971    for (var prop in data) {
972      if (typeof data[prop] == "function") continue;
973      options.data = data[prop];
974      if (!arg3) {
975        options.value = prop;
976        options.text = data[prop];
977      }
978      else {
979        options.value = data[prop];
980        options.text = prop;
981      }
982      if (options.text != null || options.value) {
983        var opt = options.optionCreator(options);
984        opt.text = options.text;
985        opt.value = options.value;
986        ele.options[ele.options.length] = opt;
987      }
988    }
989  }
990
991  // All error routes through this function result in a return, so highlight now
992  dwr.util.highlight(ele, options); 
993};
994
995/**
996 * @private Get the data from an array function for dwr.util.addOptions
997 */
998dwr.util._getValueFrom = function(data, method) {
999  if (method == null) return data;
1000  else if (typeof method == 'function') return method(data);
1001  else return data[method];
1002};
1003
1004/**
1005 * @private Default option creation function
1006 */
1007dwr.util._defaultOptionCreator = function(options) {
1008  return options.document.createElement("option");
1009};
1010
1011/**
1012 * @private Default list item creation function
1013 */
1014dwr.util._defaultListItemCreator = function(options) {
1015  return options.document.createElement("li");
1016};
1017
1018/**
1019 * Remove all the options from a select list (specified by id)
1020 * @see http://getahead.org/dwr/browser/lists
1021 */
1022dwr.util.removeAllOptions = function(ele) {
1023  ele = dwr.util._getElementById(ele, "removeAllOptions()");
1024  if (ele == null) return;
1025  var useOptions = dwr.util._isHTMLElement(ele, "select");
1026  var useLi = dwr.util._isHTMLElement(ele, ["ul", "ol"]);
1027  if (!useOptions && !useLi) {
1028    dwr.util._debug("removeAllOptions() can only be used with select, ol and ul elements. Attempt to use: " + dwr.util._detailedTypeOf(ele));
1029    return;
1030  }
1031  if (useOptions) {
1032    ele.options.length = 0;
1033  }
1034  else {
1035    while (ele.childNodes.length > 0) {
1036      ele.removeChild(ele.firstChild);
1037    }
1038  }
1039};
1040
1041/**
1042 * Create rows inside a the table, tbody, thead or tfoot element (given by id).
1043 * @see http://getahead.org/dwr/browser/tables
1044 */
1045dwr.util.addRows = function(ele, data, cellFuncs, options) {
1046  ele = dwr.util._getElementById(ele, "addRows()");
1047  if (ele == null) return;
1048  if (!dwr.util._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
1049    dwr.util._debug("addRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + dwr.util._detailedTypeOf(ele));
1050    return;
1051  }
1052  if (!options) options = {};
1053  if (!options.rowCreator) options.rowCreator = dwr.util._defaultRowCreator;
1054  if (!options.cellCreator) options.cellCreator = dwr.util._defaultCellCreator;
1055  options.document = ele.ownerDocument;
1056  var tr, rowNum;
1057  if (dwr.util._isArray(data)) {
1058    for (rowNum = 0; rowNum < data.length; rowNum++) {
1059      options.rowData = data[rowNum];
1060      options.rowIndex = rowNum;
1061      options.rowNum = rowNum;
1062      options.data = null;
1063      options.cellNum = -1;
1064      tr = dwr.util._addRowInner(cellFuncs, options);
1065      if (tr != null) ele.appendChild(tr);
1066    }
1067  }
1068  else if (typeof data == "object") {
1069    rowNum = 0;
1070    for (var rowIndex in data) {
1071      options.rowData = data[rowIndex];
1072      options.rowIndex = rowIndex;
1073      options.rowNum = rowNum;
1074      options.data = null;
1075      options.cellNum = -1;
1076      tr = dwr.util._addRowInner(cellFuncs, options);
1077      if (tr != null) ele.appendChild(tr);
1078      rowNum++;
1079    }
1080  }
1081
1082  dwr.util.highlight(ele, options);
1083};
1084
1085/**
1086 * @private The contents we put in empty table cells to workaround IE's border bug.
1087 */
1088dwr.util._emptyTableCellReplacement = "<div style='width:0;height:0;overflow:hidden;'></div>";
1089
1090/**
1091 * @private Internal function to draw a single row of a table.
1092 */
1093dwr.util._addRowInner = function(cellFuncs, options) {
1094  var tr = options.rowCreator(options);
1095  if (tr == null) return null;
1096  for (var cellNum = 0; cellNum < cellFuncs.length; cellNum++) {
1097    var func = cellFuncs[cellNum];
1098    if (typeof func == 'function') options.data = func(options.rowData, options);
1099    else options.data = func || "";
1100    options.cellNum = cellNum;
1101    var td = options.cellCreator(options);
1102    if (td != null) {
1103      if (options.data) {
1104        if (dwr.util._isHTMLElement(options.data)) td.appendChild(options.data);
1105        else {
1106          if (dwr.util._shouldEscapeHtml(options) && typeof(options.data) == "string") {
1107            td.innerHTML = dwr.util.escapeHtml(options.data);
1108          }
1109          else {
1110            td.innerHTML = options.data;
1111          }
1112        }
1113      }
1114      else {
1115        td.innerHTML = dwr.util._emptyTableCellReplacement;
1116      }
1117      tr.appendChild(td);
1118    }
1119  }
1120  return tr;
1121};
1122
1123/**
1124 * @private Default row creation function
1125 */
1126dwr.util._defaultRowCreator = function(options) {
1127  return options.document.createElement("tr");
1128};
1129
1130/**
1131 * @private Default cell creation function
1132 */
1133dwr.util._defaultCellCreator = function(options) {
1134  return options.document.createElement("td");
1135};
1136
1137/**
1138 * Remove all the children of a given node.
1139 * @see http://getahead.org/dwr/browser/tables
1140 */
1141dwr.util.removeAllRows = function(ele, options) {
1142  ele = dwr.util._getElementById(ele, "removeAllRows()");
1143  if (ele == null) return;
1144  if (!options) options = {};
1145  if (!options.filter) options.filter = function() { return true; };
1146  if (!dwr.util._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
1147    dwr.util._debug("removeAllRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + dwr.util._detailedTypeOf(ele));
1148    return;
1149  }
1150  var child = ele.firstChild;
1151  var next;
1152  while (child != null) {
1153    next = child.nextSibling;
1154    if (options.filter(child)) {
1155      ele.removeChild(child);
1156    }
1157    child = next;
1158  }
1159};
1160
1161/**
1162 * dwr.util.byId(ele).className = "X", that we can call from Java easily.
1163 */
1164dwr.util.setClassName = function(ele, className) {
1165  ele = dwr.util._getElementById(ele, "setClassName()");
1166  if (ele == null) return;
1167  ele.className = className;
1168};
1169
1170/**
1171 * dwr.util.byId(ele).className += "X", that we can call from Java easily.
1172 */
1173dwr.util.addClassName = function(ele, className) {
1174  ele = dwr.util._getElementById(ele, "addClassName()");
1175  if (ele == null) return;
1176  ele.className += " " + className;
1177};
1178
1179/**
1180 * dwr.util.byId(ele).className -= "X", that we can call from Java easily
1181 * From code originally by Gavin Kistner
1182 */
1183dwr.util.removeClassName = function(ele, className) {
1184  ele = dwr.util._getElementById(ele, "removeClassName()");
1185  if (ele == null) return;
1186  var regex = new RegExp("(^|\\s)" + className + "(\\s|$)", 'g');
1187  ele.className = ele.className.replace(regex, '');
1188};
1189
1190/**
1191 * dwr.util.byId(ele).className |= "X", that we can call from Java easily.
1192 */
1193dwr.util.toggleClassName = function(ele, className) {
1194  ele = dwr.util._getElementById(ele, "toggleClassName()");
1195  if (ele == null) return;
1196  var regex = new RegExp("(^|\\s)" + className + "(\\s|$)");
1197  if (regex.test(ele.className)) {
1198    ele.className = ele.className.replace(regex, '');
1199  }
1200  else {
1201    ele.className += " " + className;
1202  }
1203};
1204
1205/**
1206 * Clone a node and insert it into the document just above the 'template' node
1207 * @see http://getahead.org/dwr/???
1208 */
1209dwr.util.cloneNode = function(ele, options) {
1210  ele = dwr.util._getElementById(ele, "cloneNode()");
1211  if (ele == null) return null;
1212  if (options == null) options = {};
1213  var clone = ele.cloneNode(true);
1214  if (options.idPrefix || options.idSuffix) {
1215    dwr.util._updateIds(clone, options);
1216  }
1217  else {
1218    dwr.util._removeIds(clone);
1219  }
1220  ele.parentNode.insertBefore(clone, ele);
1221  return clone;
1222};
1223
1224/**
1225 * @private Update all of the ids in an element tree
1226 */
1227dwr.util._updateIds = function(ele, options) {
1228  if (options == null) options = {};
1229  if (ele.id) {
1230    ele.setAttribute("id", (options.idPrefix || "") + ele.id + (options.idSuffix || ""));
1231  }
1232  var children = ele.childNodes;
1233  for (var i = 0; i < children.length; i++) {
1234    var child = children.item(i);
1235    if (child.nodeType == 1 /*Node.ELEMENT_NODE*/) {
1236      dwr.util._updateIds(child, options);
1237    }
1238  }
1239};
1240
1241/**
1242 * @private Remove all the Ids from an element
1243 */
1244dwr.util._removeIds = function(ele) {
1245  if (ele.id) ele.removeAttribute("id");
1246  var children = ele.childNodes;
1247  for (var i = 0; i < children.length; i++) {
1248    var child = children.item(i);
1249    if (child.nodeType == 1 /*Node.ELEMENT_NODE*/) {
1250      dwr.util._removeIds(child);
1251    }
1252  }
1253};
1254
1255/**
1256 * Clone a template node and its embedded template child nodes according to
1257 * cardinalities (of arrays) in supplied data.  
1258 */
1259dwr.util.cloneNodeForValues = function(templateEle, data, options) {
1260  templateEle = dwr.util._getElementById(templateEle, "cloneNodeForValues()");
1261  if (templateEle == null) return null;
1262  if (options == null) options = {};
1263  var idpath;
1264  if (options.idPrefix != null)
1265    idpath = options.idPrefix;
1266  else
1267    idpath = templateEle.id || ""; 
1268  return dwr.util._cloneNodeForValuesRecursive(templateEle, data, idpath, options);
1269};
1270
1271/**
1272 * @private Recursive helper for cloneNodeForValues(). 
1273 */
1274dwr.util._cloneNodeForValuesRecursive = function(templateEle, data, idpath, options) {
1275  // Incoming array -> make an id for each item and call clone of the template 
1276  // for each of them
1277  if (dwr.util._isArray(data)) {
1278    var clones = [];
1279    for (var i = 0; i < data.length; i++) {
1280      var item = data[i];
1281      var clone = dwr.util._cloneNodeForValuesRecursive(templateEle, item, idpath + "[" + i + "]", options);
1282      clones.push(clone);
1283    }
1284    return clones;
1285  }
1286  else
1287  // Incoming object (not array) -> clone the template, add id prefixes, add 
1288  // clone to DOM, and then recurse into any array properties if they contain 
1289  // objects and there is a suitable template
1290  if (dwr.util._isObject(data) && !dwr.util._isArray(data)) {
1291    var clone = templateEle.cloneNode(true);
1292    if (options.updateCloneStyle && clone.style) {
1293      for (var propname in options.updateCloneStyle) {
1294        clone.style[propname] = options.updateCloneStyle[propname];
1295      }
1296    }
1297    dwr.util._replaceIds(clone, templateEle.id, idpath);
1298    templateEle.parentNode.insertBefore(clone, templateEle);
1299    dwr.util._cloneSubArrays(data, idpath, options);
1300    return clone;
1301  }
1302
1303  // It is an error to end up here so we return nothing
1304  return null;
1305};
1306
1307/**
1308 * @private Substitute a leading idpath fragment with another idpath for all 
1309 * element ids tree, and remove ids that don't match the idpath. 
1310 */
1311dwr.util._replaceIds = function(ele, oldidpath, newidpath) {
1312  if (ele.id) {
1313    var newId = null;
1314    if (ele.id == oldidpath) {
1315      newId = newidpath;
1316    }
1317    else if (ele.id.length > oldidpath.length) {
1318      if (ele.id.substr(0, oldidpath.length) == oldidpath) {
1319        var trailingChar = ele.id.charAt(oldidpath.length);
1320        if (trailingChar == "." || trailingChar == "[") {
1321          newId = newidpath + ele.id.substr(oldidpath.length);
1322        }
1323      }
1324    }
1325    if (newId) {
1326      ele.setAttribute("id", newId);
1327    }
1328    else {
1329      ele.removeAttribute("id");
1330    }
1331  }
1332  var children = ele.childNodes;
1333  for (var i = 0; i < children.length; i++) {
1334    var child = children.item(i);
1335    if (child.nodeType == 1 /*Node.ELEMENT_NODE*/) {
1336      dwr.util._replaceIds(child, oldidpath, newidpath);
1337    }
1338  }
1339};
1340
1341/**
1342 * @private Finds arrays in supplied data and uses any corresponding template 
1343 * node to make a clone for each item in the array. 
1344 */
1345dwr.util._cloneSubArrays = function(data, idpath, options) {
1346  for (prop in data) {
1347    var value = data[prop];
1348    // Look for potential recursive cloning in all array properties
1349    if (dwr.util._isArray(value)) {
1350      // Only arrays with objects are interesting for cloning
1351      if (value.length > 0 && dwr.util._isObject(value[0])) {
1352        var subTemplateId = idpath + "." + prop;
1353        var subTemplateEle = dwr.util.byId(subTemplateId);
1354        if (subTemplateEle != null) {
1355          dwr.util._cloneNodeForValuesRecursive(subTemplateEle, value, subTemplateId, options);
1356        }
1357      }
1358    }
1359    // Continue looking for arrays in object properties
1360    else if (dwr.util._isObject(value)) {
1361      dwr.util._cloneSubArrays(value, idpath + "." + prop, options);
1362    }
1363  }
1364};
1365
1366/**
1367 * @private Helper to turn a string into an element with an error message
1368 */
1369dwr.util._getElementById = function(ele, source) {
1370  var orig = ele;
1371  ele = dwr.util.byId(ele);
1372  if (ele == null) {
1373    dwr.util._debug(source + " can't find an element with id: " + orig + ".");
1374  }
1375  return ele;
1376};
1377
1378/**
1379 * @private Is the given node an HTML element (optionally of a given type)?
1380 * @param ele The element to test
1381 * @param nodeName eg "input", "textarea" - check for node name (optional)
1382 *         if nodeName is an array then check all for a match.
1383 */
1384dwr.util._isHTMLElement = function(ele, nodeName) {
1385  if (ele == null || typeof ele != "object" || ele.nodeName == null) {
1386    return false;
1387  }
1388  if (nodeName != null) {
1389    var test = ele.nodeName.toLowerCase();
1390    if (typeof nodeName == "string") {
1391      return test == nodeName.toLowerCase();
1392    }
1393    if (dwr.util._isArray(nodeName)) {
1394      var match = false;
1395      for (var i = 0; i < nodeName.length && !match; i++) {
1396        if (test == nodeName[i].toLowerCase()) {
1397          match =  true;
1398        }
1399      }
1400      return match;
1401    }
1402    dwr.util._debug("dwr.util._isHTMLElement was passed test node name that is neither a string or array of strings");
1403    return false;
1404  }
1405  return true;
1406};
1407
1408/**
1409 * @private Like typeOf except that more information for an object is returned other than "object"
1410 */
1411dwr.util._detailedTypeOf = function(x) {
1412  var reply = typeof x;
1413  if (reply == "object") {
1414    reply = Object.prototype.toString.apply(x); // Returns "[object class]"
1415    reply = reply.substring(8, reply.length-1);  // Just get the class bit
1416  }
1417  return reply;
1418};
1419
1420/**
1421 * @private Object detector. Excluding null from objects.
1422 */
1423dwr.util._isObject = function(data) {
1424  return (data && typeof data == "object");
1425};
1426
1427/**
1428 * @private Array detector. Note: instanceof doesn't work with multiple frames.
1429 */
1430dwr.util._isArray = function(data) {
1431  return (data && Object.prototype.toString.call(data)=="[object Array]");
1432};
1433
1434/**
1435 * @private Array like detector. Note: instanceof doesn't work with multiple frames.
1436 */
1437dwr.util._isArrayLike = function(data) {
1438  return data 
1439    && (typeof data.length == "number") // must have .length
1440    && ((data.propertyIsEnumerable && data.propertyIsEnumerable("length")==false) || !data.constructor || data!="[object Object]") // .length must be native prop
1441    && !dwr.util._isString(data) // don't be fooled by string
1442    && !dwr.util._isFunction(data) // don't be fooled by function
1443    && !data.tagName; // don't be fooled by elements
1444};
1445
1446/**
1447 * @private String detector.
1448 */
1449dwr.util._isString = function(data) {
1450  return (data && (typeof data == "string" || Object.prototype.toString.call(data) == "[object String]"));
1451};
1452
1453/**
1454 * @private Function detector.
1455 */
1456dwr.util._isFunction = function(data) {
1457  return (data && (typeof data == "function" || Object.prototype.toString.call(data) == "[object Function]") 
1458    && data != "[object NodeList]"); // need to workaround NodeList on Safari
1459};
1460
1461/**
1462 * @private Date detector. Note: instanceof doesn't work with multiple frames.
1463 */
1464dwr.util._isDate = function(data) {
1465  return (data && Object.prototype.toString.call(data)=="[object Date]");
1466};
1467
1468/**
1469 * @private Used by setValue. Gets around the missing functionallity in IE.
1470 */
1471dwr.util._importNode = function(doc, importedNode, deep) {
1472  var newNode;
1473
1474  if (importedNode.nodeType == 1 /*Node.ELEMENT_NODE*/) {
1475    newNode = doc.createElement(importedNode.nodeName);
1476
1477    for (var i = 0; i < importedNode.attributes.length; i++) {
1478      var attr = importedNode.attributes[i];
1479      if (attr.nodeValue != null && attr.nodeValue != '') {
1480        newNode.setAttribute(attr.name, attr.nodeValue);
1481      }
1482    }
1483
1484    if (importedNode.style != null) {
1485      newNode.style.cssText = importedNode.style.cssText;
1486    }
1487  }
1488  else if (importedNode.nodeType == 3 /*Node.TEXT_NODE*/) {
1489    newNode = doc.createTextNode(importedNode.nodeValue);
1490  }
1491
1492  if (deep && importedNode.hasChildNodes()) {
1493    for (i = 0; i < importedNode.childNodes.length; i++) {
1494      newNode.appendChild(dwr.util._importNode(doc, importedNode.childNodes[i], true));
1495    }
1496  }
1497
1498  return newNode;
1499};
1500
1501/** @private Used internally when some message needs to get to the programmer */
1502dwr.util._debug = function(message, stacktrace) {
1503  var written = false;
1504  try {
1505    if (window.console) {
1506      if (stacktrace && window.console.trace) window.console.trace();
1507      window.console.log(message);
1508      written = true;
1509    }
1510    else if (window.opera && window.opera.postError) {
1511      window.opera.postError(message);
1512      written = true;
1513    }
1514  }
1515  catch (ex) { /* ignore */ }
1516
1517  if (!written) {
1518    var debug = document.getElementById("dwr-debug");
1519    if (debug) {
1520      var contents = message + "<br/>" + debug.innerHTML;
1521      if (contents.length > 2048) contents = contents.substring(0, 2048);
1522      debug.innerHTML = contents;
1523    }
1524  }
1525};
1526

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.