| 1 | // SpryData.js - version 0.35 - Spry Pre-Release 1.5 |
|---|
| 2 | // |
|---|
| 3 | // Copyright (c) 2006. Adobe Systems Incorporated. |
|---|
| 4 | // All rights reserved. |
|---|
| 5 | // |
|---|
| 6 | // Redistribution and use in source and binary forms, with or without |
|---|
| 7 | // modification, are permitted provided that the following conditions are met: |
|---|
| 8 | // |
|---|
| 9 | // * Redistributions of source code must retain the above copyright notice, |
|---|
| 10 | // this list of conditions and the following disclaimer. |
|---|
| 11 | // * Redistributions in binary form must reproduce the above copyright notice, |
|---|
| 12 | // this list of conditions and the following disclaimer in the documentation |
|---|
| 13 | // and/or other materials provided with the distribution. |
|---|
| 14 | // * Neither the name of Adobe Systems Incorporated nor the names of its |
|---|
| 15 | // contributors may be used to endorse or promote products derived from this |
|---|
| 16 | // software without specific prior written permission. |
|---|
| 17 | // |
|---|
| 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|---|
| 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|---|
| 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|---|
| 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|---|
| 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|---|
| 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|---|
| 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|---|
| 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|---|
| 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|---|
| 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|---|
| 28 | // POSSIBILITY OF SUCH DAMAGE. |
|---|
| 29 | |
|---|
| 30 | var Spry; if (!Spry) Spry = {}; |
|---|
| 31 | |
|---|
| 32 | ////////////////////////////////////////////////////////////////////// |
|---|
| 33 | // |
|---|
| 34 | // Spry.Utils |
|---|
| 35 | // |
|---|
| 36 | ////////////////////////////////////////////////////////////////////// |
|---|
| 37 | |
|---|
| 38 | if (!Spry.Utils) Spry.Utils = {}; |
|---|
| 39 | |
|---|
| 40 | Spry.Utils.msProgIDs = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; |
|---|
| 41 | |
|---|
| 42 | Spry.Utils.createXMLHttpRequest = function() |
|---|
| 43 | { |
|---|
| 44 | var req = null; |
|---|
| 45 | try |
|---|
| 46 | { |
|---|
| 47 | // Try to use the ActiveX version of XMLHttpRequest. This will |
|---|
| 48 | // allow developers to load file URLs in IE7 when running in the |
|---|
| 49 | // local zone. |
|---|
| 50 | |
|---|
| 51 | if (window.ActiveXObject) |
|---|
| 52 | { |
|---|
| 53 | while (!req && Spry.Utils.msProgIDs.length) |
|---|
| 54 | { |
|---|
| 55 | try { req = new ActiveXObject(Spry.Utils.msProgIDs[0]); } catch (e) { req = null; } |
|---|
| 56 | if (!req) |
|---|
| 57 | Spry.Utils.msProgIDs.splice(0, 1); |
|---|
| 58 | } |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | // We're either running in a non-IE browser, or we failed to |
|---|
| 62 | // create the ActiveX version of the XMLHttpRequest object. |
|---|
| 63 | // Try to use the native version of XMLHttpRequest if it exists. |
|---|
| 64 | |
|---|
| 65 | if (!req && window.XMLHttpRequest) |
|---|
| 66 | req = new XMLHttpRequest(); |
|---|
| 67 | } |
|---|
| 68 | catch (e) { req = null; } |
|---|
| 69 | |
|---|
| 70 | if (!req) |
|---|
| 71 | Spry.Debug.reportError("Failed to create an XMLHttpRequest object!" ); |
|---|
| 72 | |
|---|
| 73 | return req; |
|---|
| 74 | }; |
|---|
| 75 | |
|---|
| 76 | Spry.Utils.loadURL = function(method, url, async, callback, opts) |
|---|
| 77 | { |
|---|
| 78 | var req = new Spry.Utils.loadURL.Request(); |
|---|
| 79 | req.method = method; |
|---|
| 80 | req.url = url; |
|---|
| 81 | req.async = async; |
|---|
| 82 | req.successCallback = callback; |
|---|
| 83 | Spry.Utils.setOptions(req, opts); |
|---|
| 84 | |
|---|
| 85 | try |
|---|
| 86 | { |
|---|
| 87 | req.xhRequest = Spry.Utils.createXMLHttpRequest(); |
|---|
| 88 | if (!req.xhRequest) |
|---|
| 89 | return null; |
|---|
| 90 | |
|---|
| 91 | if (req.async) |
|---|
| 92 | req.xhRequest.onreadystatechange = function() { Spry.Utils.loadURL.callback(req); }; |
|---|
| 93 | |
|---|
| 94 | req.xhRequest.open(req.method, req.url, req.async, req.username, req.password); |
|---|
| 95 | |
|---|
| 96 | if (req.headers) |
|---|
| 97 | { |
|---|
| 98 | for (var name in req.headers) |
|---|
| 99 | req.xhRequest.setRequestHeader(name, req.headers[name]); |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | req.xhRequest.send(req.postData); |
|---|
| 103 | |
|---|
| 104 | if (!req.async) |
|---|
| 105 | Spry.Utils.loadURL.callback(req); |
|---|
| 106 | } |
|---|
| 107 | catch(e) |
|---|
| 108 | { |
|---|
| 109 | if (req.errorCallback) |
|---|
| 110 | req.errorCallback(req); |
|---|
| 111 | else |
|---|
| 112 | Spry.Debug.reportError("Exception caught while loading " + url + ": " + e); |
|---|
| 113 | req = null; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | return req; |
|---|
| 117 | }; |
|---|
| 118 | |
|---|
| 119 | Spry.Utils.loadURL.callback = function(req) |
|---|
| 120 | { |
|---|
| 121 | if (!req || req.xhRequest.readyState != 4) |
|---|
| 122 | return; |
|---|
| 123 | if (req.successCallback && (req.xhRequest.status == 200 || req.xhRequest.status == 0)) |
|---|
| 124 | req.successCallback(req); |
|---|
| 125 | else if (req.errorCallback) |
|---|
| 126 | req.errorCallback(req); |
|---|
| 127 | }; |
|---|
| 128 | |
|---|
| 129 | Spry.Utils.loadURL.Request = function() |
|---|
| 130 | { |
|---|
| 131 | var props = Spry.Utils.loadURL.Request.props; |
|---|
| 132 | var numProps = props.length; |
|---|
| 133 | |
|---|
| 134 | for (var i = 0; i < numProps; i++) |
|---|
| 135 | this[props[i]] = null; |
|---|
| 136 | |
|---|
| 137 | this.method = "GET"; |
|---|
| 138 | this.async = true; |
|---|
| 139 | this.headers = {}; |
|---|
| 140 | }; |
|---|
| 141 | |
|---|
| 142 | Spry.Utils.loadURL.Request.props = [ "method", "url", "async", "username", "password", "postData", "successCallback", "errorCallback", "headers", "userData", "xhRequest" ]; |
|---|
| 143 | |
|---|
| 144 | Spry.Utils.loadURL.Request.prototype.extractRequestOptions = function(opts, undefineRequestProps) |
|---|
| 145 | { |
|---|
| 146 | if (!opts) |
|---|
| 147 | return; |
|---|
| 148 | |
|---|
| 149 | var props = Spry.Utils.loadURL.Request.props; |
|---|
| 150 | var numProps = props.length; |
|---|
| 151 | |
|---|
| 152 | for (var i = 0; i < numProps; i++) |
|---|
| 153 | { |
|---|
| 154 | var prop = props[i]; |
|---|
| 155 | if (opts[prop] != undefined) |
|---|
| 156 | { |
|---|
| 157 | this[prop] = opts[prop]; |
|---|
| 158 | if (undefineRequestProps) |
|---|
| 159 | opts[prop] = undefined; |
|---|
| 160 | } |
|---|
| 161 | } |
|---|
| 162 | }; |
|---|
| 163 | |
|---|
| 164 | Spry.Utils.loadURL.Request.prototype.clone = function() |
|---|
| 165 | { |
|---|
| 166 | var props = Spry.Utils.loadURL.Request.props; |
|---|
| 167 | var numProps = props.length; |
|---|
| 168 | var req = new Spry.Utils.loadURL.Request; |
|---|
| 169 | for (var i = 0; i < numProps; i++) |
|---|
| 170 | req[props[i]] = this[props[i]]; |
|---|
| 171 | if (this.headers) |
|---|
| 172 | { |
|---|
| 173 | req.headers = {}; |
|---|
| 174 | Spry.Utils.setOptions(req.headers, this.headers); |
|---|
| 175 | } |
|---|
| 176 | return req; |
|---|
| 177 | }; |
|---|
| 178 | |
|---|
| 179 | Spry.Utils.setInnerHTML = function(ele, str, preventScripts) |
|---|
| 180 | { |
|---|
| 181 | if (!ele) |
|---|
| 182 | return; |
|---|
| 183 | ele = Spry.$(ele); |
|---|
| 184 | var scriptExpr = "<script[^>]*>(.|\s|\n|\r)*?</script>"; |
|---|
| 185 | ele.innerHTML = str.replace(new RegExp(scriptExpr, "img"), ""); |
|---|
| 186 | |
|---|
| 187 | if (preventScripts) |
|---|
| 188 | return; |
|---|
| 189 | |
|---|
| 190 | var matches = str.match(new RegExp(scriptExpr, "img")); |
|---|
| 191 | if (matches) |
|---|
| 192 | { |
|---|
| 193 | var numMatches = matches.length; |
|---|
| 194 | for (var i = 0; i < numMatches; i++) |
|---|
| 195 | { |
|---|
| 196 | var s = matches[i].replace(/<script[^>]*>[\s\r\n]*(<\!--)?|(-->)?[\s\r\n]*<\/script>/img, ""); |
|---|
| 197 | Spry.Utils.eval(s); |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | }; |
|---|
| 201 | |
|---|
| 202 | Spry.Utils.updateContent = function (ele, url, finishFunc, opts) |
|---|
| 203 | { |
|---|
| 204 | Spry.Utils.loadURL("GET", url, true, function(req) |
|---|
| 205 | { |
|---|
| 206 | Spry.Utils.setInnerHTML(ele, req.xhRequest.responseText); |
|---|
| 207 | if (finishFunc) |
|---|
| 208 | finishFunc(ele, url); |
|---|
| 209 | }, opts); |
|---|
| 210 | }; |
|---|
| 211 | |
|---|
| 212 | Spry.Utils.addEventListener = function(element, eventType, handler, capture) |
|---|
| 213 | { |
|---|
| 214 | try |
|---|
| 215 | { |
|---|
| 216 | element = Spry.$(element); |
|---|
| 217 | if (element.addEventListener) |
|---|
| 218 | element.addEventListener(eventType, handler, capture); |
|---|
| 219 | else if (element.attachEvent) |
|---|
| 220 | element.attachEvent("on" + eventType, handler); |
|---|
| 221 | } |
|---|
| 222 | catch (e) {} |
|---|
| 223 | }; |
|---|
| 224 | |
|---|
| 225 | Spry.Utils.removeEventListener = function(element, eventType, handler, capture) |
|---|
| 226 | { |
|---|
| 227 | try |
|---|
| 228 | { |
|---|
| 229 | element = Spry.$(element); |
|---|
| 230 | if (element.removeEventListener) |
|---|
| 231 | element.removeEventListener(eventType, handler, capture); |
|---|
| 232 | else if (element.detachEvent) |
|---|
| 233 | element.detachEvent("on" + eventType, handler); |
|---|
| 234 | } |
|---|
| 235 | catch (e) {} |
|---|
| 236 | }; |
|---|
| 237 | |
|---|
| 238 | Spry.Utils.addLoadListener = function(handler) |
|---|
| 239 | { |
|---|
| 240 | if (typeof window.addEventListener != 'undefined') |
|---|
| 241 | window.addEventListener('load', handler, false); |
|---|
| 242 | else if (typeof document.addEventListener != 'undefined') |
|---|
| 243 | document.addEventListener('load', handler, false); |
|---|
| 244 | else if (typeof window.attachEvent != 'undefined') |
|---|
| 245 | window.attachEvent('onload', handler); |
|---|
| 246 | }; |
|---|
| 247 | |
|---|
| 248 | Spry.Utils.eval = function(str) |
|---|
| 249 | { |
|---|
| 250 | // Call this method from your JS function when |
|---|
| 251 | // you don't want the JS expression to access or |
|---|
| 252 | // interfere with any local variables in your JS |
|---|
| 253 | // function. |
|---|
| 254 | |
|---|
| 255 | return eval(str); |
|---|
| 256 | }; |
|---|
| 257 | |
|---|
| 258 | Spry.Utils.escapeQuotesAndLineBreaks = function(str) |
|---|
| 259 | { |
|---|
| 260 | if (str) |
|---|
| 261 | { |
|---|
| 262 | str = str.replace(/\\/g, "\\\\"); |
|---|
| 263 | str = str.replace(/["']/g, "\\$&"); |
|---|
| 264 | str = str.replace(/\n/g, "\\n"); |
|---|
| 265 | str = str.replace(/\r/g, "\\r"); |
|---|
| 266 | } |
|---|
| 267 | return str; |
|---|
| 268 | }; |
|---|
| 269 | |
|---|
| 270 | Spry.Utils.encodeEntities = function(str) |
|---|
| 271 | { |
|---|
| 272 | if (str && str.search(/[&<>"]/) != -1) |
|---|
| 273 | { |
|---|
| 274 | str = str.replace(/&/g, "&"); |
|---|
| 275 | str = str.replace(/</g, "<"); |
|---|
| 276 | str = str.replace(/>/g, ">"); |
|---|
| 277 | str = str.replace(/"/g, """); |
|---|
| 278 | } |
|---|
| 279 | return str |
|---|
| 280 | }; |
|---|
| 281 | |
|---|
| 282 | Spry.Utils.decodeEntities = function(str) |
|---|
| 283 | { |
|---|
| 284 | var d = Spry.Utils.decodeEntities.div; |
|---|
| 285 | if (!d) |
|---|
| 286 | { |
|---|
| 287 | d = document.createElement('div'); |
|---|
| 288 | Spry.Utils.decodeEntities.div = d; |
|---|
| 289 | if (!d) return str; |
|---|
| 290 | } |
|---|
| 291 | d.innerHTML = str; |
|---|
| 292 | if (d.childNodes.length == 1 && d.firstChild.nodeType == 3 /* Node.TEXT_NODE */ && d.firstChild.nextSibling == null) |
|---|
| 293 | str = d.firstChild.data; |
|---|
| 294 | else |
|---|
| 295 | { |
|---|
| 296 | // Hmmm, innerHTML processing of str produced content |
|---|
| 297 | // we weren't expecting, so just replace entities we |
|---|
| 298 | // expect folks will use in node attributes that contain |
|---|
| 299 | // JavaScript. |
|---|
| 300 | str = str.replace(/</gi, "<"); |
|---|
| 301 | str = str.replace(/>/gi, ">"); |
|---|
| 302 | str = str.replace(/"/gi, "\""); |
|---|
| 303 | str = str.replace(/&/gi, "&"); |
|---|
| 304 | } |
|---|
| 305 | return str; |
|---|
| 306 | }; |
|---|
| 307 | |
|---|
| 308 | Spry.Utils.fixupIETagAttributes = function(inStr) |
|---|
| 309 | { |
|---|
| 310 | var outStr = ""; |
|---|
| 311 | |
|---|
| 312 | // Break the tag string into 3 pieces. |
|---|
| 313 | |
|---|
| 314 | var tagStart = inStr.match(/^<[^\s>]+\s*/)[0]; |
|---|
| 315 | var tagEnd = inStr.match(/\s*\/?>$/)[0]; |
|---|
| 316 | var tagAttrs = inStr.replace(/^<[^\s>]+\s*|\s*\/?>/g, ""); |
|---|
| 317 | |
|---|
| 318 | // Write out the start of the tag. |
|---|
| 319 | outStr += tagStart; |
|---|
| 320 | |
|---|
| 321 | // If the tag has attributes, parse it out manually to avoid accidentally fixing up |
|---|
| 322 | // attributes that contain JavaScript expressions. |
|---|
| 323 | |
|---|
| 324 | if (tagAttrs) |
|---|
| 325 | { |
|---|
| 326 | var startIndex = 0; |
|---|
| 327 | var endIndex = 0; |
|---|
| 328 | |
|---|
| 329 | while (startIndex < tagAttrs.length) |
|---|
| 330 | { |
|---|
| 331 | // Find the '=' char of the attribute. |
|---|
| 332 | while (tagAttrs.charAt(endIndex) != '=' && endIndex < tagAttrs.length) |
|---|
| 333 | ++endIndex; |
|---|
| 334 | |
|---|
| 335 | // If we are at the end of the string, just write out what we've |
|---|
| 336 | // collected. |
|---|
| 337 | |
|---|
| 338 | if (endIndex >= tagAttrs.length) |
|---|
| 339 | { |
|---|
| 340 | outStr += tagAttrs.substring(startIndex, endIndex); |
|---|
| 341 | break; |
|---|
| 342 | } |
|---|
| 343 | |
|---|
| 344 | // Step past the '=' character and write out what we've |
|---|
| 345 | // collected so far. |
|---|
| 346 | |
|---|
| 347 | ++endIndex; |
|---|
| 348 | outStr += tagAttrs.substring(startIndex, endIndex); |
|---|
| 349 | startIndex = endIndex; |
|---|
| 350 | |
|---|
| 351 | if (tagAttrs.charAt(endIndex) == '"' || tagAttrs.charAt(endIndex) == "'") |
|---|
| 352 | { |
|---|
| 353 | // Attribute is quoted. Advance us past the quoted value! |
|---|
| 354 | var savedIndex = endIndex++; |
|---|
| 355 | while (endIndex < tagAttrs.length) |
|---|
| 356 | { |
|---|
| 357 | if (tagAttrs.charAt(endIndex) == tagAttrs.charAt(savedIndex)) |
|---|
| 358 | { |
|---|
| 359 | endIndex++; |
|---|
| 360 | break; |
|---|
| 361 | } |
|---|
| 362 | else if (tagAttrs.charAt(endIndex) == "\\") |
|---|
| 363 | endIndex++; |
|---|
| 364 | endIndex++; |
|---|
| 365 | } |
|---|
| 366 | |
|---|
| 367 | outStr += tagAttrs.substring(startIndex, endIndex); |
|---|
| 368 | startIndex = endIndex; |
|---|
| 369 | } |
|---|
| 370 | else |
|---|
| 371 | { |
|---|
| 372 | // This attribute value wasn't quoted! Wrap it with quotes and |
|---|
| 373 | // write out everything till we hit a space, or the end of the |
|---|
| 374 | // string. |
|---|
| 375 | |
|---|
| 376 | outStr += "\""; |
|---|
| 377 | |
|---|
| 378 | var sIndex = tagAttrs.slice(endIndex).search(/\s/); |
|---|
| 379 | endIndex = (sIndex != -1) ? (endIndex + sIndex) : tagAttrs.length; |
|---|
| 380 | outStr += tagAttrs.slice(startIndex, endIndex); |
|---|
| 381 | outStr += "\""; |
|---|
| 382 | startIndex = endIndex; |
|---|
| 383 | } |
|---|
| 384 | } |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | outStr += tagEnd; |
|---|
| 388 | |
|---|
| 389 | // Write out the end of the tag. |
|---|
| 390 | return outStr; |
|---|
| 391 | }; |
|---|
| 392 | |
|---|
| 393 | Spry.Utils.fixUpIEInnerHTML = function(inStr) |
|---|
| 394 | { |
|---|
| 395 | var outStr = ""; |
|---|
| 396 | |
|---|
| 397 | // Create a regular expression that will match: |
|---|
| 398 | // <!-- |
|---|
| 399 | // <![CDATA[ |
|---|
| 400 | // <tag> |
|---|
| 401 | // --> |
|---|
| 402 | // ]]> |
|---|
| 403 | // ]]> // Yet another workaround for an IE innerHTML bug. |
|---|
| 404 | // |
|---|
| 405 | // The idea here is that we only want to fix up attribute values on tags that |
|---|
| 406 | // are not in any comments or CDATA. |
|---|
| 407 | |
|---|
| 408 | var regexp = new RegExp("<\\!--|<\\!\\[CDATA\\[|<\\w+[^<>]*>|-->|\\]\\](>|\>)", "g"); |
|---|
| 409 | var searchStartIndex = 0; |
|---|
| 410 | var skipFixUp = 0; |
|---|
| 411 | |
|---|
| 412 | while (inStr.length) |
|---|
| 413 | { |
|---|
| 414 | var results = regexp.exec(inStr); |
|---|
| 415 | if (!results || !results[0]) |
|---|
| 416 | { |
|---|
| 417 | outStr += inStr.substr(searchStartIndex, inStr.length - searchStartIndex); |
|---|
| 418 | break; |
|---|
| 419 | } |
|---|
| 420 | |
|---|
| 421 | if (results.index != searchStartIndex) |
|---|
| 422 | { |
|---|
| 423 | // We found a match but it's not at the start of the inStr. |
|---|
| 424 | // Create a string token for everything that precedes the match. |
|---|
| 425 | outStr += inStr.substr(searchStartIndex, results.index - searchStartIndex); |
|---|
| 426 | } |
|---|
| 427 | |
|---|
| 428 | if (results[0] == "<!--" || results[0] == "<![CDATA[") |
|---|
| 429 | { |
|---|
| 430 | ++skipFixUp; |
|---|
| 431 | outStr += results[0]; |
|---|
| 432 | } |
|---|
| 433 | else if (results[0] == "-->" || results[0] == "]]>" || (skipFixUp && results[0] == "]]>")) |
|---|
| 434 | { |
|---|
| 435 | --skipFixUp; |
|---|
| 436 | outStr += results[0]; |
|---|
| 437 | } |
|---|
| 438 | else if (!skipFixUp && results[0].charAt(0) == '<') |
|---|
| 439 | outStr += Spry.Utils.fixupIETagAttributes(results[0]); |
|---|
| 440 | else |
|---|
| 441 | outStr += results[0]; |
|---|
| 442 | |
|---|
| 443 | searchStartIndex = regexp.lastIndex; |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | return outStr; |
|---|
| 447 | }; |
|---|
| 448 | |
|---|
| 449 | Spry.Utils.stringToXMLDoc = function(str) |
|---|
| 450 | { |
|---|
| 451 | var xmlDoc = null; |
|---|
| 452 | |
|---|
| 453 | try |
|---|
| 454 | { |
|---|
| 455 | // Attempt to parse the string using the IE method. |
|---|
| 456 | |
|---|
| 457 | var xmlDOMObj = new ActiveXObject("Microsoft.XMLDOM"); |
|---|
| 458 | xmlDOMObj.async = false; |
|---|
| 459 | xmlDOMObj.loadXML(str); |
|---|
| 460 | xmlDoc = xmlDOMObj; |
|---|
| 461 | } |
|---|
| 462 | catch (e) |
|---|
| 463 | { |
|---|
| 464 | // The IE method didn't work. Try the Mozilla way. |
|---|
| 465 | |
|---|
| 466 | try |
|---|
| 467 | { |
|---|
| 468 | var domParser = new DOMParser; |
|---|
| 469 | xmlDoc = domParser.parseFromString(str, 'text/xml'); |
|---|
| 470 | } |
|---|
| 471 | catch (e) |
|---|
| 472 | { |
|---|
| 473 | Spry.Debug.reportError("Caught exception in Spry.Utils.stringToXMLDoc(): " + e + "\n"); |
|---|
| 474 | xmlDoc = null; |
|---|
| 475 | } |
|---|
| 476 | } |
|---|
| 477 | |
|---|
| 478 | return xmlDoc; |
|---|
| 479 | }; |
|---|
| 480 | |
|---|
| 481 | Spry.Utils.serializeObject = function(obj) |
|---|
| 482 | { |
|---|
| 483 | // Create a JSON representation of a given object. |
|---|
| 484 | |
|---|
| 485 | var str = ""; |
|---|
| 486 | var firstItem = true; |
|---|
| 487 | |
|---|
| 488 | if (obj == null || obj == undefined) |
|---|
| 489 | return str + obj; |
|---|
| 490 | |
|---|
| 491 | var objType = typeof obj; |
|---|
| 492 | |
|---|
| 493 | if (objType == "number" || objType == "boolean") |
|---|
| 494 | str += obj; |
|---|
| 495 | else if (objType == "string") |
|---|
| 496 | str += "\"" + Spry.Utils.escapeQuotesAndLineBreaks(obj) + "\""; |
|---|
| 497 | else if (obj.constructor == Array) |
|---|
| 498 | { |
|---|
| 499 | str += "["; |
|---|
| 500 | for (var i = 0; i < obj.length; i++) |
|---|
| 501 | { |
|---|
| 502 | if (!firstItem) |
|---|
| 503 | str += ", "; |
|---|
| 504 | str += Spry.Utils.serializeObject(obj[i]); |
|---|
| 505 | firstItem = false; |
|---|
| 506 | } |
|---|
| 507 | str += "]"; |
|---|
| 508 | } |
|---|
| 509 | else if (objType == "object") |
|---|
| 510 | { |
|---|
| 511 | str += "{"; |
|---|
| 512 | for (var p in obj) |
|---|
| 513 | { |
|---|
| 514 | if (!firstItem) |
|---|
| 515 | str += ", "; |
|---|
| 516 | str += "\"" + p + "\": " + Spry.Utils.serializeObject(obj[p]); |
|---|
| 517 | firstItem = false; |
|---|
| 518 | } |
|---|
| 519 | str += "}"; |
|---|
| 520 | } |
|---|
| 521 | return str; |
|---|
| 522 | }; |
|---|
| 523 | |
|---|
| 524 | Spry.Utils.getNodesByFunc = function(root, func) |
|---|
| 525 | { |
|---|
| 526 | var nodeStack = new Array; |
|---|
| 527 | var resultArr = new Array; |
|---|
| 528 | var node = root; |
|---|
| 529 | |
|---|
| 530 | while (node) |
|---|
| 531 | { |
|---|
| 532 | if (func(node)) |
|---|
| 533 | resultArr.push(node); |
|---|
| 534 | |
|---|
| 535 | if (node.hasChildNodes()) |
|---|
| 536 | { |
|---|
| 537 | nodeStack.push(node); |
|---|
| 538 | node = node.firstChild; |
|---|
| 539 | } |
|---|
| 540 | else |
|---|
| 541 | { |
|---|
| 542 | if (node == root) |
|---|
| 543 | node = null; |
|---|
| 544 | else |
|---|
| 545 | try { node = node.nextSibling; } catch (e) { node = null; }; |
|---|
| 546 | } |
|---|
| 547 | |
|---|
| 548 | while (!node && nodeStack.length > 0) |
|---|
| 549 | { |
|---|
| 550 | node = nodeStack.pop(); |
|---|
| 551 | if (node == root) |
|---|
| 552 | node = null; |
|---|
| 553 | else |
|---|
| 554 | try { node = node.nextSibling; } catch (e) { node = null; } |
|---|
| 555 | } |
|---|
| 556 | } |
|---|
| 557 | |
|---|
| 558 | if (nodeStack && nodeStack.length > 0) |
|---|
| 559 | Spry.Debug.trace("-- WARNING: Spry.Utils.getNodesByFunc() failed to traverse all nodes!\n"); |
|---|
| 560 | |
|---|
| 561 | return resultArr; |
|---|
| 562 | }; |
|---|
| 563 | |
|---|
| 564 | Spry.Utils.addClassName = function(ele, className) |
|---|
| 565 | { |
|---|
| 566 | ele = Spry.$(ele); |
|---|
| 567 | if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1)) |
|---|
| 568 | return; |
|---|
| 569 | ele.className += (ele.className ? " " : "") + className; |
|---|
| 570 | }; |
|---|
| 571 | |
|---|
| 572 | Spry.Utils.removeClassName = function(ele, className) |
|---|
| 573 | { |
|---|
| 574 | ele = Spry.$(ele); |
|---|
| 575 | if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)) |
|---|
| 576 | return; |
|---|
| 577 | ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ""); |
|---|
| 578 | }; |
|---|
| 579 | |
|---|
| 580 | Spry.Utils.getFirstChildWithNodeName = function(node, nodeName) |
|---|
| 581 | { |
|---|
| 582 | var child = node.firstChild; |
|---|
| 583 | |
|---|
| 584 | while (child) |
|---|
| 585 | { |
|---|
| 586 | if (child.nodeName == nodeName) |
|---|
| 587 | return child; |
|---|
| 588 | child = child.nextSibling; |
|---|
| 589 | } |
|---|
| 590 | |
|---|
| 591 | return null; |
|---|
| 592 | }; |
|---|
| 593 | |
|---|
| 594 | Spry.Utils.nodeContainsElementNode = function(node) |
|---|
| 595 | { |
|---|
| 596 | if (node) |
|---|
| 597 | { |
|---|
| 598 | node = node.firstChild; |
|---|
| 599 | |
|---|
| 600 | while (node) |
|---|
| 601 | { |
|---|
| 602 | if (node.nodeType == 1 /* Node.ELEMENT_NODE */) |
|---|
| 603 | return true; |
|---|
| 604 | |
|---|
| 605 | node = node.nextSibling; |
|---|
| 606 | } |
|---|
| 607 | } |
|---|
| 608 | return false; |
|---|
| 609 | }; |
|---|
| 610 | |
|---|
| 611 | Spry.Utils.getNodeText = function(node) |
|---|
| 612 | { |
|---|
| 613 | var txt = ""; |
|---|
| 614 | |
|---|
| 615 | if (!node) |
|---|
| 616 | return; |
|---|
| 617 | |
|---|
| 618 | try |
|---|
| 619 | { |
|---|
| 620 | var child = node.firstChild; |
|---|
| 621 | |
|---|
| 622 | while (child) |
|---|
| 623 | { |
|---|
| 624 | try |
|---|
| 625 | { |
|---|
| 626 | if (child.nodeType == 3 /* TEXT_NODE */) |
|---|
| 627 | txt += Spry.Utils.encodeEntities(child.data); |
|---|
| 628 | else if (child.nodeType == 4 /* CDATA_SECTION_NODE */) |
|---|
| 629 | txt += child.data; |
|---|
| 630 | } catch (e) { Spry.Debug.reportError("Spry.Utils.getNodeText() exception caught: " + e + "\n"); } |
|---|
| 631 | |
|---|
| 632 | child = child.nextSibling; |
|---|
| 633 | } |
|---|
| 634 | } |
|---|
| 635 | catch (e) { Spry.Debug.reportError("Spry.Utils.getNodeText() exception caught: " + e + "\n"); } |
|---|
| 636 | |
|---|
| 637 | return txt; |
|---|
| 638 | }; |
|---|
| 639 | |
|---|
| 640 | Spry.Utils.CreateObjectForNode = function(node) |
|---|
| 641 | { |
|---|
| 642 | if (!node) |
|---|
| 643 | return null; |
|---|
| 644 | |
|---|
| 645 | var obj = new Object(); |
|---|
| 646 | var i = 0; |
|---|
| 647 | var attr = null; |
|---|
| 648 | |
|---|
| 649 | try |
|---|
| 650 | { |
|---|
| 651 | for (i = 0; i < node.attributes.length; i++) |
|---|
| 652 | { |
|---|
| 653 | attr = node.attributes[i]; |
|---|
| 654 | if (attr && attr.nodeType == 2 /* Node.ATTRIBUTE_NODE */) |
|---|
| 655 | obj["@" + attr.name] = attr.value; |
|---|
| 656 | } |
|---|
| 657 | } |
|---|
| 658 | catch (e) |
|---|
| 659 | { |
|---|
| 660 | Spry.Debug.reportError("Spry.Utils.CreateObjectForNode() caught exception while accessing attributes: " + e + "\n"); |
|---|
| 661 | } |
|---|
| 662 | |
|---|
| 663 | var child = node.firstChild; |
|---|
| 664 | |
|---|
| 665 | if (child && !child.nextSibling && child.nodeType != 1 /* Node.ELEMENT_NODE */) |
|---|
| 666 | { |
|---|
| 667 | // We have a single child and it's not an element. It must |
|---|
| 668 | // be the text value for this node. Add it to the record set and |
|---|
| 669 | // give it the column the same name as the node. |
|---|
| 670 | |
|---|
| 671 | obj[node.nodeName] = Spry.Utils.getNodeText(node); |
|---|
| 672 | } |
|---|
| 673 | |
|---|
| 674 | while (child) |
|---|
| 675 | { |
|---|
| 676 | // Add the text value for each child element. Note that |
|---|
| 677 | // We skip elements that have element children (sub-elements) |
|---|
| 678 | // because we don't handle multi-level data sets right now. |
|---|
| 679 | |
|---|
| 680 | if (child.nodeType == 1 /* Node.ELEMENT_NODE */) |
|---|
| 681 | { |
|---|
| 682 | if (!Spry.Utils.nodeContainsElementNode(child)) |
|---|
| 683 | { |
|---|
| 684 | obj[child.nodeName] = Spry.Utils.getNodeText(child); |
|---|
| 685 | |
|---|
| 686 | // Now add properties for any attributes on the child. The property |
|---|
| 687 | // name will be of the form "<child.nodeName>/@<attr.name>". |
|---|
| 688 | try |
|---|
| 689 | { |
|---|
| 690 | var namePrefix = child.nodeName + "/@"; |
|---|
| 691 | |
|---|
| 692 | for (i = 0; i < child.attributes.length; i++) |
|---|
| 693 | { |
|---|
| 694 | attr = child.attributes[i]; |
|---|
| 695 | if (attr && attr.nodeType == 2 /* Node.ATTRIBUTE_NODE */) |
|---|
| 696 | obj[namePrefix + attr.name] = attr.value; |
|---|
| 697 | } |
|---|
| 698 | } |
|---|
| 699 | catch (e) |
|---|
| 700 | { |
|---|
| 701 | Spry.Debug.reportError("Spry.Utils.CreateObjectForNode() caught exception while accessing attributes: " + e + "\n"); |
|---|
| 702 | } |
|---|
| 703 | } |
|---|
| 704 | } |
|---|
| 705 | |
|---|
| 706 | child = child.nextSibling; |
|---|
| 707 | } |
|---|
| 708 | |
|---|
| 709 | return obj; |
|---|
| 710 | }; |
|---|
| 711 | |
|---|
| 712 | Spry.Utils.getRecordSetFromXMLDoc = function(xmlDoc, path, suppressColumns) |
|---|
| 713 | { |
|---|
| 714 | if (!xmlDoc || !path) |
|---|
| 715 | return null; |
|---|
| 716 | |
|---|
| 717 | var recordSet = new Object(); |
|---|
| 718 | recordSet.xmlDoc = xmlDoc; |
|---|
| 719 | recordSet.xmlPath = path; |
|---|
| 720 | recordSet.dataHash = new Object; |
|---|
| 721 | recordSet.data = new Array; |
|---|
| 722 | recordSet.getData = function() { return this.data; }; |
|---|
| 723 | |
|---|
| 724 | // Use the XPath library to find the nodes that will |
|---|
| 725 | // make up our data set. The result should be an array |
|---|
| 726 | // of subtrees that we need to flatten. |
|---|
| 727 | |
|---|
| 728 | var ctx = new ExprContext(xmlDoc); |
|---|
| 729 | var pathExpr = xpathParse(path); |
|---|
| 730 | var e = pathExpr.evaluate(ctx); |
|---|
| 731 | |
|---|
| 732 | // XXX: Note that we should check the result type of the evaluation |
|---|
| 733 | // just in case it's a boolean, string, or number value instead of |
|---|
| 734 | // a node set. |
|---|
| 735 | |
|---|
| 736 | var nodeArray = e.nodeSetValue(); |
|---|
| 737 | |
|---|
| 738 | var isDOMNodeArray = true; |
|---|
| 739 | |
|---|
| 740 | if (nodeArray && nodeArray.length > 0) |
|---|
| 741 | isDOMNodeArray = nodeArray[0].nodeType != 2 /* Node.ATTRIBUTE_NODE */; |
|---|
| 742 | |
|---|
| 743 | var nextID = 0; |
|---|
| 744 | |
|---|
| 745 | // We now have the set of nodes that make up our data set |
|---|
| 746 | // so process each one. |
|---|
| 747 | |
|---|
| 748 | for (var i = 0; i < nodeArray.length; i++) |
|---|
| 749 | { |
|---|
| 750 | var rowObj = null; |
|---|
| 751 | |
|---|
| 752 | if (suppressColumns) |
|---|
| 753 | rowObj = new Object; |
|---|
| 754 | else |
|---|
| 755 | { |
|---|
| 756 | if (isDOMNodeArray) |
|---|
| 757 | rowObj = Spry.Utils.CreateObjectForNode(nodeArray[i]); |
|---|
| 758 | else // Must be a Node.ATTRIBUTE_NODE array. |
|---|
| 759 | { |
|---|
| 760 | rowObj = new Object; |
|---|
| 761 | rowObj["@" + nodeArray[i].name] = nodeArray[i].value; |
|---|
| 762 | } |
|---|
| 763 | } |
|---|
| 764 | |
|---|
| 765 | if (rowObj) |
|---|
| 766 | { |
|---|
| 767 | // We want to make sure that every row has a unique ID and since we |
|---|
| 768 | // we don't know which column, if any, in this recordSet is a unique |
|---|
| 769 | // identifier, we generate a unique ID ourselves and store it under |
|---|
| 770 | // the ds_RowID column in the row object. |
|---|
| 771 | |
|---|
| 772 | rowObj['ds_RowID'] = nextID++; |
|---|
| 773 | rowObj['ds_XMLNode'] = nodeArray[i]; |
|---|
| 774 | recordSet.dataHash[rowObj['ds_RowID']] = rowObj; |
|---|
| 775 | recordSet.data.push(rowObj); |
|---|
| 776 | } |
|---|
| 777 | } |
|---|
| 778 | |
|---|
| 779 | return recordSet; |
|---|
| 780 | }; |
|---|
| 781 | |
|---|
| 782 | Spry.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps) |
|---|
| 783 | { |
|---|
| 784 | if (!optionsObj) |
|---|
| 785 | return; |
|---|
| 786 | |
|---|
| 787 | for (var optionName in optionsObj) |
|---|
| 788 | { |
|---|
| 789 | if (ignoreUndefinedProps && optionsObj[optionName] == undefined) |
|---|
| 790 | continue; |
|---|
| 791 | obj[optionName] = optionsObj[optionName]; |
|---|
| 792 | } |
|---|
| 793 | }; |
|---|
| 794 | |
|---|
| 795 | Spry.Utils.SelectionManager = {}; |
|---|
| 796 | Spry.Utils.SelectionManager.selectionGroups = new Object; |
|---|
| 797 | |
|---|
| 798 | Spry.Utils.SelectionManager.SelectionGroup = function() |
|---|
| 799 | { |
|---|
| 800 | this.selectedElements = new Array; |
|---|
| 801 | }; |
|---|
| 802 | |
|---|
| 803 | Spry.Utils.SelectionManager.SelectionGroup.prototype.select = function(element, className, multiSelect) |
|---|
| 804 | { |
|---|
| 805 | var selObj = null; |
|---|
| 806 | |
|---|
| 807 | if (!multiSelect) |
|---|
| 808 | { |
|---|
| 809 | // Multiple selection is not enabled, so clear any |
|---|
| 810 | // selected elements from our list. |
|---|
| 811 | |
|---|
| 812 | this.clearSelection(); |
|---|
| 813 | } |
|---|
| 814 | else |
|---|
| 815 | { |
|---|
| 816 | // Multiple selection is enabled, so check to see if element |
|---|
| 817 | // is already in the array. If it is, make sure the className |
|---|
| 818 | // is the className that was passed in. |
|---|
| 819 | |
|---|
| 820 | for (var i = 0; i < this.selectedElements.length; i++) |
|---|
| 821 | { |
|---|
| 822 | selObj = this.selectedElements[i].element; |
|---|
| 823 | |
|---|
| 824 | if (selObj.element == element) |
|---|
| 825 | { |
|---|
| 826 | if (selObj.className != className) |
|---|
| 827 | { |
|---|
| 828 | Spry.Utils.removeClassName(element, selObj.className); |
|---|
| 829 | Spry.Utils.addClassName(element, className); |
|---|
| 830 | } |
|---|
| 831 | return; |
|---|
| 832 | } |
|---|
| 833 | } |
|---|
| 834 | } |
|---|
| 835 | |
|---|
| 836 | // Add the element to our list of selected elements. |
|---|
| 837 | |
|---|
| 838 | selObj = new Object; |
|---|
| 839 | selObj.element = element; |
|---|
| 840 | selObj.className = className; |
|---|
| 841 | this.selectedElements.push(selObj); |
|---|
| 842 | Spry.Utils.addClassName(element, className); |
|---|
| 843 | }; |
|---|
| 844 | |
|---|
| 845 | Spry.Utils.SelectionManager.SelectionGroup.prototype.unSelect = function(element) |
|---|
| 846 | { |
|---|
| 847 | for (var i = 0; i < this.selectedElements.length; i++) |
|---|
| 848 | { |
|---|
| 849 | var selObj = this.selectedElements[i].element; |
|---|
| 850 | |
|---|
| 851 | if (selObj.element == element) |
|---|
| 852 | { |
|---|
| 853 | Spry.Utils.removeClassName(selObj.element, selObj.className); |
|---|
| 854 | return; |
|---|
| 855 | } |
|---|
| 856 | } |
|---|
| 857 | }; |
|---|
| 858 | |
|---|
| 859 | Spry.Utils.SelectionManager.SelectionGroup.prototype.clearSelection = function() |
|---|
| 860 | { |
|---|
| 861 | var selObj = null; |
|---|
| 862 | |
|---|
| 863 | do |
|---|
| 864 | { |
|---|
| 865 | selObj = this.selectedElements.shift(); |
|---|
| 866 | if (selObj) |
|---|
| 867 | Spry.Utils.removeClassName(selObj.element, selObj.className); |
|---|
| 868 | } |
|---|
| 869 | while (selObj); |
|---|
| 870 | }; |
|---|
| 871 | |
|---|
| 872 | Spry.Utils.SelectionManager.getSelectionGroup = function(selectionGroupName) |
|---|
| 873 | { |
|---|
| 874 | if (!selectionGroupName) |
|---|
| 875 | return null; |
|---|
| 876 | |
|---|
| 877 | var groupObj = Spry.Utils.SelectionManager.selectionGroups[selectionGroupName]; |
|---|
| 878 | |
|---|
| 879 | if (!groupObj) |
|---|
| 880 | { |
|---|
| 881 | groupObj = new Spry.Utils.SelectionManager.SelectionGroup(); |
|---|
| 882 | Spry.Utils.SelectionManager.selectionGroups[selectionGroupName] = groupObj; |
|---|
| 883 | } |
|---|
| 884 | |
|---|
| 885 | return groupObj; |
|---|
| 886 | }; |
|---|
| 887 | |
|---|
| 888 | Spry.Utils.SelectionManager.select = function(selectionGroupName, element, className, multiSelect) |
|---|
| 889 | { |
|---|
| 890 | var groupObj = Spry.Utils.SelectionManager.getSelectionGroup(selectionGroupName); |
|---|
| 891 | |
|---|
| 892 | if (!groupObj) |
|---|
| 893 | return; |
|---|
| 894 | |
|---|
| 895 | groupObj.select(element, className, multiSelect); |
|---|
| 896 | }; |
|---|
| 897 | |
|---|
| 898 | Spry.Utils.SelectionManager.unSelect = function(selectionGroupName, element) |
|---|
| 899 | { |
|---|
| 900 | var groupObj = Spry.Utils.SelectionManager.getSelectionGroup(selectionGroupName); |
|---|
| 901 | |
|---|
| 902 | if (!groupObj) |
|---|
| 903 | return; |
|---|
| 904 | |
|---|
| 905 | groupObj.unSelect(element, className); |
|---|
| 906 | }; |
|---|
| 907 | |
|---|
| 908 | Spry.Utils.SelectionManager.clearSelection = function(selectionGroupName) |
|---|
| 909 | { |
|---|
| 910 | var groupObj = Spry.Utils.SelectionManager.getSelectionGroup(selectionGroupName); |
|---|
| 911 | |
|---|
| 912 | if (!groupObj) |
|---|
| 913 | return; |
|---|
| 914 | |
|---|
| 915 | groupObj.clearSelection(); |
|---|
| 916 | }; |
|---|
| 917 | |
|---|
| 918 | ////////////////////////////////////////////////////////////////////// |
|---|
| 919 | // |
|---|
| 920 | // Define Prototype's $() convenience function, but make sure it is |
|---|
| 921 | // namespaced under Spry so that we avoid collisions with other |
|---|
| 922 | // toolkits. |
|---|
| 923 | // |
|---|
| 924 | ////////////////////////////////////////////////////////////////////// |
|---|
| 925 | |
|---|
| 926 | Spry.$ = function(element) |
|---|
| 927 | { |
|---|
| 928 | if (arguments.length > 1) |
|---|
| 929 | { |
|---|
| 930 | for (var i = 0, elements = [], length = arguments.length; i < length; i++) |
|---|
| 931 | elements.push(Spry.$(arguments[i])); |
|---|
| 932 | return elements; |
|---|
| 933 | } |
|---|
| 934 | if (typeof element == 'string') |
|---|
| 935 | element = document.getElementById(element); |
|---|
| 936 | return element; |
|---|
| 937 | }; |
|---|
| 938 | |
|---|
| 939 | Spry.Utils.Notifier = function() |
|---|
| 940 | { |
|---|
| 941 | this.observers = []; |
|---|
| 942 | this.suppressNotifications = 0; |
|---|
| 943 | }; |
|---|
| 944 | |
|---|
| 945 | Spry.Utils.Notifier.prototype.addObserver = function(observer) |
|---|
| 946 | { |
|---|
| 947 | if (!observer) |
|---|
| 948 | return; |
|---|
| 949 | |
|---|
| 950 | // Make sure the observer isn't already on the list. |
|---|
| 951 | |
|---|
| 952 | var len = this.observers.length; |
|---|
| 953 | for (var i = 0; i < len; i++) |
|---|
| 954 | { |
|---|
| 955 | if (this.observers[i] == observer) |
|---|
| 956 | return; |
|---|
| 957 | } |
|---|
| 958 | this.observers[len] = observer; |
|---|
| 959 | }; |
|---|
| 960 | |
|---|
| 961 | Spry.Utils.Notifier.prototype.removeObserver = function(observer) |
|---|
| 962 | { |
|---|
| 963 | if (!observer) |
|---|
| 964 | return; |
|---|
| 965 | |
|---|
| 966 | for (var i = 0; i < this.observers.length; i++) |
|---|
| 967 | { |
|---|
| 968 | if (this.observers[i] == observer) |
|---|
| 969 | { |
|---|
| 970 | this.observers.splice(i, 1); |
|---|
| 971 | break; |
|---|
| 972 | } |
|---|
| 973 | } |
|---|
| 974 | }; |
|---|
| 975 | |
|---|
| 976 | Spry.Utils.Notifier.prototype.notifyObservers = function(methodName, data) |
|---|
| 977 | { |
|---|
| 978 | if (!methodName) |
|---|
| 979 | return; |
|---|
| 980 | |
|---|
| 981 | if (!this.suppressNotifications) |
|---|
| 982 | { |
|---|
| 983 | var len = this.observers.length; |
|---|
| 984 | for (var i = 0; i < len; i++) |
|---|
| 985 | { |
|---|
| 986 | var obs = this.observers[i]; |
|---|
| 987 | if (obs) |
|---|
| 988 | { |
|---|
| 989 | if (typeof obs == "function") |
|---|
| 990 | obs(methodName, this, data); |
|---|
| 991 | else if (obs[methodName]) |
|---|
| 992 | obs[methodName](this, data); |
|---|
| 993 | } |
|---|
| 994 | } |
|---|
| 995 | } |
|---|
| 996 | }; |
|---|
| 997 | |
|---|
| 998 | Spry.Utils.Notifier.prototype.enableNotifications = function() |
|---|
| 999 | { |
|---|
| 1000 | if (--this.suppressNotifications < 0) |
|---|
| 1001 | { |
|---|
| 1002 | this.suppressNotifications = 0; |
|---|
| 1003 | Spry.Debug.reportError("Unbalanced enableNotifications() call!\n"); |
|---|
| 1004 | } |
|---|
| 1005 | }; |
|---|
| 1006 | |
|---|
| 1007 | Spry.Utils.Notifier.prototype.disableNotifications = function() |
|---|
| 1008 | { |
|---|
| 1009 | ++this.suppressNotifications; |
|---|
| 1010 | }; |
|---|
| 1011 | |
|---|
| 1012 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1013 | // |
|---|
| 1014 | // Spry.Debug |
|---|
| 1015 | // |
|---|
| 1016 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1017 | |
|---|
| 1018 | Spry.Debug = {}; |
|---|
| 1019 | Spry.Debug.enableTrace = true; |
|---|
| 1020 | Spry.Debug.debugWindow = null; |
|---|
| 1021 | Spry.Debug.onloadDidFire = false; |
|---|
| 1022 | |
|---|
| 1023 | Spry.Utils.addLoadListener(function() { Spry.Debug.onloadDidFire = true; Spry.Debug.flushQueuedMessages(); }); |
|---|
| 1024 | |
|---|
| 1025 | Spry.Debug.flushQueuedMessages = function() |
|---|
| 1026 | { |
|---|
| 1027 | if (Spry.Debug.flushQueuedMessages.msgs) |
|---|
| 1028 | { |
|---|
| 1029 | var msgs = Spry.Debug.flushQueuedMessages.msgs; |
|---|
| 1030 | for (var i = 0; i < msgs.length; i++) |
|---|
| 1031 | Spry.Debug.debugOut(msgs[i].msg, msgs[i].color); |
|---|
| 1032 | Spry.Debug.flushQueuedMessages.msgs = null; |
|---|
| 1033 | } |
|---|
| 1034 | }; |
|---|
| 1035 | |
|---|
| 1036 | Spry.Debug.createDebugWindow = function() |
|---|
| 1037 | { |
|---|
| 1038 | if (!Spry.Debug.enableTrace || Spry.Debug.debugWindow || !Spry.Debug.onloadDidFire) |
|---|
| 1039 | return; |
|---|
| 1040 | try |
|---|
| 1041 | { |
|---|
| 1042 | Spry.Debug.debugWindow = document.createElement("div"); |
|---|
| 1043 | var div = Spry.Debug.debugWindow; |
|---|
| 1044 | div.style.fontSize = "12px"; |
|---|
| 1045 | div.style.fontFamily = "console"; |
|---|
| 1046 | div.style.position = "absolute"; |
|---|
| 1047 | div.style.width = "400px"; |
|---|
| 1048 | div.style.height = "300px"; |
|---|
| 1049 | div.style.overflow = "auto"; |
|---|
| 1050 | div.style.border = "solid 1px black"; |
|---|
| 1051 | div.style.backgroundColor = "white"; |
|---|
| 1052 | div.style.color = "black"; |
|---|
| 1053 | div.style.bottom = "0px"; |
|---|
| 1054 | div.style.right = "0px"; |
|---|
| 1055 | // div.style.opacity = "0.5"; |
|---|
| 1056 | // div.style.filter = "alpha(opacity=50)"; |
|---|
| 1057 | div.setAttribute("id", "SpryDebugWindow"); |
|---|
| 1058 | document.body.appendChild(Spry.Debug.debugWindow); |
|---|
| 1059 | } |
|---|
| 1060 | catch (e) {} |
|---|
| 1061 | }; |
|---|
| 1062 | |
|---|
| 1063 | Spry.Debug.debugOut = function(str, bgColor) |
|---|
| 1064 | { |
|---|
| 1065 | if (!Spry.Debug.debugWindow) |
|---|
| 1066 | { |
|---|
| 1067 | Spry.Debug.createDebugWindow(); |
|---|
| 1068 | if (!Spry.Debug.debugWindow) |
|---|
| 1069 | { |
|---|
| 1070 | if (!Spry.Debug.flushQueuedMessages.msgs) |
|---|
| 1071 | Spry.Debug.flushQueuedMessages.msgs = new Array; |
|---|
| 1072 | Spry.Debug.flushQueuedMessages.msgs.push({msg: str, color: bgColor}); |
|---|
| 1073 | return; |
|---|
| 1074 | } |
|---|
| 1075 | } |
|---|
| 1076 | |
|---|
| 1077 | var d = document.createElement("div"); |
|---|
| 1078 | if (bgColor) |
|---|
| 1079 | d.style.backgroundColor = bgColor; |
|---|
| 1080 | d.innerHTML = str; |
|---|
| 1081 | Spry.Debug.debugWindow.appendChild(d); |
|---|
| 1082 | }; |
|---|
| 1083 | |
|---|
| 1084 | Spry.Debug.trace = function(str) |
|---|
| 1085 | { |
|---|
| 1086 | Spry.Debug.debugOut(str); |
|---|
| 1087 | }; |
|---|
| 1088 | |
|---|
| 1089 | Spry.Debug.reportError = function(str) |
|---|
| 1090 | { |
|---|
| 1091 | Spry.Debug.debugOut(str, "red"); |
|---|
| 1092 | }; |
|---|
| 1093 | |
|---|
| 1094 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1095 | // |
|---|
| 1096 | // Spry.Data |
|---|
| 1097 | // |
|---|
| 1098 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1099 | |
|---|
| 1100 | Spry.Data = {}; |
|---|
| 1101 | Spry.Data.regionsArray = {}; |
|---|
| 1102 | |
|---|
| 1103 | Spry.Data.initRegions = function(rootNode) |
|---|
| 1104 | { |
|---|
| 1105 | if (!rootNode) |
|---|
| 1106 | rootNode = document.body; |
|---|
| 1107 | |
|---|
| 1108 | var lastRegionFound = null; |
|---|
| 1109 | |
|---|
| 1110 | var regions = Spry.Utils.getNodesByFunc(rootNode, function(node) |
|---|
| 1111 | { |
|---|
| 1112 | try |
|---|
| 1113 | { |
|---|
| 1114 | if (node.nodeType != 1 /* Node.ELEMENT_NODE */) |
|---|
| 1115 | return false; |
|---|
| 1116 | |
|---|
| 1117 | // Region elements must have an spryregion attribute with a |
|---|
| 1118 | // non-empty value. An id attribute is also required so we can |
|---|
| 1119 | // reference the region by name if necessary. |
|---|
| 1120 | |
|---|
| 1121 | var attrName = "spry:region"; |
|---|
| 1122 | var attr = node.attributes.getNamedItem(attrName); |
|---|
| 1123 | if (!attr) |
|---|
| 1124 | { |
|---|
| 1125 | attrName = "spry:detailregion"; |
|---|
| 1126 | attr = node.attributes.getNamedItem(attrName); |
|---|
| 1127 | } |
|---|
| 1128 | if (attr) |
|---|
| 1129 | { |
|---|
| 1130 | if (lastRegionFound) |
|---|
| 1131 | { |
|---|
| 1132 | var parent = node.parentNode; |
|---|
| 1133 | while (parent) |
|---|
| 1134 | { |
|---|
| 1135 | if (parent == lastRegionFound) |
|---|
| 1136 | { |
|---|
| 1137 | Spry.Debug.reportError("Found a nested " + attrName + " in the following markup. Nested regions are currently not supported.<br/><pre>" + Spry.Utils.encodeEntities(parent.innerHTML) + "</pre>"); |
|---|
| 1138 | return false; |
|---|
| 1139 | } |
|---|
| 1140 | parent = parent.parentNode; |
|---|
| 1141 | } |
|---|
| 1142 | } |
|---|
| 1143 | |
|---|
| 1144 | if (attr.value) |
|---|
| 1145 | { |
|---|
| 1146 | attr = node.attributes.getNamedItem("id"); |
|---|
| 1147 | if (!attr || !attr.value) |
|---|
| 1148 | { |
|---|
| 1149 | // The node is missing an id attribute so add one. |
|---|
| 1150 | node.setAttribute("id", "spryregion" + (++Spry.Data.initRegions.nextUniqueRegionID)); |
|---|
| 1151 | } |
|---|
| 1152 | |
|---|
| 1153 | lastRegionFound = node; |
|---|
| 1154 | return true; |
|---|
| 1155 | } |
|---|
| 1156 | else |
|---|
| 1157 | Spry.Debug.reportError(attrName + " attributes require one or more data set names as values!"); |
|---|
| 1158 | } |
|---|
| 1159 | } |
|---|
| 1160 | catch(e) {} |
|---|
| 1161 | return false; |
|---|
| 1162 | }); |
|---|
| 1163 | |
|---|
| 1164 | var name, dataSets, i; |
|---|
| 1165 | |
|---|
| 1166 | for (i = 0; i < regions.length; i++) |
|---|
| 1167 | { |
|---|
| 1168 | var rgn = regions[i]; |
|---|
| 1169 | |
|---|
| 1170 | var isDetailRegion = false; |
|---|
| 1171 | |
|---|
| 1172 | // Get the region name. |
|---|
| 1173 | name = rgn.attributes.getNamedItem("id").value; |
|---|
| 1174 | |
|---|
| 1175 | attr = rgn.attributes.getNamedItem("spry:region"); |
|---|
| 1176 | if (!attr) |
|---|
| 1177 | { |
|---|
| 1178 | attr = rgn.attributes.getNamedItem("spry:detailregion"); |
|---|
| 1179 | isDetailRegion = true; |
|---|
| 1180 | } |
|---|
| 1181 | |
|---|
| 1182 | if (!attr.value) |
|---|
| 1183 | { |
|---|
| 1184 | Spry.Debug.reportError("spry:region and spry:detailregion attributes require one or more data set names as values!"); |
|---|
| 1185 | continue; |
|---|
| 1186 | } |
|---|
| 1187 | |
|---|
| 1188 | // Remove the spry:region or spry:detailregion attribute so it doesn't appear in |
|---|
| 1189 | // the output generated by our processing of the dynamic region. |
|---|
| 1190 | rgn.attributes.removeNamedItem(attr.nodeName); |
|---|
| 1191 | |
|---|
| 1192 | // Remove the hiddenRegionCSS class from the rgn. |
|---|
| 1193 | Spry.Utils.removeClassName(rgn, Spry.Data.Region.hiddenRegionClassName); |
|---|
| 1194 | |
|---|
| 1195 | // Get the DataSets that should be bound to the region. |
|---|
| 1196 | dataSets = Spry.Data.Region.strToDataSetsArray(attr.value); |
|---|
| 1197 | |
|---|
| 1198 | if (!dataSets.length) |
|---|
| 1199 | { |
|---|
| 1200 | Spry.Debug.reportError("spry:region or spry:detailregion attribute has no data set!"); |
|---|
| 1201 | continue; |
|---|
| 1202 | } |
|---|
| 1203 | |
|---|
| 1204 | var hasBehaviorAttributes = false; |
|---|
| 1205 | var hasSpryContent = false; |
|---|
| 1206 | var dataStr = ""; |
|---|
| 1207 | |
|---|
| 1208 | var parent = null; |
|---|
| 1209 | var regionStates = {}; |
|---|
| 1210 | var regionStateMap = {}; |
|---|
| 1211 | |
|---|
| 1212 | // Check if there are any attributes on the region node that remap |
|---|
| 1213 | // the default states. |
|---|
| 1214 | |
|---|
| 1215 | attr = rgn.attributes.getNamedItem("spry:readystate"); |
|---|
| 1216 | if (attr && attr.value) |
|---|
| 1217 | regionStateMap["ready"] = attr.value; |
|---|
| 1218 | attr = rgn.attributes.getNamedItem("spry:errorstate"); |
|---|
| 1219 | if (attr && attr.value) |
|---|
| 1220 | regionStateMap["error"] = attr.value; |
|---|
| 1221 | attr = rgn.attributes.getNamedItem("spry:loadingstate"); |
|---|
| 1222 | if (attr && attr.value) |
|---|
| 1223 | regionStateMap["loading"] = attr.value; |
|---|
| 1224 | attr = rgn.attributes.getNamedItem("spry:expiredstate"); |
|---|
| 1225 | if (attr && attr.value) |
|---|
| 1226 | regionStateMap["expired"] = attr.value; |
|---|
| 1227 | |
|---|
| 1228 | // Find all of the processing instruction regions in the region. |
|---|
| 1229 | // Insert comments around the regions we find so we can identify them |
|---|
| 1230 | // easily when tokenizing the region html string. |
|---|
| 1231 | |
|---|
| 1232 | var piRegions = Spry.Utils.getNodesByFunc(rgn, function(node) |
|---|
| 1233 | { |
|---|
| 1234 | try |
|---|
| 1235 | { |
|---|
| 1236 | if (node.nodeType == 1 /* ELEMENT_NODE */) |
|---|
| 1237 | { |
|---|
| 1238 | var attributes = node.attributes; |
|---|
| 1239 | var numPI = Spry.Data.Region.PI.orderedInstructions.length; |
|---|
| 1240 | var lastStartComment = null; |
|---|
| 1241 | var lastEndComment = null; |
|---|
| 1242 | |
|---|
| 1243 | for (var i = 0; i < numPI; i++) |
|---|
| 1244 | { |
|---|
| 1245 | var piName = Spry.Data.Region.PI.orderedInstructions[i]; |
|---|
| 1246 | var attr = attributes.getNamedItem(piName); |
|---|
| 1247 | if (!attr) |
|---|
| 1248 | continue; |
|---|
| 1249 | |
|---|
| 1250 | var piDesc = Spry.Data.Region.PI.instructions[piName]; |
|---|
| 1251 | var childrenOnly = (node == rgn) ? true : piDesc.childrenOnly; |
|---|
| 1252 | var openTag = piDesc.getOpenTag(node, piName); |
|---|
| 1253 | var closeTag = piDesc.getCloseTag(node, piName); |
|---|
| 1254 | |
|---|
| 1255 | if (childrenOnly) |
|---|
| 1256 | { |
|---|
| 1257 | var oComment = document.createComment(openTag); |
|---|
| 1258 | var cComment = document.createComment(closeTag) |
|---|
| 1259 | |
|---|
| 1260 | if (!lastStartComment) |
|---|
| 1261 | node.insertBefore(oComment, node.firstChild); |
|---|
| 1262 | else |
|---|
| 1263 | node.insertBefore(oComment, lastStartComment.nextSibling); |
|---|
| 1264 | lastStartComment = oComment; |
|---|
| 1265 | |
|---|
| 1266 | if (!lastEndComment) |
|---|
| 1267 | node.appendChild(cComment); |
|---|
| 1268 | else |
|---|
| 1269 | node.insertBefore(cComment, lastEndComment); |
|---|
| 1270 | lastEndComment = cComment; |
|---|
| 1271 | } |
|---|
| 1272 | else |
|---|
| 1273 | { |
|---|
| 1274 | var parent = node.parentNode; |
|---|
| 1275 | parent.insertBefore(document.createComment(openTag), node); |
|---|
| 1276 | parent.insertBefore(document.createComment(closeTag), node.nextSibling); |
|---|
| 1277 | } |
|---|
| 1278 | |
|---|
| 1279 | // If this is a spry:state processing instruction, record the state name |
|---|
| 1280 | // so we know that we should re-generate the region if we ever see that state. |
|---|
| 1281 | |
|---|
| 1282 | if (piName == "spry:state") |
|---|
| 1283 | regionStates[attr.value] = true; |
|---|
| 1284 | |
|---|
| 1285 | node.removeAttribute(piName); |
|---|
| 1286 | } |
|---|
| 1287 | |
|---|
| 1288 | if (Spry.Data.Region.enableBehaviorAttributes) |
|---|
| 1289 | { |
|---|
| 1290 | var bAttrs = Spry.Data.Region.behaviorAttrs; |
|---|
| 1291 | for (var behaviorAttrName in bAttrs) |
|---|
| 1292 | { |
|---|
| 1293 | var bAttr = attributes.getNamedItem(behaviorAttrName); |
|---|
| 1294 | if (bAttr) |
|---|
| 1295 | { |
|---|
| 1296 | hasBehaviorAttributes = true; |
|---|
| 1297 | if (bAttrs[behaviorAttrName].setup) |
|---|
| 1298 | bAttrs[behaviorAttrName].setup(node, bAttr.value); |
|---|
| 1299 | } |
|---|
| 1300 | } |
|---|
| 1301 | } |
|---|
| 1302 | } |
|---|
| 1303 | } |
|---|
| 1304 | catch(e) {} |
|---|
| 1305 | return false; |
|---|
| 1306 | }); |
|---|
| 1307 | |
|---|
| 1308 | // Get the data in the region. |
|---|
| 1309 | dataStr = rgn.innerHTML; |
|---|
| 1310 | |
|---|
| 1311 | // Argh! IE has an innerHTML bug where it will remove the quotes around any |
|---|
| 1312 | // attribute value that it thinks is a single word. This includes removing quotes |
|---|
| 1313 | // around our data references which is problematic since a single data reference |
|---|
| 1314 | // can be replaced with multiple words. If we are running in IE, we have to call |
|---|
| 1315 | // fixUpIEInnerHTML to get around this problem. |
|---|
| 1316 | |
|---|
| 1317 | if (window.ActiveXObject && !Spry.Data.Region.disableIEInnerHTMLFixUp && dataStr.search(/=\{/) != -1) |
|---|
| 1318 | { |
|---|
| 1319 | if (Spry.Data.Region.debug) |
|---|
| 1320 | Spry.Debug.trace("<hr />Performing IE innerHTML fix up of Region: " + name + "<br /><br />" + Spry.Utils.encodeEntities(dataStr)); |
|---|
| 1321 | |
|---|
| 1322 | dataStr = Spry.Utils.fixUpIEInnerHTML(dataStr); |
|---|
| 1323 | } |
|---|
| 1324 | |
|---|
| 1325 | if (Spry.Data.Region.debug) |
|---|
| 1326 | Spry.Debug.trace("<hr />Region template markup for '" + name + "':<br /><br />" + Spry.Utils.encodeEntities(dataStr)); |
|---|
| 1327 | |
|---|
| 1328 | if (!hasSpryContent) |
|---|
| 1329 | { |
|---|
| 1330 | // Clear the region. |
|---|
| 1331 | rgn.innerHTML = ""; |
|---|
| 1332 | } |
|---|
| 1333 | |
|---|
| 1334 | // Create a Spry.Data.Region object for this region. |
|---|
| 1335 | var region = new Spry.Data.Region(rgn, name, isDetailRegion, dataStr, dataSets, regionStates, regionStateMap, hasBehaviorAttributes); |
|---|
| 1336 | Spry.Data.regionsArray[region.name] = region; |
|---|
| 1337 | } |
|---|
| 1338 | |
|---|
| 1339 | Spry.Data.updateAllRegions(); |
|---|
| 1340 | }; |
|---|
| 1341 | |
|---|
| 1342 | Spry.Data.initRegions.nextUniqueRegionID = 0; |
|---|
| 1343 | |
|---|
| 1344 | Spry.Data.updateRegion = function(regionName) |
|---|
| 1345 | { |
|---|
| 1346 | if (!regionName || !Spry.Data.regionsArray || !Spry.Data.regionsArray[regionName]) |
|---|
| 1347 | return; |
|---|
| 1348 | |
|---|
| 1349 | try { Spry.Data.regionsArray[regionName].updateContent(); } |
|---|
| 1350 | catch(e) { Spry.Debug.reportError("Spry.Data.updateRegion(" + regionName + ") caught an exception: " + e + "\n"); } |
|---|
| 1351 | }; |
|---|
| 1352 | |
|---|
| 1353 | Spry.Data.getRegion = function(regionName) |
|---|
| 1354 | { |
|---|
| 1355 | return Spry.Data.regionsArray[regionName]; |
|---|
| 1356 | }; |
|---|
| 1357 | |
|---|
| 1358 | |
|---|
| 1359 | Spry.Data.updateAllRegions = function() |
|---|
| 1360 | { |
|---|
| 1361 | if (!Spry.Data.regionsArray) |
|---|
| 1362 | return; |
|---|
| 1363 | |
|---|
| 1364 | for (var regionName in Spry.Data.regionsArray) |
|---|
| 1365 | Spry.Data.updateRegion(regionName); |
|---|
| 1366 | }; |
|---|
| 1367 | |
|---|
| 1368 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1369 | // |
|---|
| 1370 | // Spry.Data.DataSet |
|---|
| 1371 | // |
|---|
| 1372 | ////////////////////////////////////////////////////////////////////// |
|---|
| 1373 | |
|---|
| 1374 | Spry.Data.DataSet = function(options) |
|---|
| 1375 | { |
|---|
| 1376 | Spry.Utils.Notifier.call(this); |
|---|
| 1377 | |
|---|
| 1378 | this.name = ""; |
|---|
| 1379 | this.internalID = Spry.Data.DataSet.nextDataSetID++; |
|---|
| 1380 | this.curRowID = 0; |
|---|
| 1381 | this.data = []; |
|---|
| 1382 | this.unfilteredData = null; |
|---|
| 1383 | this.dataHash = {}; |
|---|
| 1384 | this.columnTypes = {}; |
|---|
| 1385 | this.filterFunc = null; // non-destructive filter function |
|---|
| 1386 | this.filterDataFunc = null; // destructive filter function |
|---|
| 1387 | |
|---|
| 1388 | this.distinctOnLoad = false; |
|---|
| 1389 | this.distinctFieldsOnLoad = null; |
|---|
| 1390 | this.sortOnLoad = null; |
|---|
| 1391 | this.sortOrderOnLoad = "ascending"; |
|---|
| 1392 | this.keepSorted = false; |
|---|
| 1393 | |
|---|
| 1394 | this.dataWasLoaded = false; |
|---|
| 1395 | this.pendingRequest = null; |
|---|
| 1396 | |
|---|
| 1397 | this.lastSortColumns = []; |
|---|
| 1398 | this.lastSortOrder = ""; |
|---|
| 1399 | |
|---|
| 1400 | this.loadIntervalID = 0; |
|---|
| 1401 | |
|---|
| 1402 | Spry.Utils.setOptions(this, options); |
|---|
| 1403 | }; |
|---|
| 1404 | |
|---|
| 1405 | Spry.Data.DataSet.prototype = new Spry.Utils.Notifier(); |
|---|
| 1406 | Spry.Data.DataSet.prototype.constructor = Spry.Data.DataSet; |
|---|
| 1407 | |
|---|
| 1408 | Spry.Data.DataSet.prototype.getData = function(unfiltered) |
|---|
| 1409 | { |
|---|
| 1410 | return (unfiltered && this.unfilteredData) ? this.unfilteredData : this.data; |
|---|
| 1411 | }; |
|---|
| 1412 | |
|---|
| 1413 | Spry.Data.DataSet.prototype.getUnfilteredData = function() |
|---|
| 1414 | { |
|---|
| 1415 | // XXX: Deprecated. |
|---|
| 1416 | return this.getData(true); |
|---|
| 1417 | }; |
|---|
| 1418 | |
|---|
| 1419 | Spry.Data.DataSet.prototype.getLoadDataRequestIsPending = function() |
|---|
| 1420 | { |
|---|
| 1421 | return this.pendingRequest != null; |
|---|
| 1422 | }; |
|---|
| 1423 | |
|---|
| 1424 | Spry.Data.DataSet.prototype.getDataWasLoaded = function() |
|---|
| 1425 | { |
|---|
| 1426 | return this.dataWasLoaded; |
|---|
| 1427 | }; |
|---|
| 1428 | |
|---|
| 1429 | Spry.Data.DataSet.prototype.setDataFromArray = function(arr, fireSyncLoad) |
|---|
| 1430 | { |
|---|
| 1431 | this.notifyObservers("onPreLoad"); |
|---|
| 1432 | |
|---|
| 1433 | this.unfilteredData = null; |
|---|
| 1434 | this.filteredData = null; |
|---|
| 1435 | this.data = []; |
|---|
| 1436 | this.dataHash = {}; |
|---|
| 1437 | |
|---|
| 1438 | var arrLen = arr.length; |
|---|
| 1439 | |
|---|
| 1440 | for (var i = 0; i < arrLen; i++) |
|---|
| 1441 | { |
|---|
| 1442 | var row = arr[i]; |
|---|
| 1443 | if (row.ds_RowID == undefined) |
|---|
| 1444 | row.ds_RowID = i; |
|---|
| 1445 | this.dataHash[row.ds_RowID] = row; |
|---|
| 1446 | this.data.push(row); |
|---|
| 1447 | } |
|---|
| 1448 | |
|---|
| 1449 | this.loadData(fireSyncLoad); |
|---|
| 1450 | }; |
|---|
| 1451 | |
|---|
| 1452 | Spry.Data.DataSet.prototype.loadData = function(syncLoad) |
|---|
| 1453 | { |
|---|
| 1454 | // The idea here is that folks using the base class DataSet directly |
|---|
| 1455 | // would change the data in the DataSet manually and then call loadData() |
|---|
| 1456 | // to fire off an async notifications to say that it was ready for consumption. |
|---|
| 1457 | // |
|---|
| 1458 | // Firing off data changed notificataions synchronously from this method |
|---|
| 1459 | // can wreak havoc with complicated master/detail regions that use data sets |
|---|
| 1460 | // that have master/detail relationships with other data sets. Our data set |
|---|
| 1461 | // logic already handles async data loading nicely so we use a timer to fire |
|---|
| 1462 | // off the data changed notification to insure that it happens after this |
|---|
| 1463 | // function is finished and the JS stack unwinds. |
|---|
| 1464 | // |
|---|
| 1465 | // Other classes that derive from this class and load data synchronously |
|---|
| 1466 | // inside their loadData() implementation should also fire off an async |
|---|
| 1467 | // notification in this same manner to avoid this same problem. |
|---|
| 1468 | |
|---|
| 1469 | var self = this; |
|---|
| 1470 | |
|---|
| 1471 | this.pendingRequest = new Object; |
|---|
| 1472 | this.dataWasLoaded = false; |
|---|
| 1473 | |
|---|
| 1474 | var loadCallbackFunc = function() |
|---|
| 1475 | { |
|---|
| 1476 | self.pendingRequest = null; |
|---|
| 1477 | self.dataWasLoaded = true; |
|---|
| 1478 | |
|---|
| 1479 | self.applyColumnTypes(); |
|---|
| 1480 | self.filterAndSortData(); |
|---|
| 1481 | |
|---|
| 1482 | self.notifyObservers("onPostLoad"); |
|---|
| 1483 | self.notifyObservers("onDataChanged"); |
|---|
| 1484 | }; |
|---|
| 1485 | |
|---|
| 1486 | if (syncLoad) |
|---|
| 1487 | loadCallbackFunc(); |
|---|
| 1488 | else |
|---|
| 1489 | this.pendingRequest.timer = setTimeout(loadCallbackFunc, 0); |
|---|
| 1490 | }; |
|---|
| 1491 | |
|---|
| 1492 | |
|---|
| 1493 | Spry.Data.DataSet.prototype.filterAndSortData = function() |
|---|
| 1494 | { |
|---|
| 1495 | // If there is a data filter installed, run it. |
|---|
| 1496 | |
|---|
| 1497 | if (this.filterDataFunc) |
|---|
| 1498 | this.filterData(this.filterDataFunc, true); |
|---|
| 1499 | |
|---|
| 1500 | // If the distinct flag was set, run through all the records in the recordset |
|---|
| 1501 | // and toss out any that are duplicates. |
|---|
| 1502 | |
|---|
| 1503 | if (this.distinctOnLoad) |
|---|
| 1504 | this.distinct(this.distinctFieldsOnLoad); |
|---|
| 1505 | |
|---|
| 1506 | // If sortOnLoad was set, sort the data based on the columns |
|---|
| 1507 | // specified in sortOnLoad. |
|---|
| 1508 | |
|---|
| 1509 | if (this.keepSorted && this.getSortColumn()) |
|---|
| 1510 | this.sort(this.lastSortColumns, this.lastSortOrder) |
|---|
| 1511 | else if (this.sortOnLoad) |
|---|
| 1512 | this.sort(this.sortOnLoad, this.sortOrderOnLoad); |
|---|
| 1513 | |
|---|
| 1514 | // If there is a view filter installed, run it. |
|---|
| 1515 | |
|---|
| 1516 | if (this.filterFunc) |
|---|
| 1517 | this.filter(this.filterFunc, true); |
|---|
| 1518 | |
|---|
| 1519 | // The default "current" row is the first row of the data set. |
|---|
| 1520 | if (this.data && this.data.length > 0) |
|---|
| 1521 | this.curRowID = this.data[0]['ds_RowID']; |
|---|
| 1522 | else |
|---|
| 1523 | this.curRowID = 0; |
|---|
| 1524 | }; |
|---|
| 1525 | |
|---|
| 1526 | Spry.Data.DataSet.prototype.cancelLoadData = function() |
|---|
| 1527 | { |
|---|
| 1528 | if (this.pendingRequest && this.pendingRequest.timer) |
|---|
| 1529 | clearTimeout(this.pendingRequest.timer); |
|---|
| 1530 | this.pendingRequest = null; |
|---|
| 1531 | }; |
|---|
| 1532 | |
|---|
| 1533 | Spry.Data.DataSet.prototype.getRowCount = function(unfiltered) |
|---|
| 1534 | { |
|---|
| 1535 | var rows = this.getData(unfiltered); |
|---|
| 1536 | return rows ? rows.length : 0; |
|---|
| 1537 | }; |
|---|
| 1538 | |
|---|
| 1539 | Spry.Data.DataSet.prototype.getRowByID = function(rowID) |
|---|
| 1540 | { |
|---|
| 1541 | if (!this.data) |
|---|
| 1542 | return null; |
|---|
| 1543 | return this.dataHash[rowID]; |
|---|
| 1544 | }; |
|---|
| 1545 | |
|---|
| 1546 | Spry.Data.DataSet.prototype.getRowByRowNumber = function(rowNumber, unfiltered) |
|---|
| 1547 | { |
|---|
| 1548 | var rows = this.getData(unfiltered); |
|---|
| 1549 | if (rows && rowNumber >= 0 && rowNumber < rows.length) |
|---|
| 1550 | return rows[rowNumber]; |
|---|
| 1551 | return null; |
|---|
| 1552 | }; |
|---|
| 1553 | |
|---|
| 1554 | Spry.Data.DataSet.prototype.getCurrentRow = function() |
|---|
| 1555 | { |
|---|
| 1556 | return this.getRowByID(this.curRowID); |
|---|
| 1557 | }; |
|---|
| 1558 | |
|---|
| 1559 | Spry.Data.DataSet.prototype.setCurrentRow = function(rowID) |
|---|
| 1560 | { |
|---|
| 1561 | if (this.curRowID == rowID) |
|---|
| 1562 | return; |
|---|
| 1563 | |
|---|
| 1564 | var nData = { oldRowID: this.curRowID, newRowID: rowID }; |
|---|
| 1565 | this.curRowID = rowID; |
|---|
| 1566 | this.notifyObservers("onCurrentRowChanged", nData); |
|---|
| 1567 | }; |
|---|
| 1568 | |
|---|
| 1569 | Spry.Data.DataSet.prototype.getRowNumber = function(row, unfiltered) |
|---|
| 1570 | { |
|---|
| 1571 | if (row) |
|---|
| 1572 | { |
|---|
| 1573 | var rows = this.getData(unfiltered); |
|---|
| 1574 | if (rows && rows.length) |
|---|
| 1575 | { |
|---|
| 1576 | var numRows = rows.length; |
|---|
| 1577 | for (var i = 0; i < numRows; i++) |
|---|
| 1578 | { |
|---|
| 1579 | if (rows[i] == row) |
|---|
| 1580 | return i; |
|---|
| 1581 | } |
|---|
| 1582 | } |
|---|
| 1583 | } |
|---|
| 1584 | return -1; |
|---|
| 1585 | }; |
|---|
| 1586 | |
|---|
| 1587 | Spry.Data.DataSet.prototype.getCurrentRowNumber = function() |
|---|
| 1588 | { |
|---|
| 1589 | return this.getRowNumber(this.getCurrentRow()); |
|---|
| 1590 | }; |
|---|
| 1591 | |
|---|
| 1592 | Spry.Data.DataSet.prototype.getCurrentRowID = function() |
|---|
| 1593 | { |
|---|
| 1594 | return this.curRowID; |
|---|
| 1595 | }; |
|---|
| 1596 | |
|---|
| 1597 | Spry.Data.DataSet.prototype.setCurrentRowNumber = function(rowNumber) |
|---|
| 1598 | { |
|---|
| 1599 | if (!this.data || rowNumber >= this.data.length) |
|---|
| 1600 | { |
|---|
| 1601 | Spry.Debug.trace("Invalid row number: " + rowNumber + "\n"); |
|---|
| 1602 | return; |
|---|
| 1603 | } |
|---|
| 1604 | |
|---|
| 1605 | var rowID = this.data[rowNumber]["ds_RowID"]; |
|---|
| 1606 | |
|---|
| 1607 | if (rowID == undefined || this.curRowID == rowID) |
|---|
| 1608 | return; |
|---|
| 1609 | |
|---|
| 1610 | this.setCurrentRow(rowID); |
|---|
| 1611 | }; |
|---|
| 1612 | |
|---|
| 1613 | Spry.Data.DataSet.prototype.findRowsWithColumnValues = function(valueObj, firstMatchOnly, unfiltered) |
|---|
| 1614 | { |
|---|
| 1615 | var results = []; |
|---|
| 1616 | var rows = this.getData(unfiltered); |
|---|
| 1617 | if (rows) |
|---|
| 1618 | { |
|---|
| 1619 | var numRows = rows.length; |
|---|
| 1620 | for (var i = 0; i < numRows; i++) |
|---|
| 1621 | { |
|---|
| 1622 | var row = rows[i]; |
|---|
| 1623 | var matched = true; |
|---|
| 1624 | |
|---|
| 1625 | for (var colName in valueObj) |
|---|
| 1626 | { |
|---|
| 1627 | if (valueObj[colName] != row[colName]) |
|---|
| 1628 | { |
|---|
| 1629 | matched = false; |
|---|
| 1630 | break; |
|---|
| 1631 | } |
|---|
| 1632 | } |
|---|
| 1633 | |
|---|
| 1634 | if (matched) |
|---|
| 1635 | { |
|---|
| 1636 | if (firstMatchOnly) |
|---|
| 1637 | return row; |
|---|
| 1638 | results.push(row); |
|---|
| 1639 | } |
|---|
| 1640 | } |
|---|
| 1641 | } |
|---|
| 1642 | |
|---|
| 1643 | return firstMatchOnly ? null : results; |
|---|
| 1644 | }; |
|---|
| 1645 | |
|---|
| 1646 | Spry.Data.DataSet.prototype.setColumnType = function(columnNames, columnType) |
|---|
| 1647 | { |
|---|
| 1648 | if (columnNames) |
|---|
| 1649 | { |
|---|
| 1650 | if (typeof columnNames == "string") |
|---|
| 1651 | columnNames = [ columnNames ]; |
|---|
| 1652 | for (var i = 0; i < columnNames.length; i++) |
|---|
| 1653 | this.columnTypes[columnNames[i]] = columnType; |
|---|
| 1654 | } |
|---|
| 1655 | }; |
|---|
| 1656 | |
|---|
| 1657 | Spry.Data.DataSet.prototype.getColumnType = function(columnName) |
|---|
| 1658 | { |
|---|
| 1659 | if (this.columnTypes[columnName]) |
|---|
| 1660 | return this.columnTypes[columnName]; |
|---|
| 1661 | return "string"; |
|---|
| 1662 | }; |
|---|
| 1663 | |
|---|
| 1664 | Spry.Data.DataSet.prototype.applyColumnTypes = function() |
|---|
| 1665 | { |
|---|
| 1666 | var rows = this.getData(true); |
|---|
| 1667 | var numRows = rows.length; |
|---|
| 1668 | var colNames = []; |
|---|
| 1669 | |
|---|
| 1670 | if (numRows < 1) |
|---|
| 1671 | return; |
|---|
| 1672 | |
|---|
| 1673 | for (var cname in this.columnTypes) |
|---|
| 1674 | { |
|---|
| 1675 | var ctype = this.columnTypes[cname]; |
|---|
| 1676 | if (ctype != "string") |
|---|
| 1677 | { |
|---|
| 1678 | for (var i = 0; i < numRows; i++) |
|---|
| 1679 | { |
|---|
| 1680 | var row = rows[i]; |
|---|
| 1681 | var val = row[cname]; |
|---|
| 1682 | if (val != undefined) |
|---|
| 1683 | { |
|---|
| 1684 | if (ctype == "number") |
|---|
| 1685 | row[cname] = new Number(val); |
|---|
| 1686 | else if (ctype == "html") |
|---|
| 1687 | row[cname] = Spry.Utils.decodeEntities(val); |
|---|
| 1688 | } |
|---|
| 1689 | } |
|---|
| 1690 | } |
|---|
| 1691 | } |
|---|
| 1692 | }; |
|---|
| 1693 | |
|---|
| 1694 | Spry.Data.DataSet.prototype.distinct = function(columnNames) |
|---|
| 1695 | { |
|---|
| 1696 | if (this.data) |
|---|
| 1697 | { |
|---|
| 1698 | var oldData = this.data; |
|---|
| 1699 | this.data = []; |
|---|
| 1700 | this.dataHash = {}; |
|---|
| 1701 | var dataChanged = false; |
|---|
| 1702 | |
|---|
| 1703 | var alreadySeenHash = {}; |
|---|
| 1704 | var i = 0; |
|---|
| 1705 | |
|---|
| 1706 | var keys = []; |
|---|
| 1707 | |
|---|
| 1708 | if (typeof columnNames == "string") |
|---|
| 1709 | keys = [columnNames]; |
|---|
| 1710 | else if (columnNames) |
|---|
| 1711 | keys = columnNames; |
|---|
| 1712 | else |
|---|
| 1713 | for (var recField in oldData[0]) |
|---|
| 1714 | keys[i++] = recField; |
|---|
| 1715 | |
|---|
| 1716 | for (var i = 0; i < oldData.length; i++) |
|---|
| 1717 | { |
|---|
| 1718 | var rec = oldData[i]; |
|---|
| 1719 | var hashStr = ""; |
|---|
| 1720 | for (var j=0; j < keys.length; j++) |
|---|
| 1721 | { |
|---|
| 1722 | recField = keys[j]; |
|---|
| 1723 | if (recField != "ds_RowID") |
|---|
| 1724 | { |
|---|
| 1725 | if (hashStr) |
|---|
| 1726 | hashStr += ","; |
|---|
| 1727 | hashStr += recField + ":" + "\"" + rec[recField] + "\""; |
|---|
| 1728 | } |
|---|
| 1729 | } |
|---|
| 1730 | if (!alreadySeenHash[hashStr]) |
|---|
| 1731 | { |
|---|
| 1732 | this.data.push(rec); |
|---|
| 1733 | this.dataHash[rec['ds_RowID']] = rec; |
|---|
| 1734 | alreadySeenHash[hashStr] = true; |
|---|
| 1735 | } |
|---|
| 1736 | else |
|---|
| 1737 | dataChanged = true; |
|---|
| 1738 | } |
|---|
| 1739 | if (dataChanged) |
|---|
| 1740 | this.notifyObservers('onDataChanged'); |
|---|
| 1741 | } |
|---|
| 1742 | }; |
|---|
| 1743 | |
|---|
| 1744 | Spry.Data.DataSet.prototype.getSortColumn = function() { |
|---|
| 1745 | return (this.lastSortColumns && this.lastSortColumns.length > 0) ? this.lastSortColumns[0] : ""; |
|---|
| 1746 | }; |
|---|
| 1747 | |
|---|
| 1748 | Spry.Data.DataSet.prototype.getSortOrder = function() { |
|---|
| 1749 | return this.lastSortOrder ? this.lastSortOrder : ""; |
|---|
| 1750 | }; |
|---|
| 1751 | |
|---|
| 1752 | Spry.Data.DataSet.prototype.sort = function(columnNames, sortOrder) |
|---|
| 1753 | { |
|---|
| 1754 | // columnNames can be either the name of a column to |
|---|
| 1755 | // sort on, or an array of column names, but it can't be |
|---|
| 1756 | // null/undefined. |
|---|
| 1757 | |
|---|
| 1758 | if (!columnNames) |
|---|
| 1759 | return; |
|---|
| 1760 | |
|---|
| 1761 | // If only one column name was specified for sorting, do a |
|---|
| 1762 | // secondary sort on ds_RowID so we get a stable sort order. |
|---|
| 1763 | |
|---|
| 1764 | if (typeof columnNames == "string") |
|---|
| 1765 | columnNames = [ columnNames, "ds_RowID" ]; |
|---|
| 1766 | else if (columnNames.length < 2 && columnNames[0] != "ds_RowID") |
|---|
| 1767 | columnNames.push("ds_RowID"); |
|---|
| 1768 | |
|---|
| 1769 | if (!sortOrder) |
|---|
| 1770 | sortOrder = "toggle"; |
|---|
| 1771 | |
|---|
| 1772 | if (sortOrder == "toggle") |
|---|
| 1773 | { |
|---|
| 1774 | if (this.lastSortColumns.length > 0 && this.lastSortColumns[0] == columnNames[0] && this.lastSortOrder == "ascending") |
|---|
| 1775 | sortOrder = "descending"; |
|---|
| 1776 | else |
|---|
| 1777 | sortOrder = "ascending"; |
|---|
| 1778 | } |
|---|
| 1779 | |
|---|
| 1780 | if (sortOrder != "ascending" && sortOrder != "descending") |
|---|
| 1781 | { |
|---|
| 1782 | Spry.Debug.reportError("Invalid sort order type specified: " + sortOrder + "\n"); |
|---|
| 1783 | return; |
|---|
| 1784 | } |
|---|
| 1785 | |
|---|
| 1786 | var nData = { |
|---|
| 1787 | oldSortColumns: this.lastSortColumns, |
|---|
| 1788 | oldSortOrder: this.lastSortOrder, |
|---|
| 1789 | newSortColumns: columnNames, |
|---|
| 1790 | newSortOrder: sortOrder |
|---|
| 1791 | }; |
|---|
| 1792 | this.notifyObservers("onPreSort", nData); |
|---|
| 1793 | |
|---|
| 1794 | var cname = columnNames[columnNames.length - 1]; |
|---|
| 1795 | var sortfunc = Spry.Data.DataSet.prototype.sort.getSortFunc(cname, this.getColumnType(cname), sortOrder); |
|---|
| 1796 | |
|---|
| 1797 | for (var i = columnNames.length - 2; i >= 0; i--) |
|---|
| 1798 | { |
|---|
| 1799 | cname = columnNames[i]; |
|---|
| 1800 | sortfunc = Spry.Data.DataSet.prototype.sort.buildSecondarySortFunc(Spry.Data.DataSet.prototype.sort.getSortFunc(cname, this.getColumnType(cname), sortOrder), sortfunc); |
|---|
| 1801 | } |
|---|
| 1802 | |
|---|
| 1803 | if (this.unfilteredData) |
|---|
| 1804 | { |
|---|
| 1805 | this.unfilteredData.sort(sortfunc); |
|---|
| 1806 | if (this.filterFunc) |
|---|
| 1807 | this.filter(this.filterFunc, true); |
|---|
| 1808 | } |
|---|
| 1809 | else |
|---|
| 1810 | this.data.sort(sortfunc); |
|---|
| 1811 | |
|---|
| 1812 | this.lastSortColumns = columnNames.slice(0); // Copy the array. |
|---|
| 1813 | this.lastSortOrder = sortOrder; |
|---|
| 1814 | |
|---|
| 1815 | this.notifyObservers("onPostSort", nData); |
|---|
| 1816 | }; |
|---|
| 1817 | |
|---|
| 1818 | Spry.Data.DataSet.prototype.sort.getSortFunc = function(prop, type, order) |
|---|
| 1819 | { |
|---|
| 1820 | var sortfunc = null; |
|---|
| 1821 | if (type == "number") |
|---|
| 1822 | { |
|---|
| 1823 | if (order == "ascending") |
|---|
| 1824 | sortfunc = function(a, b) |
|---|
| 1825 | { |
|---|
| 1826 | a = a[prop]; b = b[prop]; |
|---|
| 1827 | if (a == undefined || b == undefined) |
|---|
| 1828 | return (a == b) ? 0 : (a ? 1 : -1); |
|---|
| 1829 | return a-b; |
|---|
| 1830 | }; |
|---|
| 1831 | else // order == "descending" |
|---|
| 1832 | sortfunc = function(a, b) |
|---|
| 1833 | { |
|---|
| 1834 | a = a[prop]; b = b[prop]; |
|---|
| 1835 | if (a == undefined || b == undefined) |
|---|
| 1836 | return (a == b) ? 0 : (a ? -1 : 1); |
|---|
| 1837 | return b-a; |
|---|
| 1838 | }; |
|---|
| 1839 | } |
|---|
| 1840 | else if (type == "date") |
|---|
| 1841 | { |
|---|
| 1842 | if (order == "ascending") |
|---|
| 1843 | sortfunc = function(a, b) |
|---|
| 1844 | { |
|---|
| 1845 | var dA = a[prop]; |
|---|
| 1846 | var dB = b[prop]; |
|---|
| 1847 | dA = dA ? (new Date(dA)) : 0; |
|---|
| 1848 | dB = dB ? (new Date(dB)) : 0; |
|---|
| 1849 | return dA - dB; |
|---|
| 1850 | }; |
|---|
| 1851 | else // order == "descending" |
|---|
| 1852 | sortfunc = function(a, b) |
|---|
| 1853 | { |
|---|
| 1854 | var dA = a[prop]; |
|---|
| 1855 | var dB = b[prop]; |
|---|
| 1856 | dA = dA ? (new Date(dA)) : 0; |
|---|
| 1857 | dB = dB ? (new Date(dB)) : 0; |
|---|
| 1858 | return dB - dA; |
|---|
| 1859 | }; |
|---|
| 1860 | } |
|---|
| 1861 | else // type == "string" || type == "html" |
|---|
| 1862 | { |
|---|
| 1863 | if (order == "ascending") |
|---|
| 1864 | sortfunc = function(a, b){ |
|---|
| 1865 | a = a[prop]; |
|---|
| 1866 | b = b[prop]; |
|---|
| 1867 | if (a == undefined || b == undefined) |
|---|
| 1868 | return (a == b) ? 0 : (a ? 1 : -1); |
|---|
| 1869 | var tA = a.toString(); |
|---|
| 1870 | var tB = b.toString(); |
|---|
| 1871 | var tA_l = tA.toLowerCase(); |
|---|
| 1872 | var tB_l = tB.toLowerCase(); |
|---|
| 1873 | var min_len = tA.length > tB.length ? tB.length : tA.length; |
|---|
| 1874 | |
|---|
| 1875 | for (var i=0; i < min_len; i++) |
|---|
| 1876 | { |
|---|
| 1877 | var a_l_c = tA_l.charAt(i); |
|---|
| 1878 | var b_l_c = tB_l.charAt(i); |
|---|
| 1879 | var a_c = tA.charAt(i); |
|---|
| 1880 | var b_c = tB.charAt(i); |
|---|
| 1881 | if (a_l_c > b_l_c) |
|---|
| 1882 | return 1; |
|---|
| 1883 | else if (a_l_c < b_l_c) |
|---|
| 1884 | return -1; |
|---|
| 1885 | else if (a_c > b_c) |
|---|
| 1886 | return 1; |
|---|
| 1887 | else if (a_c < b_c) |
|---|
| 1888 | return -1; |
|---|
| 1889 | } |
|---|
| 1890 | if(tA.length == tB.length) |
|---|
| 1891 | return 0; |
|---|
| 1892 | else if (tA.length > tB.length) |
|---|
| 1893 | return 1; |
|---|
| 1894 | return -1; |
|---|
| 1895 | }; |
|---|
| 1896 | else // order == "descending" |
|---|
| 1897 | sortfunc = function(a, b){ |
|---|
| 1898 | a = a[prop]; |
|---|
| 1899 | b = b[prop]; |
|---|
| 1900 | if (a == undefined || b == undefined) |
|---|
| 1901 | return (a == b) ? 0 : (a ? -1 : 1); |
|---|
| 1902 | var tA = a.toString(); |
|---|
| 1903 | var tB = b.toString(); |
|---|
| 1904 | var tA_l = tA.toLowerCase(); |
|---|
| 1905 | var tB_l = tB.toLowerCase(); |
|---|
| 1906 | var min_len = tA.length > tB.length ? tB.length : tA.length; |
|---|
| 1907 | for (var i=0; i < min_len; i++) |
|---|
| 1908 | { |
|---|
| 1909 | var a_l_c = tA_l.charAt(i); |
|---|
| 1910 | var b_l_c = tB_l.charAt(i); |
|---|
| 1911 | var a_c = tA.charAt(i); |
|---|
| 1912 | var b_c = tB.charAt(i); |
|---|
| 1913 | if (a_l_c > b_l_c) |
|---|
| 1914 | return -1; |
|---|
| 1915 | else if (a_l_c < b_l_c) |
|---|
| 1916 | return 1; |
|---|
| 1917 | else if (a_c > b_c) |
|---|
| 1918 | return -1; |
|---|
| 1919 | else if (a_c < b_c) |
|---|
| 1920 | return 1; |
|---|
| 1921 | } |
|---|
| 1922 | if(tA.length == tB.length) |
|---|
| 1923 | return 0; |
|---|
| 1924 | else if (tA.length > tB.length) |
|---|
| 1925 | return -1; |
|---|
| 1926 | return 1; |
|---|
| 1927 | }; |
|---|
| 1928 | } |
|---|
| 1929 | |
|---|
| 1930 | return sortfunc; |
|---|
| 1931 | }; |
|---|
| 1932 | |
|---|
| 1933 | Spry.Data.DataSet.prototype.sort.buildSecondarySortFunc = function(funcA, funcB) |
|---|
| 1934 | { |
|---|
| 1935 | return function(a, b) |
|---|
| 1936 | { |
|---|
| 1937 | var ret = funcA(a, b); |
|---|
| 1938 | if (ret == 0) |
|---|
| 1939 | ret = funcB(a, b); |
|---|
| 1940 | return ret; |
|---|
| 1941 | }; |
|---|
| 1942 | }; |
|---|
| 1943 | |
|---|
| 1944 | Spry.Data.DataSet.prototype.filterData = function(filterFunc, filterOnly) |
|---|
| 1945 | { |
|---|
| 1946 | // This is a destructive filter function. |
|---|
| 1947 | |
|---|
| 1948 | var dataChanged = false; |
|---|
| 1949 | |
|---|
| 1950 | if (!filterFunc) |
|---|
| 1951 | { |
|---|
| 1952 | // Caller wants to remove the filter. |
|---|
| 1953 | |
|---|
| 1954 | this.filterDataFunc = null; |
|---|
| 1955 | dataChanged = true; |
|---|
| 1956 | } |
|---|
| 1957 | else |
|---|
| 1958 | { |
|---|
| 1959 | this.filterDataFunc = filterFunc; |
|---|
| 1960 | |
|---|
| 1961 | if (this.dataWasLoaded && ((this.unfilteredData && this.unfilteredData.length) || (this.data && this.data.length))) |
|---|
| 1962 | { |
|---|
| 1963 | if (this.unfilteredData) |
|---|
| 1964 | { |
|---|
| 1965 | this.data = this.unfilteredData; |
|---|
| 1966 | this.unfilteredData = null; |
|---|
| 1967 | } |
|---|
| 1968 | |
|---|
| 1969 | var oldData = this.data; |
|---|
| 1970 | this.data = []; |
|---|
| 1971 | this.dataHash = {}; |
|---|
| 1972 | |
|---|
| 1973 | for (var i = 0; i < oldData.length; i++) |
|---|
| 1974 | { |
|---|
| 1975 | var newRow = filterFunc(this, oldData[i], i); |
|---|
| 1976 | if (newRow) |
|---|
| 1977 | { |
|---|
| 1978 | this.data.push(newRow); |
|---|
| 1979 | this.dataHash[newRow["ds_RowID"]] = newRow; |
|---|
| 1980 | } |
|---|
| 1981 | } |
|---|
| 1982 | |
|---|
| 1983 | dataChanged = true; |
|---|
| 1984 | } |
|---|
| 1985 | } |
|---|
| 1986 | |
|---|
| 1987 | if (dataChanged) |
|---|
| 1988 | { |
|---|
| 1989 | if (!filterOnly) |
|---|
| 1990 | { |
|---|
| 1991 | this.disableNotifications(); |
|---|
| 1992 | if (this.filterFunc) |
|---|
| 1993 | this.filter(this.filterFunc, true); |
|---|
| 1994 | this.enableNotifications(); |
|---|
| 1995 | } |
|---|
| 1996 | |
|---|
| 1997 | this.notifyObservers("onDataChanged"); |
|---|
| 1998 | } |
|---|
| 1999 | }; |
|---|
| 2000 | |
|---|
| 2001 | Spry.Data.DataSet.prototype.filter = function(filterFunc, filterOnly) |
|---|
| 2002 | { |
|---|
| 2003 | // This is a non-destructive filter function. |
|---|
| 2004 | |
|---|
| 2005 | var dataChanged = false; |
|---|
| 2006 | |
|---|
| 2007 | if (!filterFunc) |
|---|
| 2008 | { |
|---|
| 2009 | if (this.filterFunc && this.unfilteredData) |
|---|
| 2010 | { |
|---|
| 2011 | // Caller wants to remove the filter. Restore the unfiltered |
|---|
| 2012 | // data and trigger a data changed notification. |
|---|
| 2013 | |
|---|
| 2014 | this.data = this.unfilteredData; |
|---|
| 2015 | this.unfilteredData = null; |
|---|
| 2016 | this.filterFunc = null; |
|---|
| 2017 | dataChanged = true; |
|---|
| 2018 | } |
|---|
| 2019 | } |
|---|
| 2020 | else |
|---|
| 2021 | { |
|---|
| 2022 | this.filterFunc = filterFunc; |
|---|
| 2023 | |
|---|
| 2024 | if (this.dataWasLoaded && (this.unfilteredData || (this.data && this.data.length))) |
|---|
| 2025 | { |
|---|
| 2026 | if (!this.unfilteredData) |
|---|
| 2027 | this.unfilteredData = this.data; |
|---|
| 2028 | |
|---|
| 2029 | var udata = this.unfilteredData; |
|---|
| 2030 | this.data = []; |
|---|
| 2031 | |
|---|
| 2032 | for (var i = 0; i < udata.length; i++) |
|---|
| 2033 | { |
|---|
| 2034 | var newRow = filterFunc(this, udata[i], i); |
|---|
| 2035 | |
|---|
| 2036 | if (newRow) |
|---|
| 2037 | this.data.push(newRow); |
|---|
| 2038 | } |
|---|
| 2039 | |
|---|
| 2040 | dataChanged = true; |
|---|
| 2041 | } |
|---|
| 2042 | } |
|---|
| 2043 | |
|---|
| 2044 | if (dataChanged) |
|---|
| 2045 | this.notifyObservers("onDataChanged"); |
|---|
| 2046 | }; |
|---|
| 2047 | |
|---|
| 2048 | Spry.Data.DataSet.prototype.startLoadInterval = function(interval) |
|---|
| 2049 | { |
|---|
| 2050 | this.stopLoadInterval(); |
|---|
| 2051 | if (interval > 0) |
|---|
| 2052 | { |
|---|
| 2053 | var self = this; |
|---|
| 2054 | this.loadInterval = interval; |
|---|
| 2055 | this.loadIntervalID = setInterval(function() { self.loadData(); }, interval); |
|---|
| 2056 | } |
|---|
| 2057 | }; |
|---|
| 2058 | |
|---|
| 2059 | Spry.Data.DataSet.prototype.stopLoadInterval = function() |
|---|
| 2060 | { |
|---|
| 2061 | if (this.loadIntervalID) |
|---|
| 2062 | clearInterval(this.loadIntervalID); |
|---|
| 2063 | this.loadInterval = 0; |
|---|
| 2064 | this.loadIntervalID = null; |
|---|
| 2065 | }; |
|---|
| 2066 | |
|---|
| 2067 | Spry.Data.DataSet.nextDataSetID = 0; |
|---|
| 2068 | |
|---|
| 2069 | ////////////////////////////////////////////////////////////////////// |
|---|
| 2070 | // |
|---|
| 2071 | // Spry.Data.HTTPSourceDataSet |
|---|
| 2072 | // base class for any DataSet that uses external |
|---|
| 2073 | // |
|---|
| 2074 | ////////////////////////////////////////////////////////////////////// |
|---|
| 2075 | |
|---|
| 2076 | Spry.Data.HTTPSourceDataSet = function(dataSetURL, dataSetOptions) |
|---|
| 2077 | { |
|---|
| 2078 | // Call the constructor for our DataSet base class so that |
|---|
| 2079 | // our base class properties get defined. We'll call setOptions |
|---|
| 2080 | // manually after we set up our HTTPSourceDataSet properties. |
|---|
| 2081 | |
|---|
| 2082 | Spry.Data.DataSet.call(this); |
|---|
| 2083 | |
|---|
| 2084 | // HTTPSourceDataSet Properties: |
|---|
| 2085 | |
|---|
| 2086 | this.url = dataSetURL; |
|---|
| 2087 | this.dataSetsForDataRefStrings = new Array; |
|---|
| 2088 | this.hasDataRefStrings = false; |
|---|
| 2089 | this.useCache = true; |
|---|
| 2090 | |
|---|
| 2091 | this.setRequestInfo(dataSetOptions, true); |
|---|
| 2092 | |
|---|
| 2093 | Spry.Utils.setOptions(this, dataSetOptions, true); |
|---|
| 2094 | |
|---|
| 2095 | this.recalculateDataSetDependencies(); |
|---|
| 2096 | |
|---|
| 2097 | if (this.loadInterval > 0) |
|---|
| 2098 | this.startLoadInterval(this.loadInterval); |
|---|
| 2099 | }; // End of Spry.Data.HTTPSourceDataSet() constructor. |
|---|
| 2100 | |
|---|
| 2101 | Spry.Data.HTTPSourceDataSet.prototype = new Spry.Data.DataSet(); |
|---|
| 2102 | Spry.Data.HTTPSourceDataSet.prototype.constructor = Spry.Data.HTTPSourceDataSet; |
|---|
| 2103 | |
|---|
| 2104 | Spry.Data.HTTPSourceDataSet.prototype.setRequestInfo = function(requestInfo, undefineRequestProps) |
|---|
| 2105 | { |
|---|
| 2106 | // Create a loadURL request object to store any load options |
|---|
| 2107 | // the caller specified. We'll fill in the URL at the last minute |
|---|
| 2108 | // before we make the actual load request because our URL needs |
|---|
| 2109 | // to be processed at the last possible minute in case it contains |
|---|
| 2110 | // data references. |
|---|
| 2111 | |
|---|
| 2112 | this.requestInfo = new Spry.Utils.loadURL.Request(); |
|---|
| 2113 | this.requestInfo.extractRequestOptions(requestInfo, undefineRequestProps); |
|---|
| 2114 | |
|---|
| 2115 | // If the caller wants to use "POST" to fetch the data, but didn't |
|---|
| 2116 | // provide the content type, default to x-www-form-urlencoded. |
|---|
| 2117 | |
|---|
| 2118 | if (this.requestInfo.method == "POST") |
|---|
| 2119 | { |
|---|
| 2120 | if (!this.requestInfo.headers) |
|---|
| 2121 | this.requestInfo.headers = {}; |
|---|
| 2122 | if (!this.requestInfo.headers['Content-Type']) |
|---|
| 2123 | this.requestInfo.headers['Content-Type'] = "application/x-www-form-urlencoded; charset=UTF-8"; |
|---|
| 2124 | } |
|---|
| 2125 | }; |
|---|
| 2126 | |
|---|
| 2127 | Spry.Data.HTTPSourceDataSet.prototype.recalculateDataSetDependencies = function() |
|---|
| 2128 | { |
|---|
| 2129 | this.hasDataRefStrings = false; |
|---|
| 2130 | |
|---|
| 2131 | // Clear all old callbacks that may have been registered. |
|---|
| 2132 | |
|---|
| 2133 | var i = 0; |
|---|
| 2134 | for (i = 0; i < this.dataSetsForDataRefStrings.length; i++) |
|---|
| 2135 | { |
|---|
| 2136 | var ds = this.dataSetsForDataRefStrings[i]; |
|---|
| 2137 | if (ds) |
|---|
| 2138 | ds.removeObserver(this); |
|---|
| 2139 | } |
|---|
| 2140 | |
|---|
| 2141 | // Now run through the strings that may contain data references and figure |
|---|
| 2142 | // out what data sets they require. Note that the data references in these |
|---|
| 2143 | // strings must be fully qualified with a data set name. (ex: {dsDataSetName::columnName}) |
|---|
| 2144 | |
|---|
| 2145 | this.dataSetsForDataRefStrings = new Array(); |
|---|
| 2146 | |
|---|
| 2147 | var regionStrs = this.getDataRefStrings(); |
|---|
| 2148 | |
|---|
| 2149 | var dsCount = 0; |
|---|
| 2150 | |
|---|
| 2151 | for (var n = 0; n < regionStrs.length; n++) |
|---|
| 2152 | { |
|---|
| 2153 | var tokens = Spry.Data.Region.getTokensFromStr(regionStrs[n]); |
|---|
| 2154 | |
|---|
| 2155 | for (i = 0; tokens && i < tokens.length; i++) |
|---|
| 2156 | { |
|---|
| 2157 | if (tokens[i].search(/{[^}:]+::[^}]+}/) != -1) |
|---|
| 2158 | { |
|---|
| 2159 | var dsName = tokens[i].replace(/^\{|::.*\}/g, ""); |
|---|
| 2160 | var ds = null; |
|---|
| 2161 | if (!this.dataSetsForDataRefStrings[dsName]) |
|---|
| 2162 | { |
|---|
| 2163 | try { ds = eval(dsName); } catch (e) { ds = null; } |
|---|
| 2164 | |
|---|
| 2165 | if (dsName && ds) |
|---|
| 2166 | { |
|---|
| 2167 | // The dataSetsForDataRefStrings array serves as both an |
|---|
| 2168 | // array of data sets and a hash lookup by name. |
|---|
| 2169 | |
|---|
| 2170 | this.dataSetsForDataRefStrings[dsName] = ds; |
|---|
| 2171 | this.dataSetsForDataRefStrings[dsCount++] = ds; |
|---|
| 2172 | this.hasDataRefStrings = true; |
|---|
| 2173 | } |
|---|
| 2174 | } |
|---|
| 2175 | } |
|---|
| 2176 | } |
|---|
| 2177 | } |
|---|
| 2178 | |
|---|
| 2179 | // Set up observers on any data sets our URL depends on. |
|---|
| 2180 | |
|---|
| 2181 | for (i = 0; i < this.dataSetsForDataRefStrings.length; i++) |
|---|
| 2182 | { |
|---|
| 2183 | var ds = this.dataSetsForDataRefStrings[i]; |
|---|
| 2184 | ds.addObserver(this); |
|---|
| 2185 | } |
|---|
| 2186 | }; |
|---|
| 2187 | |
|---|
| 2188 | Spry.Data.HTTPSourceDataSet.prototype.getDataRefStrings = function() |
|---|
| 2189 | { |
|---|
| 2190 | var strArr = []; |
|---|
| 2191 | if (this.url) strArr.push(this.url); |
|---|
| 2192 | if (this.requestInfo && this.requestInfo.postData) strArr.push(this.requestInfo.postData); |
|---|
| 2193 | return strArr; |
|---|
| 2194 | }; |
|---|
| 2195 | |
|---|
| 2196 | Spry.Data.HTTPSourceDataSet.prototype.attemptLoadData = function() |
|---|
| 2197 | { |
|---|
| 2198 | // We only want to trigger a load when all of our data sets have data! |
|---|
| 2199 | for (var i = 0; i < this.dataSetsForDataRefStrings.length; i++) |
|---|
| 2200 | { |
|---|
| 2201 | var ds = this.dataSetsForDataRefStrings[i]; |
|---|
| 2202 | if (ds.getLoadDataRequestIsPending() || !ds.getDataWasLoaded()) |
|---|
| 2203 | return; |
|---|
| 2204 | } |
|---|
| 2205 | |
|---|
| 2206 | this.loadData(); |
|---|
| 2207 | }; |
|---|
| 2208 | |
|---|
| 2209 | Spry.Data.HTTPSourceDataSet.prototype.onCurrentRowChanged = function(ds, data) |
|---|
| 2210 | { |
|---|
| 2211 | this.attemptLoadData(); |
|---|
| 2212 | }; |
|---|
| 2213 | |
|---|
| 2214 | Spry.Data.HTTPSourceDataSet.prototype.onPostSort = function(ds, data) |
|---|
| 2215 | { |
|---|
| 2216 | this.attemptLoadData(); |
|---|
| 2217 | }; |
|---|
| 2218 | |
|---|
| 2219 | Spry.Data.HTTPSourceDataSet.prototype.onDataChanged = function(ds, data) |
|---|
| 2220 | { |
|---|
| 2221 | this.attemptLoadData(); |
|---|
| 2222 | }; |
|---|
| 2223 | |
|---|
| 2224 | Spry.Data.HTTPSourceDataSet.prototype.loadData = function() |
|---|
| 2225 | { |
|---|
| 2226 | if (!this.url) |
|---|
| 2227 | return; |
|---|
| 2228 | |
|---|
| 2229 | this.cancelLoadData(); |
|---|
| 2230 | |
|---|
| 2231 | var url = this.url; |
|---|
| 2232 | var postData = this.requestInfo.postData; |
|---|
| 2233 | |
|---|
| 2234 | if (this.hasDataRefStrings) |
|---|
| 2235 | { |
|---|
| 2236 | var allDataSetsReady = true; |
|---|
| 2237 | |
|---|
| 2238 | for (var i = 0; i < this.dataSetsForDataRefStrings.length; i++) |
|---|
| 2239 | { |
|---|
| 2240 | var ds = this.dataSetsForDataRefStrings[i]; |
|---|
| 2241 | if (ds.getLoadDataRequestIsPending()) |
|---|
| 2242 | allDataSetsReady = false; |
|---|
| 2243 | else if (!ds.getDataWasLoaded()) |
|---|
| 2244 | { |
|---|
| 2245 | // Kick off the load of this data set! |
|---|
| 2246 | ds.loadData(); |
|---|
| 2247 | allDataSetsReady = false; |
|---|
| 2248 | } |
|---|
| 2249 | } |
|---|
| 2250 | |
|---|
| 2251 | // If our data sets aren't ready, just return. We'll |
|---|
| 2252 | // get called back to load our data when they are all |
|---|
| 2253 | // done. |
|---|
| 2254 | |
|---|
| 2255 | if (!allDataSetsReady) |
|---|
| 2256 | return; |
|---|
| 2257 | |
|---|
| 2258 | url = Spry.Data.Region.processDataRefString(null, this.url, this.dataSetsForDataRefStrings); |
|---|
| 2259 | if (!url) |
|---|
| 2260 | return; |
|---|
| 2261 | |
|---|
| 2262 | if (postData && (typeof postData) == "string") |
|---|
| 2263 | postData = Spry.Data.Region.processDataRefString(null, postData, this.dataSetsForDataRefStrings); |
|---|
| 2264 | } |
|---|
| 2265 | |
|---|
| 2266 | this.notifyObservers("onPreLoad"); |
|---|
| 2267 | |
|---|
| 2268 | this.data = null; |
|---|
| 2269 | this.dataWasLoaded = false; |
|---|
| 2270 | this.unfilteredData = null; |
|---|
| 2271 | this.dataHash = null; |
|---|
| 2272 | this.curRowID = 0; |
|---|
| 2273 | |
|---|
| 2274 | // At this point the url should've been processed if it contained any |
|---|
| 2275 | // data references. Set the url of the requestInfo structure and pass it |
|---|
| 2276 | // to LoadManager.loadData(). |
|---|
| 2277 | |
|---|
| 2278 | var req = this.requestInfo.clone(); |
|---|
| 2279 | req.url = url; |
|---|
| 2280 | req.postData = postData; |
|---|
| 2281 | |
|---|
| 2282 | this.pendingRequest = new Object; |
|---|
| 2283 | this.pendingRequest.data = Spry.Data.HTTPSourceDataSet.LoadManager.loadData(req, this, this.useCache); |
|---|
| 2284 | }; |
|---|
| 2285 | |
|---|
| 2286 | Spry.Data.HTTPSourceDataSet.prototype.cancelLoadData = function() |
|---|
| 2287 | { |
|---|
| 2288 | if (this.pendingRequest) |
|---|
| 2289 | { |
|---|
| 2290 | Spry.Data.HTTPSourceDataSet.LoadManager.cancelLoadData(this.pendingRequest.data, this); |
|---|
| 2291 | this.pendingRequest = null; |
|---|
| 2292 | } |
|---|
| 2293 | }; |
|---|
| 2294 | |
|---|
| 2295 | Spry.Data.HTTPSourceDataSet.prototype.getURL = function() { return this.url; }; |
|---|
| 2296 | Spry.Data.HTTPSourceDataSet.prototype.setURL = function(url, requestOptions) |
|---|
| 2297 | { |
|---|
| 2298 | if (this.url == url) |
|---|
| 2299 | { |
|---|
| 2300 | // The urls match so we may not have to do anything, but |
|---|
| 2301 | // before we bail early, check to see if the method and |
|---|
| 2302 | // postData that was last used was the same. If there is a |
|---|
| 2303 | // difference, we need to process the new URL. |
|---|
| 2304 | |
|---|
| 2305 | if (!requestOptions || (this.requestInfo.method == requestOptions.method && (requestOptions.method != "POST" || this.requestInfo.postData == requestOptions.postData))) |
|---|
| 2306 | return; |
|---|
| 2307 | } |
|---|
| 2308 | |
|---|
| 2309 | this.url = url; |
|---|
| 2310 | |
|---|
| 2311 | this.setRequestInfo(requestOptions); |
|---|
| 2312 | |
|---|
| 2313 | this.cancelLoadData(); |
|---|
| 2314 | this.recalculateDataSetDependencies(); |
|---|
| 2315 | this.dataWasLoaded = false; |
|---|
| 2316 | }; |
|---|
| 2317 | |
|---|
| 2318 | Spry.Data.HTTPSourceDataSet.prototype.setDataFromDoc = function(rawDataDoc) |
|---|
| 2319 | { |
|---|
| 2320 | this.pendingRequest = null; |
|---|
| 2321 | |
|---|
| 2322 | this.loadDataIntoDataSet(rawDataDoc); |
|---|
| 2323 | this.applyColumnTypes(); |
|---|
| 2324 | this.filterAndSortData(); |
|---|
| 2325 | |
|---|
| 2326 | this.notifyObservers("onPostLoad"); |
|---|
| 2327 | this.notifyObservers("onDataChanged"); |
|---|
| 2328 | }; |
|---|
| 2329 | |
|---|
| 2330 | Spry.Data.HTTPSourceDataSet.prototype.loadDataIntoDataSet = function(rawDataDoc) |
|---|
| 2331 | { |
|---|
| 2332 | // this method needs to be overwritten by the descendent classes; |
|---|
| 2333 | // internal data structures (data & dataHash) have to load data from the source document (ResponseText | ResponseDoc); |
|---|
| 2334 | |
|---|
| 2335 | this.dataHash = new Object; |
|---|
| 2336 | this.data = new Array; |
|---|
| 2337 | this.dataWasLoaded = true; |
|---|
| 2338 | }; |
|---|
| 2339 | |
|---|
| 2340 | Spry.Data.HTTPSourceDataSet.prototype.xhRequestProcessor = function(xhRequest) |
|---|
| 2341 | { |
|---|
| 2342 | // This method needs to be overwritten by the descendent classes if other objects (like responseXML) |
|---|
| 2343 | // are going to be used as a data source |
|---|
| 2344 | // This implementation returns the responseText from xhRequest |
|---|
| 2345 | |
|---|
| 2346 | var resp = xhRequest.responseText; |
|---|
| 2347 | |
|---|
| 2348 | if (xhRequest.status == 200 || xhRequest.status == 0) |
|---|
| 2349 | return resp; |
|---|
| 2350 | return null; |
|---|
| 2351 | }; |
|---|
| 2352 | |
|---|
| 2353 | Spry.Data.HTTPSourceDataSet.prototype.sessionExpiredChecker = function(req) |
|---|
| 2354 | { |
|---|
| 2355 | if (req.xhRequest.responseText == 'session expired') |
|---|
| 2356 | return true; |
|---|
| 2357 | return false; |
|---|
| 2358 | }; |
|---|
| 2359 | |
|---|
| 2360 | Spry.Data.HTTPSourceDataSet.prototype.setSessionExpiredChecker = function(checker) |
|---|
| 2361 | { |
|---|
| 2362 | this.sessionExpiredChecker = checker; |
|---|
| 2363 | }; |
|---|
| 2364 | |
|---|
| 2365 | |
|---|
| 2366 | Spry.Data.HTTPSourceDataSet.prototype.onRequestResponse = function(cachedRequest, req) |
|---|
| 2367 | { |
|---|
| 2368 | this.setDataFromDoc(cachedRequest.rawData); |
|---|
| 2369 | }; |
|---|
| 2370 | |
|---|
| 2371 | Spry.Data.HTTPSourceDataSet.prototype.onRequestError = function(cachedRequest, req) |
|---|
| 2372 | { |
|---|
| 2373 | this.notifyObservers("onLoadError", req); |
|---|
| 2374 | // Spry.Debug.reportError("Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.loadDataCallback(" + req.xhRequest.status + ") failed to load: " + req.url + "\n"); |
|---|
| 2375 | }; |
|---|
| 2376 | |
|---|
| 2377 | Spry.Data.HTTPSourceDataSet.prototype.onRequestSessionExpired = function(cachedRequest, req) |
|---|
| 2378 | { |
|---|
| 2379 | this.notifyObservers("onSessionExpired", req); |
|---|
| 2380 | //Spry.Debug.reportError("Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.loadDataCallback(" + req.xhRequest.status + ") failed to load: " + req.url + "\n"); |
|---|
| 2381 | }; |
|---|
| 2382 | |
|---|
| 2383 | |
|---|
| 2384 | Spry.Data.HTTPSourceDataSet.LoadManager = {}; |
|---|
| 2385 | Spry.Data.HTTPSourceDataSet.LoadManager.cache = []; |
|---|
| 2386 | |
|---|
| 2387 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest = function(reqInfo, xhRequestProcessor, sessionExpiredChecker) |
|---|
| 2388 | { |
|---|
| 2389 | Spry.Utils.Notifier.call(this); |
|---|
| 2390 | |
|---|
| 2391 | this.reqInfo = reqInfo; |
|---|
| 2392 | this.rawData = null; |
|---|
| 2393 | this.timer = null; |
|---|
| 2394 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.NOT_LOADED; |
|---|
| 2395 | this.xhRequestProcessor = xhRequestProcessor; |
|---|
| 2396 | this.sessionExpiredChecker = sessionExpiredChecker; |
|---|
| 2397 | }; |
|---|
| 2398 | |
|---|
| 2399 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.prototype = new Spry.Utils.Notifier(); |
|---|
| 2400 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.prototype.constructor = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest; |
|---|
| 2401 | |
|---|
| 2402 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.NOT_LOADED = 1; |
|---|
| 2403 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_REQUESTED = 2; |
|---|
| 2404 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_FAILED = 3; |
|---|
| 2405 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_SUCCESSFUL = 4; |
|---|
| 2406 | |
|---|
| 2407 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.prototype.loadDataCallback = function(req) |
|---|
| 2408 | { |
|---|
| 2409 | if (req.xhRequest.readyState != 4) |
|---|
| 2410 | return; |
|---|
| 2411 | |
|---|
| 2412 | var rawData = null; |
|---|
| 2413 | if (this.xhRequestProcessor) rawData = this.xhRequestProcessor(req.xhRequest); |
|---|
| 2414 | |
|---|
| 2415 | if (this.sessionExpiredChecker) |
|---|
| 2416 | { |
|---|
| 2417 | Spry.Utils.setOptions(req, {'rawData': rawData}, false); |
|---|
| 2418 | if (this.sessionExpiredChecker(req)) |
|---|
| 2419 | { |
|---|
| 2420 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_FAILED; |
|---|
| 2421 | this.notifyObservers("onRequestSessionExpired", req); |
|---|
| 2422 | this.observers.length = 0; |
|---|
| 2423 | return; |
|---|
| 2424 | } |
|---|
| 2425 | } |
|---|
| 2426 | |
|---|
| 2427 | if (!rawData) |
|---|
| 2428 | { |
|---|
| 2429 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_FAILED; |
|---|
| 2430 | this.notifyObservers("onRequestError", req); |
|---|
| 2431 | this.observers.length = 0; // Clear the observers list. |
|---|
| 2432 | return; |
|---|
| 2433 | } |
|---|
| 2434 | |
|---|
| 2435 | this.rawData = rawData; |
|---|
| 2436 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_SUCCESSFUL; |
|---|
| 2437 | |
|---|
| 2438 | // Notify all of the cached request's observers! |
|---|
| 2439 | this.notifyObservers("onRequestResponse", req); |
|---|
| 2440 | |
|---|
| 2441 | // Clear the observers list. |
|---|
| 2442 | this.observers.length = 0; |
|---|
| 2443 | }; |
|---|
| 2444 | |
|---|
| 2445 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.prototype.loadData = function() |
|---|
| 2446 | { |
|---|
| 2447 | // IE will synchronously fire our loadDataCallback() during the call |
|---|
| 2448 | // to an async Spry.Utils.loadURL() if the data for the url is already |
|---|
| 2449 | // in the browser's local cache. This can wreak havoc with complicated master/detail |
|---|
| 2450 | // regions that use data sets that have master/detail relationships with other |
|---|
| 2451 | // data sets. Our data set logic already handles async data loading nicely so we |
|---|
| 2452 | // use a timer to fire off the async Spry.Utils.loadURL() call to insure that any |
|---|
| 2453 | // data loading happens asynchronously after this function is finished. |
|---|
| 2454 | |
|---|
| 2455 | var self = this; |
|---|
| 2456 | this.cancelLoadData(); |
|---|
| 2457 | this.rawData = null; |
|---|
| 2458 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_REQUESTED; |
|---|
| 2459 | |
|---|
| 2460 | var reqInfo = this.reqInfo.clone(); |
|---|
| 2461 | reqInfo.successCallback = function(req) { self.loadDataCallback(req); }; |
|---|
| 2462 | reqInfo.errorCallback = reqInfo.successCallback; |
|---|
| 2463 | |
|---|
| 2464 | this.timer = setTimeout(function() |
|---|
| 2465 | { |
|---|
| 2466 | self.timer = null; |
|---|
| 2467 | Spry.Utils.loadURL(reqInfo.method, reqInfo.url, reqInfo.async, reqInfo.successCallback, reqInfo); |
|---|
| 2468 | }, 0); |
|---|
| 2469 | }; |
|---|
| 2470 | |
|---|
| 2471 | Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.prototype.cancelLoadData = function() |
|---|
| 2472 | { |
|---|
| 2473 | if (this.state == Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_REQUESTED) |
|---|
| 2474 | { |
|---|
| 2475 | if (this.timer) |
|---|
| 2476 | { |
|---|
| 2477 | this.timer.clearTimeout(); |
|---|
| 2478 | this.timer = null; |
|---|
| 2479 | } |
|---|
| 2480 | |
|---|
| 2481 | this.rawData = null; |
|---|
| 2482 | this.state = Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.NOT_LOADED; |
|---|
| 2483 | } |
|---|
| 2484 | }; |
|---|
| 2485 | |
|---|
| 2486 | Spry.Data.HTTPSourceDataSet.LoadManager.getCacheKey = function(reqInfo) |
|---|
| 2487 | { |
|---|
| 2488 | return reqInfo.method + "::" + reqInfo.url + "::" + reqInfo.postData + "::" + reqInfo.username; |
|---|
| 2489 | }; |
|---|
| 2490 | |
|---|
| 2491 | Spry.Data.HTTPSourceDataSet.LoadManager.loadData = function(reqInfo, ds, useCache) |
|---|
| 2492 | { |
|---|
| 2493 | if (!reqInfo) |
|---|
| 2494 | return null; |
|---|
| 2495 | |
|---|
| 2496 | var cacheObj = null; |
|---|
| 2497 | var cacheKey = null; |
|---|
| 2498 | |
|---|
| 2499 | if (useCache) |
|---|
| 2500 | { |
|---|
| 2501 | cacheKey = Spry.Data.HTTPSourceDataSet.LoadManager.getCacheKey(reqInfo); |
|---|
| 2502 | cacheObj = Spry.Data.HTTPSourceDataSet.LoadManager.cache[cacheKey]; |
|---|
| 2503 | } |
|---|
| 2504 | |
|---|
| 2505 | if (cacheObj) |
|---|
| 2506 | { |
|---|
| 2507 | if (cacheObj.state == Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_REQUESTED) |
|---|
| 2508 | { |
|---|
| 2509 | if (ds) |
|---|
| 2510 | cacheObj.addObserver(ds); |
|---|
| 2511 | return cacheObj; |
|---|
| 2512 | } |
|---|
| 2513 | else if (cacheObj.state == Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest.LOAD_SUCCESSFUL) |
|---|
| 2514 | { |
|---|
| 2515 | // Data is already cached so if we have a data set, trigger an async call |
|---|
| 2516 | // that tells it to load its data. |
|---|
| 2517 | if (ds) |
|---|
| 2518 | setTimeout(function() { ds.setDataFromDoc(cacheObj.rawData); }, 0); |
|---|
| 2519 | return cacheObj; |
|---|
| 2520 | } |
|---|
| 2521 | } |
|---|
| 2522 | |
|---|
| 2523 | // We're either loading this url for the first time, or an error occurred when |
|---|
| 2524 | // we last tried to load it, or the caller requested a forced load. |
|---|
| 2525 | |
|---|
| 2526 | if (!cacheObj) |
|---|
| 2527 | { |
|---|
| 2528 | cacheObj = new Spry.Data.HTTPSourceDataSet.LoadManager.CachedRequest(reqInfo, (ds ? ds.xhRequestProcessor : null), (ds ? ds.sessionExpiredChecker : null)); |
|---|
| 2529 | |
|---|
| 2530 | if (useCache) |
|---|
| 2531 | { |
|---|
| 2532 | Spry.Data.HTTPSourceDataSet.LoadManager.cache[cacheKey] = cacheObj; |
|---|
| 2533 | |
|---|
| 2534 | // Add an observer that will remove the cacheObj from the cache |
|---|
| 2535 | // if there is a load request failure. |
|---|
| 2536 | cacheObj.addObserver({ onRequestError: function() { Spry.Data.HTTPSourceDataSet.LoadManager.cache[cacheKey] = undefined; }}); |
|---|
| 2537 | } |
|---|
| 2538 | } |
|---|
| 2539 | |
|---|
| 2540 | if (ds) |
|---|
| 2541 | cacheObj.addObserver(ds); |
|---|
| 2542 | |
|---|
| 2543 | cacheObj.loadData(); |
|---|
| 2544 | |
|---|
| 2545 | return cacheObj; |
|---|
| 2546 | }; |
|---|
| 2547 | |
|---|
| 2548 | Spry.Data.HTTPSourceDataSet.LoadManager.cancelLoadData = function(cacheObj, ds) |
|---|
| 2549 | { |
|---|
| 2550 | if (cacheObj) |
|---|
| 2551 | { |
|---|
| 2552 | if (ds) |
|---|
| 2553 | cacheObj.removeObserver(ds); |
|---|
| 2554 | else |
|---|
| 2555 | cacheObj.cancelLoadData(); |
|---|
| 2556 | } |
|---|
| 2557 | }; |
|---|
| 2558 | |
|---|
| 2559 | ////////////////////////////////////////////////////////////////////// |
|---|
| 2560 | // |
|---|
| 2561 | // Spry.Data.XMLDataSet |
|---|
| 2562 | // |
|---|
| 2563 | ////////////////////////////////////////////////////////////////////// |
|---|
| 2564 | |
|---|
| 2565 | Spry.Data.XMLDataSet = function(dataSetURL, dataSetPath, dataSetOptions) |
|---|
| 2566 | { |
|---|
| 2567 | // Call the constructor for our HTTPSourceDataSet base class so that |
|---|
| 2568 | // our base class properties get defined. |
|---|
| 2569 | |
|---|
| 2570 | this.xpath = dataSetPath; |
|---|
| 2571 | this.doc = null; |
|---|
| 2572 | this.subPaths = []; |
|---|
| 2573 | |
|---|
| 2574 | Spry.Data.HTTPSourceDataSet.call(this, dataSetURL, dataSetOptions); |
|---|
| 2575 | |
|---|
| 2576 | // Callers are allowed to pass either a string, an object or an array of |
|---|
| 2577 | // strings and/or objects for the 'subPaths' option, so make sure we normalize |
|---|
| 2578 | // the subPaths value to be an array. |
|---|
| 2579 | |
|---|
| 2580 | var jwType = typeof this.subPaths; |
|---|
| 2581 | if (jwType == "string" || (jwType == "object" && this.subPaths.constructor != Array)) |
|---|
| 2582 | this.subPaths = [ this.subPaths ]; |
|---|
| 2583 | }; // End of Spry.Data.XMLDataSet() constructor. |
|---|
| 2584 | |
|---|
| 2585 | Spry.Data.XMLDataSet.prototype = new Spry.Data.HTTPSourceDataSet(); |
|---|
| 2586 | Spry.Data.XMLDataSet.prototype.constructor = Spry.Data.XMLDataSet; |
|---|
| 2587 | |
|---|
| 2588 | |
|---|
| 2589 | Spry.Data.XMLDataSet.prototype.getDataRefStrings = function() |
|---|
| 2590 | { |
|---|
| 2591 | var strArr = []; |
|---|
| 2592 | if (this.url) strArr.push(this.url); |
|---|
| 2593 | if (this.xpath) strArr.push(this.xpath); |
|---|
| 2594 | if (this.requestInfo && this.requestInfo.postData) strArr.push(this.requestInfo.postData); |
|---|
| 2595 | return strArr; |
|---|
| 2596 | }; |
|---|
| 2597 | |
|---|
| 2598 | Spry.Data.XMLDataSet.prototype.getDocument = function() { return this.doc; }; |
|---|
| 2599 | Spry.Data.XMLDataSet.prototype.getXPath = function() { return this.xpath; }; |
|---|
| 2600 | Spry.Data.XMLDataSet.prototype.setXPath = function(path) |
|---|
| 2601 | { |
|---|
| 2602 | if (this.xpath != path) |
|---|
| 2603 | { |
|---|
| 2604 | this.xpath = path; |
|---|
| 2605 | if (this.dataWasLoaded && this.doc) |
|---|
| 2606 | { |
|---|
| 2607 | this.notifyObservers("onPreLoad"); |
|---|
| 2608 | this.setDataFromDoc(this.doc); |
|---|
| 2609 | } |
|---|
| 2610 | } |
|---|
| 2611 | }; |
|---|
| 2612 | |
|---|
| 2613 | Spry.Data.XMLDataSet.PathNode = function(path) |
|---|
| 2614 | { |
|---|
| 2615 | this.path = path; |
|---|
| 2616 | this.subPaths = []; |
|---|
| 2617 | this.xpath = ""; |
|---|
| 2618 | }; |
|---|
| 2619 | |
|---|
| 2620 | Spry.Data.XMLDataSet.PathNode.prototype.addSubPath = function(path) |
|---|
| 2621 | { |
|---|
| 2622 | var node = this.findSubPath(path); |
|---|
| 2623 | if (!node) |
|---|
| 2624 | { |
|---|
| 2625 | node = new Spry.Data.XMLDataSet.PathNode(path); |
|---|
| 2626 | this.subPaths.push(node); |
|---|
| 2627 | } |
|---|
| 2628 | return node; |
|---|
| 2629 | }; |
|---|
| 2630 | |
|---|
| 2631 | Spry.Data.XMLDataSet.PathNode.prototype.findSubPath = function(path) |
|---|
| 2632 | { |
|---|
| 2633 | var numSubPaths = this.subPaths.length; |
|---|
| 2634 | for (var i = 0; i < numSubPaths; i++) |
|---|
| 2635 | { |
|---|
| 2636 | var subPath = this.subPaths[i]; |
|---|
| 2637 | if (path == subPath.path) |
|---|
| 2638 | return subPath; |
|---|
| 2639 | } |
|---|
| 2640 | return null; |
|---|
| 2641 | }; |
|---|
| 2642 | |
|---|
| 2643 | Spry.Data.XMLDataSet.PathNode.prototype.consolidate = function() |
|---|
| 2644 | { |
|---|
| 2645 | // This method recursively runs through the path tree and |
|---|
| 2646 | // tries to flatten any nodes that have no XPath and one child. |
|---|
| 2647 | // The flattening involves merging the parent's path component |
|---|
| 2648 | // with its child path component. |
|---|
| 2649 | |
|---|
| 2650 | var numSubPaths = this.subPaths.length; |
|---|
| 2651 | if (!this.xpath && numSubPaths == 1) |
|---|
| 2652 | { |
|---|
| 2653 | // Consolidate! |
|---|
| 2654 | var subPath = this.subPaths[0]; |
|---|
| 2655 | this.path += ((subPath[0] != "/") ? "/" : "") + subPath.path; |
|---|
| 2656 | this.xpath = subPath.xpath; |
|---|
| 2657 | this.subPaths = subPath.subPaths; |
|---|
| 2658 | this.consolidate(); |
|---|
| 2659 | return; |
|---|
| 2660 | } |
|---|
| 2661 | |
|---|
| 2662 | for (var i = 0; i < numSubPaths; i++) |
|---|
| 2663 | this.subPaths[i].consolidate(); |
|---|
| 2664 | }; |
|---|
| 2665 | |
|---|
| 2666 | /* This method is commented out so that it gets stripped when the file |
|---|
| 2667 | is minimized. Please do not remove this from the full version of the |
|---|
| 2668 | file! It is needed for debugging. |
|---|
| 2669 | |
|---|
| 2670 | Spry.Data.XMLDataSet.PathNode.prototype.dump = function(indentStr) |
|---|
| 2671 | { |
|---|
| 2672 | var didPre = false; |
|---|
| 2673 | var result = ""; |
|---|
| 2674 | if (!indentStr) |
|---|
| 2675 | { |
|---|
| 2676 | indentStr = ""; |
|---|
| 2677 | didPre = true; |
|---|
| 2678 | result = "<pre>"; |
|---|
| 2679 | } |
|---|
| 2680 | result += indentStr + "<strong>" + this.path + "</strong>" + (this.xpath ? " <em>-- xpath(" + Spry.Utils.encodeEntities(this.xpath) + ")</em>" : "") + "\n"; |
|---|
| 2681 | var numSubPaths = this.subPaths.length; |
|---|
| 2682 | indentStr += " "; |
|---|
| 2683 | for (var i = 0; i < numSubPaths; i++) |
|---|
| 2684 | result += this.subPaths[i].dump(indentStr); |
|---|
| 2685 | if (didPre) |
|---|
| 2686 | result += "</pre>"; |
|---|
| 2687 | return result; |
|---|
| 2688 | }; |
|---|
| 2689 | */ |
|---|
| 2690 | |
|---|
| 2691 | Spry.Data.XMLDataSet.prototype.convertXPathsToPathTree = function(xpathArray) |
|---|
| 2692 | { |
|---|
| 2693 | var xpaLen = xpathArray.length; |
|---|
| 2694 | var root = new Spry.Data.XMLDataSet.PathNode(""); |
|---|
| 2695 | |
|---|
| 2696 | for (var i = 0; i < xpaLen; i++) |
|---|
| 2697 | { |
|---|
| 2698 | // Convert any "//" in the XPath to our placeholder value. |
|---|
| 2699 | // We need to do that so they don't get removed when we split the |
|---|
| 2700 | // path into components. |
|---|
| 2701 | |
|---|
| 2702 | var xpath = xpathArray[i]; |
|---|
| 2703 | var cleanXPath = xpath.replace(/\/\//g, "/__SPRYDS__"); |
|---|
| 2704 | cleanXPath = cleanXPath.replace(/^\//, ""); // Strip any leading slash. |
|---|
| 2705 | var pathItems = cleanXPath.split(/\//); |
|---|
| 2706 | var pathItemsLen = pathItems.length; |
|---|
| 2707 | |
|---|
| 2708 | // Now add each path component to our tree. |
|---|
| 2709 | |
|---|
| 2710 | var node = root; |
|---|
| 2711 | for (var j = 0; j < pathItemsLen; j++) |
|---|
| 2712 | { |
|---|
| 2713 | // If this path component has a placeholder in it, convert it |
|---|
| 2714 | // back to a double slash. |
|---|
| 2715 | |
|---|
| 2716 | var path = pathItems[j].replace(/__SPRYDS__/, "//"); |
|---|
| 2717 | node = node.addSubPath(path); |
|---|
| 2718 | } |
|---|
| 2719 | |
|---|
| 2720 | // Now add the full xpath to the node that represents the |
|---|
| 2721 | // last path component in our path. |
|---|
| 2722 | |
|---|
| 2723 | node.xpath = xpath; |
|---|
| 2724 | } |
|---|
| 2725 | |
|---|
| 2726 | // Now that we have a tree of nodes. Tell the root to consolidate |
|---|
| 2727 | // itself so we get a tree that is as flat as possible. This reduces |
|---|
| 2728 | // the number of XPaths we will have to flatten. |
|---|
| 2729 | |
|---|
| 2730 | root.consolidate(); |
|---|
| 2731 | return root; |
|---|
| 2732 | }; |
|---|
| 2733 | |
|---|
| 2734 | Spry.Data.XMLDataSet.prototype.flattenSubPaths = function(rs, subPaths) |
|---|
| 2735 | { |
|---|
| 2736 | if (!rs || !subPaths) |
|---|
| 2737 | return; |
|---|
| 2738 | |
|---|
| 2739 | var numSubPaths = subPaths.length; |
|---|
| 2740 | if (numSubPaths < 1) |
|---|
| 2741 | return; |
|---|
| 2742 | |
|---|
| 2743 | var data = rs.data; |
|---|
| 2744 | var dataHash = {}; |
|---|
| 2745 | |
|---|
| 2746 | // Convert all of the templated subPaths to XPaths with real values. |
|---|
| 2747 | // We also need a "cleaned" version of the XPath which contains no |
|---|
| 2748 | // expressions in it, so that we can pre-pend it to the column names |
|---|
| 2749 | // of any nested data we find. |
|---|
| 2750 | |
|---|
| 2751 | var xpathArray = []; |
|---|
| 2752 | var cleanedXPathArray = []; |
|---|
| 2753 | |
|---|
| 2754 | for (var i = 0; i < numSubPaths; i++) |
|---|
| 2755 | { |
|---|
| 2756 | // The elements of the subPaths array can be XPath strings, |
|---|
| 2757 | // or objects that describe a path with nested sub-paths below |
|---|
| 2758 | // it, so make sure we properly extract out the XPath to use. |
|---|
| 2759 | |
|---|
| 2760 | var subPath = subPaths[i]; |
|---|
| 2761 | if (typeof subPath == "object") |
|---|
| 2762 | subPath = subPath.path; |
|---|
| 2763 | if (!subPath) |
|---|
| 2764 | subPath = ""; |
|---|
| 2765 | |
|---|
| 2766 | // Convert any data references in the XPath to real values! |
|---|
| 2767 | |
|---|
| 2768 | xpathArray[i] = Spry.Data.Region.processDataRefString(null, subPath, this.dataSetsForDataRefStrings); |
|---|
| 2769 | |
|---|
| 2770 | // Create a clean version of the XPath by stripping out any |
|---|
| 2771 | // expressions it may contain. |
|---|
| 2772 | |
|---|
| 2773 | cleanedXPathArray[i] = xpathArray[i].replace(/\[.*\]/g, ""); |
|---|
| 2774 | } |
|---|
| 2775 | |
|---|
| 2776 | // For each row of the base record set passed in, generate a flattened |
|---|
| 2777 | // recordset from each subPath, and then join the results with the base |
|---|
| 2778 | // row. The row from the base data set will be duplicated to match the |
|---|
| 2779 | // number of rows matched by the subPath. The results are then merged. |
|---|
| 2780 | |
|---|
| 2781 | var row; |
|---|
| 2782 | var numRows = data.length; |
|---|
| 2783 | var newData = []; |
|---|
| 2784 | |
|---|
| 2785 | // Iterate over each row of the base record set. |
|---|
| 2786 | |
|---|
| 2787 | for (var i = 0; i < numRows; i++) |
|---|
| 2788 | { |
|---|
| 2789 | row = data[i]; |
|---|
| 2790 | var newRows = [ row ]; |
|---|
| 2791 | |
|---|
| 2792 | // Iterate over every subPath passed into this function. |
|---|
| 2793 | |
|---|
| 2794 | for (var j = 0; j < numSubPaths; j++) |
|---|
| 2795 | { |
|---|
| 2796 | // Search for all nodes that match the given XPath underneath |
|---|
| 2797 | // the XML node for the base row and flatten the data into |
|---|
| 2798 | // a tabular recordset structure. |
|---|
| 2799 | |
|---|
| 2800 | var newRS = Spry.Utils.getRecordSetFromXMLDoc(row.ds_XMLNode, xpathArray[j], (subPaths[j].xpath ? false : true)); |
|---|
| 2801 | |
|---|
| 2802 | // If this subPath has additional subPaths beneath it, |
|---|
| 2803 | // flatten and join them with the recordset we just created. |
|---|
| 2804 | |
|---|
| 2805 | if (newRS && newRS.data && newRS.data.length) |
|---|
| 2806 | { |
|---|
| 2807 | if (typeof subPaths[j] == "object" && subPaths[j].subPaths) |
|---|
| 2808 | { |
|---|
| 2809 | // The subPaths property can be either an XPath string, |
|---|
| 2810 | // an Object describing a subPath and paths beneath it, |
|---|
| 2811 | // or an Array of XPath strings or objects. We need to |
|---|
| 2812 | // normalize these variations into an array to simplify |
|---|
| 2813 | // our processing. |
|---|
| 2814 | |
|---|
| 2815 | var sp = subPaths[j].subPaths; |
|---|
| 2816 | spType = typeof sp; |
|---|
| 2817 | if (spType == "string") |
|---|
| 2818 | sp = [ sp ]; |
|---|
| 2819 | else if (spType == "object" && spType.constructor == Object) |
|---|
| 2820 | sp = [ sp ]; |
|---|
| 2821 | |
|---|
| 2822 | // Now that we have a normalized array of sub paths, flatten |
|---|
| 2823 | // them and join them to the recordSet we just calculated. |
|---|
| 2824 | |
|---|
| 2825 | this.flattenSubPaths(newRS, sp); |
|---|
| 2826 | } |
|---|
| 2827 | |
|---|
| 2828 | var newRSData = newRS.data; |
|---|
| 2829 | var numRSRows = newRSData.length; |
|---|
| 2830 | |
|---|
| 2831 | var cleanedXPath = cleanedXPathArray[j] + "/"; |
|---|
| 2832 | |
|---|
| 2833 | var numNewRows = newRows.length; |
|---|
| 2834 | var joinedRows = []; |
|---|
| 2835 | |
|---|
| 2836 | // Iterate over all rows in our newRows array. Note that the |
|---|
| 2837 | // contents of newRows changes after the execution of this |
|---|
| 2838 | // loop, allowing us to perform more joins when more than |
|---|
| 2839 | // one subPath is specified. |
|---|
| 2840 | |
|---|
| 2841 | for (var k = 0; k < numNewRows; k++) |
|---|
| 2842 | { |
|---|
| 2843 | var newRow = newRows[k]; |
|---|
| 2844 | |
|---|
| 2845 | // Iterate over all rows in the record set generated |
|---|
| 2846 | // from the current subPath. We are going to create |
|---|
| 2847 | // m*n rows for the joined table, where m is the number |
|---|
| 2848 | // of rows in the newRows array, and n is the number of |
|---|
| 2849 | // rows in the current subPath recordset. |
|---|
| 2850 | |
|---|
| 2851 | for (var l = 0; l < numRSRows; l++) |
|---|
| 2852 | { |
|---|
| 2853 | // Create a new row that will house the join result. |
|---|
| 2854 | |
|---|
| 2855 | var newRowObj = new Object; |
|---|
| 2856 | var newRSRow = newRSData[l]; |
|---|
| 2857 | |
|---|
| 2858 | // Copy the columns from the newRow into our row |
|---|
| 2859 | // object. |
|---|
| 2860 | |
|---|
| 2861 | for (prop in newRow) |
|---|
| 2862 | newRowObj[prop] = newRow[prop]; |
|---|
| 2863 | |
|---|
| 2864 | // Copy the data from the current row of the record set |
|---|
| 2865 | // into our new row object, but make sure to store the |
|---|
| 2866 | // data in columns that have the subPath prepended to |
|---|
| 2867 | // it so that it doesn't collide with any columns from |
|---|
| 2868 | // the newRows row data. |
|---|
| 2869 | |
|---|
| 2870 | for (var prop in newRSRow) |
|---|
| 2871 | { |
|---|
| 2872 | // The new propery name will have the subPath used prepended to it. |
|---|
| 2873 | var newPropName = cleanedXPath + prop; |
|---|
| 2874 | |
|---|
| 2875 | // We need to handle the case where the tag name of the node matched |
|---|
| 2876 | // by the XPath has a value. In that specific case, the name of the |
|---|
| 2877 | // property should be the cleanedXPath itself. For example: |
|---|
| 2878 | // |
|---|
| 2879 | // <employees> |
|---|
| 2880 | // <employee>Bob</employee> |
|---|
| 2881 | // <employee>Joe</employee> |
|---|
| 2882 | // </employees> |
|---|
| 2883 | // |
|---|
| 2884 | // XPath: /employees/employee |
|---|
| 2885 | // |
|---|
| 2886 | // The property name that contains "Bob" and "Joe" will be "employee". |
|---|
| 2887 | // So in our new row, we need to call this column "/employees/employee" |
|---|
| 2888 | // instead of "/employees/employee/employee" which would be incorrect. |
|---|
| 2889 | |
|---|
| 2890 | if (cleanedXPath == (prop + "/") || cleanedXPath.search(new RegExp("\\/" + prop + "\\/$")) != -1) |
|---|
| 2891 | newPropName = cleanedXPathArray[j]; |
|---|
| 2892 | |
|---|
| 2893 | // Copy the props to the new object using the new property name. |
|---|
| 2894 | |
|---|
| 2895 | newRowObj[newPropName] = newRSRow[prop]; |
|---|
| 2896 | } |
|---|
| 2897 | |
|---|
| 2898 | // Now add this row to the array that tracks all of the new |
|---|
| 2899 | // rows we've just created. |
|---|
| 2900 | |
|---|
| 2901 | joinedRows.push(newRowObj); |
|---|
| 2902 | } |
|---|
| 2903 | } |
|---|
| 2904 | |
|---|
| 2905 | // Set the newRows array equal to our joinedRows we just created, |
|---|
| 2906 | // so that when we flatten the data for the next subPath, it gets |
|---|
| 2907 | // joined with our new set of rows. |
|---|
| 2908 | |
|---|
| 2909 | newRows = joinedRows; |
|---|
| 2910 | } |
|---|
| 2911 | } |
|---|
| 2912 | |
|---|
| 2913 | newData = newData.concat(newRows); |
|---|
| 2914 | } |
|---|
| 2915 | |
|---|
| 2916 | // Now that we have a new set of joined rows, we need to run through |
|---|
| 2917 | // all of the rows and make sure they all have a unique row ID and |
|---|
| 2918 | // rebuild our dataHash. |
|---|
| 2919 | |
|---|
| 2920 | data = newData; |
|---|
| 2921 | numRows = data.length; |
|---|
| 2922 | |
|---|
| 2923 | for (i = 0; i < numRows; i++) |
|---|
| 2924 | { |
|---|
| 2925 | row = data[i]; |
|---|
| 2926 | row.ds_RowID = i; |
|---|
| 2927 | dataHash[row.ds_RowID] = row; |
|---|
| 2928 | } |
|---|
| 2929 | |
|---|
| 2930 | // We're all done, so stuff the new data and dataHash |
|---|
| 2931 | // back into the base recordSet. |
|---|
| 2932 | |
|---|
| 2933 | rs.data = data; |
|---|
| 2934 | rs.dataHash = dataHash; |
|---|
| 2935 | }; |
|---|
| 2936 | |
|---|
| 2937 | Spry.Data.XMLDataSet.prototype.loadDataIntoDataSet = function(rawDataDoc) |
|---|
| 2938 | { |
|---|
| 2939 | var rs = null; |
|---|
| 2940 | var mainXPath = Spry.Data.Region.processDataRefString(null, this.xpath, this.dataSetsForDataRefStrings); |
|---|
| 2941 | var subPaths = this.subPaths; |
|---|
| 2942 | var suppressColumns = false; |
|---|
| 2943 | |
|---|
| 2944 | if (this.subPaths && this.subPaths.length > 0) |
|---|
| 2945 | { |
|---|
| 2946 | // Some subPaths were specified. Convert any data references in each subPath |
|---|
| 2947 | // to real data. While we're at it, convert any subPaths that are relative |
|---|
| 2948 | // to our main XPath to absolute paths. |
|---|
| 2949 | |
|---|
| 2950 | var processedSubPaths = []; |
|---|
| 2951 | var numSubPaths = subPaths.length; |
|---|
| 2952 | for (var i = 0; i < numSubPaths; i++) |
|---|
| 2953 | { |
|---|
| 2954 | var subPathStr = Spry.Data.Region.processDataRefString(null, subPaths[i], this.dataSetsForDataRefStrings); |
|---|
| 2955 | if (subPathStr.charAt(0) != '/') |
|---|
| 2956 | subPathStr = mainXPath + "/" + subPathStr; |
|---|
| 2957 | processedSubPaths.push(subPathStr); |
|---|
| 2958 | } |
|---|
| 2959 | |
|---|
| 2960 | // We need to add our main XPath to the set of subPaths and generate a path |
|---|
| 2961 | // tree so we can find the XPath to the common parent of all the paths, just |
|---|
| 2962 | // in case the user specified a path that was outside of our main XPath. |
|---|
| 2963 | |
|---|
| 2964 | processedSubPaths.unshift(mainXPath); |
|---|
| 2965 | var commonParent = this.convertXPathsToPathTree(processedSubPaths); |
|---|
| 2966 | |
|---|
| 2967 | // The root node of the resulting path tree should contain the XPath |
|---|
| 2968 | // to the common parent. Make this the XPath we generate our initial |
|---|
| 2969 | // set of rows from so we can group the results of flattening the other |
|---|
| 2970 | // subPaths in predictable/expected manner. |
|---|
| 2971 | |
|---|
| 2972 | mainXPath = commonParent.path; |
|---|
| 2973 | subPaths = commonParent.subPaths; |
|---|
| 2974 | |
|---|
| 2975 | // If the XPath to the common parent we calculated isn't our main XPath |
|---|
| 2976 | // or any of the subPaths specified by the user, it is used purely for |
|---|
| 2977 | // grouping and joining the data we will flatten. We don't want to include |
|---|
| 2978 | // any of the columns for the rows created for the common parent XPath since |
|---|
| 2979 | // the user did not ask for it. |
|---|
| 2980 | |
|---|
| 2981 | suppressColumns = commonParent.xpath ? false : true; |
|---|
| 2982 | } |
|---|
| 2983 | |
|---|
| 2984 | rs = Spry.Utils.getRecordSetFromXMLDoc(rawDataDoc, mainXPath, suppressColumns); |
|---|
| 2985 | |
|---|
| 2986 | if (!rs) |
|---|
| 2987 | { |
|---|
| 2988 | Spry.Debug.reportError("Spry.Data.XMLDataSet.loadDataIntoDataSet() failed to create dataSet '" + this.name + "'for '" + this.xpath + "' - " + this.url + "\n"); |
|---|
| 2989 | return; |
|---|
| 2990 | } |
|---|
| 2991 | |
|---|
| 2992 | // Now that we have our base set of rows, flatten any additional subPaths |
|---|
| 2993 | // specified by the user. |
|---|
| 2994 | |
|---|
| 2995 | this.flattenSubPaths(rs, subPaths); |
|---|
| 2996 | |
|---|
| 2997 | this.doc = rs.xmlDoc; |
|---|
| 2998 | this.data = rs.data; |
|---|
| 2999 | this.dataHash = rs.dataHash; |
|---|
| 3000 | this.dataWasLoaded = (this.doc != null); |
|---|
| 3001 | }; |
|---|
| 3002 | |
|---|
| 3003 | Spry.Data.XMLDataSet.prototype.xhRequestProcessor = function(xhRequest) |
|---|
| 3004 | { |
|---|
| 3005 | // XMLDataSet uses the responseXML from the xhRequest |
|---|
| 3006 | |
|---|
| 3007 | var resp = xhRequest.responseXML; |
|---|
| 3008 | var manualParseRequired = false; |
|---|
| 3009 | |
|---|
| 3010 | if (xhRequest.status != 200) |
|---|
| 3011 | { |
|---|
| 3012 | if (xhRequest.status == 0) |
|---|
| 3013 | { |
|---|
| 3014 | // The page that is attempting to load data was probably loaded with |
|---|
| 3015 | // a file:// url. Mozilla based browsers will actually provide the complete DOM |
|---|
| 3016 | // tree for the data, but IE provides an empty document node so try to parse |
|---|
| 3017 | // the xml text manually to create a dom tree we can use. |
|---|
| 3018 | |
|---|
| 3019 | if (xhRequest.responseText && (!resp || !resp.firstChild)) |
|---|
| 3020 | manualParseRequired = true; |
|---|
| 3021 | } |
|---|
| 3022 | } |
|---|
| 3023 | else if (!resp) |
|---|
| 3024 | { |
|---|
| 3025 | // The server said it sent us data, but for some reason we don't have |
|---|
| 3026 | // an XML DOM document. Some browsers won't auto-create an XML DOM |
|---|
| 3027 | // unless the server used a content-type of "text/xml" or "application/xml". |
|---|
| 3028 | // Try to manually parse the XML string, just in case the server |
|---|
| 3029 | // gave us an unexpected Content-Type. |
|---|
| 3030 | |
|---|
| 3031 | manualParseRequired = true; |
|---|
| 3032 | } |
|---|
| 3033 | |
|---|
| 3034 | if (manualParseRequired) |
|---|
| 3035 | resp = Spry.Utils.stringToXMLDoc(xhRequest.responseText); |
|---|
| 3036 | |
|---|
| 3037 | if (!resp || !resp.firstChild || resp.firstChild.nodeName == "parsererror") |
|---|
| 3038 | return null; |
|---|
| 3039 | |
|---|
| 3040 | return resp; |
|---|
| 3041 | }; |
|---|
| 3042 | |
|---|
| 3043 | Spry.Data.XMLDataSet.prototype.sessionExpiredChecker = function(req) |
|---|
| 3044 | { |
|---|
| 3045 | if (req.xhRequest.responseText == 'session expired') |
|---|
| 3046 | return true; |
|---|
| 3047 | else |
|---|
| 3048 | { |
|---|
| 3049 | if (req.rawData) |
|---|
| 3050 | { |
|---|
| 3051 | var firstChild = req.rawData.documentElement.firstChild; |
|---|
| 3052 | if (firstChild && firstChild.nodeValue == "session expired") |
|---|
| 3053 | return true; |
|---|
| 3054 | } |
|---|
| 3055 | } |
|---|
| 3056 | return false; |
|---|
| 3057 | }; |
|---|
| 3058 | |
|---|
| 3059 | ////////////////////////////////////////////////////////////////////// |
|---|
| 3060 | // |
|---|
| 3061 | // Spry.Data.Region |
|---|
| 3062 | // |
|---|
| 3063 | ////////////////////////////////////////////////////////////////////// |
|---|
| 3064 | |
|---|
| 3065 | Spry.Data.Region = function(regionNode, name, isDetailRegion, data, dataSets, regionStates, regionStateMap, hasBehaviorAttributes) |
|---|
| 3066 | { |
|---|
| 3067 | this.regionNode = regionNode; |
|---|
| 3068 | this.name = name; |
|---|
| 3069 | this.isDetailRegion = isDetailRegion; |
|---|
| 3070 | this.data = data; |
|---|
| 3071 | this.dataSets = dataSets; |
|---|
| 3072 | this.hasBehaviorAttributes = hasBehaviorAttributes; |
|---|
| 3073 | this.tokens = null; |
|---|
| 3074 | this.currentState = null; |
|---|
| 3075 | this.states = { ready: true }; |
|---|
| 3076 | this.stateMap = {}; |
|---|
| 3077 | |
|---|
| 3078 | Spry.Utils.setOptions(this.states, regionStates); |
|---|
| 3079 | Spry.Utils.setOptions(this.stateMap, regionStateMap); |
|---|
| 3080 | |
|---|
| 3081 | // Add the region as an observer to the dataSet! |
|---|
| 3082 | for (var i = 0; i < this.dataSets.length; i++) |
|---|
| 3083 | { |
|---|
| 3084 | var ds = this.dataSets[i]; |
|---|
| 3085 | |
|---|
| 3086 | try |
|---|
| 3087 | { |
|---|
| 3088 | if (ds) |
|---|
| 3089 | ds.addObserver(this); |
|---|
| 3090 | } |
|---|
| 3091 | catch(e) { Spry.Debug.reportError("Failed to add '" + this.name + "' as a dataSet observer!\n"); } |
|---|
| 3092 | } |
|---|
| 3093 | }; // End of Spry.Data.Region() constructor. |
|---|
| 3094 | |
|---|
| 3095 | Spry.Data.Region.hiddenRegionClassName = "SpryHiddenRegion"; |
|---|
| 3096 | Spry.Data.Region.evenRowClassName = "even"; |
|---|
| 3097 | Spry.Data.Region.oddRowClassName = "odd"; |
|---|
| 3098 | Spry.Data.Region.notifiers = {}; |
|---|
| 3099 | Spry.Data.Region.evalScripts = true; |
|---|
| 3100 | |
|---|
| 3101 | Spry.Data.Region.addObserver = function(regionID, observer) |
|---|
| 3102 | { |
|---|
| 3103 | var n = Spry.Data.Region.notifiers[regionID]; |
|---|
| 3104 | if (!n) |
|---|
| 3105 | { |
|---|
| 3106 | n = new Spry.Utils.Notifier(); |
|---|
| 3107 | Spry.Data.Region.notifiers[regionID] = n; |
|---|
| 3108 | } |
|---|
| 3109 | n.addObserver(observer); |
|---|
| 3110 | }; |
|---|
| 3111 | |
|---|
| 3112 | Spry.Data.Region.removeObserver = function(regionID, observer) |
|---|
| 3113 | { |
|---|
| 3114 | var n = Spry.Data.Region.notifiers[regionID]; |
|---|
| 3115 | if (n) |
|---|
| 3116 | n.removeObserver(observer); |
|---|
| 3117 | }; |
|---|
| 3118 | |
|---|
| 3119 | Spry.Data.Region.notifyObservers = function(methodName, region, data) |
|---|
| 3120 | { |
|---|
| 3121 | var n = Spry.Data.Region.notifiers[region.name]; |
|---|
| 3122 | if (n) |
|---|
| 3123 | { |
|---|
| 3124 | var dataObj = {}; |
|---|
| 3125 | if (data && typeof data == "object") |
|---|
| 3126 | dataObj = data; |
|---|
| 3127 | else |
|---|
| 3128 | dataObj.data = data; |
|---|
| 3129 | |
|---|
| 3130 | dataObj.region = region; |
|---|
| 3131 | dataObj.regionID = region.name; |
|---|
| 3132 | dataObj.regionNode = region.regionNode; |
|---|
| 3133 | |
|---|
| 3134 | n.notifyObservers(methodName, dataObj); |
|---|
| 3135 | } |
|---|
| 3136 | }; |
|---|
| 3137 | |
|---|
| 3138 | Spry.Data.Region.RS_Error = 0x01; |
|---|
| 3139 | Spry.Data.Region.RS_LoadingData = 0x02; |
|---|
| 3140 | Spry.Data.Region.RS_PreUpdate = 0x04; |
|---|
| 3141 | Spry.Data.Region.RS_PostUpdate = 0x08; |
|---|
| 3142 | |
|---|
| 3143 | Spry.Data.Region.prototype.getState = function() |
|---|
| 3144 | { |
|---|
| 3145 | return this.currentState; |
|---|
| 3146 | }; |
|---|
| 3147 | |
|---|
| 3148 | Spry.Data.Region.prototype.mapState = function(stateName, newStateName) |
|---|
| 3149 | { |
|---|
| 3150 | this.stateMap[stateName] = newStateName; |
|---|
| 3151 | }; |
|---|
| 3152 | |
|---|
| 3153 | Spry.Data.Region.prototype.getMappedState = function(stateName) |
|---|
| 3154 | { |
|---|
| 3155 | var mappedState = this.stateMap[stateName]; |
|---|
| 3156 | return mappedState ? mappedState : stateName; |
|---|
| 3157 | }; |
|---|
| 3158 | |
|---|
| 3159 | Spry.Data.Region.prototype.setState = function(stateName, suppressNotfications) |
|---|
| 3160 | { |
|---|
| 3161 | var stateObj = { state: stateName, mappedState: this.getMappedState(stateName) }; |
|---|
| 3162 | if (!suppressNotfications) |
|---|
| 3163 | Spry.Data.Region.notifyObservers("onPreStateChange", this, stateObj); |
|---|
| 3164 | |
|---|
| 3165 | this.currentState = stateObj.mappedState ? stateObj.mappedState : stateName; |
|---|
| 3166 | |
|---|
| 3167 | // If the region has content that is specific to this |
|---|
| 3168 | // state, regenerate the region so that its markup is updated. |
|---|
| 3169 | |
|---|
| 3170 | if (this.states[stateName]) |
|---|
| 3171 | { |
|---|
| 3172 | var notificationData = { state: this.currentState }; |
|---|
| 3173 | if (!suppressNotfications) |
|---|
| 3174 | Spry.Data.Region.notifyObservers("onPreUpdate", this, notificationData); |
|---|
| 3175 | |
|---|
| 3176 | // Make the region transform the xml data. The result is |
|---|
| 3177 | // a string that we need to parse and insert into the document. |
|---|
| 3178 | |
|---|
| 3179 | var str = this.transform(); |
|---|
| 3180 | |
|---|
| 3181 | // Clear out any previous transformed content. |
|---|
| 3182 | // this.clearContent(); |
|---|
| 3183 | |
|---|
| 3184 | if (Spry.Data.Region.debug) |
|---|
| 3185 | Spry.Debug.trace("<hr />Generated region markup for '" + this.name + "':<br /><br />" + Spry.Utils.encodeEntities(str)); |
|---|
| 3186 | |
|---|
| 3187 | // Now insert the new transformed content into the document. |
|---|
| 3188 | Spry.Utils.setInnerHTML(this.regionNode, str, !Spry.Data.Region.evalScripts); |
|---|
| 3189 | |
|---|
| 3190 | // Now run through the content looking for attributes |
|---|
| 3191 | // that tell us what behaviors to attach to each element. |
|---|
| 3192 | if (this.hasBehaviorAttributes) |
|---|
| 3193 | this.attachBehaviors(); |
|---|
| 3194 | |
|---|
| 3195 | if (!suppressNotfications) |
|---|
| 3196 | Spry.Data.Region.notifyObservers("onPostUpdate", this, notificationData); |
|---|
| 3197 | } |
|---|
| 3198 | |
|---|
| 3199 | if (!suppressNotfications) |
|---|
| 3200 | Spry.Data.Region.notifyObservers("onPostStateChange", this, stateObj); |
|---|
| 3201 | }; |
|---|
| 3202 | |
|---|
| 3203 | Spry.Data.Region.prototype.getDataSets = function() |
|---|
| 3204 | { |
|---|
| 3205 | return this.dataSets; |
|---|
| 3206 | }; |
|---|
| 3207 | |
|---|
| 3208 | Spry.Data.Region.prototype.addDataSet = function(aDataSet) |
|---|
| 3209 | { |
|---|
| 3210 | if (!aDataSet) |
|---|
| 3211 | return; |
|---|
| 3212 | |
|---|
| 3213 | if (!this.dataSets) |
|---|
| 3214 | this.dataSets = new Array; |
|---|
| 3215 | |
|---|
| 3216 | // Check to see if the data set is already in our list. |
|---|
| 3217 | |
|---|
| 3218 | for (var i = 0; i < this.dataSets.length; i++) |
|---|
| 3219 | { |
|---|
| 3220 | if (this.dataSets[i] == aDataSet) |
|---|
| 3221 | return; // It's already in our list! |
|---|
| 3222 | } |
|---|
| 3223 | |
|---|
| 3224 | this.dataSets.push(aDataSet); |
|---|
| 3225 | aDataSet.addObserver(this); |
|---|
| 3226 | }; |
|---|
| 3227 | |
|---|
| 3228 | Spry.Data.Region.prototype.removeDataSet = function(aDataSet) |
|---|
| 3229 | { |
|---|
| 3230 | if (!aDataSet || this.dataSets) |
|---|
| 3231 | return; |
|---|
| 3232 | |
|---|
| 3233 | for (var i = 0; i < this.dataSets.length; i++) |
|---|
| 3234 | { |
|---|
| 3235 | if (this.dataSets[i] == aDataSet) |
|---|
| 3236 | { |
|---|
| 3237 | this.dataSets.splice(i, 1); |
|---|
| 3238 | aDataSet.removeObserver(this); |
|---|
| 3239 | return; |
|---|
| 3240 | } |
|---|
| 3241 | } |
|---|
| 3242 | }; |
|---|
| 3243 | |
|---|
| 3244 | Spry.Data.Region.prototype.onPreLoad = function(dataSet) |
|---|
| 3245 | { |
|---|
| 3246 | if (this.currentState != "loading") |
|---|
| 3247 | this.setState("loading"); |
|---|
| 3248 | }; |
|---|
| 3249 | |
|---|
| 3250 | Spry.Data.Region.prototype.onLoadError = function(dataSet) |
|---|
| 3251 | { |
|---|
| 3252 | if (this.currentState != "error") |
|---|
| 3253 | this.setState("error"); |
|---|
| 3254 | Spry.Data.Region.notifyObservers("onError", this); |
|---|
| 3255 | }; |
|---|
| 3256 | |
|---|
| 3257 | Spry.Data.Region.prototype.onSessionExpired = function(dataSet) |
|---|
| 3258 | { |
|---|
| 3259 | if (this.currentState != "expired") |
|---|
| 3260 | this.setState("expired"); |
|---|
| 3261 | Spry.Data.Region.notifyObservers("onExpired", this); |
|---|
| 3262 | }; |
|---|
| 3263 | |
|---|
| 3264 | Spry.Data.Region.prototype.onCurrentRowChanged = function(dataSet, data) |
|---|
| 3265 | { |
|---|
| 3266 | if (this.isDetailRegion) |
|---|
| 3267 | this.updateContent(); |
|---|
| 3268 | }; |
|---|
| 3269 | |
|---|
| 3270 | Spry.Data.Region.prototype.onPostSort = function(dataSet, data) |
|---|
| 3271 | { |
|---|
| 3272 | this.updateContent(); |
|---|
| 3273 | }; |
|---|
| 3274 | |
|---|
| 3275 | Spry.Data.Region.prototype.onDataChanged = function(dataSet, data) |
|---|
| 3276 | { |
|---|
| 3277 | this.updateContent(); |
|---|
| 3278 | }; |
|---|
| 3279 | |
|---|
| 3280 | Spry.Data.Region.enableBehaviorAttributes = true; |
|---|
| 3281 | Spry.Data.Region.behaviorAttrs = {}; |
|---|
| 3282 | |
|---|
| 3283 | Spry.Data.Region.behaviorAttrs["spry:select"] = |
|---|
| 3284 | { |
|---|
| 3285 | attach: function(rgn, node, value) |
|---|
| 3286 | { |
|---|
| 3287 | var selectGroupName = null; |
|---|
| 3288 | try { selectGroupName = node.attributes.getNamedItem("spry:selectgroup").value; } catch (e) {} |
|---|
| 3289 | if (!selectGroupName) |
|---|
| 3290 | selectGroupName = "default"; |
|---|
| 3291 | |
|---|
| 3292 | Spry.Utils.addEventListener(node, "click", function(event) { Spry.Utils.SelectionManager.select(selectGroupName, node, value); }, false); |
|---|
| 3293 | |
|---|
| 3294 | if (node.attributes.getNamedItem("spry:selected")) |
|---|
| 3295 | Spry.Utils.SelectionManager.select(selectGroupName, node, value); |
|---|
| 3296 | } |
|---|
| 3297 | }; |
|---|
| 3298 | |
|---|
| 3299 | Spry.Data.Region.behaviorAttrs["spry:hover"] = |
|---|
| 3300 | { |
|---|
| 3301 | attach: function(rgn, node, value) |
|---|
| 3302 | { |
|---|
| 3303 | Spry.Utils.addEventListener(node, "mouseover", function(event){ Spry.Utils.addClassName(node, value); }, false); |
|---|
| 3304 | Spry.Utils.addEventListener(node, "mouseout", function(event){ Spry.Utils.removeClassName(node, value); }, false); |
|---|
| 3305 | } |
|---|
| 3306 | }; |
|---|
| 3307 | |
|---|
| 3308 | Spry.Data.Region.setUpRowNumberForEvenOddAttr = function(node, attr, value, rowNumAttrName) |
|---|
| 3309 | { |
|---|
| 3310 | // The format for the spry:even and spry:odd attributes are as follows: |
|---|
| 3311 | // |
|---|
| 3312 | // <div spry:even="dataSetName cssEvenClassName" spry:odd="dataSetName cssOddClassName"> |
|---|
| 3313 | // |
|---|
| 3314 | // The dataSetName is optional, and if not specified, the first data set |
|---|
| 3315 | // listed for the region is used. |
|---|
| 3316 | // |
|---|
| 3317 | // cssEvenClassName and cssOddClassName are required and *must* be specified. They can be |
|---|
| 3318 | // any user defined CSS class name. |
|---|
| 3319 | |
|---|
| 3320 | if (!value) |
|---|
| 3321 | { |
|---|
| 3322 | Spry.Debug.showError("The " + attr + " attribute requires a CSS class name as its value!"); |
|---|
| 3323 | node.attributes.removeNamedItem(attr); |
|---|
| 3324 | return; |
|---|
| 3325 | } |
|---|
| 3326 | |
|---|
| 3327 | var dsName = ""; |
|---|
| 3328 | var valArr = value.split(/\s/); |
|---|
| 3329 | if (valArr.length > 1) |
|---|
| 3330 | { |
|---|
| 3331 | // Extract out the data set name and reset the attribute so |
|---|
| 3332 | // that it only contains the CSS class name to use. |
|---|
| 3333 | |
|---|
| 3334 | dsName = valArr[0]; |
|---|
| 3335 | node.setAttribute(attr, valArr[1]); |
|---|
| 3336 | } |
|---|
| 3337 | |
|---|
| 3338 | // Tag the node with an attribute that will allow us to fetch the row |
|---|
| 3339 | // number used when it is written out during the re-generation process. |
|---|
| 3340 | |
|---|
| 3341 | node.setAttribute(rowNumAttrName, "{" + (dsName ? (dsName + "::") : "") + "ds_RowNumber}"); |
|---|
| 3342 | }; |
|---|
| 3343 | |
|---|
| 3344 | Spry.Data.Region.behaviorAttrs["spry:even"] = |
|---|
| 3345 | { |
|---|
| 3346 | setup: function(node, value) |
|---|
| 3347 | { |
|---|
| 3348 | Spry.Data.Region.setUpRowNumberForEvenOddAttr(node, "spry:even", value, "spryevenrownumber"); |
|---|
| 3349 | }, |
|---|
| 3350 | |
|---|
| 3351 | attach: function(rgn, node, value) |
|---|
| 3352 | { |
|---|
| 3353 | if (value) |
|---|
| 3354 | { |
|---|
| 3355 | rowNumAttr = node.attributes.getNamedItem("spryevenrownumber"); |
|---|
| 3356 | if (rowNumAttr && rowNumAttr.value) |
|---|
| 3357 | { |
|---|
| 3358 | var rowNum = parseInt(rowNumAttr.value); |
|---|
| 3359 | if (rowNum % 2) |
|---|
| 3360 | Spry.Utils.addClassName(node, value); |
|---|
| 3361 | } |
|---|
| 3362 | } |
|---|
| 3363 | node.removeAttribute("spry:even"); |
|---|
| 3364 | node.removeAttribute("spryevenrownumber"); |
|---|
| 3365 | } |
|---|
| 3366 | }; |
|---|
| 3367 | |
|---|
| 3368 | Spry.Data.Region.behaviorAttrs["spry:odd"] = |
|---|
| 3369 | { |
|---|
| 3370 | setup: function(node, value) |
|---|
| 3371 | { |
|---|
| 3372 | Spry.Data.Region.setUpRowNumberForEvenOddAttr(node, "spry:odd", value, "spryoddrownumber"); |
|---|
| 3373 | }, |
|---|
| 3374 | |
|---|
| 3375 | attach: function(rgn, node, value) |
|---|
| 3376 | { |
|---|
| 3377 | if (value) |
|---|
| 3378 | { |
|---|
| 3379 | rowNumAttr = node.attributes.getNamedItem("spryoddrownumber"); |
|---|
| 3380 | if (rowNumAttr && rowNumAttr.value) |
|---|
| 3381 | { |
|---|
| 3382 | var rowNum = parseInt(rowNumAttr.value); |
|---|
| 3383 | if (rowNum % 2 == 0) |
|---|
| 3384 | Spry.Utils.addClassName(node, value); |
|---|
| 3385 | } |
|---|
| 3386 | } |
|---|
| 3387 | node.removeAttribute("spry:odd"); |
|---|
| 3388 | node.removeAttribute("spryoddrownumber"); |
|---|
| 3389 | } |
|---|
| 3390 | }; |
|---|
| 3391 | |
|---|
| 3392 | Spry.Data.Region.setRowAttrClickHandler = function(node, dsName, rowAttr, funcName) |
|---|
| 3393 | { |
|---|
| 3394 | if (dsName) |
|---|
| 3395 | { |
|---|
| 3396 | var ds = null; |
|---|
| 3397 | try { ds = Spry.Utils.eval(dsName); } catch(e) { ds = null; }; |
|---|
| 3398 | if (ds) |
|---|
| 3399 | { |
|---|
| 3400 | rowIDAttr = node.attributes.getNamedItem(rowAttr); |
|---|
| 3401 | if (rowIDAttr) |
|---|
| 3402 | { |
|---|
| 3403 | var rowAttrVal = rowIDAttr.value; |
|---|
| 3404 | if (rowAttrVal) |
|---|
| 3405 | Spry.Utils.addEventListener(node, "click", function(event){ ds[funcName](rowAttrVal); }, false); |
|---|
| 3406 | } |
|---|
| 3407 | } |
|---|
| 3408 | } |
|---|
| 3409 | }; |
|---|
| 3410 | |
|---|
| 3411 | Spry.Data.Region.behaviorAttrs["spry:setrow"] = |
|---|
| 3412 | { |
|---|
| 3413 | setup: function(node, value) |
|---|
| 3414 | { |
|---|
| 3415 | if (!value) |
|---|
| 3416 | { |
|---|
| 3417 | Spry.Debug.reportError("The spry:setrow attribute requires a data set name as its value!"); |
|---|
| 3418 | node.removeAttribute("spry:setrow"); |
|---|
| 3419 | return; |
|---|
| 3420 | } |
|---|
| 3421 | |
|---|
| 3422 | // Tag the node with an attribute that will allow us to fetch the id of the |
|---|
| 3423 | // row used when it is written out during the re-generation process. |
|---|
| 3424 | |
|---|
| 3425 | node.setAttribute("spryrowid", "{" + value + "::ds_RowID}"); |
|---|
| 3426 | }, |
|---|
| 3427 | |
|---|
| 3428 | attach: function(rgn, node, value) |
|---|
| 3429 | { |
|---|
| 3430 | Spry.Data.Region.setRowAttrClickHandler(node, value, "spryrowid", "setCurrentRow"); |
|---|
| 3431 | node.removeAttribute("spry:setrow"); |
|---|
| 3432 | node.removeAttribute("spryrowid"); |
|---|
| 3433 | } |
|---|
| 3434 | }; |
|---|
| 3435 | |
|---|
| 3436 | Spry.Data.Region.behaviorAttrs["spry:setrownumber"] = |
|---|
| 3437 | { |
|---|
| 3438 | setup: function(node, value) |
|---|
| 3439 | { |
|---|
| 3440 | if (!value) |
|---|
| 3441 | { |
|---|
| 3442 | Spry.Debug.reportError("The spry:setrownumber attribute requires a data set name as its value!"); |
|---|
| 3443 | node.removeAttribute("spry:setrownumber"); |
|---|
| 3444 | return; |
|---|
| 3445 | } |
|---|
| 3446 | |
|---|
| 3447 | // Tag the node with an attribute that will allow us to fetch the row number |
|---|
| 3448 | // of the row used when it is written out during the re-generation process. |
|---|
| 3449 | |
|---|
| 3450 | node.setAttribute("spryrownumber", "{" + value + "::ds_RowID}"); |
|---|
| 3451 | }, |
|---|
| 3452 | |
|---|
| 3453 | attach: function(rgn, node, value) |
|---|
| 3454 | { |
|---|
| 3455 | Spry.Data.Region.setRowAttrClickHandler(node, value, "spryrownumber", "setCurrentRowNumber"); |
|---|
| 3456 | node.removeAttribute("spry:setrownumber"); |
|---|
| 3457 | node.removeAttribute("spryrownumber"); |
|---|
| 3458 | } |
|---|
| 3459 | }; |
|---|
| 3460 | |
|---|
| 3461 | Spry.Data.Region.behaviorAttrs["spry:sort"] = |
|---|
| 3462 | { |
|---|
| 3463 | attach: function(rgn, node, value) |
|---|
| 3464 | { |
|---|
| 3465 | if (!value) |
|---|
| 3466 | return; |
|---|
| 3467 | |
|---|
| 3468 | // The format of a spry:sort attribute is as follows: |
|---|
| 3469 | // |
|---|
| 3470 | // <div spry:sort="dataSetName column1Name column2Name ... sortOrderName"> |
|---|
| 3471 | // |
|---|
| 3472 | // The dataSetName and sortOrderName are optional, but when specified, they |
|---|
| 3473 | // must appear in the order mentioned above. If the dataSetName is not specified, |
|---|
| 3474 | // the first data set listed for the region is used. If the sortOrderName is not |
|---|
| 3475 | // specified, the sort defaults to "toggle". |
|---|
| 3476 | // |
|---|
| 3477 | // The user *must* specify at least one column name. |
|---|
| 3478 | |
|---|
| 3479 | var ds = rgn.getDataSets()[0]; |
|---|
| 3480 | var sortOrder = "toggle"; |
|---|
| 3481 | |
|---|
| 3482 | var colArray = value.split(/\s/); |
|---|
| 3483 | if (colArray.length > 1) |
|---|
| 3484 | { |
|---|
| 3485 | // Check the first string in the attribute to see if a data set was |
|---|
| 3486 | // specified. If so, make sure we use it for the sort. |
|---|
| 3487 | |
|---|
| 3488 | try |
|---|
| 3489 | { |
|---|
| 3490 | var specifiedDS = eval(colArray[0]); |
|---|
| 3491 | if (specifiedDS && (typeof specifiedDS) == "object") |
|---|
| 3492 | { |
|---|
| 3493 | ds = specifiedDS; |
|---|
| 3494 | colArray.shift(); |
|---|
| 3495 | } |
|---|
| 3496 | |
|---|
| 3497 | } catch(e) {} |
|---|
| 3498 | |
|---|
| 3499 | // Check to see if the last string in the attribute is the name of |
|---|
| 3500 | // a sort order. If so, use that sort order during the sort. |
|---|
| 3501 | |
|---|
| 3502 | if (colArray.length > 1) |
|---|
| 3503 | { |
|---|
| 3504 | var str = colArray[colArray.length - 1]; |
|---|
| 3505 | if (str == "ascending" || str == "descending" || str == "toggle") |
|---|
| 3506 | { |
|---|
| 3507 | sortOrder = str; |
|---|
| 3508 | colArray.pop(); |
|---|
| 3509 | } |
|---|
| 3510 | } |
|---|
| 3511 | } |
|---|
| 3512 | |
|---|
| 3513 | // If we have a data set and some column names, add a non-destructive |
|---|
| 3514 | // onclick handler that will perform a toggle sort on the data set. |
|---|
| 3515 | |
|---|
| 3516 | if (ds && colArray.length > 0) |
|---|
| 3517 | Spry.Utils.addEventListener(node, "click", function(event){ ds.sort(colArray, sortOrder); }, false); |
|---|
| 3518 | |
|---|
| 3519 | node.removeAttribute("spry:sort"); |
|---|
| 3520 | } |
|---|
| 3521 | }; |
|---|
| 3522 | |
|---|
| 3523 | Spry.Data.Region.prototype.attachBehaviors = function() |
|---|
| 3524 | { |
|---|
| 3525 | var rgn = this; |
|---|
| 3526 | Spry.Utils.getNodesByFunc(this.regionNode, function(node) |
|---|
| 3527 | { |
|---|
| 3528 | if (!node || node.nodeType != 1 /* Node.ELEMENT_NODE */) |
|---|
| 3529 | return false; |
|---|
| 3530 | try |
|---|
| 3531 | { |
|---|
| 3532 | var bAttrs = Spry.Data.Region.behaviorAttrs; |
|---|
| 3533 | for (var bAttrName in bAttrs) |
|---|
| 3534 | { |
|---|
| 3535 | var attr = node.attributes.getNamedItem(bAttrName); |
|---|
| 3536 | if (attr) |
|---|
| 3537 | { |
|---|
| 3538 | var behavior = bAttrs[bAttrName]; |
|---|
| 3539 | if (behavior && behavior.attach) |
|---|
| 3540 | behavior.attach(rgn, node, attr.value); |
|---|
| 3541 | } |
|---|
| 3542 | } |
|---|
| 3543 | } catch(e) {} |
|---|
| 3544 | |
|---|
| 3545 | return false; |
|---|
| 3546 | }); |
|---|
| 3547 | }; |
|---|
| 3548 | |
|---|
| 3549 | Spry.Data.Region.prototype.updateContent = function() |
|---|
| 3550 | { |
|---|
| 3551 | var allDataSetsReady = true; |
|---|
| 3552 | |
|---|
| 3553 | var dsArray = this.getDataSets(); |
|---|
| 3554 | |
|---|
| 3555 | if (!dsArray || dsArray.length < 1) |
|---|
| 3556 | { |
|---|
| 3557 | Spry.Debug.reportError("updateContent(): Region '" + this.name + "' has no data set!\n"); |
|---|
| 3558 | return; |
|---|
| 3559 | } |
|---|
| 3560 | |
|---|
| 3561 | for (var i = 0; i < dsArray.length; i++) |
|---|
| 3562 | { |
|---|
| 3563 | var ds = dsArray[i]; |
|---|
| 3564 | |
|---|
| 3565 | if (ds) |
|---|
| 3566 | { |
|---|
| 3567 | if (ds.getLoadDataRequestIsPending()) |
|---|
| 3568 | allDataSetsReady = false; |
|---|
| 3569 | else if (!ds.getDataWasLoaded()) |
|---|
| 3570 | { |
|---|
| 3571 | // Kick off the loading of the data if it hasn't happened yet. |
|---|
| 3572 | ds.loadData(); |
|---|
| 3573 | allDataSetsReady = false; |
|---|
| 3574 | } |
|---|
| 3575 | } |
|---|
| 3576 | } |
|---|
| 3577 | |
|---|
| 3578 | if (!allDataSetsReady) |
|---|
| 3579 | { |
|---|
| 3580 | Spry.Data.Region.notifyObservers("onLoadingData", this); |
|---|
| 3581 | |
|---|
| 3582 | // Just return, this method will get called again automatically |
|---|
| 3583 | // as each data set load completes! |
|---|
| 3584 | return; |
|---|
| 3585 | } |
|---|
| 3586 | |
|---|
| 3587 | this.setState("ready"); |
|---|
| 3588 | }; |
|---|
| 3589 | |
|---|
| 3590 | Spry.Data.Region.prototype.clearContent = function() |
|---|
| 3591 | { |
|---|
| 3592 | this.regionNode.innerHTML = ""; |
|---|
| 3593 | }; |
|---|
| 3594 | |
|---|
| 3595 | Spry.Data.Region.processContentPI = function(inStr) |
|---|
| 3596 | { |
|---|
| 3597 | var outStr = ""; |
|---|
| 3598 | var regexp = /<!--\s*<\/?spry:content\s*[^>]*>\s*-->/mg; |
|---|
| 3599 | var searchStartIndex = 0; |
|---|
| 3600 | var processingContentTag = 0; |
|---|
| 3601 | |
|---|
| 3602 | while (inStr.length) |
|---|
| 3603 | { |
|---|
| 3604 | var results = regexp.exec(inStr); |
|---|
| 3605 | if (!results || !results[0]) |
|---|
| 3606 | { |
|---|
| 3607 | outStr += inStr.substr(searchStartIndex, inStr.length - searchStartIndex); |
|---|
| 3608 | break; |
|---|
| 3609 | } |
|---|
| 3610 | |
|---|
| 3611 | if (!processingContentTag && results.index != searchStartIndex) |
|---|
| 3612 | { |
|---|
| 3613 | // We found a match but it's not at the start of the inStr. |
|---|
| 3614 | // Create a string token for everything that precedes the match. |
|---|
| 3615 | outStr += inStr.substr(searchStartIndex, results.index - searchStartIndex); |
|---|
| 3616 | } |
|---|
| 3617 | |
|---|
| 3618 | if (results[0].search(/<\//) != -1) |
|---|
| 3619 | { |
|---|
| 3620 | --processingContentTag; |
|---|
| 3621 | if (processingContentTag) |
|---|
| 3622 | Spry.Debug.reportError("Nested spry:content regions are not allowed!\n"); |
|---|
| 3623 | } |
|---|
| 3624 | else |
|---|
| 3625 | { |
|---|
| 3626 | ++processingContentTag; |
|---|
| 3627 | var dataRefStr = results[0].replace(/.*\bdataref="/, ""); |
|---|
| 3628 | outStr += dataRefStr.replace(/".*$/, ""); |
|---|
| 3629 | } |
|---|
| 3630 | |
|---|
| 3631 | searchStartIndex = regexp.lastIndex; |
|---|
| 3632 | } |
|---|
| 3633 | |
|---|
| 3634 | return outStr; |
|---|
| 3635 | } |
|---|
| 3636 | |
|---|
| 3637 | Spry.Data.Region.prototype.tokenizeData = function(dataStr) |
|---|
| 3638 | { |
|---|
| 3639 | // If there is no data, there's nothing to do. |
|---|
| 3640 | if (!dataStr) |
|---|
| 3641 | return null; |
|---|
| 3642 | |
|---|
| 3643 | var rootToken = new Spry.Data.Region.Token(Spry.Data.Region.Token.LIST_TOKEN, null, null, null); |
|---|
| 3644 | var tokenStack = new Array; |
|---|
| 3645 | var parseStr = Spry.Data.Region.processContentPI(dataStr); |
|---|
| 3646 | |
|---|
| 3647 | tokenStack.push(rootToken); |
|---|
| 3648 | |
|---|
| 3649 | // Create a regular expression that will match one of the following: |
|---|
| 3650 | // |
|---|
| 3651 | // <spry:repeat select="regionName" test="true"> |
|---|
| 3652 | // </spry:repeat> |
|---|
| 3653 | // {valueReference} |
|---|
| 3654 | var regexp = /((<!--\s*){0,1}<\/{0,1}spry:[^>]+>(\s*-->){0,1})|((\{|%7[bB])[^\}\s%]+(\}|%7[dD]))/mg; |
|---|
| 3655 | var searchStartIndex = 0; |
|---|
| 3656 | |
|---|
| 3657 | while(parseStr.length) |
|---|
| 3658 | { |
|---|
| 3659 | var results = regexp.exec(parseStr); |
|---|
| 3660 | var token = null; |
|---|
| 3661 | |
|---|
| 3662 | if (!results || !results[0]) |
|---|
| 3663 | { |
|---|
| 3664 | // If we get here, the rest of the parseStr should be |
|---|
| 3665 | // just a plain string. Create a token for it and then |
|---|
| 3666 | // break out of the list. |
|---|
| 3667 | var str = parseStr.substr(searchStartIndex, parseStr.length - searchStartIndex); |
|---|
| 3668 | token = new Spry.Data.Region.Token(Spry.Data.Region.Token.STRING_TOKEN, null, str, str); |
|---|
| 3669 | tokenStack[tokenStack.length - 1].addChild(token); |
|---|
| 3670 | break; |
|---|
| 3671 | } |
|---|
| 3672 | |
|---|
| 3673 | if (results.index != searchStartIndex) |
|---|
| 3674 | { |
|---|
| 3675 | // We found a match but it's not at the start of the parseStr. |
|---|
| 3676 | // Create a string token for everything that precedes the match. |
|---|
| 3677 | var str = parseStr.substr(searchStartIndex, results.index - searchStartIndex); |
|---|
| 3678 | token = new Spry.Data.Region.Token(Spry.Data.Region.Token.STRING_TOKEN, null, str, str); |
|---|
| 3679 | tokenStack[tokenStack.length - 1].addChild(token); |
|---|
| 3680 | } |
|---|
| 3681 | |
|---|
| 3682 | // We found a string that needs to be turned into a token. Create a token |
|---|
| 3683 | // for it and then update parseStr for the next iteration. |
|---|
| 3684 | if (results[0].search(/^({|%7[bB])/) != -1 /* results[0].charAt(0) == '{' */) |
|---|
| 3685 | { |
|---|
| 3686 | var valueName = results[0]; |
|---|
| 3687 | var regionStr = results[0]; |
|---|
| 3688 | |
|---|
| 3689 | // Strip off brace and url encode brace chars inside the valueName. |
|---|
| 3690 | |
|---|
| 3691 | valueName = valueName.replace(/^({|%7[bB])/, ""); |
|---|
| 3692 | valueName = valueName.replace(/(}|%7[dD])$/, ""); |
|---|
| 3693 | |
|---|
| 3694 | // Check to see if our value begins with the name of a data set. |
|---|
| 3695 | // For example: {dataSet:tokenValue}. If it is, we need to save |
|---|
| 3696 | // the data set name so we know which data set to use to get the |
|---|
| 3697 | // value for the token during the region transform. |
|---|
| 3698 | |
|---|
| 3699 | var dataSetName = null; |
|---|
| 3700 | var splitArray = valueName.split(/::/); |
|---|
| 3701 | |
|---|
| 3702 | if (splitArray.length > 1) |
|---|
| 3703 | { |
|---|
| 3704 | dataSetName = splitArray[0]; |
|---|
| 3705 | valueName = splitArray[1]; |
|---|
| 3706 | } |
|---|
| 3707 | |
|---|
| 3708 | // Convert any url encoded braces to regular brace chars. |
|---|
| 3709 | |
|---|
| 3710 | regionStr = regionStr.replace(/^%7[bB]/, "{"); |
|---|
| 3711 | regionStr = regionStr.replace(/%7[dD]$/, "}"); |
|---|
| 3712 | |
|---|
| 3713 | // Now create a token for the placeholder. |
|---|
| 3714 | |
|---|
| 3715 | token = new Spry.Data.Region.Token(Spry.Data.Region.Token.VALUE_TOKEN, dataSetName, valueName, new String(regionStr)); |
|---|
| 3716 | tokenStack[tokenStack.length - 1].addChild(token); |
|---|
| 3717 | } |
|---|
| 3718 | else if (results[0].charAt(0) == '<') |
|---|
| 3719 | { |
|---|
| 3720 | // Extract out the name of the processing instruction. |
|---|
| 3721 | var piName = results[0].replace(/^(<!--\s*){0,1}<\/?/, ""); |
|---|
| 3722 | piName = piName.replace(/>(\s*-->){0,1}|\s.*$/, ""); |
|---|
| 3723 | |
|---|
| 3724 | if (results[0].search(/<\//) != -1 /* results[0].charAt(1) == '/' */) |
|---|
| 3725 | { |
|---|
| 3726 | // We found a processing instruction close tag. Pop the top of the |
|---|
| 3727 | // token stack! |
|---|
| 3728 | // |
|---|
| 3729 | // XXX: We need to make sure that the close tag name matches the one |
|---|
| 3730 | // on the top of the token stack! |
|---|
| 3731 | if (tokenStack[tokenStack.length - 1].tokenType != Spry.Data.Region.Token.PROCESSING_INSTRUCTION_TOKEN) |
|---|
| 3732 | { |
|---|
| 3733 | Spry.Debug.reportError("Invalid processing instruction close tag: " + piName + " -- " + results[0] + "\n"); |
|---|
| 3734 | return null; |
|---|
| 3735 | } |
|---|
| 3736 | |
|---|
| 3737 | tokenStack.pop(); |
|---|
| 3738 | } |
|---|
| 3739 | else |
|---|
| 3740 | { |
|---|
| 3741 | // Create the processing instruction token, add it as a child of the token |
|---|
| 3742 | // at the top of the token stack, and then push it on the stack so that it |
|---|
| 3743 | // becomes the parent of any tokens between it and its close tag. |
|---|
| 3744 | |
|---|
| 3745 | var piDesc = Spry.Data.Region.PI.instructions[piName]; |
|---|
| 3746 | |
|---|
| 3747 | if (piDesc) |
|---|
| 3748 | { |
|---|
| 3749 | var dataSet = null; |
|---|
| 3750 | |
|---|
| 3751 | var selectedDataSetName = ""; |
|---|
| 3752 | if (results[0].search(/^.*\bselect=\"/) != -1) |
|---|
| 3753 | { |
|---|
| 3754 | selectedDataSetName = results[0].replace(/^.*\bselect=\"/, ""); |
|---|
| 3755 | selectedDataSetName = selectedDataSetName.replace(/".*$/, ""); |
|---|
| 3756 | |
|---|
| 3757 | if (selectedDataSetName) |
|---|
| 3758 | { |
|---|
| 3759 | try |
|---|
| 3760 | { |
|---|
| 3761 | dataSet = eval(selectedDataSetName); |
|---|
| 3762 | } |
|---|
| 3763 | catch (e) |
|---|
| 3764 | { |
|---|
| 3765 | Spry.Debug.reportError("Caught exception in tokenizeData() while trying to retrieve data set (" + selectedDataSetName + "): " + e + "\n"); |
|---|
| 3766 | dataSet = null; |
|---|
| 3767 | selectedDataSetName = ""; |
|---|
| 3768 | } |
|---|
| 3769 | } |
|---|
| 3770 | } |
|---|
| 3771 | |
|---|
| 3772 | // Check if the repeat has a test attribute. |
|---|
| 3773 | var jsExpr = null; |
|---|
| 3774 | if (results[0].search(/^.*\btest=\"/) != -1) |
|---|
| 3775 | { |
|---|
| 3776 | jsExpr = results[0].replace(/^.*\btest=\"/, ""); |
|---|
| 3777 | jsExpr = jsExpr.replace(/".*$/, ""); |
|---|
| 3778 | jsExpr = Spry.Utils.decodeEntities(jsExpr); |
|---|
| 3779 | } |
|---|
| 3780 | |
|---|
| 3781 | // Check if the instruction has a state name specified. |
|---|
| 3782 | var regionState = null; |
|---|
| 3783 | if (results[0].search(/^.*\bname=\"/) != -1) |
|---|
| 3784 | { |
|---|
| 3785 | regionState = results[0].replace(/^.*\bname=\"/, ""); |
|---|
| 3786 | regionState = regionState.replace(/".*$/, ""); |
|---|
| 3787 | regionState = Spry.Utils.decodeEntities(regionState); |
|---|
| 3788 | } |
|---|
| 3789 | |
|---|
| 3790 | var piData = new Spry.Data.Region.Token.PIData(piName, selectedDataSetName, jsExpr, regionState); |
|---|
| 3791 | |
|---|
| 3792 | token = new Spry.Data.Region.Token(Spry.Data.Region.Token.PROCESSING_INSTRUCTION_TOKEN, dataSet, piData, new String(results[0])); |
|---|
| 3793 | |
|---|
| 3794 | tokenStack[tokenStack.length - 1].addChild(token); |
|---|
| 3795 | tokenStack.push(token); |
|---|
| 3796 | } |
|---|
| 3797 | else |
|---|
| 3798 | { |
|---|
| 3799 | Spry.Debug.reportError("Unsupported region processing instruction: " + results[0] + "\n"); |
|---|
| 3800 | return null; |
|---|
| 3801 | } |
|---|
| 3802 | } |
|---|
| 3803 | } |
|---|
| 3804 | else |
|---|
| 3805 | { |
|---|
| 3806 | Spry.Debug.reportError("Invalid region token: " + results[0] + "\n"); |
|---|
| 3807 | return null; |
|---|
| 3808 | } |
|---|
| 3809 | |
|---|
| 3810 | searchStartIndex = regexp.lastIndex; |
|---|
| 3811 | } |
|---|
| 3812 | |
|---|
| 3813 | return rootToken; |
|---|
| 3814 | }; |
|---|
| 3815 | |
|---|
| 3816 | Spry.Data.Region.prototype.processTokenChildren = function(outputArr, token, processContext) |
|---|
| 3817 | { |
|---|
| 3818 | var children = token.children; |
|---|
| 3819 | var len = children.length; |
|---|
| 3820 | |
|---|
| 3821 | for (var i = 0; i < len; i++) |
|---|
| 3822 | this.processTokens(outputArr, children[i], processContext); |
|---|
| 3823 | }; |
|---|
| 3824 | |
|---|
| 3825 | Spry.Data.Region.prototype.processTokens = function(outputArr, token, processContext) |
|---|
| 3826 | { |
|---|
| 3827 | var i = 0; |
|---|
| 3828 | |
|---|
| 3829 | switch(token.tokenType) |
|---|
| 3830 | { |
|---|
| 3831 | case Spry.Data.Region.Token.LIST_TOKEN: |
|---|
| 3832 | this.processTokenChildren(outputArr, token, processContext); |
|---|
| 3833 | break; |
|---|
| 3834 | case Spry.Data.Region.Token.STRING_TOKEN: |
|---|
| 3835 | outputArr.push(token.data); |
|---|
| 3836 | break; |
|---|
| 3837 | case Spry.Data.Region.Token.PROCESSING_INSTRUCTION_TOKEN: |
|---|
| 3838 | if (token.data.name == "spry:repeat") |
|---|
| 3839 | { |
|---|
| 3840 | var dataSet = null; |
|---|
| 3841 | |
|---|
| 3842 | if (token.dataSet) |
|---|
| 3843 | dataSet = token.dataSet; |
|---|
| 3844 | else |
|---|
| 3845 | dataSet = this.dataSets[0]; |
|---|
| 3846 | |
|---|
| 3847 | if (dataSet) |
|---|
| 3848 | { |
|---|
| 3849 | var dsContext = processContext.getDataSetContext(dataSet); |
|---|
| 3850 | if (!dsContext) |
|---|
| 3851 | { |
|---|
| 3852 | Spry.Debug.reportError("processTokens() failed to get a data set context!\n"); |
|---|
| 3853 | break; |
|---|
| 3854 | } |
|---|
| 3855 | |
|---|
| 3856 | dsContext.pushState(); |
|---|
| 3857 | |
|---|
| 3858 | var dataSetRows = dsContext.getData(); |
|---|
| 3859 | var numRows = dataSetRows.length; |
|---|
| 3860 | for (i = 0; i < numRows; i++) |
|---|
| 3861 | { |
|---|
| 3862 | dsContext.setRowIndex(i); |
|---|
| 3863 | var testVal = true; |
|---|
| 3864 | if (token.data.jsExpr) |
|---|
| 3865 | { |
|---|
| 3866 | var jsExpr = Spry.Data.Region.processDataRefString(processContext, token.data.jsExpr, null, true); |
|---|
| 3867 | try { testVal = Spry.Utils.eval(jsExpr); } |
|---|
| 3868 | catch(e) |
|---|
| 3869 | { |
|---|
| 3870 | Spry.Debug.trace("Caught exception in Spry.Data.Region.prototype.processTokens while evaluating: " + jsExpr + "\n Exception:" + e + "\n"); |
|---|
| 3871 | testVal = true; |
|---|
| 3872 | } |
|---|
| 3873 | } |
|---|
| 3874 | |
|---|
| 3875 | if (testVal) |
|---|
| 3876 | this.processTokenChildren(outputArr, token, processContext); |
|---|
| 3877 | } |
|---|
| 3878 | dsContext.popState(); |
|---|
| 3879 | } |
|---|
| 3880 | } |
|---|
| 3881 | else if (token.data.name == "spry:if") |
|---|
| 3882 | { |
|---|
| 3883 | var testVal = true; |
|---|
| 3884 | |
|---|
| 3885 | if (token.data.jsExpr) |
|---|
| 3886 | { |
|---|
| 3887 | var jsExpr = Spry.Data.Region.processDataRefString(processContext, token.data.jsExpr, null, true); |
|---|
| 3888 | |
|---|
| 3889 | try { testVal = Spry.Utils.eval(jsExpr); } |
|---|
| 3890 | catch(e) |
|---|
| 3891 | { |
|---|
| 3892 | Spry.Debug.trace("Caught exception in Spry.Data.Region.prototype.processTokens while evaluating: " + jsExpr + "\n Exception:" + e + "\n"); |
|---|
| 3893 | testVal = true; |
|---|
| 3894 | } |
|---|
| 3895 | } |
|---|
| 3896 | |
|---|
| 3897 | if (testVal) |
|---|
| 3898 | this.processTokenChildren(outputArr, token, processContext); |
|---|
| 3899 | } |
|---|
| 3900 | else if (token.data.name == "spry:choose") |
|---|
| 3901 | { |
|---|
| 3902 | var defaultChild = null; |
|---|
| 3903 | var childToProcess = null; |
|---|
| 3904 | var testVal = false; |
|---|
| 3905 | var j = 0; |
|---|
| 3906 | |
|---|
| 3907 | // All of the children of the spry:choose token should be of the type spry:when or spry:default. |
|---|
| 3908 | // Run through all of the spry:when children and see if any of their test expressions return true. |
|---|
| 3909 | // If one does, then process its children tokens. If none of the test expressions return true, |
|---|
| 3910 | // process the spry:default token's children, if it exists. |
|---|
| 3911 | |
|---|
| 3912 | for (j = 0; j < token.children.length; j++) |
|---|
| 3913 | { |
|---|
| 3914 | var child = token.children[j]; |
|---|
| 3915 | if (child.tokenType == Spry.Data.Region.Token.PROCESSING_INSTRUCTION_TOKEN) |
|---|
| 3916 | { |
|---|
| 3917 | if (child.data.name == "spry:when") |
|---|
| 3918 | { |
|---|
| 3919 | if (child.data.jsExpr) |
|---|
| 3920 | { |
|---|
| 3921 | var jsExpr = Spry.Data.Region.processDataRefString(processContext, child.data.jsExpr, null, true); |
|---|
| 3922 | try { testVal = Spry.Utils.eval(jsExpr); } |
|---|
| 3923 | catch(e) |
|---|
| 3924 | { |
|---|
| 3925 | Spry.Debug.trace("Caught exception in Spry.Data.Region.prototype.processTokens while evaluating: " + jsExpr + "\n Exception:" + e + "\n"); |
|---|
| 3926 | testVal = false; |
|---|
| 3927 | } |
|---|
| 3928 | |
|---|
| 3929 | if (testVal) |
|---|
| 3930 | { |
|---|
| 3931 | childToProcess = child; |
|---|
| 3932 | break; |
|---|
| 3933 | } |
|---|
| 3934 | } |
|---|
| 3935 | } |
|---|
| 3936 | else if (child.data.name == "spry:default") |
|---|
| 3937 | defaultChild = child; |
|---|
| 3938 | } |
|---|
| 3939 | } |
|---|
| 3940 | |
|---|
| 3941 | // If we didn't find a match, use the token for the default case. |
|---|
| 3942 | |
|---|
| 3943 | if (!childToProcess && defaultChild) |
|---|
| 3944 | childToProcess = defaultChild; |
|---|
| 3945 | |
|---|
| 3946 | if (childToProcess) |
|---|
| 3947 | this.processTokenChildren(outputArr, childToProcess, processContext); |
|---|
| 3948 | } |
|---|
| 3949 | else if (token.data.name == "spry:state") |
|---|
| 3950 | { |
|---|
| 3951 | var testVal = true; |
|---|
| 3952 | |
|---|
| 3953 | if (!token.data.regionState || token.data.regionState == this.currentState) |
|---|
| 3954 | this.processTokenChildren(outputArr, token, processContext); |
|---|
| 3955 | } |
|---|
| 3956 | else |
|---|
| 3957 | { |
|---|
| 3958 | Spry.Debug.reportError("processTokens(): Unknown processing instruction: " + token.data.name + "\n"); |
|---|
| 3959 | return ""; |
|---|
| 3960 | } |
|---|
| 3961 | break; |
|---|
| 3962 | case Spry.Data.Region.Token.VALUE_TOKEN: |
|---|
| 3963 | |
|---|
| 3964 | var dataSet = token.dataSet; |
|---|
| 3965 | if (!dataSet && this.dataSets && this.dataSets.length > 0 && this.dataSets[0]) |
|---|
| 3966 | { |
|---|
| 3967 | // No dataSet was specified by the token, so use whatever the first |
|---|
| 3968 | // data set specified in the region. |
|---|
| 3969 | |
|---|
| 3970 | dataSet = this.dataSets[0]; |
|---|
| 3971 | } |
|---|
| 3972 | if (!dataSet) |
|---|
| 3973 | { |
|---|
| 3974 | Spry.Debug.reportError("processTokens(): Value reference has no data set specified: " + token.regionStr + "\n"); |
|---|
| 3975 | return ""; |
|---|
| 3976 | } |
|---|
| 3977 | |
|---|
| 3978 | var dsContext = processContext.getDataSetContext(dataSet); |
|---|
| 3979 | if (!dsContext) |
|---|
| 3980 | { |
|---|
| 3981 | Spry.Debug.reportError("processTokens: Failed to get a data set context!\n"); |
|---|
| 3982 | return ""; |
|---|
| 3983 | } |
|---|
| 3984 | |
|---|
| 3985 | var ds = dsContext.getDataSet(); |
|---|
| 3986 | |
|---|
| 3987 | if (token.data == "ds_RowNumber") |
|---|
| 3988 | outputArr.push(dsContext.getRowIndex()); |
|---|
| 3989 | else if (token.data == "ds_RowNumberPlus1") |
|---|
| 3990 | outputArr.push(dsContext.getRowIndex() + 1); |
|---|
| 3991 | else if (token.data == "ds_RowCount") |
|---|
| 3992 | outputArr.push(dsContext.getNumRows()); |
|---|
| 3993 | else if (token.data == "ds_UnfilteredRowCount") |
|---|
| 3994 | outputArr.push(dsContext.getNumRows(true)); |
|---|
| 3995 | else if (token.data == "ds_CurrentRowNumber") |
|---|
| 3996 | outputArr.push(ds.getRowNumber(ds.getCurrentRow())); |
|---|
| 3997 | else if (token.data == "ds_CurrentRowID") |
|---|
| 3998 | outputArr.push(ds.getCurrentRowID()); |
|---|
| 3999 | else if (token.data == "ds_EvenOddRow") |
|---|
| 4000 | outputArr.push((dsContext.getRowIndex() % 2) ? Spry.Data.Region.evenRowClassName : Spry.Data.Region.oddRowClassName); |
|---|
| 4001 | else if (token.data == "ds_SortOrder") |
|---|
| 4002 | outputArr.push(ds.getSortOrder()); |
|---|
| 4003 | else if (token.data == "ds_SortColumn") |
|---|
| 4004 | outputArr.push(ds.getSortColumn()); |
|---|
| 4005 | else |
|---|
| 4006 | { |
|---|
| 4007 | var curDataSetRow = dsContext.getCurrentRow(); |
|---|
| 4008 | if (curDataSetRow) |
|---|
| 4009 | outputArr.push(curDataSetRow[token.data]); |
|---|
| 4010 | } |
|---|
| 4011 | break; |
|---|
| 4012 | default: |
|---|
| 4013 | Spry.Debug.reportError("processTokens(): Invalid token type: " + token.regionStr + "\n"); |
|---|
| 4014 | break; |
|---|
| 4015 | } |
|---|
| 4016 | }; |
|---|
| 4017 | |
|---|
| 4018 | Spry.Data.Region.prototype.transform = function() |
|---|
| 4019 | { |
|---|
| 4020 | if (this.data && !this.tokens) |
|---|
| 4021 | this.tokens = this.tokenizeData(this.data); |
|---|
| 4022 | |
|---|
| 4023 | if (!this.tokens) |
|---|
| 4024 | return ""; |
|---|
| 4025 | |
|---|
| 4026 | processContext = new Spry.Data.Region.ProcessingContext(this); |
|---|
| 4027 | if (!processContext) |
|---|
| 4028 | return ""; |
|---|
| 4029 | |
|---|
| 4030 | // Now call processTokens to transform our tokens into real data strings. |
|---|
| 4031 | // We use an array to gather the strings during processing as a performance |
|---|
| 4032 | // enhancement for IE to avoid n-square problems of adding to an existing |
|---|
| 4033 | // string. For example: |
|---|
| 4034 | // |
|---|
| 4035 | // for (var i = 0; i < token.children.length; i++) |
|---|
| 4036 | // outputStr += this.processTokens(token.children[i], processContext); |
|---|
| 4037 | // |
|---|
| 4038 | // Using an array with a final join reduced one of our test cases from over |
|---|
| 4039 | // a minute to about 15 seconds. |
|---|
| 4040 | |
|---|
| 4041 | var outputArr = [ "" ]; |
|---|
| 4042 | this.processTokens(outputArr, this.tokens, processContext); |
|---|
| 4043 | return outputArr.join(""); |
|---|
| 4044 | }; |
|---|
| 4045 | |
|---|
| 4046 | Spry.Data.Region.PI = {}; |
|---|
| 4047 | Spry.Data.Region.PI.instructions = {}; |
|---|
| 4048 | |
|---|
| 4049 | Spry.Data.Region.PI.buildOpenTagForValueAttr = function(ele, piName, attrName) |
|---|
| 4050 | { |
|---|
| 4051 | if (!ele || !piName) |
|---|
| 4052 | return ""; |
|---|
| 4053 | |
|---|
| 4054 | var jsExpr = ""; |
|---|
| 4055 | |
|---|
| 4056 | try |
|---|
| 4057 | { |
|---|
| 4058 | var testAttr = ele.attributes.getNamedItem(piName); |
|---|
| 4059 | if (testAttr && testAttr.value) |
|---|
| 4060 | jsExpr = Spry.Utils.encodeEntities(testAttr.value); |
|---|
| 4061 | } |
|---|
| 4062 | catch (e) { jsExpr = ""; } |
|---|
| 4063 | |
|---|
| 4064 | if (!jsExpr) |
|---|
| 4065 | { |
|---|
| 4066 | Spry.Debug.reportError(piName + " attribute requires a JavaScript expression that returns true or false!\n"); |
|---|
| 4067 | return ""; |
|---|
| 4068 | } |
|---|
| 4069 | |
|---|
| 4070 | return "<" + Spry.Data.Region.PI.instructions[piName].tagName + " " + attrName +"=\"" + jsExpr + "\">"; |
|---|
| 4071 | }; |
|---|
| 4072 | |
|---|
| 4073 | Spry.Data.Region.PI.buildOpenTagForTest = function(ele, piName) |
|---|
| 4074 | { |
|---|
| 4075 | return Spry.Data.Region.PI.buildOpenTagForValueAttr(ele, piName, "test"); |
|---|
| 4076 | }; |
|---|
| 4077 | |
|---|
| 4078 | Spry.Data.Region.PI.buildOpenTagForState = function(ele, piName) |
|---|
| 4079 | { |
|---|
| 4080 | return Spry.Data.Region.PI.buildOpenTagForValueAttr(ele, piName, "name"); |
|---|
| 4081 | }; |
|---|
| 4082 | |
|---|
| 4083 | Spry.Data.Region.PI.buildOpenTagForRepeat = function(ele, piName) |
|---|
| 4084 | { |
|---|
| 4085 | if (!ele || !piName) |
|---|
| 4086 | return ""; |
|---|
| 4087 | |
|---|
| 4088 | var selectAttrStr = ""; |
|---|
| 4089 | |
|---|
| 4090 | try |
|---|
| 4091 | { |
|---|
| 4092 | var selectAttr = ele.attributes.getNamedItem(piName); |
|---|
| 4093 | if (selectAttr && selectAttr.value) |
|---|
| 4094 | { |
|---|
| 4095 | selectAttrStr = selectAttr.value; |
|---|
| 4096 | selectAttrStr = selectAttrStr.replace(/\s/g, ""); |
|---|
| 4097 | } |
|---|
| 4098 | } |
|---|
| 4099 | catch (e) { selectAttrStr = ""; } |
|---|
| 4100 | |
|---|
| 4101 | if (!selectAttrStr) |
|---|
| 4102 | { |
|---|
| 4103 | Spry.Debug.reportError(piName + " attribute requires a data set name!\n"); |
|---|
| 4104 | return ""; |
|---|
| 4105 | } |
|---|
| 4106 | |
|---|
| 4107 | var testAttrStr = ""; |
|---|
| 4108 | |
|---|
| 4109 | try |
|---|
| 4110 | { |
|---|
| 4111 | var testAttr = ele.attributes.getNamedItem("spry:test"); |
|---|
| 4112 | if (testAttr) |
|---|
| 4113 | { |
|---|
| 4114 | if (testAttr.value) |
|---|
| 4115 | testAttrStr = " test=\"" + Spry.Utils.encodeEntities(testAttr.value) + "\""; |
|---|
| 4116 | ele.attributes.removeNamedItem(testAttr.nodeName); |
|---|
| 4117 | } |
|---|
| 4118 | } |
|---|
| 4119 | catch (e) { testAttrStr = ""; } |
|---|
| 4120 | |
|---|
| 4121 | return "<" + Spry.Data.Region.PI.instructions[piName].tagName + " select=\"" + selectAttrStr + "\"" + testAttrStr + ">"; |
|---|
| 4122 | }; |
|---|
| 4123 | |
|---|
| 4124 | Spry.Data.Region.PI.buildOpenTagForContent = function(ele, piName) |
|---|
| 4125 | { |
|---|
| 4126 | if (!ele || !piName) |
|---|
| 4127 | return ""; |
|---|
| 4128 | |
|---|
| 4129 | var dataRefStr = ""; |
|---|
| 4130 | |
|---|
| 4131 | try |
|---|
| 4132 | { |
|---|
| 4133 | var contentAttr = ele.attributes.getNamedItem(piName); |
|---|
| 4134 | if (contentAttr && contentAttr.value) |
|---|
| 4135 | dataRefStr = Spry.Utils.encodeEntities(contentAttr.value); |
|---|
| 4136 | } |
|---|
| 4137 | catch (e) { dataRefStr = ""; } |
|---|
| 4138 | |
|---|
| 4139 | if (!dataRefStr) |
|---|
| 4140 | { |
|---|
| 4141 | Spry.Debug.reportError(piName + " attribute requires a data reference!\n"); |
|---|
| 4142 | return ""; |
|---|
| 4143 | } |
|---|
| 4144 | |
|---|
| 4145 | return "<" + Spry.Data.Region.PI.instructions[piName].tagName + " dataref=\"" + dataRefStr + "\">"; |
|---|
| 4146 | }; |
|---|
| 4147 | |
|---|
| 4148 | Spry.Data.Region.PI.buildOpenTag = function(ele, piName) |
|---|
| 4149 | { |
|---|
| 4150 | return "<" + Spry.Data.Region.PI.instructions[piName].tagName + ">"; |
|---|
| 4151 | }; |
|---|
| 4152 | |
|---|
| 4153 | Spry.Data.Region.PI.buildCloseTag = function(ele, piName) |
|---|
| 4154 | { |
|---|
| 4155 | return "</" + Spry.Data.Region.PI.instructions[piName].tagName + ">"; |
|---|
| 4156 | }; |
|---|
| 4157 | |
|---|
| 4158 | Spry.Data.Region.PI.instructions["spry:state"] = { tagName: "spry:state", childrenOnly: false, getOpenTag: Spry.Data.Region.PI.buildOpenTagForState, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4159 | Spry.Data.Region.PI.instructions["spry:if"] = { tagName: "spry:if", childrenOnly: false, getOpenTag: Spry.Data.Region.PI.buildOpenTagForTest, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4160 | Spry.Data.Region.PI.instructions["spry:repeat"] = { tagName: "spry:repeat", childrenOnly: false, getOpenTag: Spry.Data.Region.PI.buildOpenTagForRepeat, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4161 | Spry.Data.Region.PI.instructions["spry:repeatchildren"] = { tagName: "spry:repeat", childrenOnly: true, getOpenTag: Spry.Data.Region.PI.buildOpenTagForRepeat, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4162 | Spry.Data.Region.PI.instructions["spry:choose"] = { tagName: "spry:choose", childrenOnly: true, getOpenTag: Spry.Data.Region.PI.buildOpenTag, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4163 | Spry.Data.Region.PI.instructions["spry:when"] = { tagName: "spry:when", childrenOnly: false, getOpenTag: Spry.Data.Region.PI.buildOpenTagForTest, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4164 | Spry.Data.Region.PI.instructions["spry:default"] = { tagName: "spry:default", childrenOnly: false, getOpenTag: Spry.Data.Region.PI.buildOpenTag, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4165 | Spry.Data.Region.PI.instructions["spry:content"] = { tagName: "spry:content", childrenOnly: true, getOpenTag: Spry.Data.Region.PI.buildOpenTagForContent, getCloseTag: Spry.Data.Region.PI.buildCloseTag }; |
|---|
| 4166 | |
|---|
| 4167 | Spry.Data.Region.PI.orderedInstructions = [ "spry:state", "spry:if", "spry:repeat", "spry:repeatchildren", "spry:choose", "spry:when", "spry:default", "spry:content" ]; |
|---|
| 4168 | |
|---|
| 4169 | Spry.Data.Region.getTokensFromStr = function(str) |
|---|
| 4170 | { |
|---|
| 4171 | // XXX: This will need to be modified if we support |
|---|
| 4172 | // tokens that use javascript between the braces! |
|---|
| 4173 | if (!str) |
|---|
| 4174 | return null; |
|---|
| 4175 | return str.match(/{[^}]+}/g); |
|---|
| 4176 | }; |
|---|
| 4177 | |
|---|
| 4178 | Spry.Data.Region.processDataRefString = function(processingContext, regionStr, dataSetsToUse, isJSExpr) |
|---|
| 4179 | { |
|---|
| 4180 | if (!regionStr) |
|---|
| 4181 | return ""; |
|---|
| 4182 | |
|---|
| 4183 | if (!processingContext && !dataSetsToUse) |
|---|
| 4184 | return regionStr; |
|---|
| 4185 | |
|---|
| 4186 | var resultStr = ""; |
|---|
| 4187 | var re = new RegExp("\\{([^\\}:]+::)?[^\\}]+\\}", "g"); |
|---|
| 4188 | var startSearchIndex = 0; |
|---|
| 4189 | |
|---|
| 4190 | while (startSearchIndex < regionStr.length) |
|---|
| 4191 | { |
|---|
| 4192 | var reArray = re.exec(regionStr); |
|---|
| 4193 | if (!reArray || !reArray[0]) |
|---|
| 4194 | { |
|---|
| 4195 | resultStr += regionStr.substr(startSearchIndex, regionStr.length - startSearchIndex); |
|---|
| 4196 | return resultStr; |
|---|
| 4197 | } |
|---|
| 4198 | |
|---|
| 4199 | if (reArray.index != startSearchIndex) |
|---|
| 4200 | resultStr += regionStr.substr(startSearchIndex, reArray.index - startSearchIndex); |
|---|
| 4201 | |
|---|
| 4202 | var dsName = ""; |
|---|
| 4203 | if (reArray[0].search(/^\{[^}:]+::/) != -1) |
|---|
| 4204 | dsName = reArray[0].replace(/^\{|::.*/g, ""); |
|---|
| 4205 | |
|---|
| 4206 | var fieldName = reArray[0].replace(/^\{|.*::|\}/g, ""); |
|---|
| 4207 | var row = null; |
|---|
| 4208 | |
|---|
| 4209 | if (processingContext) |
|---|
| 4210 | { |
|---|
| 4211 | var dsContext = processingContext.getDataSetContext(dsName); |
|---|
| 4212 | |
|---|
| 4213 | if (fieldName == "ds_RowNumber") |
|---|
| 4214 | { |
|---|
| 4215 | resultStr += dsContext.getRowIndex(); |
|---|
| 4216 | row = null; |
|---|
| 4217 | } |
|---|
| 4218 | else if (fieldName == "ds_RowNumberPlus1") |
|---|
| 4219 | { |
|---|
| 4220 | resultStr += (dsContext.getRowIndex() + 1); |
|---|
| 4221 | row = null; |
|---|
| 4222 | } |
|---|
| 4223 | else if (fieldName == "ds_RowCount") |
|---|
| 4224 | { |
|---|
| 4225 | resultStr += dsContext.getNumRows(); |
|---|
| 4226 | row = null; |
|---|
| 4227 | } |
|---|
| 4228 | else if (fieldName == "ds_UnfilteredRowCount") |
|---|
| 4229 | { |
|---|
| 4230 | resultStr += dsContext.getNumRows(true); |
|---|
| 4231 | row = null; |
|---|
| 4232 | } |
|---|
| 4233 | else if (fieldName == "ds_CurrentRowNumber") |
|---|
| 4234 | { |
|---|
| 4235 | var ds = dsContext.getDataSet(); |
|---|
| 4236 | resultStr += ds.getRowNumber(ds.getCurrentRow()); |
|---|
| 4237 | row = null; |
|---|
| 4238 | } |
|---|
| 4239 | else if (fieldName == "ds_CurrentRowID") |
|---|
| 4240 | { |
|---|
| 4241 | var ds = dsContext.getDataSet(); |
|---|
| 4242 | resultStr += "" + ds.getCurrentRowID(); |
|---|
| 4243 | row = null; |
|---|
| 4244 | } |
|---|
| 4245 | else if (fieldName == "ds_EvenOddRow") |
|---|
| 4246 | { |
|---|
| 4247 | resultStr += (dsContext.getRowIndex() % 2) ? Spry.Data.Region.evenRowClassName : Spry.Data.Region.oddRowClassName; |
|---|
| 4248 | row = null; |
|---|
| 4249 | } |
|---|
| 4250 | else if (fieldName == "ds_SortOrder") |
|---|
| 4251 | { |
|---|
| 4252 | resultStr += dsContext.getDataSet().getSortOrder(); |
|---|
| 4253 | row = null; |
|---|
| 4254 | } |
|---|
| 4255 | else if (fieldName == "ds_SortColumn") |
|---|
| 4256 | { |
|---|
| 4257 | resultStr += dsContext.getDataSet().getSortColumn(); |
|---|
| 4258 | row = null; |
|---|
| 4259 | } |
|---|
| 4260 | else |
|---|
| 4261 | row = processingContext.getCurrentRowForDataSet(dsName); |
|---|
| 4262 | } |
|---|
| 4263 | else |
|---|
| 4264 | { |
|---|
| 4265 | var ds = dsName ? dataSetsToUse[dsName] : dataSetsToUse[0]; |
|---|
| 4266 | if (ds) |
|---|
| 4267 | row = ds.getCurrentRow(); |
|---|
| 4268 | } |
|---|
| 4269 | |
|---|
| 4270 | if (row) |
|---|
| 4271 | resultStr += isJSExpr ? Spry.Utils.escapeQuotesAndLineBreaks("" + row[fieldName]) : row[fieldName]; |
|---|
| 4272 | |
|---|
| 4273 | if (startSearchIndex == re.lastIndex) |
|---|
| 4274 | { |
|---|
| 4275 | // On IE if there was a match near the end of the string, it sometimes |
|---|
| 4276 | // leaves re.lastIndex pointing to the value it had before the last time |
|---|
| 4277 | // we called re.exec. We check for this case to prevent an infinite loop! |
|---|
| 4278 | // We need to write out any text in regionStr that comes after the last |
|---|
| 4279 | // match. |
|---|
| 4280 | |
|---|
| 4281 | var leftOverIndex = reArray.index + reArray[0].length; |
|---|
| 4282 | if (leftOverIndex < regionStr.length) |
|---|
| 4283 | resultStr += regionStr.substr(leftOverIndex); |
|---|
| 4284 | |
|---|
| 4285 | break; |
|---|
| 4286 | } |
|---|
| 4287 | |
|---|
| 4288 | startSearchIndex = re.lastIndex; |
|---|
| 4289 | } |
|---|
| 4290 | |
|---|
| 4291 | return resultStr; |
|---|
| 4292 | }; |
|---|
| 4293 | |
|---|
| 4294 | Spry.Data.Region.strToDataSetsArray = function(str, returnRegionNames) |
|---|
| 4295 | { |
|---|
| 4296 | var dataSetsArr = new Array; |
|---|
| 4297 | var foundHash = {}; |
|---|
| 4298 | |
|---|
| 4299 | if (!str) |
|---|
| 4300 | return dataSetsArr; |
|---|
| 4301 | |
|---|
| 4302 | str = str.replace(/\s+/g, " "); |
|---|
| 4303 | str = str.replace(/^\s|\s$/g, ""); |
|---|
| 4304 | var arr = str.split(/ /); |
|---|
| 4305 | |
|---|
| 4306 | |
|---|
| 4307 | for (var i = 0; i < arr.length; i++) |
|---|
| 4308 | { |
|---|
| 4309 | if (arr[i] && !Spry.Data.Region.PI.instructions[arr[i]]) |
|---|
| 4310 | { |
|---|
| 4311 | try { |
|---|
| 4312 | var dataSet = eval(arr[i]); |
|---|
| 4313 | |
|---|
| 4314 | if (!foundHash[arr[i]]) |
|---|
| 4315 | { |
|---|
| 4316 | if (returnRegionNames) |
|---|
| 4317 | dataSetsArr.push(arr[i]); |
|---|
| 4318 | else |
|---|
| 4319 | dataSetsArr.push(dataSet); |
|---|
| 4320 | foundHash[arr[i]] = true; |
|---|
| 4321 | } |
|---|
| 4322 | } |
|---|
| 4323 | catch (e) { /* Spry.Debug.trace("Caught exception: " + e + "\n"); */ } |
|---|
| 4324 | } |
|---|
| 4325 | } |
|---|
| 4326 | |
|---|
| 4327 | return dataSetsArr; |
|---|
| 4328 | }; |
|---|
| 4329 | |
|---|
| 4330 | Spry.Data.Region.DSContext = function(dataSet, processingContext) |
|---|
| 4331 | { |
|---|
| 4332 | var m_dataSet = dataSet; |
|---|
| 4333 | var m_processingContext = processingContext; |
|---|
| 4334 | var m_curRowIndexArray = [ { rowIndex: -1 } ]; // -1 means return whatever the current row is inside the data set. |
|---|
| 4335 | var m_parent = null; |
|---|
| 4336 | var m_children = []; |
|---|
| 4337 | |
|---|
| 4338 | // Private Methods: |
|---|
| 4339 | |
|---|
| 4340 | function getInternalRowIndex() { return m_curRowIndexArray[m_curRowIndexArray.length - 1].rowIndex; } |
|---|
| 4341 | |
|---|
| 4342 | // Public Methods: |
|---|
| 4343 | this.resetAll = function() { m_curRowIndexArray = [ { rowIndex: m_dataSet.getCurrentRow() } ] }; |
|---|
| 4344 | this.getDataSet = function() { return m_dataSet; }; |
|---|
| 4345 | this.getNumRows = function(unfiltered) |
|---|
| 4346 | { |
|---|
| 4347 | var data = this.getCurrentState().data; |
|---|
| 4348 | return data ? data.length : m_dataSet.getRowCount(unfiltered); |
|---|
| 4349 | }; |
|---|
| 4350 | this.getData = function() |
|---|
| 4351 | { |
|---|
| 4352 | var data = this.getCurrentState().data; |
|---|
| 4353 | return data ? data : m_dataSet.getData(); |
|---|
| 4354 | }; |
|---|
| 4355 | this.setData = function(data) |
|---|
| 4356 | { |
|---|
| 4357 | this.getCurrentState().data = data; |
|---|
| 4358 | } |
|---|
| 4359 | this.getCurrentRow = function() |
|---|
| 4360 | { |
|---|
| 4361 | if (m_curRowIndexArray.length < 2 || getInternalRowIndex() < 0) |
|---|
| 4362 | return m_dataSet.getCurrentRow(); |
|---|
| 4363 | |
|---|
| 4364 | var data = this.getData(); |
|---|
| 4365 | var curRowIndex = getInternalRowIndex(); |
|---|
| 4366 | |
|---|
| 4367 | if (curRowIndex < 0 || curRowIndex > data.length) |
|---|
| 4368 | { |
|---|
| 4369 | Spry.Debug.reportError("Invalid index used in Spry.Data.Region.DSContext.getCurrentRow()!\n"); |
|---|
| 4370 | return null; |
|---|
| 4371 | } |
|---|
| 4372 | |
|---|
| 4373 | return data[curRowIndex]; |
|---|
| 4374 | }; |
|---|
| 4375 | this.getRowIndex = function() |
|---|
| 4376 | { |
|---|
| 4377 | var curRowIndex = getInternalRowIndex(); |
|---|
| 4378 | if (curRowIndex >= 0) |
|---|
| 4379 | return curRowIndex; |
|---|
| 4380 | |
|---|
| 4381 | return m_dataSet.getRowNumber(m_dataSet.getCurrentRow()); |
|---|
| 4382 | }; |
|---|
| 4383 | this.setRowIndex = function(rowIndex) |
|---|
| 4384 | { |
|---|
| 4385 | this.getCurrentState().rowIndex = rowIndex; |
|---|
| 4386 | |
|---|
| 4387 | var data = this.getData(); |
|---|
| 4388 | var numChildren = m_children.length; |
|---|
| 4389 | for (var i = 0; i < numChildren; i++) |
|---|
| 4390 | m_children[i].syncDataWithParentRow(this, rowIndex, data); |
|---|
| 4391 | }; |
|---|
| 4392 | this.syncDataWithParentRow = function(parentDSContext, rowIndex, parentData) |
|---|
| 4393 | { |
|---|
| 4394 | var row = parentData[rowIndex]; |
|---|
| 4395 | if (row) |
|---|
| 4396 | { |
|---|
| 4397 | nestedDS = m_dataSet.getNestedDataSetForParentRow(row); |
|---|
| 4398 | if (nestedDS) |
|---|
| 4399 | { |
|---|
| 4400 | var currentState = this.getCurrentState(); |
|---|
| 4401 | currentState.data = nestedDS.getData(); |
|---|
| 4402 | currentState.rowIndex = nestedDS.getCurrentRowNumber(); |
|---|
| 4403 | |
|---|
| 4404 | var numChildren = m_children.length; |
|---|
| 4405 | for (var i = 0; i < numChildren; i++) |
|---|
| 4406 | m_children[i].syncDataWithParentRow(this, currentState.rowIndex, currentState.data); |
|---|
| 4407 | } |
|---|
| 4408 | } |
|---|
| 4409 | }; |
|---|
| 4410 | this.pushState = function() |
|---|
| 4411 | { |
|---|
| 4412 | var curState = this.getCurrentState(); |
|---|
| 4413 | var newState = new Object; |
|---|
| 4414 | newState.rowIndex = curState.rowIndex; |
|---|
| 4415 | newState.data = curState.data; |
|---|
| 4416 | |
|---|
| 4417 | m_curRowIndexArray.push(newState); |
|---|
| 4418 | |
|---|
| 4419 | var numChildren = m_children.length; |
|---|
| 4420 | for (var i = 0; i < numChildren; i++) |
|---|
| 4421 | m_children[i].pushState(); |
|---|
| 4422 | }; |
|---|
| 4423 | this.popState = function() |
|---|
| 4424 | { |
|---|
| 4425 | if (m_curRowIndexArray.length < 2) |
|---|
| 4426 | { |
|---|
| 4427 | // Our array should always have at least one element in it! |
|---|
| 4428 | Spry.Debug.reportError("Stack underflow in Spry.Data.Region.DSContext.popState()!\n"); |
|---|
| 4429 | return; |
|---|
| 4430 | } |
|---|
| 4431 | |
|---|
| 4432 | var numChildren = m_children.length; |
|---|
| 4433 | for (var i = 0; i < numChildren; i++) |
|---|
| 4434 | m_children[i].popState(); |
|---|
| 4435 | |
|---|
| 4436 | m_curRowIndexArray.pop(); |
|---|
| 4437 | }; |
|---|
| 4438 | this.getCurrentState = function() |
|---|
| 4439 | { |
|---|
| 4440 | return m_curRowIndexArray[m_curRowIndexArray.length - 1]; |
|---|
| 4441 | }; |
|---|
| 4442 | this.addChild = function(childDSContext) |
|---|
| 4443 | { |
|---|
| 4444 | var numChildren = m_children.length; |
|---|
| 4445 | for (var i = 0; i < numChildren; i++) |
|---|
| 4446 | { |
|---|
| 4447 | if (m_children[i] == childDSContext) |
|---|
| 4448 | return; |
|---|
| 4449 | } |
|---|
| 4450 | m_children.push(childDSContext); |
|---|
| 4451 | }; |
|---|
| 4452 | }; |
|---|
| 4453 | |
|---|
| 4454 | Spry.Data.Region.ProcessingContext = function(region) |
|---|
| 4455 | { |
|---|
| 4456 | this.region = region; |
|---|
| 4457 | this.dataSetContexts = []; |
|---|
| 4458 | |
|---|
| 4459 | if (region && region.dataSets) |
|---|
| 4460 | { |
|---|
| 4461 | // Run through each data set in the list and check to see if we need |
|---|
| 4462 | // to add its parent to the list of data sets we track. |
|---|
| 4463 | var dsArray = region.dataSets.slice(0); |
|---|
| 4464 | var dsArrayLen = dsArray.length; |
|---|
| 4465 | for (var i = 0; i < dsArrayLen; i++) |
|---|
| 4466 | { |
|---|
| 4467 | var ds = region.dataSets[i]; |
|---|
| 4468 | while (ds && ds.getParentDataSet) |
|---|
| 4469 | { |
|---|
| 4470 | var doesExist = false; |
|---|
| 4471 | ds = ds.getParentDataSet(); |
|---|
| 4472 | if (ds && this.indexOf(dsArray, ds) == -1) |
|---|
| 4473 | dsArray.push(ds); |
|---|
| 4474 | } |
|---|
| 4475 | } |
|---|
| 4476 | |
|---|
| 4477 | // Create a data set context for every data set in our list. |
|---|
| 4478 | |
|---|
| 4479 | for (i = 0; i < dsArray.length; i++) |
|---|
| 4480 | this.dataSetContexts.push(new Spry.Data.Region.DSContext(dsArray[i], this)); |
|---|
| 4481 | |
|---|
| 4482 | // Now run through the list of data set contexts and wire up the parent/child |
|---|
| 4483 | // relationships so that notifications get dispatched as expected. |
|---|
| 4484 | |
|---|
| 4485 | var dsContexts = this.dataSetContexts; |
|---|
| 4486 | var numDSContexts = dsContexts.length; |
|---|
| 4487 | |
|---|
| 4488 | for (i = 0; i < numDSContexts; i++) |
|---|
| 4489 | { |
|---|
| 4490 | var dsc = dsContexts[i]; |
|---|
| 4491 | var ds = dsc.getDataSet(); |
|---|
| 4492 | if (ds.getParentDataSet) |
|---|
| 4493 | { |
|---|
| 4494 | var parentDS = ds.getParentDataSet(); |
|---|
| 4495 | if (parentDS) |
|---|
| 4496 | { |
|---|
| 4497 | var pdsc = this.getDataSetContext(parentDS); |
|---|
| 4498 | if (pdsc) pdsc.addChild(dsc); |
|---|
| 4499 | } |
|---|
| 4500 | } |
|---|
| 4501 | } |
|---|
| 4502 | } |
|---|
| 4503 | }; |
|---|
| 4504 | |
|---|
| 4505 | Spry.Data.Region.ProcessingContext.prototype.indexOf = function(arr, item) |
|---|
| 4506 | { |
|---|
| 4507 | // Given an array, return the index of item in that array |
|---|
| 4508 | // or -1 if it doesn't exist. |
|---|
| 4509 | |
|---|
| 4510 | if (arr) |
|---|
| 4511 | { |
|---|
| 4512 | var arrLen = arr.length; |
|---|
| 4513 | for (var i = 0; i < arrLen; i++) |
|---|
| 4514 | if (arr[i] == item) |
|---|
| 4515 | return i; |
|---|
| 4516 | } |
|---|
| 4517 | return -1; |
|---|
| 4518 | }; |
|---|
| 4519 | |
|---|
| 4520 | Spry.Data.Region.ProcessingContext.prototype.getDataSetContext = function(dataSet) |
|---|
| 4521 | { |
|---|
| 4522 | if (!dataSet) |
|---|
| 4523 | { |
|---|
| 4524 | // We were called without a specified data set or |
|---|
| 4525 | // data set name. Assume the caller wants the first |
|---|
| 4526 | // data set in the processing context. |
|---|
| 4527 | |
|---|
| 4528 | if (this.dataSetContexts.length > 0) |
|---|
| 4529 | return this.dataSetContexts[0]; |
|---|
| 4530 | return null; |
|---|
| 4531 | } |
|---|
| 4532 | |
|---|
| 4533 | if (typeof dataSet == 'string') |
|---|
| 4534 | { |
|---|
| 4535 | try { dataSet = eval(dataSet); } catch (e) { dataSet = null; } |
|---|
| 4536 | if (!dataSet) |
|---|
| 4537 | return null; |
|---|
| 4538 | } |
|---|
| 4539 | |
|---|
| 4540 | for (var i = 0; i < this.dataSetContexts.length; i++) |
|---|
| 4541 | { |
|---|
| 4542 | var dsc = this.dataSetContexts[i]; |
|---|
| 4543 | if (dsc.getDataSet() == dataSet) |
|---|
| 4544 | return dsc; |
|---|
| 4545 | } |
|---|
| 4546 | |
|---|
| 4547 | return null; |
|---|
| 4548 | }; |
|---|
| 4549 | |
|---|
| 4550 | Spry.Data.Region.ProcessingContext.prototype.getCurrentRowForDataSet = function(dataSet) |
|---|
| 4551 | { |
|---|
| 4552 | var dsc = this.getDataSetContext(dataSet); |
|---|
| 4553 | if (dsc) |
|---|
| 4554 | return dsc.getCurrentRow(); |
|---|
| 4555 | return null; |
|---|
| 4556 | }; |
|---|
| 4557 | |
|---|
| 4558 | Spry.Data.Region.Token = function(tokenType, dataSet, data, regionStr) |
|---|
| 4559 | { |
|---|
| 4560 | var self = this; |
|---|
| 4561 | this.tokenType = tokenType; |
|---|
| 4562 | this.dataSet = dataSet; |
|---|
| 4563 | this.data = data; |
|---|
| 4564 | this.regionStr = regionStr; |
|---|
| 4565 | this.parent = null; |
|---|
| 4566 | this.children = null; |
|---|
| 4567 | }; |
|---|
| 4568 | |
|---|
| 4569 | Spry.Data.Region.Token.prototype.addChild = function(child) |
|---|
| 4570 | { |
|---|
| 4571 | if (!child) |
|---|
| 4572 | return; |
|---|
| 4573 | |
|---|
| 4574 | if (!this.children) |
|---|
| 4575 | this.children = new Array; |
|---|
| 4576 | |
|---|
| 4577 | this.children.push(child); |
|---|
| 4578 | child.parent = this; |
|---|
| 4579 | }; |
|---|
| 4580 | |
|---|
| 4581 | Spry.Data.Region.Token.LIST_TOKEN = 0; |
|---|
| 4582 | Spry.Data.Region.Token.STRING_TOKEN = 1; |
|---|
| 4583 | Spry.Data.Region.Token.PROCESSING_INSTRUCTION_TOKEN = 2; |
|---|
| 4584 | Spry.Data.Region.Token.VALUE_TOKEN = 3; |
|---|
| 4585 | |
|---|
| 4586 | Spry.Data.Region.Token.PIData = function(piName, data, jsExpr, regionState) |
|---|
| 4587 | { |
|---|
| 4588 | var self = this; |
|---|
| 4589 | this.name = piName; |
|---|
| 4590 | this.data = data; |
|---|
| 4591 | this.jsExpr = jsExpr; |
|---|
| 4592 | this.regionState = regionState; |
|---|
| 4593 | }; |
|---|
| 4594 | |
|---|
| 4595 | Spry.Utils.addLoadListener(function() { setTimeout(function() { Spry.Data.initRegions(); }, 0); }); |
|---|