/* * copyright 2005 joe walker * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ /** * declare an object to which we can add real functions. */ if (dwr == null) var dwr = {}; if (dwr.util == null) dwr.util = {}; if (dwrutil == null) var dwrutil = dwr.util; /** @private the flag we use to decide if we should escape html */ dwr.util._escapehtml = true; /** * set the global escapehtml flag */ dwr.util.setescapehtml = function(escapehtml) { dwr.util._escapehtml = escapehtml; }; /** @private work out from an options list and global settings if we should be esccaping */ dwr.util._shouldescapehtml = function(options) { if (options && options.escapehtml != null) { return options.escapehtml; } return dwr.util._escapehtml; }; /** * return a string with &, < and > replaced with their entities * @see todo */ dwr.util.escapehtml = function(original) { return original.replace(/&/g,'&').replace(//g,'>'); }; /** * replace common xml entities with characters (see dwr.util.escapehtml()) * @see todo */ dwr.util.unescapehtml = function(original) { return original.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }; /** * replace characters dangerous for xss reasons with visually similar characters * @see todo */ dwr.util.replacexmlcharacters = function(original) { original = original.replace("&", "+"); original = original.replace("<", "\u2039"); original = original.replace(">", "\u203a"); original = original.replace("\'", "\u2018"); original = original.replace("\"", "\u201c"); return original; }; /** * return true iff the input string contains any xss dangerous characters * @see todo */ dwr.util.containsxssriskycharacters = function(original) { return (original.indexof('&') != -1 || original.indexof('<') != -1 || original.indexof('>') != -1 || original.indexof('\'') != -1 || original.indexof('\"') != -1); }; /** * enables you to react to return being pressed in an input * @see http://getahead.org/dwr/browser/util/selectrange */ dwr.util.onreturn = function(event, action) { if (!event) event = window.event; if (event && event.keycode && event.keycode == 13) action(); }; /** * select a specific range in a text box. useful for 'google suggest' type functions. * @see http://getahead.org/dwr/browser/util/selectrange */ dwr.util.selectrange = function(ele, start, end) { ele = dwr.util._getelementbyid(ele, "selectrange()"); if (ele == null) return; if (ele.setselectionrange) { ele.setselectionrange(start, end); } else if (ele.createtextrange) { var range = ele.createtextrange(); range.movestart("character", start); range.moveend("character", end - ele.value.length); range.select(); } ele.focus(); }; /** * find the element in the current html document with the given id or ids * @see http://getahead.org/dwr/browser/util/$ */ if (document.getelementbyid) { dwr.util.byid = function() { var elements = new array(); for (var i = 0; i < arguments.length; i++) { var element = arguments[i]; if (typeof element == 'string') { element = document.getelementbyid(element); } if (arguments.length == 1) { return element; } elements.push(element); } return elements; }; } else if (document.all) { dwr.util.byid = function() { var elements = new array(); for (var i = 0; i < arguments.length; i++) { var element = arguments[i]; if (typeof element == 'string') { element = document.all[element]; } if (arguments.length == 1) { return element; } elements.push(element); } return elements; }; } /** * alias $ to dwr.util.byid * @see http://getahead.org/dwr/browser/util/$ */ if (window['$'] == null) { window['$'] = dwr.util.byid; } /** * this function pretty-prints simple data or whole object graphs, f ex as an aid in debugging. * @see http://getahead.org/dwr/browser/util/todescriptivestring */ dwr.util.todescriptivestring = function(data, showlevels, options) { if (showlevels === undefined) showlevels = 1; var opt = {}; if (dwr.util._isobject(options)) opt = options; var defaultoptions = { escapehtml:false, baseindent: "", childindent: "\u00a0\u00a0", lineterminator: "\n", onelinemaxitems: 5, shortstringmaxlength: 13, propertynamemaxlength: 30 }; for (var p in defaultoptions) { if (!(p in opt)) { opt[p] = defaultoptions[p]; } } var skipdomproperties = { document:true, ownerdocument:true, all:true, parentelement:true, parentnode:true, offsetparent:true, children:true, firstchild:true, lastchild:true, previoussibling:true, nextsibling:true, innerhtml:true, outerhtml:true, innertext:true, outertext:true, textcontent:true, attributes:true, style:true, currentstyle:true, runtimestyle:true, parenttextedit:true }; function recursive(data, showlevels, indentdepth, options) { var reply = ""; try { // string if (typeof data == "string") { var str = data; if (showlevels == 0 && str.length > options.shortstringmaxlength) str = str.substring(0, options.shortstringmaxlength-3) + "..."; if (options.escapehtml) { // do the escape separately for every line as escapehtml() on some // browsers (ie) will strip line breaks and we want to preserve them var lines = str.split("\n"); for (var i = 0; i < lines.length; i++) lines[i] = dwr.util.escapehtml(lines[i]); str = lines.join("\n"); } if (showlevels == 0) { // short format str = str.replace(/\n|\r|\t/g, function(ch) { switch (ch) { case "\n": return "\\n"; case "\r": return ""; case "\t": return "\\t"; } }); } else { // long format str = str.replace(/\n|\r|\t/g, function(ch) { switch (ch) { case "\n": return options.lineterminator + indent(indentdepth+1, options); case "\r": return ""; case "\t": return "\\t"; } }); } reply = '"' + str + '"'; } // function else if (typeof data == "function") { reply = "function"; } // array else if (dwr.util._isarray(data)) { if (showlevels == 0) { // short format (don't show items) if (data.length > 0) reply = "[...]"; else reply = "[]"; } else { // long format (show items) var strarr = []; strarr.push("["); var count = 0; for (var i = 0; i < data.length; i++) { if (! (i in data)) continue; var itemvalue = data[i]; if (count > 0) strarr.push(", "); if (showlevels == 1) { // one-line format if (count == options.onelinemaxitems) { strarr.push("..."); break; } } else { // multi-line format strarr.push(options.lineterminator + indent(indentdepth+1, options)); } if (i != count) { strarr.push(i); strarr.push(":"); } strarr.push(recursive(itemvalue, showlevels-1, indentdepth+1, options)); count++; } if (showlevels > 1) strarr.push(options.lineterminator + indent(indentdepth, options)); strarr.push("]"); reply = strarr.join(""); } } // objects except date else if (dwr.util._isobject(data) && !dwr.util._isdate(data)) { if (showlevels == 0) { // short format (don't show properties) reply = dwr.util._detailedtypeof(data); } else { // long format (show properties) var strarr = []; if (dwr.util._detailedtypeof(data) != "object") { strarr.push(dwr.util._detailedtypeof(data)); if (typeof data.valueof() != "object") { strarr.push(":"); strarr.push(recursive(data.valueof(), 1, indentdepth, options)); } strarr.push(" "); } strarr.push("{"); var isdomobject = dwr.util._ishtmlelement(data); var count = 0; for (var prop in data) { var propvalue = data[prop]; if (isdomobject) { if (!propvalue) continue; if (typeof propvalue == "function") continue; if (skipdomproperties[prop]) continue; if (prop.touppercase() == prop) continue; } if (count > 0) strarr.push(", "); if (showlevels == 1) { // one-line format if (count == options.onelinemaxitems) { strarr.push("..."); break; } } else { // multi-line format strarr.push(options.lineterminator + indent(indentdepth+1, options)); } strarr.push(prop.length > options.propertynamemaxlength ? prop.substring(0, options.propertynamemaxlength-3) + "..." : prop); strarr.push(":"); strarr.push(recursive(propvalue, showlevels-1, indentdepth+1, options)); count++; } if (showlevels > 1 && count > 0) strarr.push(options.lineterminator + indent(indentdepth, options)); strarr.push("}"); reply = strarr.join(""); } } // undefined, null, number, boolean, date else { reply = "" + data; } return reply; } catch(err) { return (err.message ? err.message : ""+err); } } function indent(count, options) { var strarr = []; strarr.push(options.baseindent); for (var i=0; i= 1) ele = nodes.item(0); } if (ele == null) { dwr.util._debug("setvalue() can't find an element with id/name: " + orig + "."); return; } // all paths now lead to some update so we highlight a change dwr.util.highlight(ele, options); if (dwr.util._ishtmlelement(ele, "select")) { if (ele.type == "select-multiple" && dwr.util._isarray(val)) dwr.util._selectlistitems(ele, val); else dwr.util._selectlistitem(ele, val); return; } if (dwr.util._ishtmlelement(ele, "input")) { if (ele.type == "radio" || ele.type == "checkbox") { if (nodes && nodes.length >= 1) { for (var i = 0; i < nodes.length; i++) { var node = nodes.item(i); if (node.type != ele.type) continue; if (dwr.util._isarray(val)) { node.checked = false; for (var j = 0; j < val.length; j++) if (val[j] == node.value) node.checked = true; } else { node.checked = (node.value == val); } } } else { ele.checked = (val == true); } } else ele.value = val; return; } if (dwr.util._ishtmlelement(ele, "textarea")) { ele.value = val; return; } // if the value to be set is a dom object then we try importing the node // rather than serializing it out if (val.nodetype) { if (val.nodetype == 9 /*node.document_node*/) val = val.documentelement; val = dwr.util._importnode(ele.ownerdocument, val, true); ele.appendchild(val); return; } // fall back to innerhtml and friends if (dwr.util._shouldescapehtml(options)) { if ("textcontent" in ele) ele.textcontent = val.tostring(); else if ("innertext" in ele) ele.innertext = val.tostring(); else ele.innerhtml = dwr.util.escapehtml(val.tostring()); } else { ele.innerhtml = val; } }; /** * @private find multiple items in a select list and select them. used by setvalue() * @param ele the select list item * @param val the array of values to select */ dwr.util._selectlistitems = function(ele, val) { // we deal with select list elements by selecting the matching option // begin by searching through the values var found = false; var i; var j; for (i = 0; i < ele.options.length; i++) { ele.options[i].selected = false; for (j = 0; j < val.length; j++) { if (ele.options[i].value == val[j]) { ele.options[i].selected = true; } } } // if that fails then try searching through the visible text if (found) return; for (i = 0; i < ele.options.length; i++) { for (j = 0; j < val.length; j++) { if (ele.options[i].text == val[j]) { ele.options[i].selected = true; } } } }; /** * @private find an item in a select list and select it. used by setvalue() * @param ele the select list item * @param val the value to select */ dwr.util._selectlistitem = function(ele, val) { // we deal with select list elements by selecting the matching option // begin by searching through the values var found = false; var i; for (i = 0; i < ele.options.length; i++) { if (ele.options[i].value == val) { ele.options[i].selected = true; found = true; } else { ele.options[i].selected = false; } } // if that fails then try searching through the visible text if (found) return; for (i = 0; i < ele.options.length; i++) { ele.options[i].selected = (ele.options[i].text == val); } }; /** * read the current value for a given html element. * @see http://getahead.org/dwr/browser/util/getvalue */ dwr.util.getvalue = function(ele, options) { if (options == null) options = {}; var orig = ele; if (typeof ele == "string") { ele = dwr.util.byid(ele); // we can work with names and need to sometimes for radio buttons, and ie has // an annoying bug where getelementbyid() returns an element based on name if // it doesn't find it by id. here we don't want to do that, so: if (ele && ele.id != orig) ele = null; } var nodes = null; if (ele == null) { // now it is time to look by name nodes = document.getelementsbyname(orig); if (nodes.length >= 1) ele = nodes.item(0); } if (ele == null) { dwr.util._debug("getvalue() can't find an element with id/name: " + orig + "."); return ""; } if (dwr.util._ishtmlelement(ele, "select")) { // using "type" property instead of "multiple" as "type" is an official // client-side property since js 1.1 if (ele.type == "select-multiple") { var reply = new array(); for (var i = 0; i < ele.options.length; i++) { var item = ele.options[i]; if (item.selected) { var valueattr = item.getattributenode("value"); if (valueattr && valueattr.specified) { reply.push(item.value); } else { reply.push(item.text); } } } return reply; } else { var sel = ele.selectedindex; if (sel != -1) { var item = ele.options[sel]; var valueattr = item.getattributenode("value"); if (valueattr && valueattr.specified) { return item.value; } return item.text; } else { return ""; } } } if (dwr.util._ishtmlelement(ele, "input")) { if (ele.type == "radio") { if (nodes && nodes.length >= 1) { for (var i = 0; i < nodes.length; i++) { var node = nodes.item(i); if (node.type == ele.type) { if (node.checked) return node.value; } } } return ele.checked; } if (ele.type == "checkbox") { if (nodes && nodes.length >= 1) { var reply = []; for (var i = 0; i < nodes.length; i++) { var node = nodes.item(i); if (node.type == ele.type) { if (node.checked) reply.push(node.value); } } return reply; } return ele.checked; } return ele.value; } if (dwr.util._ishtmlelement(ele, "textarea")) { return ele.value; } if (dwr.util._shouldescapehtml(options)) { if (ele.textcontent) return ele.textcontent; else if (ele.innertext) return ele.innertext; } return ele.innerhtml; }; /** * gettext() is like getvalue() except that it reads the text (and not the value) from select elements * @see http://getahead.org/dwr/browser/util/gettext */ dwr.util.gettext = function(ele) { ele = dwr.util._getelementbyid(ele, "gettext()"); if (ele == null) return null; if (!dwr.util._ishtmlelement(ele, "select")) { dwr.util._debug("gettext() can only be used with select elements. attempt to use: " + dwr.util._detailedtypeof(ele) + " from id: " + orig + "."); return ""; } // this is a bit of a scam because it assumes single select // but i'm not sure how we should treat multi-select. var sel = ele.selectedindex; if (sel != -1) { return ele.options[sel].text; } else { return ""; } }; /** * given a map, or a recursive structure consisting of arrays and maps, call * setvalue() for all leaf entries and use intermediate levels to form nested * element ids. * @see http://getahead.org/dwr/browser/util/setvalues */ dwr.util.setvalues = function(data, options) { var prefix = ""; var depth = 100; if (options && options.prefix) prefix = options.prefix; if (options && options.idprefix) prefix = options.idprefix; if (options && "depth" in options) depth = options.depth; dwr.util._setvaluesrecursive(data, prefix, depth, options); }; /** * @private recursive helper for setvalues() */ dwr.util._setvaluesrecursive = function(data, idpath, depth, options) { if (depth == 0) return; // array containing objects -> add "[n]" to prefix and make recursive call // for each item object if (dwr.util._isarray(data) && data.length > 0 && dwr.util._isobject(data[0])) { for (var i = 0; i < data.length; i++) { dwr.util._setvaluesrecursive(data[i], idpath+"["+i+"]", depth-1, options); } } // object (not array) -> handle nested object properties else if (dwr.util._isobject(data) && !dwr.util._isarray(data)) { for (var prop in data) { var subidpath = idpath ? idpath+"."+prop : prop; // object (not array), or array containing objects -> call ourselves recursively if (dwr.util._isobject(data[prop]) && !dwr.util._isarray(data[prop]) && !dwr.util._isdate(data[prop]) || dwr.util._isarray(data[prop]) && data[prop].length > 0 && dwr.util._isobject(data[prop][0])) { dwr.util._setvaluesrecursive(data[prop], subidpath, depth-1, options); } // functions -> skip else if (typeof data[prop] == "function") { // nop } // only simple values left (or array of simple values, or empty array) // -> call setvalue() else { // are there any elements with that id or name if (dwr.util.byid(subidpath) != null || document.getelementsbyname(subidpath).length >= 1) { dwr.util.setvalue(subidpath, data[prop], options); } } } } }; /** * given a map, or a recursive structure consisting of arrays and maps, call * getvalue() for all leaf entries and use intermediate levels to form nested * element ids. * given a string or element that refers to a form, create an object from the * elements of the form. * @see http://getahead.org/dwr/browser/util/getvalues */ dwr.util.getvalues = function(data, options) { if (typeof data == "string" || dwr.util._ishtmlelement(data)) { return dwr.util.getformvalues(data); } else { var prefix = ""; var depth = 100; if (options != null && options.prefix) prefix = options.prefix; if (options != null && options.idprefix) prefix = options.idprefix; if (options != null && "depth" in options) depth = options.depth; dwr.util._getvaluesrecursive(data, prefix, depth, options); return data; } }; /** * given a string or element that refers to a form, create an object from the * elements of the form. * @see http://getahead.org/dwr/browser/util/getvalues */ dwr.util.getformvalues = function(eleornameorid) { var ele = null; if (typeof eleornameorid == "string") { ele = document.forms[eleornameorid]; if (ele == null) ele = dwr.util.byid(eleornameorid); } else if (dwr.util._ishtmlelement(eleornameorid)) { ele = eleornameorid; } if (ele != null) { if (ele.elements == null) { alert("getformvalues() requires an object or reference to a form element."); return null; } var reply = {}; var name; var value; for (var i = 0; i < ele.elements.length; i++) { if (ele[i].type in {button:0,submit:0,reset:0,image:0,file:0}) continue; if (ele[i].name) { name = ele[i].name; value = dwr.util.getvalue(name); } else { if (ele[i].id) name = ele[i].id; else name = "element" + i; value = dwr.util.getvalue(ele[i]); } reply[name] = value; } return reply; } }; /** * @private recursive helper for getvalues(). */ dwr.util._getvaluesrecursive = function(data, idpath, depth, options) { if (depth == 0) return; // array containing objects -> add "[n]" to idpath and make recursive call // for each item object if (dwr.util._isarray(data) && data.length > 0 && dwr.util._isobject(data[0])) { for (var i = 0; i < data.length; i++) { dwr.util._getvaluesrecursive(data[i], idpath+"["+i+"]", depth-1, options); } } // object (not array) -> handle nested object properties else if (dwr.util._isobject(data) && !dwr.util._isarray(data)) { for (var prop in data) { var subidpath = idpath ? idpath+"."+prop : prop; // object, or array containing objects -> call ourselves recursively if (dwr.util._isobject(data[prop]) && !dwr.util._isarray(data[prop]) || dwr.util._isarray(data[prop]) && data[prop].length > 0 && dwr.util._isobject(data[prop][0])) { dwr.util._getvaluesrecursive(data[prop], subidpath, depth-1, options); } // functions -> skip else if (typeof data[prop] == "function") { // nop } // only simple values left (or array of simple values, or empty array) // -> call getvalue() else { // are there any elements with that id or name if (dwr.util.byid(subidpath) != null || document.getelementsbyname(subidpath).length >= 1) { data[prop] = dwr.util.getvalue(subidpath); } } } } }; /** * add options to a list from an array or map. * @see http://getahead.org/dwr/browser/lists */ dwr.util.addoptions = function(ele, data/*, options*/) { ele = dwr.util._getelementbyid(ele, "addoptions()"); if (ele == null) return; var useoptions = dwr.util._ishtmlelement(ele, "select"); var useli = dwr.util._ishtmlelement(ele, ["ul", "ol"]); if (!useoptions && !useli) { dwr.util._debug("addoptions() can only be used with select/ul/ol elements. attempt to use: " + dwr.util._detailedtypeof(ele)); return; } if (data == null) return; var argcount = arguments.length; var options = {}; var lastarg = arguments[argcount - 1]; if (argcount > 2 && dwr.util._isobject(lastarg)) { options = lastarg; argcount--; } var arg3 = null; if (argcount >= 3) arg3 = arguments[2]; var arg4 = null; if (argcount >= 4) arg4 = arguments[3]; if (!options.optioncreator && useoptions) options.optioncreator = dwr.util._defaultoptioncreator; if (!options.optioncreator && useli) options.optioncreator = dwr.util._defaultlistitemcreator; options.document = ele.ownerdocument; var text, value, li; if (dwr.util._isarray(data)) { // loop through the data that we do have for (var i = 0; i < data.length; i++) { options.data = data[i]; options.text = null; options.value = null; if (useoptions) { if (arg3 != null) { if (arg4 != null) { options.text = dwr.util._getvaluefrom(data[i], arg4); options.value = dwr.util._getvaluefrom(data[i], arg3); } else options.text = options.value = dwr.util._getvaluefrom(data[i], arg3); } else options.text = options.value = dwr.util._getvaluefrom(data[i]); if (options.text != null || options.value) { var opt = options.optioncreator(options); opt.text = options.text; opt.value = options.value; ele.options[ele.options.length] = opt; } } else { options.value = dwr.util._getvaluefrom(data[i], arg3); if (options.value != null) { li = options.optioncreator(options); if (dwr.util._shouldescapehtml(options)) { options.value = dwr.util.escapehtml(options.value); } li.innerhtml = options.value; ele.appendchild(li); } } } } else if (arg4 != null) { if (!useoptions) { alert("dwr.util.addoptions can only create select lists from objects."); return; } for (var prop in data) { options.data = data[prop]; options.value = dwr.util._getvaluefrom(data[prop], arg3); options.text = dwr.util._getvaluefrom(data[prop], arg4); if (options.text != null || options.value) { var opt = options.optioncreator(options); opt.text = options.text; opt.value = options.value; ele.options[ele.options.length] = opt; } } } else { if (!useoptions) { dwr.util._debug("dwr.util.addoptions can only create select lists from objects."); return; } for (var prop in data) { if (typeof data[prop] == "function") continue; options.data = data[prop]; if (!arg3) { options.value = prop; options.text = data[prop]; } else { options.value = data[prop]; options.text = prop; } if (options.text != null || options.value) { var opt = options.optioncreator(options); opt.text = options.text; opt.value = options.value; ele.options[ele.options.length] = opt; } } } // all error routes through this function result in a return, so highlight now dwr.util.highlight(ele, options); }; /** * @private get the data from an array function for dwr.util.addoptions */ dwr.util._getvaluefrom = function(data, method) { if (method == null) return data; else if (typeof method == 'function') return method(data); else return data[method]; }; /** * @private default option creation function */ dwr.util._defaultoptioncreator = function(options) { return options.document.createelement("option"); }; /** * @private default list item creation function */ dwr.util._defaultlistitemcreator = function(options) { return options.document.createelement("li"); }; /** * remove all the options from a select list (specified by id) * @see http://getahead.org/dwr/browser/lists */ dwr.util.removealloptions = function(ele) { ele = dwr.util._getelementbyid(ele, "removealloptions()"); if (ele == null) return; var useoptions = dwr.util._ishtmlelement(ele, "select"); var useli = dwr.util._ishtmlelement(ele, ["ul", "ol"]); if (!useoptions && !useli) { dwr.util._debug("removealloptions() can only be used with select, ol and ul elements. attempt to use: " + dwr.util._detailedtypeof(ele)); return; } if (useoptions) { ele.options.length = 0; } else { while (ele.childnodes.length > 0) { ele.removechild(ele.firstchild); } } }; /** * create rows inside a the table, tbody, thead or tfoot element (given by id). * @see http://getahead.org/dwr/browser/tables */ dwr.util.addrows = function(ele, data, cellfuncs, options) { ele = dwr.util._getelementbyid(ele, "addrows()"); if (ele == null) return; if (!dwr.util._ishtmlelement(ele, ["table", "tbody", "thead", "tfoot"])) { dwr.util._debug("addrows() can only be used with table, tbody, thead and tfoot elements. attempt to use: " + dwr.util._detailedtypeof(ele)); return; } if (!options) options = {}; if (!options.rowcreator) options.rowcreator = dwr.util._defaultrowcreator; if (!options.cellcreator) options.cellcreator = dwr.util._defaultcellcreator; options.document = ele.ownerdocument; var tr, rownum; if (dwr.util._isarray(data)) { for (rownum = 0; rownum < data.length; rownum++) { options.rowdata = data[rownum]; options.rowindex = rownum; options.rownum = rownum; options.data = null; options.cellnum = -1; tr = dwr.util._addrowinner(cellfuncs, options); if (tr != null) ele.appendchild(tr); } } else if (typeof data == "object") { rownum = 0; for (var rowindex in data) { options.rowdata = data[rowindex]; options.rowindex = rowindex; options.rownum = rownum; options.data = null; options.cellnum = -1; tr = dwr.util._addrowinner(cellfuncs, options); if (tr != null) ele.appendchild(tr); rownum++; } } dwr.util.highlight(ele, options); }; /** * @private internal function to draw a single row of a table. */ dwr.util._addrowinner = function(cellfuncs, options) { var tr = options.rowcreator(options); if (tr == null) return null; for (var cellnum = 0; cellnum < cellfuncs.length; cellnum++) { var func = cellfuncs[cellnum]; if (typeof func == 'function') options.data = func(options.rowdata, options); else options.data = func || ""; options.cellnum = cellnum; var td = options.cellcreator(options); if (td != null) { if (options.data != null) { if (dwr.util._ishtmlelement(options.data)) td.appendchild(options.data); else { if (dwr.util._shouldescapehtml(options) && typeof(options.data) == "string") { td.innerhtml = dwr.util.escapehtml(options.data); } else { td.innerhtml = options.data; } } } tr.appendchild(td); } } return tr; }; /** * @private default row creation function */ dwr.util._defaultrowcreator = function(options) { return options.document.createelement("tr"); }; /** * @private default cell creation function */ dwr.util._defaultcellcreator = function(options) { return options.document.createelement("td"); }; /** * remove all the children of a given node. * @see http://getahead.org/dwr/browser/tables */ dwr.util.removeallrows = function(ele, options) { ele = dwr.util._getelementbyid(ele, "removeallrows()"); if (ele == null) return; if (!options) options = {}; if (!options.filter) options.filter = function() { return true; }; if (!dwr.util._ishtmlelement(ele, ["table", "tbody", "thead", "tfoot"])) { dwr.util._debug("removeallrows() can only be used with table, tbody, thead and tfoot elements. attempt to use: " + dwr.util._detailedtypeof(ele)); return; } var child = ele.firstchild; var next; while (child != null) { next = child.nextsibling; if (options.filter(child)) { ele.removechild(child); } child = next; } }; /** * dwr.util.byid(ele).classname = "x", that we can call from java easily. */ dwr.util.setclassname = function(ele, classname) { ele = dwr.util._getelementbyid(ele, "setclassname()"); if (ele == null) return; ele.classname = classname; }; /** * dwr.util.byid(ele).classname += "x", that we can call from java easily. */ dwr.util.addclassname = function(ele, classname) { ele = dwr.util._getelementbyid(ele, "addclassname()"); if (ele == null) return; ele.classname += " " + classname; }; /** * dwr.util.byid(ele).classname -= "x", that we can call from java easily * from code originally by gavin kistner */ dwr.util.removeclassname = function(ele, classname) { ele = dwr.util._getelementbyid(ele, "removeclassname()"); if (ele == null) return; var regex = new regexp("(^|\\s)" + classname + "(\\s|$)", 'g'); ele.classname = ele.classname.replace(regex, ''); }; /** * dwr.util.byid(ele).classname |= "x", that we can call from java easily. */ dwr.util.toggleclassname = function(ele, classname) { ele = dwr.util._getelementbyid(ele, "toggleclassname()"); if (ele == null) return; var regex = new regexp("(^|\\s)" + classname + "(\\s|$)"); if (regex.test(ele.classname)) { ele.classname = ele.classname.replace(regex, ''); } else { ele.classname += " " + classname; } }; /** * clone a node and insert it into the document just above the 'template' node * @see http://getahead.org/dwr/??? */ dwr.util.clonenode = function(ele, options) { ele = dwr.util._getelementbyid(ele, "clonenode()"); if (ele == null) return null; if (options == null) options = {}; var clone = ele.clonenode(true); if (options.idprefix || options.idsuffix) { dwr.util._updateids(clone, options); } else { dwr.util._removeids(clone); } ele.parentnode.insertbefore(clone, ele); return clone; }; /** * @private update all of the ids in an element tree */ dwr.util._updateids = function(ele, options) { if (options == null) options = {}; if (ele.id) { ele.setattribute("id", (options.idprefix || "") + ele.id + (options.idsuffix || "")); } var children = ele.childnodes; for (var i = 0; i < children.length; i++) { var child = children.item(i); if (child.nodetype == 1 /*node.element_node*/) { dwr.util._updateids(child, options); } } }; /** * @private remove all the ids from an element */ dwr.util._removeids = function(ele) { if (ele.id) ele.removeattribute("id"); var children = ele.childnodes; for (var i = 0; i < children.length; i++) { var child = children.item(i); if (child.nodetype == 1 /*node.element_node*/) { dwr.util._removeids(child); } } }; /** * clone a template node and its embedded template child nodes according to * cardinalities (of arrays) in supplied data. */ dwr.util.clonenodeforvalues = function(templateele, data, options) { templateele = dwr.util._getelementbyid(templateele, "clonenodeforvalues()"); if (templateele == null) return null; if (options == null) options = {}; var idpath; if (options.idprefix != null) idpath = options.idprefix; else idpath = templateele.id || ""; return dwr.util._clonenodeforvaluesrecursive(templateele, data, idpath, options); }; /** * @private recursive helper for clonenodeforvalues(). */ dwr.util._clonenodeforvaluesrecursive = function(templateele, data, idpath, options) { // incoming array -> make an id for each item and call clone of the template // for each of them if (dwr.util._isarray(data)) { var clones = []; for (var i = 0; i < data.length; i++) { var item = data[i]; var clone = dwr.util._clonenodeforvaluesrecursive(templateele, item, idpath + "[" + i + "]", options); clones.push(clone); } return clones; } else // incoming object (not array) -> clone the template, add id prefixes, add // clone to dom, and then recurse into any array properties if they contain // objects and there is a suitable template if (dwr.util._isobject(data) && !dwr.util._isarray(data)) { var clone = templateele.clonenode(true); if (options.updateclonestyle && clone.style) { for (var propname in options.updateclonestyle) { clone.style[propname] = options.updateclonestyle[propname]; } } dwr.util._replaceids(clone, templateele.id, idpath); templateele.parentnode.insertbefore(clone, templateele); dwr.util._clonesubarrays(data, idpath, options); return clone; } // it is an error to end up here so we return nothing return null; }; /** * @private substitute a leading idpath fragment with another idpath for all * element ids tree, and remove ids that don't match the idpath. */ dwr.util._replaceids = function(ele, oldidpath, newidpath) { if (ele.id) { var newid = null; if (ele.id == oldidpath) { newid = newidpath; } else if (ele.id.length > oldidpath.length) { if (ele.id.substr(0, oldidpath.length) == oldidpath) { var trailingchar = ele.id.charat(oldidpath.length); if (trailingchar == "." || trailingchar == "[") { newid = newidpath + ele.id.substr(oldidpath.length); } } } if (newid) { ele.setattribute("id", newid); } else { ele.removeattribute("id"); } } var children = ele.childnodes; for (var i = 0; i < children.length; i++) { var child = children.item(i); if (child.nodetype == 1 /*node.element_node*/) { dwr.util._replaceids(child, oldidpath, newidpath); } } }; /** * @private finds arrays in supplied data and uses any corresponding template * node to make a clone for each item in the array. */ dwr.util._clonesubarrays = function(data, idpath, options) { for (prop in data) { var value = data[prop]; // look for potential recursive cloning in all array properties if (dwr.util._isarray(value)) { // only arrays with objects are interesting for cloning if (value.length > 0 && dwr.util._isobject(value[0])) { var subtemplateid = idpath + "." + prop; var subtemplateele = dwr.util.byid(subtemplateid); if (subtemplateele != null) { dwr.util._clonenodeforvaluesrecursive(subtemplateele, value, subtemplateid, options); } } } // continue looking for arrays in object properties else if (dwr.util._isobject(value)) { dwr.util._clonesubarrays(value, idpath + "." + prop, options); } } }; /** * @private helper to turn a string into an element with an error message */ dwr.util._getelementbyid = function(ele, source) { var orig = ele; ele = dwr.util.byid(ele); if (ele == null) { dwr.util._debug(source + " can't find an element with id: " + orig + "."); } return ele; }; /** * @private is the given node an html element (optionally of a given type)? * @param ele the element to test * @param nodename eg "input", "textarea" - check for node name (optional) * if nodename is an array then check all for a match. */ dwr.util._ishtmlelement = function(ele, nodename) { if (ele == null || typeof ele != "object" || ele.nodename == null) { return false; } if (nodename != null) { var test = ele.nodename.tolowercase(); if (typeof nodename == "string") { return test == nodename.tolowercase(); } if (dwr.util._isarray(nodename)) { var match = false; for (var i = 0; i < nodename.length && !match; i++) { if (test == nodename[i].tolowercase()) { match = true; } } return match; } dwr.util._debug("dwr.util._ishtmlelement was passed test node name that is neither a string or array of strings"); return false; } return true; }; /** * @private like typeof except that more information for an object is returned other than "object" */ dwr.util._detailedtypeof = function(x) { var reply = typeof x; if (reply == "object") { reply = object.prototype.tostring.apply(x); // returns "[object class]" reply = reply.substring(8, reply.length-1); // just get the class bit } return reply; }; /** * @private object detector. excluding null from objects. */ dwr.util._isobject = function(data) { return (data && typeof data == "object"); }; /** * @private array detector. note: instanceof doesn't work with multiple frames. */ dwr.util._isarray = function(data) { return (data && data.join); }; /** * @private date detector. note: instanceof doesn't work with multiple frames. */ dwr.util._isdate = function(data) { return (data && data.toutcstring) ? true : false; }; /** * @private used by setvalue. gets around the missing functionallity in ie. */ dwr.util._importnode = function(doc, importednode, deep) { var newnode; if (importednode.nodetype == 1 /*node.element_node*/) { newnode = doc.createelement(importednode.nodename); for (var i = 0; i < importednode.attributes.length; i++) { var attr = importednode.attributes[i]; if (attr.nodevalue != null && attr.nodevalue != '') { newnode.setattribute(attr.name, attr.nodevalue); } } if (importednode.style != null) { newnode.style.csstext = importednode.style.csstext; } } else if (importednode.nodetype == 3 /*node.text_node*/) { newnode = doc.createtextnode(importednode.nodevalue); } if (deep && importednode.haschildnodes()) { for (i = 0; i < importednode.childnodes.length; i++) { newnode.appendchild(dwr.util._importnode(doc, importednode.childnodes[i], true)); } } return newnode; }; /** @private used internally when some message needs to get to the programmer */ dwr.util._debug = function(message, stacktrace) { var written = false; try { if (window.console) { if (stacktrace && window.console.trace) window.console.trace(); window.console.log(message); written = true; } else if (window.opera && window.opera.posterror) { window.opera.posterror(message); written = true; } } catch (ex) { /* ignore */ } if (!written) { var debug = document.getelementbyid("dwr-debug"); if (debug) { var contents = message + "
" + debug.innerhtml; if (contents.length > 2048) contents = contents.substring(0, 2048); debug.innerhtml = contents; } } };