From 9fb3d631b5f7e791625d20e2f0c775859814f7bf Mon Sep 17 00:00:00 2001 From: Frederic Debuire Date: Thu, 24 Jan 2008 16:24:00 +0000 Subject: [PATCH] --- YACOSWeb/WebContent/dwr/engine.js | 1281 +++++++++++++++++++++++++ YACOSWeb/WebContent/dwr/util.js | 1484 +++++++++++++++++++++++++++++ 2 files changed, 2765 insertions(+) create mode 100644 YACOSWeb/WebContent/dwr/engine.js create mode 100644 YACOSWeb/WebContent/dwr/util.js diff --git a/YACOSWeb/WebContent/dwr/engine.js b/YACOSWeb/WebContent/dwr/engine.js new file mode 100644 index 0000000..a846555 --- /dev/null +++ b/YACOSWeb/WebContent/dwr/engine.js @@ -0,0 +1,1281 @@ +/* + * 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.engine == null) dwr.engine = {}; +if (DWREngine == null) var DWREngine = dwr.engine; + +/** + * Set an alternative error handler from the default alert box. + * @see getahead.org/dwr/browser/engine/errors + */ +dwr.engine.setErrorHandler = function(handler) { + dwr.engine._errorHandler = handler; +}; + +/** + * Set an alternative warning handler from the default alert box. + * @see getahead.org/dwr/browser/engine/errors + */ +dwr.engine.setWarningHandler = function(handler) { + dwr.engine._warningHandler = handler; +}; + +/** + * Setter for the text/html handler - what happens if a DWR request gets an HTML + * reply rather than the expected Javascript. Often due to login timeout + */ +dwr.engine.setTextHtmlHandler = function(handler) { + dwr.engine._textHtmlHandler = handler; +}; + +/** + * Set a default timeout value for all calls. 0 (the default) turns timeouts off. + * @see getahead.org/dwr/browser/engine/errors + */ +dwr.engine.setTimeout = function(timeout) { + dwr.engine._timeout = timeout; +}; + +/** + * The Pre-Hook is called before any DWR remoting is done. + * @see getahead.org/dwr/browser/engine/hooks + */ +dwr.engine.setPreHook = function(handler) { + dwr.engine._preHook = handler; +}; + +/** + * The Post-Hook is called after any DWR remoting is done. + * @see getahead.org/dwr/browser/engine/hooks + */ +dwr.engine.setPostHook = function(handler) { + dwr.engine._postHook = handler; +}; + +/** + * Custom headers for all DWR calls + * @see getahead.org/dwr/???? + */ +dwr.engine.setHeaders = function(headers) { + dwr.engine._headers = headers; +}; + +/** + * Custom parameters for all DWR calls + * @see getahead.org/dwr/???? + */ +dwr.engine.setParameters = function(parameters) { + dwr.engine._parameters = parameters; +}; + +/** XHR remoting type constant. See dwr.engine.set[Rpc|Poll]Type() */ +dwr.engine.XMLHttpRequest = 1; + +/** XHR remoting type constant. See dwr.engine.set[Rpc|Poll]Type() */ +dwr.engine.IFrame = 2; + +/** XHR remoting type constant. See dwr.engine.setRpcType() */ +dwr.engine.ScriptTag = 3; + +/** + * Set the preferred remoting type. + * @param newType One of dwr.engine.XMLHttpRequest or dwr.engine.IFrame or dwr.engine.ScriptTag + * @see getahead.org/dwr/browser/engine/options + */ +dwr.engine.setRpcType = function(newType) { + if (newType != dwr.engine.XMLHttpRequest && newType != dwr.engine.IFrame && newType != dwr.engine.ScriptTag) { + dwr.engine._handleError(null, { name:"dwr.engine.invalidRpcType", message:"RpcType must be one of dwr.engine.XMLHttpRequest or dwr.engine.IFrame or dwr.engine.ScriptTag" }); + return; + } + dwr.engine._rpcType = newType; +}; + +/** + * Which HTTP method do we use to send results? Must be one of "GET" or "POST". + * @see getahead.org/dwr/browser/engine/options + */ +dwr.engine.setHttpMethod = function(httpMethod) { + if (httpMethod != "GET" && httpMethod != "POST") { + dwr.engine._handleError(null, { name:"dwr.engine.invalidHttpMethod", message:"Remoting method must be one of GET or POST" }); + return; + } + dwr.engine._httpMethod = httpMethod; +}; + +/** + * Ensure that remote calls happen in the order in which they were sent? (Default: false) + * @see getahead.org/dwr/browser/engine/ordering + */ +dwr.engine.setOrdered = function(ordered) { + dwr.engine._ordered = ordered; +}; + +/** + * Do we ask the XHR object to be asynchronous? (Default: true) + * @see getahead.org/dwr/browser/engine/options + */ +dwr.engine.setAsync = function(async) { + dwr.engine._async = async; +}; + +/** + * Does DWR poll the server for updates? (Default: false) + * @see getahead.org/dwr/browser/engine/options + */ +dwr.engine.setActiveReverseAjax = function(activeReverseAjax) { + if (activeReverseAjax) { + // Bail if we are already started + if (dwr.engine._activeReverseAjax) return; + dwr.engine._activeReverseAjax = true; + dwr.engine._poll(); + } + else { + // Can we cancel an existing request? + if (dwr.engine._activeReverseAjax && dwr.engine._pollReq) dwr.engine._pollReq.abort(); + dwr.engine._activeReverseAjax = false; + } + // TODO: in iframe mode, if we start, stop, start then the second start may + // well kick off a second iframe while the first is still about to return + // we should cope with this but we don't +}; + +/** + * The default message handler. + * @see getahead.org/dwr/browser/engine/errors + */ +dwr.engine.defaultErrorHandler = function(message, ex) { + dwr.engine._debug("Error: " + ex.name + ", " + ex.message, true); + if (message == null || message == "") alert("A server error has occured."); + // Ignore NS_ERROR_NOT_AVAILABLE if Mozilla is being narky + else if (message.indexOf("0x80040111") != -1) dwr.engine._debug(message); + else alert(message); +}; + +/** + * The default warning handler. + * @see getahead.org/dwr/browser/engine/errors + */ +dwr.engine.defaultWarningHandler = function(message, ex) { + dwr.engine._debug(message); +}; + +/** + * For reduced latency you can group several remote calls together using a batch. + * @see getahead.org/dwr/browser/engine/batch + */ +dwr.engine.beginBatch = function() { + if (dwr.engine._batch) { + dwr.engine._handleError(null, { name:"dwr.engine.batchBegun", message:"Batch already begun" }); + return; + } + dwr.engine._batch = dwr.engine._createBatch(); +}; + +/** + * Finished grouping a set of remote calls together. Go and execute them all. + * @see getahead.org/dwr/browser/engine/batch + */ +dwr.engine.endBatch = function(options) { + var batch = dwr.engine._batch; + if (batch == null) { + dwr.engine._handleError(null, { name:"dwr.engine.batchNotBegun", message:"No batch in progress" }); + return; + } + dwr.engine._batch = null; + if (batch.map.callCount == 0) return; + + // The hooks need to be merged carefully to preserve ordering + if (options) dwr.engine._mergeBatch(batch, options); + + // In ordered mode, we don't send unless the list of sent items is empty + if (dwr.engine._ordered && dwr.engine._batchesLength != 0) { + dwr.engine._batchQueue[dwr.engine._batchQueue.length] = batch; + } + else { + dwr.engine._sendData(batch); + } +}; + +/** @deprecated */ +dwr.engine.setPollMethod = function(type) { dwr.engine.setPollType(type); }; +dwr.engine.setMethod = function(type) { dwr.engine.setRpcType(type); }; +dwr.engine.setVerb = function(verb) { dwr.engine.setHttpMethod(verb); }; +dwr.engine.setPollType = function() { dwr.engine._debug("Manually setting the Poll Type is not supported"); }; + +//============================================================================== +// Only private stuff below here +//============================================================================== + +/** The original page id sent from the server */ +dwr.engine._origScriptSessionId = "${scriptSessionId}"; + +/** The session cookie name */ +dwr.engine._sessionCookieName = "${sessionCookieName}"; // JSESSIONID + +/** Is GET enabled for the benefit of Safari? */ +dwr.engine._allowGetForSafariButMakeForgeryEasier = "${allowGetForSafariButMakeForgeryEasier}"; + +/** The script prefix to strip in the case of scriptTagProtection. */ +dwr.engine._scriptTagProtection = "${scriptTagProtection}"; + +/** The default path to the DWR servlet */ +dwr.engine._defaultPath = "${defaultPath}"; + +/** Do we use XHR for reverse ajax because we are not streaming? */ +dwr.engine._pollWithXhr = "${pollWithXhr}"; + +/** The read page id that we calculate */ +dwr.engine._scriptSessionId = null; + +/** The function that we use to fetch/calculate a session id */ +dwr.engine._getScriptSessionId = function() { + if (dwr.engine._scriptSessionId == null) { + dwr.engine._scriptSessionId = dwr.engine._origScriptSessionId + Math.floor(Math.random() * 1000); + } + return dwr.engine._scriptSessionId; +}; + +/** A function to call if something fails. */ +dwr.engine._errorHandler = dwr.engine.defaultErrorHandler; + +/** For debugging when something unexplained happens. */ +dwr.engine._warningHandler = dwr.engine.defaultWarningHandler; + +/** A function to be called before requests are marshalled. Can be null. */ +dwr.engine._preHook = null; + +/** A function to be called after replies are received. Can be null. */ +dwr.engine._postHook = null; + +/** An map of the batches that we have sent and are awaiting a reply on. */ +dwr.engine._batches = {}; + +/** A count of the number of outstanding batches. Should be == to _batches.length unless prototype has messed things up */ +dwr.engine._batchesLength = 0; + +/** In ordered mode, the array of batches waiting to be sent */ +dwr.engine._batchQueue = []; + +/** What is the default rpc type */ +dwr.engine._rpcType = dwr.engine.XMLHttpRequest; + +/** What is the default remoting method (ie GET or POST) */ +dwr.engine._httpMethod = "POST"; + +/** Do we attempt to ensure that calls happen in the order in which they were sent? */ +dwr.engine._ordered = false; + +/** Do we make the calls async? */ +dwr.engine._async = true; + +/** The current batch (if we are in batch mode) */ +dwr.engine._batch = null; + +/** The global timeout */ +dwr.engine._timeout = 0; + +/** ActiveX objects to use when we want to convert an xml string into a DOM object. */ +dwr.engine._DOMDocument = ["Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"]; + +/** The ActiveX objects to use when we want to do an XMLHttpRequest call. */ +dwr.engine._XMLHTTP = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; + +/** Are we doing comet or polling? */ +dwr.engine._activeReverseAjax = false; + +/** The iframe that we are using to poll */ +dwr.engine._outstandingIFrames = []; + +/** The xhr object that we are using to poll */ +dwr.engine._pollReq = null; + +/** How many milliseconds between internal comet polls */ +dwr.engine._pollCometInterval = 200; + +/** How many times have we re-tried to poll? */ +dwr.engine._pollRetries = 0; +dwr.engine._maxPollRetries = 0; + +/** Do we do a document.reload if we get a text/html reply? */ +dwr.engine._textHtmlHandler = null; + +/** If you wish to send custom headers with every request */ +dwr.engine._headers = null; + +/** If you wish to send extra custom request parameters with each request */ +dwr.engine._parameters = null; + +/** Undocumented interceptors - do not use */ +dwr.engine._postSeperator = "\n"; +dwr.engine._defaultInterceptor = function(data) { return data; }; +dwr.engine._urlRewriteHandler = dwr.engine._defaultInterceptor; +dwr.engine._contentRewriteHandler = dwr.engine._defaultInterceptor; +dwr.engine._replyRewriteHandler = dwr.engine._defaultInterceptor; + +/** Batch ids allow us to know which batch the server is answering */ +dwr.engine._nextBatchId = 0; + +/** A list of the properties that need merging from calls to a batch */ +dwr.engine._propnames = [ "rpcType", "httpMethod", "async", "timeout", "errorHandler", "warningHandler", "textHtmlHandler" ]; + +/** Do we stream, or can be hacked to do so? */ +dwr.engine._partialResponseNo = 0; +dwr.engine._partialResponseYes = 1; +dwr.engine._partialResponseFlush = 2; + +/** + * @private Send a request. Called by the Javascript interface stub + * @param path part of URL after the host and before the exec bit without leading or trailing /s + * @param scriptName The class to execute + * @param methodName The method on said class to execute + * @param func The callback function to which any returned data should be passed + * if this is null, any returned data will be ignored + * @param vararg_params The parameters to pass to the above class + */ +dwr.engine._execute = function(path, scriptName, methodName, vararg_params) { + var singleShot = false; + if (dwr.engine._batch == null) { + dwr.engine.beginBatch(); + singleShot = true; + } + var batch = dwr.engine._batch; + // To make them easy to manipulate we copy the arguments into an args array + var args = []; + for (var i = 0; i < arguments.length - 3; i++) { + args[i] = arguments[i + 3]; + } + // All the paths MUST be to the same servlet + if (batch.path == null) { + batch.path = path; + } + else { + if (batch.path != path) { + dwr.engine._handleError(batch, { name:"dwr.engine.multipleServlets", message:"Can't batch requests to multiple DWR Servlets." }); + return; + } + } + // From the other params, work out which is the function (or object with + // call meta-data) and which is the call parameters + var callData; + var lastArg = args[args.length - 1]; + if (typeof lastArg == "function" || lastArg == null) callData = { callback:args.pop() }; + else callData = args.pop(); + + // Merge from the callData into the batch + dwr.engine._mergeBatch(batch, callData); + batch.handlers[batch.map.callCount] = { + exceptionHandler:callData.exceptionHandler, + callback:callData.callback + }; + + // Copy to the map the things that need serializing + var prefix = "c" + batch.map.callCount + "-"; + batch.map[prefix + "scriptName"] = scriptName; + batch.map[prefix + "methodName"] = methodName; + batch.map[prefix + "id"] = batch.map.callCount; + for (i = 0; i < args.length; i++) { + dwr.engine._serializeAll(batch, [], args[i], prefix + "param" + i); + } + + // Now we have finished remembering the call, we incr the call count + batch.map.callCount++; + if (singleShot) dwr.engine.endBatch(); +}; + +/** @private Poll the server to see if there is any data waiting */ +dwr.engine._poll = function(overridePath) { + if (!dwr.engine._activeReverseAjax) return; + + var batch = dwr.engine._createBatch(); + batch.map.id = 0; // TODO: Do we need this?? + batch.map.callCount = 1; + batch.isPoll = true; + if (dwr.engine._pollWithXhr == "true") { + batch.rpcType = dwr.engine.XMLHttpRequest; + batch.map.partialResponse = dwr.engine._partialResponseNo; + } + else { + if (navigator.userAgent.indexOf("Gecko/") != -1) { + batch.rpcType = dwr.engine.XMLHttpRequest; + batch.map.partialResponse = dwr.engine._partialResponseYes; + } + // else if (navigator.userAgent.indexOf("; MSIE")) { + // batch.rpcType = dwr.engine.IFrame; + // batch.map.partialResponse = dwr.engine._partialResponseYes; + // } + else if (navigator.userAgent.indexOf("Safari/")) { + batch.rpcType = dwr.engine.XMLHttpRequest; + batch.map.partialResponse = dwr.engine._partialResponseYes; + } + else { + batch.rpcType = dwr.engine.XMLHttpRequest; + batch.map.partialResponse = dwr.engine._partialResponseNo; + } + } + batch.httpMethod = "POST"; + batch.async = true; + batch.timeout = 0; + batch.path = (overridePath) ? overridePath : dwr.engine._defaultPath; + batch.preHooks = []; + batch.postHooks = []; + batch.errorHandler = dwr.engine._pollErrorHandler; + batch.warningHandler = dwr.engine._pollErrorHandler; + batch.handlers[0] = { + callback:function(pause) { + dwr.engine._pollRetries = 0; + setTimeout("dwr.engine._poll()", pause); + } + }; + + // Send the data + dwr.engine._sendData(batch); + if (batch.rpcType == dwr.engine.XMLHttpRequest && batch.map.partialResponse == dwr.engine._partialResponseYes) { + dwr.engine._checkCometPoll(); + } +}; + +/** Try to recover from polling errors */ +dwr.engine._pollErrorHandler = function(msg, ex) { + // if anything goes wrong then just silently try again (up to 3x) after 10s + dwr.engine._pollRetries++; + dwr.engine._debug("Reverse Ajax poll failed (pollRetries=" + dwr.engine._pollRetries + "): " + ex.name + " : " + ex.message); + if (dwr.engine._pollRetries < dwr.engine._maxPollRetries) { + setTimeout("dwr.engine._poll()", 10000); + } + else { + dwr.engine._activeReverseAjax = false; + dwr.engine._debug("Giving up."); + } +}; + +/** @private Generate a new standard batch */ +dwr.engine._createBatch = function() { + var batch = { + map:{ + callCount:0, + page:window.location.pathname + window.location.search, + httpSessionId:dwr.engine._getJSessionId(), + scriptSessionId:dwr.engine._getScriptSessionId() + }, + charsProcessed:0, paramCount:0, + parameters:{}, headers:{}, + isPoll:false, handlers:{}, preHooks:[], postHooks:[], + rpcType:dwr.engine._rpcType, + httpMethod:dwr.engine._httpMethod, + async:dwr.engine._async, + timeout:dwr.engine._timeout, + errorHandler:dwr.engine._errorHandler, + warningHandler:dwr.engine._warningHandler, + textHtmlHandler:dwr.engine._textHtmlHandler + }; + if (dwr.engine._preHook) batch.preHooks.push(dwr.engine._preHook); + if (dwr.engine._postHook) batch.postHooks.push(dwr.engine._postHook); + var propname, data; + if (dwr.engine._headers) { + for (propname in dwr.engine._headers) { + data = dwr.engine._headers[propname]; + if (typeof data != "function") batch.headers[propname] = data; + } + } + if (dwr.engine._parameters) { + for (propname in dwr.engine._parameters) { + data = dwr.engine._parameters[propname]; + if (typeof data != "function") batch.parameters[propname] = data; + } + } + return batch; +}; + +/** @private Take further options and merge them into */ +dwr.engine._mergeBatch = function(batch, overrides) { + var propname, data; + for (var i = 0; i < dwr.engine._propnames.length; i++) { + propname = dwr.engine._propnames[i]; + if (overrides[propname] != null) batch[propname] = overrides[propname]; + } + if (overrides.preHook != null) batch.preHooks.unshift(overrides.preHook); + if (overrides.postHook != null) batch.postHooks.push(overrides.postHook); + if (overrides.headers) { + for (propname in overrides.headers) { + data = overrides.headers[propname]; + if (typeof data != "function") batch.headers[propname] = data; + } + } + if (overrides.parameters) { + for (propname in overrides.parameters) { + data = overrides.parameters[propname]; + if (typeof data != "function") batch.map["p-" + propname] = "" + data; + } + } +}; + +/** @private What is our session id? */ +dwr.engine._getJSessionId = function() { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = cookies[i]; + while (cookie.charAt(0) == ' ') cookie = cookie.substring(1, cookie.length); + if (cookie.indexOf(dwr.engine._sessionCookieName + "=") == 0) { + return cookie.substring(dwr.engine._sessionCookieName.length + 1, cookie.length); + } + } + return ""; +}; + +/** @private Check for reverse Ajax activity */ +dwr.engine._checkCometPoll = function() { + for (var i = 0; i < dwr.engine._outstandingIFrames.length; i++) { + var text = ""; + var iframe = dwr.engine._outstandingIFrames[i]; + try { + text = dwr.engine._getTextFromCometIFrame(iframe); + } + catch (ex) { + dwr.engine._handleWarning(iframe.batch, ex); + } + if (text != "") dwr.engine._processCometResponse(text, iframe.batch); + } + if (dwr.engine._pollReq) { + var req = dwr.engine._pollReq; + var text = req.responseText; + if (text != null) dwr.engine._processCometResponse(text, req.batch); + } + + // If the poll resources are still there, come back again + if (dwr.engine._outstandingIFrames.length > 0 || dwr.engine._pollReq) { + setTimeout("dwr.engine._checkCometPoll()", dwr.engine._pollCometInterval); + } +}; + +/** @private Extract the whole (executed an all) text from the current iframe */ +dwr.engine._getTextFromCometIFrame = function(frameEle) { + var body = frameEle.contentWindow.document.body; + if (body == null) return ""; + var text = body.innerHTML; + // We need to prevent IE from stripping line feeds + if (text.indexOf("
") == 0 || text.indexOf("
") == 0) {
+    text = text.substring(5, text.length - 7);
+  }
+  return text;
+};
+
+/** @private Some more text might have come in, test and execute the new stuff */
+dwr.engine._processCometResponse = function(response, batch) {
+  if (batch.charsProcessed == response.length) return;
+  if (response.length == 0) {
+    batch.charsProcessed = 0;
+    return;
+  }
+
+  var firstStartTag = response.indexOf("//#DWR-START#", batch.charsProcessed);
+  if (firstStartTag == -1) {
+    // dwr.engine._debug("No start tag (search from " + batch.charsProcessed + "). skipping '" + response.substring(batch.charsProcessed) + "'");
+    batch.charsProcessed = response.length;
+    return;
+  }
+  // if (firstStartTag > 0) {
+  //   dwr.engine._debug("Start tag not at start (search from " + batch.charsProcessed + "). skipping '" + response.substring(batch.charsProcessed, firstStartTag) + "'");
+  // }
+
+  var lastEndTag = response.lastIndexOf("//#DWR-END#");
+  if (lastEndTag == -1) {
+    // dwr.engine._debug("No end tag. unchanged charsProcessed=" + batch.charsProcessed);
+    return;
+  }
+
+  // Skip the end tag too for next time, remembering CR and LF
+  if (response.charCodeAt(lastEndTag + 11) == 13 && response.charCodeAt(lastEndTag + 12) == 10) {
+    batch.charsProcessed = lastEndTag + 13;
+  }
+  else {
+    batch.charsProcessed = lastEndTag + 11;
+  }
+
+  var exec = response.substring(firstStartTag + 13, lastEndTag);
+
+  dwr.engine._receivedBatch = batch;
+  dwr.engine._eval(exec);
+  dwr.engine._receivedBatch = null;
+};
+
+/** @private Actually send the block of data in the batch object. */
+dwr.engine._sendData = function(batch) {
+  batch.map.batchId = dwr.engine._nextBatchId;
+  dwr.engine._nextBatchId++;
+  dwr.engine._batches[batch.map.batchId] = batch;
+  dwr.engine._batchesLength++;
+  batch.completed = false;
+
+  for (var i = 0; i < batch.preHooks.length; i++) {
+    batch.preHooks[i]();
+  }
+  batch.preHooks = null;
+  // Set a timeout
+  if (batch.timeout && batch.timeout != 0) {
+    batch.interval = setInterval(function() { dwr.engine._abortRequest(batch); }, batch.timeout);
+  }
+  // Get setup for XMLHttpRequest if possible
+  if (batch.rpcType == dwr.engine.XMLHttpRequest) {
+    if (window.XMLHttpRequest) {
+      batch.req = new XMLHttpRequest();
+    }
+    // IE5 for the mac claims to support window.ActiveXObject, but throws an error when it's used
+    else if (window.ActiveXObject && !(navigator.userAgent.indexOf("Mac") >= 0 && navigator.userAgent.indexOf("MSIE") >= 0)) {
+      batch.req = dwr.engine._newActiveXObject(dwr.engine._XMLHTTP);
+    }
+  }
+
+  var prop, request;
+  if (batch.req) {
+    // Proceed using XMLHttpRequest
+    if (batch.async) {
+      batch.req.onreadystatechange = function() {
+        if (typeof dwr != 'undefined') dwr.engine._stateChange(batch);
+      };
+    }
+    // If we're polling, record this for monitoring
+    if (batch.isPoll) {
+      dwr.engine._pollReq = batch.req;
+      // In IE XHR is an ActiveX control so you can't augment it like this
+      if (!document.all) batch.req.batch = batch;
+    }
+    // Workaround for Safari 1.x POST bug
+    var indexSafari = navigator.userAgent.indexOf("Safari/");
+    if (indexSafari >= 0) {
+      var version = navigator.userAgent.substring(indexSafari + 7);
+      if (parseInt(version, 10) < 400) {
+        if (dwr.engine._allowGetForSafariButMakeForgeryEasier == "true") batch.httpMethod = "GET";
+        else dwr.engine._handleWarning(batch, { name:"dwr.engine.oldSafari", message:"Safari GET support disabled. See getahead.org/dwr/server/servlet and allowGetForSafariButMakeForgeryEasier." });
+      }
+    }
+    batch.mode = batch.isPoll ? dwr.engine._ModePlainPoll : dwr.engine._ModePlainCall;
+    request = dwr.engine._constructRequest(batch);
+    try {
+      batch.req.open(batch.httpMethod, request.url, batch.async);
+      try {
+        for (prop in batch.headers) {
+          var value = batch.headers[prop];
+          if (typeof value == "string") batch.req.setRequestHeader(prop, value);
+        }
+        if (!batch.headers["Content-Type"]) batch.req.setRequestHeader("Content-Type", "text/plain");
+      }
+      catch (ex) {
+        dwr.engine._handleWarning(batch, ex);
+      }
+      batch.req.send(request.body);
+      if (!batch.async) dwr.engine._stateChange(batch);
+    }
+    catch (ex) {
+      dwr.engine._handleError(batch, ex);
+    }
+  }
+  else if (batch.rpcType != dwr.engine.ScriptTag) {
+    var idname = batch.isPoll ? "dwr-if-poll-" + batch.map.batchId : "dwr-if-" + batch.map["c0-id"];
+    // on IE try to use the htmlfile activex control
+    if (batch.isPoll && window.ActiveXObject) {
+      batch.htmlfile = new window.ActiveXObject("htmlfile");
+      batch.htmlfile.open();
+      batch.htmlfile.write("");
+      //batch.htmlfile.write("");
+      batch.htmlfile.write("
"); + batch.htmlfile.write(""); + batch.htmlfile.close(); + batch.htmlfile.parentWindow.dwr = dwr; + batch.document = batch.htmlfile; + } + else { + batch.div = document.createElement("div"); + // Add the div to the document first, otherwise IE 6 will ignore onload handler. + document.body.appendChild(batch.div); + batch.div.innerHTML = ""; + batch.document = document; + } + batch.iframe = batch.document.getElementById(idname); + batch.iframe.batch = batch; + batch.mode = batch.isPoll ? dwr.engine._ModeHtmlPoll : dwr.engine._ModeHtmlCall; + if (batch.isPoll) dwr.engine._outstandingIFrames.push(batch.iframe); + request = dwr.engine._constructRequest(batch); + if (batch.httpMethod == "GET") { + batch.iframe.setAttribute("src", request.url); + } + else { + batch.form = batch.document.createElement("form"); + batch.form.setAttribute("id", "dwr-form"); + batch.form.setAttribute("action", request.url); + batch.form.setAttribute("target", idname); + batch.form.target = idname; + batch.form.setAttribute("method", batch.httpMethod); + for (prop in batch.map) { + var value = batch.map[prop]; + if (typeof value != "function") { + var formInput = batch.document.createElement("input"); + formInput.setAttribute("type", "hidden"); + formInput.setAttribute("name", prop); + formInput.setAttribute("value", value); + batch.form.appendChild(formInput); + } + } + batch.document.body.appendChild(batch.form); + batch.form.submit(); + } + } + else { + batch.httpMethod = "GET"; // There's no such thing as ScriptTag using POST + batch.mode = batch.isPoll ? dwr.engine._ModePlainPoll : dwr.engine._ModePlainCall; + request = dwr.engine._constructRequest(batch); + batch.script = document.createElement("script"); + batch.script.id = "dwr-st-" + batch.map["c0-id"]; + batch.script.src = request.url; + document.body.appendChild(batch.script); + } +}; + +dwr.engine._ModePlainCall = "/call/plaincall/"; +dwr.engine._ModeHtmlCall = "/call/htmlcall/"; +dwr.engine._ModePlainPoll = "/call/plainpoll/"; +dwr.engine._ModeHtmlPoll = "/call/htmlpoll/"; + +/** @private Work out what the URL should look like */ +dwr.engine._constructRequest = function(batch) { + // A quick string to help people that use web log analysers + var request = { url:batch.path + batch.mode, body:null }; + if (batch.isPoll == true) { + request.url += "ReverseAjax.dwr"; + } + else if (batch.map.callCount == 1) { + request.url += batch.map["c0-scriptName"] + "." + batch.map["c0-methodName"] + ".dwr"; + } + else { + request.url += "Multiple." + batch.map.callCount + ".dwr"; + } + // Play nice with url re-writing + var sessionMatch = location.href.match(/jsessionid=([^?]+)/); + if (sessionMatch != null) { + request.url += ";jsessionid=" + sessionMatch[1]; + } + + var prop; + if (batch.httpMethod == "GET") { + // Some browsers (Opera/Safari2) seem to fail to convert the callCount value + // to a string in the loop below so we do it manually here. + batch.map.callCount = "" + batch.map.callCount; + request.url += "?"; + for (prop in batch.map) { + if (typeof batch.map[prop] != "function") { + request.url += encodeURIComponent(prop) + "=" + encodeURIComponent(batch.map[prop]) + "&"; + } + } + request.url = request.url.substring(0, request.url.length - 1); + } + else { + // PERFORMANCE: for iframe mode this is thrown away. + request.body = ""; + for (prop in batch.map) { + if (typeof batch.map[prop] != "function") { + request.body += prop + "=" + batch.map[prop] + dwr.engine._postSeperator; + } + } + request.body = dwr.engine._contentRewriteHandler(request.body); + } + request.url = dwr.engine._urlRewriteHandler(request.url); + return request; +}; + +/** @private Called by XMLHttpRequest to indicate that something has happened */ +dwr.engine._stateChange = function(batch) { + var toEval; + + if (batch.completed) { + dwr.engine._debug("Error: _stateChange() with batch.completed"); + return; + } + + var req = batch.req; + try { + if (req.readyState != 4) return; + } + catch (ex) { + dwr.engine._handleWarning(batch, ex); + // It's broken - clear up and forget this call + dwr.engine._clearUp(batch); + return; + } + + try { + var reply = req.responseText; + reply = dwr.engine._replyRewriteHandler(reply); + var status = req.status; // causes Mozilla to except on page moves + + if (reply == null || reply == "") { + dwr.engine._handleWarning(batch, { name:"dwr.engine.missingData", message:"No data received from server" }); + } + else if (status != 200) { + dwr.engine._handleError(batch, { name:"dwr.engine.http." + status, message:req.statusText }); + } + else { + var contentType = req.getResponseHeader("Content-Type"); + if (!contentType.match(/^text\/plain/) && !contentType.match(/^text\/javascript/)) { + if (contentType.match(/^text\/html/) && typeof batch.textHtmlHandler == "function") { + batch.textHtmlHandler(); + } + else { + dwr.engine._handleWarning(batch, { name:"dwr.engine.invalidMimeType", message:"Invalid content type: '" + contentType + "'" }); + } + } + else { + // Comet replies might have already partially executed + if (batch.isPoll && batch.map.partialResponse == dwr.engine._partialResponseYes) { + dwr.engine._processCometResponse(reply, batch); + } + else { + if (reply.search("//#DWR") == -1) { + dwr.engine._handleWarning(batch, { name:"dwr.engine.invalidReply", message:"Invalid reply from server" }); + } + else { + toEval = reply; + } + } + } + } + } + catch (ex) { + dwr.engine._handleWarning(batch, ex); + } + + dwr.engine._callPostHooks(batch); + + // Outside of the try/catch so errors propogate normally: + dwr.engine._receivedBatch = batch; + if (toEval != null) toEval = toEval.replace(dwr.engine._scriptTagProtection, ""); + dwr.engine._eval(toEval); + dwr.engine._receivedBatch = null; + dwr.engine._validateBatch(batch); + dwr.engine._clearUp(batch); +}; + +/** + * @private This function is invoked when a batch reply is received. + * It checks that there is a response for every call in the batch. Otherwise, + * an error will be signaled (a call without a response indicates that the + * server failed to send complete batch response). + */ +dwr.engine._validateBatch = function(batch) { + // If some call left unreplied, report an error. + if (!batch.completed) { + for (var i = 0; i < batch.map.callCount; i++) { + if (batch.handlers[i] != null) { + dwr.engine._handleWarning(batch, { name:"dwr.engine.incompleteReply", message:"Incomplete reply from server" }); + break; + } + } + } +} + +/** @private Called from iframe onload, check batch using batch-id */ +dwr.engine._iframeLoadingComplete = function(batchId) { + // dwr.engine._checkCometPoll(); + var batch = dwr.engine._batches[batchId]; + if (batch) dwr.engine._validateBatch(batch); +} + +/** @private Called by the server: Execute a callback */ +dwr.engine._remoteHandleCallback = function(batchId, callId, reply) { + var batch = dwr.engine._batches[batchId]; + if (batch == null) { + dwr.engine._debug("Warning: batch == null in remoteHandleCallback for batchId=" + batchId, true); + return; + } + // Error handlers inside here indicate an error that is nothing to do + // with DWR so we handle them differently. + try { + var handlers = batch.handlers[callId]; + batch.handlers[callId] = null; + if (!handlers) { + dwr.engine._debug("Warning: Missing handlers. callId=" + callId, true); + } + else if (typeof handlers.callback == "function") handlers.callback(reply); + } + catch (ex) { + dwr.engine._handleError(batch, ex); + } +}; + +/** @private Called by the server: Handle an exception for a call */ +dwr.engine._remoteHandleException = function(batchId, callId, ex) { + var batch = dwr.engine._batches[batchId]; + if (batch == null) { dwr.engine._debug("Warning: null batch in remoteHandleException", true); return; } + var handlers = batch.handlers[callId]; + batch.handlers[callId] = null; + if (handlers == null) { dwr.engine._debug("Warning: null handlers in remoteHandleException", true); return; } + if (ex.message == undefined) ex.message = ""; + if (typeof handlers.exceptionHandler == "function") handlers.exceptionHandler(ex.message, ex); + else if (typeof batch.errorHandler == "function") batch.errorHandler(ex.message, ex); +}; + +/** @private Called by the server: The whole batch is broken */ +dwr.engine._remoteHandleBatchException = function(ex, batchId) { + var searchBatch = (dwr.engine._receivedBatch == null && batchId != null); + if (searchBatch) { + dwr.engine._receivedBatch = dwr.engine._batches[batchId]; + } + if (ex.message == undefined) ex.message = ""; + dwr.engine._handleError(dwr.engine._receivedBatch, ex); + if (searchBatch) { + dwr.engine._receivedBatch = null; + dwr.engine._clearUp(dwr.engine._batches[batchId]); + } +}; + +/** @private Called by the server: Reverse ajax should not be used */ +dwr.engine._remotePollCometDisabled = function(ex, batchId) { + dwr.engine.setActiveReverseAjax(false); + var searchBatch = (dwr.engine._receivedBatch == null && batchId != null); + if (searchBatch) { + dwr.engine._receivedBatch = dwr.engine._batches[batchId]; + } + if (ex.message == undefined) ex.message = ""; + dwr.engine._handleError(dwr.engine._receivedBatch, ex); + if (searchBatch) { + dwr.engine._receivedBatch = null; + dwr.engine._clearUp(dwr.engine._batches[batchId]); + } +}; + +/** @private Called by the server: An IFrame reply is about to start */ +dwr.engine._remoteBeginIFrameResponse = function(iframe, batchId) { + if (iframe != null) dwr.engine._receivedBatch = iframe.batch; + dwr.engine._callPostHooks(dwr.engine._receivedBatch); +}; + +/** @private Called by the server: An IFrame reply is just completing */ +dwr.engine._remoteEndIFrameResponse = function(batchId) { + dwr.engine._clearUp(dwr.engine._receivedBatch); + dwr.engine._receivedBatch = null; +}; + +/** @private This is a hack to make the context be this window */ +dwr.engine._eval = function(script) { + if (script == null) return null; + if (script == "") { dwr.engine._debug("Warning: blank script", true); return null; } + // dwr.engine._debug("Exec: [" + script + "]", true); + return eval(script); +}; + +/** @private Called as a result of a request timeout */ +dwr.engine._abortRequest = function(batch) { + if (batch && !batch.completed) { + clearInterval(batch.interval); + dwr.engine._clearUp(batch); + if (batch.req) batch.req.abort(); + dwr.engine._handleError(batch, { name:"dwr.engine.timeout", message:"Timeout" }); + } +}; + +/** @private call all the post hooks for a batch */ +dwr.engine._callPostHooks = function(batch) { + if (batch.postHooks) { + for (var i = 0; i < batch.postHooks.length; i++) { + batch.postHooks[i](); + } + batch.postHooks = null; + } +}; + +/** @private A call has finished by whatever means and we need to shut it all down. */ +dwr.engine._clearUp = function(batch) { + if (!batch) { dwr.engine._debug("Warning: null batch in dwr.engine._clearUp()", true); return; } + if (batch.completed == "true") { dwr.engine._debug("Warning: Double complete", true); return; } + + // IFrame tidyup + if (batch.div) batch.div.parentNode.removeChild(batch.div); + if (batch.iframe) { + // If this is a poll frame then stop comet polling + for (var i = 0; i < dwr.engine._outstandingIFrames.length; i++) { + if (dwr.engine._outstandingIFrames[i] == batch.iframe) { + dwr.engine._outstandingIFrames.splice(i, 1); + } + } + batch.iframe.parentNode.removeChild(batch.iframe); + } + if (batch.form) batch.form.parentNode.removeChild(batch.form); + + // XHR tidyup: avoid IE handles increase + if (batch.req) { + // If this is a poll frame then stop comet polling + if (batch.req == dwr.engine._pollReq) dwr.engine._pollReq = null; + delete batch.req; + } + + if (batch.map && batch.map.batchId) { + delete dwr.engine._batches[batch.map.batchId]; + dwr.engine._batchesLength--; + } + + batch.completed = true; + + // If there is anything on the queue waiting to go out, then send it. + // We don't need to check for ordered mode, here because when ordered mode + // gets turned off, we still process *waiting* batches in an ordered way. + if (dwr.engine._batchQueue.length != 0) { + var sendbatch = dwr.engine._batchQueue.shift(); + dwr.engine._sendData(sendbatch); + } +}; + +/** @private Generic error handling routing to save having null checks everywhere */ +dwr.engine._handleError = function(batch, ex) { + if (typeof ex == "string") ex = { name:"unknown", message:ex }; + if (ex.message == null) ex.message = ""; + if (ex.name == null) ex.name = "unknown"; + if (batch && typeof batch.errorHandler == "function") batch.errorHandler(ex.message, ex); + else if (dwr.engine._errorHandler) dwr.engine._errorHandler(ex.message, ex); + if (batch) dwr.engine._clearUp(batch); +}; + +/** @private Generic error handling routing to save having null checks everywhere */ +dwr.engine._handleWarning = function(batch, ex) { + if (typeof ex == "string") ex = { name:"unknown", message:ex }; + if (ex.message == null) ex.message = ""; + if (ex.name == null) ex.name = "unknown"; + if (batch && typeof batch.warningHandler == "function") batch.warningHandler(ex.message, ex); + else if (dwr.engine._warningHandler) dwr.engine._warningHandler(ex.message, ex); + if (batch) dwr.engine._clearUp(batch); +}; + +/** + * @private Marshall a data item + * @param batch A map of variables to how they have been marshalled + * @param referto An array of already marshalled variables to prevent recurrsion + * @param data The data to be marshalled + * @param name The name of the data being marshalled + */ +dwr.engine._serializeAll = function(batch, referto, data, name) { + if (data == null) { + batch.map[name] = "null:null"; + return; + } + + switch (typeof data) { + case "boolean": + batch.map[name] = "boolean:" + data; + break; + case "number": + batch.map[name] = "number:" + data; + break; + case "string": + batch.map[name] = "string:" + encodeURIComponent(data); + break; + case "object": + if (data instanceof String) batch.map[name] = "String:" + encodeURIComponent(data); + else if (data instanceof Boolean) batch.map[name] = "Boolean:" + data; + else if (data instanceof Number) batch.map[name] = "Number:" + data; + else if (data instanceof Date) batch.map[name] = "Date:" + data.getTime(); + else if (data && data.join) batch.map[name] = dwr.engine._serializeArray(batch, referto, data, name); + else batch.map[name] = dwr.engine._serializeObject(batch, referto, data, name); + break; + case "function": + // We just ignore functions. + break; + default: + dwr.engine._handleWarning(null, { name:"dwr.engine.unexpectedType", message:"Unexpected type: " + typeof data + ", attempting default converter." }); + batch.map[name] = "default:" + data; + break; + } +}; + +/** @private Have we already converted this object? */ +dwr.engine._lookup = function(referto, data, name) { + var lookup; + // Can't use a map: getahead.org/ajax/javascript-gotchas + for (var i = 0; i < referto.length; i++) { + if (referto[i].data == data) { + lookup = referto[i]; + break; + } + } + if (lookup) return "reference:" + lookup.name; + referto.push({ data:data, name:name }); + return null; +}; + +/** @private Marshall an object */ +dwr.engine._serializeObject = function(batch, referto, data, name) { + var ref = dwr.engine._lookup(referto, data, name); + if (ref) return ref; + + // This check for an HTML is not complete, but is there a better way? + // Maybe we should add: data.hasChildNodes typeof "function" == true + if (data.nodeName && data.nodeType) { + return dwr.engine._serializeXml(batch, referto, data, name); + } + + // treat objects as an associative arrays + var reply = "Object_" + dwr.engine._getObjectClassName(data) + ":{"; + var element; + for (element in data) { + if (typeof data[element] != "function") { + batch.paramCount++; + var childName = "c" + dwr.engine._batch.map.callCount + "-e" + batch.paramCount; + dwr.engine._serializeAll(batch, referto, data[element], childName); + + reply += encodeURIComponent(element) + ":reference:" + childName + ", "; + } + } + + if (reply.substring(reply.length - 2) == ", ") { + reply = reply.substring(0, reply.length - 2); + } + reply += "}"; + + return reply; +}; + +/** @private Returns the classname of supplied argument obj */ +dwr.engine._errorClasses = { "Error":Error, "EvalError":EvalError, "RangeError":RangeError, "ReferenceError":ReferenceError, "SyntaxError":SyntaxError, "TypeError":TypeError, "URIError":URIError }; +dwr.engine._getObjectClassName = function(obj) { + // Try to find the classname by stringifying the object's constructor + // and extract from "function ". + if (obj && obj.constructor && obj.constructor.toString) + { + var str = obj.constructor.toString(); + var regexpmatch = str.match(/function\s+(\w+)/); + if (regexpmatch && regexpmatch.length == 2) { + return regexpmatch[1]; + } + } + + // Now manually test against the core Error classes, as these in some + // browsers successfully match to the wrong class in the + // Object.toString() test we will do later + if (obj && obj.constructor) { + for (var errorname in dwr.engine._errorClasses) { + if (obj.constructor == dwr.engine._errorClasses[errorname]) return errorname; + } + } + + // Try to find the classname by calling Object.toString() on the object + // and extracting from "[object ]" + if (obj) { + var str = Object.prototype.toString.call(obj); + var regexpmatch = str.match(/\[object\s+(\w+)/); + if (regexpmatch && regexpmatch.length==2) { + return regexpmatch[1]; + } + } + + // Supplied argument was probably not an object, but what is better? + return "Object"; +}; + +/** @private Marshall an object */ +dwr.engine._serializeXml = function(batch, referto, data, name) { + var ref = dwr.engine._lookup(referto, data, name); + if (ref) return ref; + + var output; + if (window.XMLSerializer) output = new XMLSerializer().serializeToString(data); + else if (data.toXml) output = data.toXml; + else output = data.innerHTML; + + return "XML:" + encodeURIComponent(output); +}; + +/** @private Marshall an array */ +dwr.engine._serializeArray = function(batch, referto, data, name) { + var ref = dwr.engine._lookup(referto, data, name); + if (ref) return ref; + + var reply = "Array:["; + for (var i = 0; i < data.length; i++) { + if (i != 0) reply += ","; + batch.paramCount++; + var childName = "c" + dwr.engine._batch.map.callCount + "-e" + batch.paramCount; + dwr.engine._serializeAll(batch, referto, data[i], childName); + reply += "reference:"; + reply += childName; + } + reply += "]"; + + return reply; +}; + +/** @private Convert an XML string into a DOM object. */ +dwr.engine._unserializeDocument = function(xml) { + var dom; + if (window.DOMParser) { + var parser = new DOMParser(); + dom = parser.parseFromString(xml, "text/xml"); + if (!dom.documentElement || dom.documentElement.tagName == "parsererror") { + var message = dom.documentElement.firstChild.data; + message += "\n" + dom.documentElement.firstChild.nextSibling.firstChild.data; + throw message; + } + return dom; + } + else if (window.ActiveXObject) { + dom = dwr.engine._newActiveXObject(dwr.engine._DOMDocument); + dom.loadXML(xml); // What happens on parse fail with IE? + return dom; + } + else { + var div = document.createElement("div"); + div.innerHTML = xml; + return div; + } +}; + +/** @param axarray An array of strings to attempt to create ActiveX objects from */ +dwr.engine._newActiveXObject = function(axarray) { + var returnValue; + for (var i = 0; i < axarray.length; i++) { + try { + returnValue = new ActiveXObject(axarray[i]); + break; + } + catch (ex) { /* ignore */ } + } + return returnValue; +}; + +/** @private Used internally when some message needs to get to the programmer */ +dwr.engine._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; + } + } +}; diff --git a/YACOSWeb/WebContent/dwr/util.js b/YACOSWeb/WebContent/dwr/util.js new file mode 100644 index 0000000..6687862 --- /dev/null +++ b/YACOSWeb/WebContent/dwr/util.js @@ -0,0 +1,1484 @@ +/* + * 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) { + var div = document.createElement('div'); + var text = document.createTextNode(original); + div.appendChild(text); + return div.innerHTML; +}; + +/** + * Replace common XML entities with characters (see dwr.util.escapeHtml()) + * @see TODO + */ +dwr.util.unescapeHtml = function(original) { + var div = document.createElement('div'); + div.innerHTML = original.replace(/<\/?[^>]+>/gi, ''); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; +}; + +/** + * 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/$ + */ +var $; +if (!$) { + $ = 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) && typeof(val) == "string") { + if (ele.textContent) ele.textContent = val; + else if (ele.innerText) ele.innerText = val; + else ele.innerHTML = dwr.util.escapeHtml(val); + } + 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 = ""; + if (options && options.prefix) prefix = options.prefix; + if (options && options.idPrefix) prefix = options.idPrefix; + dwr.util._setValuesRecursive(data, prefix); +}; + +/** + * @private Recursive helper for setValues() + */ +dwr.util._setValuesRecursive = function(data, idpath) { + // 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+"]"); + } + } + // 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._isArray(data[prop]) && data[prop].length > 0 && dwr.util._isObject(data[prop][0])) { + dwr.util._setValuesRecursive(data[prop], subidpath); + } + // 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]); + } + } + } + } +}; + +/** + * 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 = ""; + if (options != null && options.prefix) prefix = options.prefix; + if (options != null && options.idPrefix) prefix = options.idPrefix; + dwr.util._getValuesRecursive(data, prefix); + 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) { + // 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+"]"); + } + } + // 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); + } + // 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; + + 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 new Option(); +}; + +/** + * @private Default list item creation function + */ +dwr.util._defaultListItemCreator = function(options) { + return 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; + 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 document.createElement("tr"); +}; + +/** + * @private Default cell creation function + */ +dwr.util._defaultCellCreator = function(options) { + return 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 (typeof importedNode.style != "undefined") { + 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; + } + } +};