[483] | 1 | define(["dojo", "dojox", "dojo/data/util/sorter"], function(dojo, dojox) { |
---|
| 2 | |
---|
| 3 | dojox.data.ASYNC_MODE = 0; |
---|
| 4 | dojox.data.SYNC_MODE = 1; |
---|
| 5 | |
---|
| 6 | return dojo.declare("dojox.data.CdfStore", null, { |
---|
| 7 | // summary: |
---|
| 8 | // IMPORTANT: The CDF Store is designed to work with Tibco GI, and references Tibco's |
---|
| 9 | // JSX3 JavaScript library and will not work without it. |
---|
| 10 | // |
---|
| 11 | // The CDF Store implements dojo.data.Read, Write, and Identity api's. It is a local |
---|
| 12 | // (in memory) store that handles XML documents formatted according to the |
---|
| 13 | // Common Data Format (CDF) spec: |
---|
| 14 | // http://www.tibco.com/devnet/resources/gi/3_1/tips_and_techniques/CommonDataFormatCDF.pdf |
---|
| 15 | // |
---|
| 16 | // The purpose of this store is to provide a glue between a jsx3 CDF file and a Dijit. |
---|
| 17 | // |
---|
| 18 | // While a CDF document is an XML file, other than the initial input, all data returned |
---|
| 19 | // from and written to this store should be in object format. |
---|
| 20 | |
---|
| 21 | // identity: [const] String |
---|
| 22 | // The unique identifier for each item. Defaults to "jsxid" which is standard for a CDF |
---|
| 23 | // document. Should not be changed. |
---|
| 24 | identity: "jsxid", |
---|
| 25 | |
---|
| 26 | // url : String |
---|
| 27 | // The location from which to fetch the XML (CDF) document. |
---|
| 28 | url: "", |
---|
| 29 | |
---|
| 30 | // xmlStr: String |
---|
| 31 | // A string that can be parsed into an XML document and should be formatted according |
---|
| 32 | // to the CDF spec. |
---|
| 33 | // example: |
---|
| 34 | // | '<data jsxid="jsxroot"><record jsxtext="A"/><record jsxtext="B" jsxid="2" jsxid="2"/></data>' |
---|
| 35 | xmlStr:"", |
---|
| 36 | |
---|
| 37 | // data: Object |
---|
| 38 | // A object that will be converted into the xmlStr property, and then parsed into a CDF. |
---|
| 39 | data:null, |
---|
| 40 | |
---|
| 41 | // label: String |
---|
| 42 | // The property within each item used to define the item. |
---|
| 43 | label: "", |
---|
| 44 | |
---|
| 45 | // mode [const]: dojox.data.ASYNC_MODE|dojox.data.SYNC_MODE |
---|
| 46 | // This store supports synchronous fetches if this property is set to dojox.data.SYNC_MODE. |
---|
| 47 | mode:dojox.data.ASYNC_MODE, |
---|
| 48 | |
---|
| 49 | constructor: function(/* Object */ args){ |
---|
| 50 | // summary: |
---|
| 51 | // Constructor for the CDF store. Instantiate a new CdfStore. |
---|
| 52 | if(args){ |
---|
| 53 | this.url = args.url; |
---|
| 54 | this.xmlStr = args.xmlStr || args.str; |
---|
| 55 | if(args.data){ |
---|
| 56 | this.xmlStr = this._makeXmlString(args.data); |
---|
| 57 | } |
---|
| 58 | this.identity = args.identity || this.identity; |
---|
| 59 | this.label = args.label || this.label; |
---|
| 60 | this.mode = args.mode !== undefined ? args.mode : this.mode; |
---|
| 61 | } |
---|
| 62 | this._modifiedItems = {}; |
---|
| 63 | |
---|
| 64 | this.byId = this.fetchItemByIdentity; |
---|
| 65 | }, |
---|
| 66 | |
---|
| 67 | /* dojo/data/api/Read */ |
---|
| 68 | |
---|
| 69 | getValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* value? */ defaultValue){ |
---|
| 70 | // summary: |
---|
| 71 | // Return an property value of an item |
---|
| 72 | |
---|
| 73 | return item.getAttribute(property) || defaultValue; // anything |
---|
| 74 | }, |
---|
| 75 | |
---|
| 76 | getValues: function(/* jsx3.xml.Entity */ item, /* String */ property){ |
---|
| 77 | // summary: |
---|
| 78 | // Return an array of values |
---|
| 79 | |
---|
| 80 | // TODO!!! Can't find an example of an array in any CDF files |
---|
| 81 | var v = this.getValue(item, property, []); |
---|
| 82 | return dojo.isArray(v) ? v : [v]; |
---|
| 83 | }, |
---|
| 84 | |
---|
| 85 | getAttributes: function(/* jsx3.xml.Entity */ item){ |
---|
| 86 | // summary: |
---|
| 87 | // Return an array of property names |
---|
| 88 | |
---|
| 89 | return item.getAttributeNames(); // Array |
---|
| 90 | }, |
---|
| 91 | |
---|
| 92 | hasAttribute: function(/* jsx3.xml.Entity */ item, /* String */ property){ |
---|
| 93 | // summary: |
---|
| 94 | // Check whether an item has a property |
---|
| 95 | |
---|
| 96 | return (this.getValue(item, property) !== undefined); // Boolean |
---|
| 97 | }, |
---|
| 98 | |
---|
| 99 | hasProperty: function(/* jsx3.xml.Entity */ item, /* String */ property){ |
---|
| 100 | // summary: |
---|
| 101 | // Alias for hasAttribute |
---|
| 102 | return this.hasAttribute(item, property); |
---|
| 103 | }, |
---|
| 104 | |
---|
| 105 | containsValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* anything */ value){ |
---|
| 106 | // summary: |
---|
| 107 | // Check whether an item contains a value |
---|
| 108 | |
---|
| 109 | var values = this.getValues(item, property); |
---|
| 110 | for(var i = 0; i < values.length; i++){ |
---|
| 111 | if(values[i] === null){ continue; } |
---|
| 112 | if((typeof value === "string")){ |
---|
| 113 | if(values[i].toString && values[i].toString() === value){ |
---|
| 114 | return true; |
---|
| 115 | } |
---|
| 116 | }else if(values[i] === value){ |
---|
| 117 | return true; //boolean |
---|
| 118 | } |
---|
| 119 | } |
---|
| 120 | return false;//boolean |
---|
| 121 | }, |
---|
| 122 | |
---|
| 123 | isItem: function(/* anything */ something){ |
---|
| 124 | // summary: |
---|
| 125 | // Check whether the object is an item (jsx3.xml.Entity) |
---|
| 126 | |
---|
| 127 | if(something.getClass && something.getClass().equals(jsx3.xml.Entity.jsxclass)){ |
---|
| 128 | return true; //boolean |
---|
| 129 | } |
---|
| 130 | return false; //boolran |
---|
| 131 | }, |
---|
| 132 | |
---|
| 133 | isItemLoaded: function(/* anything */ something){ |
---|
| 134 | // summary: |
---|
| 135 | // Check whether the object is a jsx3.xml.Entity object and loaded |
---|
| 136 | |
---|
| 137 | return this.isItem(something); // Boolean |
---|
| 138 | }, |
---|
| 139 | |
---|
| 140 | loadItem: function(/* object */ keywordArgs){ |
---|
| 141 | // summary: |
---|
| 142 | // Load an item |
---|
| 143 | // description: |
---|
| 144 | // The store always loads all items, so if it's an item, then it's loaded. |
---|
| 145 | }, |
---|
| 146 | |
---|
| 147 | getFeatures: function(){ |
---|
| 148 | // summary: |
---|
| 149 | // Return supported data APIs |
---|
| 150 | |
---|
| 151 | return { |
---|
| 152 | "dojo.data.api.Read": true, |
---|
| 153 | "dojo.data.api.Write": true, |
---|
| 154 | "dojo.data.api.Identity":true |
---|
| 155 | }; // Object |
---|
| 156 | }, |
---|
| 157 | |
---|
| 158 | getLabel: function(/* jsx3.xml.Entity */ item){ |
---|
| 159 | // summary: |
---|
| 160 | // See dojo/data/api/Read.getLabel() |
---|
| 161 | |
---|
| 162 | if((this.label !== "") && this.isItem(item)){ |
---|
| 163 | var label = this.getValue(item,this.label); |
---|
| 164 | if(label){ |
---|
| 165 | return label.toString(); |
---|
| 166 | } |
---|
| 167 | } |
---|
| 168 | return undefined; //undefined |
---|
| 169 | }, |
---|
| 170 | |
---|
| 171 | getLabelAttributes: function(/* jsx3.xml.Entity */ item){ |
---|
| 172 | // summary: |
---|
| 173 | // returns an array of what properties of the item that were used |
---|
| 174 | // to generate its label |
---|
| 175 | // See dojo/data/api/Read.getLabelAttributes() |
---|
| 176 | |
---|
| 177 | if(this.label !== ""){ |
---|
| 178 | return [this.label]; //array |
---|
| 179 | } |
---|
| 180 | return null; //null |
---|
| 181 | }, |
---|
| 182 | |
---|
| 183 | |
---|
| 184 | fetch: function(/* Object? */ request){ |
---|
| 185 | // summary: |
---|
| 186 | // Returns an Array of items based on the request arguments. |
---|
| 187 | // description: |
---|
| 188 | // Returns an Array of items based on the request arguments. |
---|
| 189 | // If the store is in ASYNC mode, the items should be expected in an onComplete |
---|
| 190 | // method passed in the request object. If store is in SYNC mode, the items will |
---|
| 191 | // be return directly as well as within the onComplete method. |
---|
| 192 | // |
---|
| 193 | // note: |
---|
| 194 | // The mode can be set on store initialization or during a fetch as one of the |
---|
| 195 | // parameters. |
---|
| 196 | // |
---|
| 197 | // See: |
---|
| 198 | // |
---|
| 199 | // - http://www.tibco.com/devnet/resources/gi/3_7/api/html/jsx3/xml/Entity.html#method:selectNodes |
---|
| 200 | // - http://www.w3.org/TR/xpath |
---|
| 201 | // - http://msdn.microsoft.com/en-us/library/ms256086.aspx |
---|
| 202 | // |
---|
| 203 | // See dojo.data.Read.fetch(): |
---|
| 204 | // |
---|
| 205 | // - onBegin |
---|
| 206 | // - onComplete |
---|
| 207 | // - onItem |
---|
| 208 | // - onError |
---|
| 209 | // - scope |
---|
| 210 | // - start |
---|
| 211 | // - count |
---|
| 212 | // - sort |
---|
| 213 | // request: String |
---|
| 214 | // The items in the store are treated as objects, but this is reading an XML |
---|
| 215 | // document. Further, the actual querying of the items takes place in Tibco GI's |
---|
| 216 | // jsx3.xml.Entity. Therefore, we are using their syntax which is xpath. |
---|
| 217 | // |
---|
| 218 | // Note: |
---|
| 219 | // As conforming to a CDF document, most, if not all nodes are considered "records" |
---|
| 220 | // and their tagNames are as such. The root node is named "data". |
---|
| 221 | // example: |
---|
| 222 | // All items: |
---|
| 223 | // | store.fetch({query:"*"}); |
---|
| 224 | // example: |
---|
| 225 | // Item with a jsxid attribute equal to "1" (note you could use byId for this) |
---|
| 226 | // | store.fetch({query:"//record[@jsxid='1']"}); |
---|
| 227 | // example: |
---|
| 228 | // All items with any jsxid attribute: |
---|
| 229 | // | "//record[@jsxid='*']" |
---|
| 230 | // example: |
---|
| 231 | // The items with a jsxid of '1' or '4': |
---|
| 232 | // | "//record[@jsxid='4' or @jsxid='1']" |
---|
| 233 | // example: |
---|
| 234 | // All children within a "group" node (could be multiple group nodes): |
---|
| 235 | // "//group/record" |
---|
| 236 | // example: |
---|
| 237 | // All children within a specific group node: |
---|
| 238 | // "//group[@name='mySecondGroup']/record" |
---|
| 239 | // example: |
---|
| 240 | // Any record, anywhere in the document: |
---|
| 241 | // | "//record" |
---|
| 242 | // Only the records beneath the root (data) node: |
---|
| 243 | // | "//data/record" |
---|
| 244 | |
---|
| 245 | request = request || {}; |
---|
| 246 | if(!request.store){ |
---|
| 247 | request.store = this; |
---|
| 248 | } |
---|
| 249 | if(request.mode !== undefined){ |
---|
| 250 | this.mode = request.mode; |
---|
| 251 | } |
---|
| 252 | var self = this; |
---|
| 253 | |
---|
| 254 | var errorHandler = function(errorData){ |
---|
| 255 | if(request.onError){ |
---|
| 256 | var scope = request.scope || dojo.global; |
---|
| 257 | request.onError.call(scope, errorData, request); |
---|
| 258 | }else{ |
---|
| 259 | console.error("cdfStore Error:", errorData); |
---|
| 260 | } |
---|
| 261 | }; |
---|
| 262 | |
---|
| 263 | var fetchHandler = function(items, requestObject){ |
---|
| 264 | requestObject = requestObject || request; |
---|
| 265 | var oldAbortFunction = requestObject.abort || null; |
---|
| 266 | var aborted = false; |
---|
| 267 | |
---|
| 268 | var startIndex = requestObject.start?requestObject.start:0; |
---|
| 269 | var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(startIndex + requestObject.count):items.length; |
---|
| 270 | |
---|
| 271 | requestObject.abort = function(){ |
---|
| 272 | aborted = true; |
---|
| 273 | if(oldAbortFunction){ |
---|
| 274 | oldAbortFunction.call(requestObject); |
---|
| 275 | } |
---|
| 276 | }; |
---|
| 277 | |
---|
| 278 | var scope = requestObject.scope || dojo.global; |
---|
| 279 | if(!requestObject.store){ |
---|
| 280 | requestObject.store = self; |
---|
| 281 | } |
---|
| 282 | if(requestObject.onBegin){ |
---|
| 283 | requestObject.onBegin.call(scope, items.length, requestObject); |
---|
| 284 | } |
---|
| 285 | if(requestObject.sort){ |
---|
| 286 | items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self)); |
---|
| 287 | } |
---|
| 288 | |
---|
| 289 | if(requestObject.onItem){ |
---|
| 290 | for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){ |
---|
| 291 | var item = items[i]; |
---|
| 292 | if(!aborted){ |
---|
| 293 | requestObject.onItem.call(scope, item, requestObject); |
---|
| 294 | } |
---|
| 295 | } |
---|
| 296 | } |
---|
| 297 | if(requestObject.onComplete && !aborted){ |
---|
| 298 | if(!requestObject.onItem){ |
---|
| 299 | items = items.slice(startIndex, endIndex); |
---|
| 300 | if(requestObject.byId){ |
---|
| 301 | items = items[0]; |
---|
| 302 | } |
---|
| 303 | } |
---|
| 304 | requestObject.onComplete.call(scope, items, requestObject); |
---|
| 305 | }else{ |
---|
| 306 | items = items.slice(startIndex, endIndex); |
---|
| 307 | if(requestObject.byId){ |
---|
| 308 | items = items[0]; |
---|
| 309 | } |
---|
| 310 | } |
---|
| 311 | return items; |
---|
| 312 | }; |
---|
| 313 | |
---|
| 314 | if(!this.url && !this.data && !this.xmlStr){ |
---|
| 315 | errorHandler(new Error("No URL or data specified.")); |
---|
| 316 | return false; |
---|
| 317 | } |
---|
| 318 | var localRequest = request || "*"; // use request for _getItems() |
---|
| 319 | |
---|
| 320 | if(this.mode == dojox.data.SYNC_MODE){ |
---|
| 321 | // sync mode. items returned directly |
---|
| 322 | var res = this._loadCDF(); |
---|
| 323 | if(res instanceof Error){ |
---|
| 324 | if(request.onError){ |
---|
| 325 | request.onError.call(request.scope || dojo.global, res, request); |
---|
| 326 | }else{ |
---|
| 327 | console.error("CdfStore Error:", res); |
---|
| 328 | } |
---|
| 329 | return res; |
---|
| 330 | } |
---|
| 331 | this.cdfDoc = res; |
---|
| 332 | |
---|
| 333 | var items = this._getItems(this.cdfDoc, localRequest); |
---|
| 334 | if(items && items.length > 0){ |
---|
| 335 | items = fetchHandler(items, request); |
---|
| 336 | }else{ |
---|
| 337 | items = fetchHandler([], request); |
---|
| 338 | } |
---|
| 339 | return items; |
---|
| 340 | |
---|
| 341 | }else{ |
---|
| 342 | |
---|
| 343 | // async mode. Return a Deferred. |
---|
| 344 | var dfd = this._loadCDF(); |
---|
| 345 | dfd.addCallbacks(dojo.hitch(this, function(cdfDoc){ |
---|
| 346 | var items = this._getItems(this.cdfDoc, localRequest); |
---|
| 347 | if(items && items.length > 0){ |
---|
| 348 | fetchHandler(items, request); |
---|
| 349 | }else{ |
---|
| 350 | fetchHandler([], request); |
---|
| 351 | } |
---|
| 352 | }), |
---|
| 353 | dojo.hitch(this, function(err){ |
---|
| 354 | errorHandler(err, request); |
---|
| 355 | })); |
---|
| 356 | |
---|
| 357 | return dfd; // Object |
---|
| 358 | } |
---|
| 359 | }, |
---|
| 360 | |
---|
| 361 | |
---|
| 362 | _loadCDF: function(){ |
---|
| 363 | // summary: |
---|
| 364 | // Internal method. |
---|
| 365 | // If a cdfDoc exists, return it. Otherwise, get one from JSX3, |
---|
| 366 | // load the data or url, and return the doc or a deferred. |
---|
| 367 | var dfd = new dojo.Deferred(); |
---|
| 368 | if(this.cdfDoc){ |
---|
| 369 | if(this.mode == dojox.data.SYNC_MODE){ |
---|
| 370 | return this.cdfDoc; // jsx3.xml.CDF |
---|
| 371 | }else{ |
---|
| 372 | setTimeout(dojo.hitch(this, function(){ |
---|
| 373 | dfd.callback(this.cdfDoc); |
---|
| 374 | }), 0); |
---|
| 375 | return dfd; // dojo.Deferred |
---|
| 376 | } |
---|
| 377 | } |
---|
| 378 | |
---|
| 379 | this.cdfDoc = jsx3.xml.CDF.Document.newDocument(); |
---|
| 380 | this.cdfDoc.subscribe("response", this, function(evt){ |
---|
| 381 | dfd.callback(this.cdfDoc); |
---|
| 382 | }); |
---|
| 383 | this.cdfDoc.subscribe("error", this, function(err){ |
---|
| 384 | dfd.errback(err); |
---|
| 385 | }); |
---|
| 386 | |
---|
| 387 | this.cdfDoc.setAsync(!this.mode); |
---|
| 388 | if(this.url){ |
---|
| 389 | this.cdfDoc.load(this.url); |
---|
| 390 | }else if(this.xmlStr){ |
---|
| 391 | this.cdfDoc.loadXML(this.xmlStr); |
---|
| 392 | if(this.cdfDoc.getError().code){ |
---|
| 393 | return new Error(this.cdfDoc.getError().description); // Error |
---|
| 394 | } |
---|
| 395 | } |
---|
| 396 | |
---|
| 397 | if(this.mode == dojox.data.SYNC_MODE){ |
---|
| 398 | return this.cdfDoc; // jsx3.xml.CDF |
---|
| 399 | }else{ |
---|
| 400 | return dfd; // dojo.Deferred |
---|
| 401 | } |
---|
| 402 | }, |
---|
| 403 | |
---|
| 404 | _getItems: function(/* jsx3.xml.Entity */cdfDoc, /* Object */request){ |
---|
| 405 | // summary: |
---|
| 406 | // Internal method. |
---|
| 407 | // Requests the items from jsx3.xml.Entity with an xpath query. |
---|
| 408 | |
---|
| 409 | var itr = cdfDoc.selectNodes(request.query, false, 1); |
---|
| 410 | var items = []; |
---|
| 411 | while(itr.hasNext()){ |
---|
| 412 | items.push(itr.next()); |
---|
| 413 | } |
---|
| 414 | return items; |
---|
| 415 | }, |
---|
| 416 | |
---|
| 417 | close: function(/*dojo/data/api/Request|Object?*/ request){ |
---|
| 418 | // summary: |
---|
| 419 | // See dojo/data/api/Read.close() |
---|
| 420 | }, |
---|
| 421 | |
---|
| 422 | /* dojo/data/api/Write */ |
---|
| 423 | |
---|
| 424 | newItem: function(/* object? */ keywordArgs, /* Object|String? */ parentInfo){ |
---|
| 425 | // summary: |
---|
| 426 | // Creates a jsx3.xml.Entity item and inserts it either inside the |
---|
| 427 | // parent or appends it to the root |
---|
| 428 | |
---|
| 429 | keywordArgs = (keywordArgs || {}); |
---|
| 430 | if(keywordArgs.tagName){ |
---|
| 431 | // record tagName is automatic and this would add it |
---|
| 432 | // as a property |
---|
| 433 | if(keywordArgs.tagName!="record"){ |
---|
| 434 | // TODO: How about some sort of group? |
---|
| 435 | console.warn("Only record inserts are supported at this time"); |
---|
| 436 | } |
---|
| 437 | delete keywordArgs.tagName; |
---|
| 438 | } |
---|
| 439 | keywordArgs.jsxid = keywordArgs.jsxid || this.cdfDoc.getKey(); |
---|
| 440 | if(this.isItem(parentInfo)){ |
---|
| 441 | parentInfo = this.getIdentity(parentInfo); |
---|
| 442 | } |
---|
| 443 | var item = this.cdfDoc.insertRecord(keywordArgs, parentInfo); |
---|
| 444 | |
---|
| 445 | this._makeDirty(item); |
---|
| 446 | |
---|
| 447 | return item; // jsx3.xml.Entity |
---|
| 448 | }, |
---|
| 449 | |
---|
| 450 | deleteItem: function(/* jsx3.xml.Entity */ item){ |
---|
| 451 | // summary: |
---|
| 452 | // Delete an jsx3.xml.Entity (wrapper to a XML element). |
---|
| 453 | |
---|
| 454 | this.cdfDoc.deleteRecord(this.getIdentity(item)); |
---|
| 455 | this._makeDirty(item); |
---|
| 456 | return true; //boolean |
---|
| 457 | }, |
---|
| 458 | |
---|
| 459 | setValue: function(/* jsx3.xml.Entity */ item, /* String */ property, /* almost anything */ value){ |
---|
| 460 | // summary: |
---|
| 461 | // Set an property value |
---|
| 462 | |
---|
| 463 | this._makeDirty(item); |
---|
| 464 | item.setAttribute(property, value); |
---|
| 465 | return true; // Boolean |
---|
| 466 | }, |
---|
| 467 | |
---|
| 468 | setValues: function(/* jsx3.xml.Entity */ item, /* String */ property, /*array*/ values){ |
---|
| 469 | // summary: |
---|
| 470 | // Set property values. |
---|
| 471 | |
---|
| 472 | // TODO: Needs to be fully implemented. |
---|
| 473 | |
---|
| 474 | this._makeDirty(item); |
---|
| 475 | console.warn("cdfStore.setValues only partially implemented."); |
---|
| 476 | return item.setAttribute(property, values); |
---|
| 477 | |
---|
| 478 | }, |
---|
| 479 | |
---|
| 480 | unsetAttribute: function(/* jsx3.xml.Entity */ item, /* String */ property){ |
---|
| 481 | // summary: |
---|
| 482 | // Remove an property |
---|
| 483 | |
---|
| 484 | this._makeDirty(item); |
---|
| 485 | item.removeAttribute(property); |
---|
| 486 | return true; // Boolean |
---|
| 487 | }, |
---|
| 488 | |
---|
| 489 | revert: function(){ |
---|
| 490 | // summary: |
---|
| 491 | // Invalidate changes (new and/or modified elements) |
---|
| 492 | // Resets data by simply deleting the reference to the cdfDoc. |
---|
| 493 | // Subsequent fetches will load the new data. |
---|
| 494 | // |
---|
| 495 | // Note: |
---|
| 496 | // Any items outside the store will no longer be valid and may cause errors. |
---|
| 497 | |
---|
| 498 | delete this.cdfDoc; |
---|
| 499 | this._modifiedItems = {}; |
---|
| 500 | return true; //boolean |
---|
| 501 | }, |
---|
| 502 | |
---|
| 503 | isDirty: function(/* jsx3.xml.Entity ? */ item){ |
---|
| 504 | // summary: |
---|
| 505 | // Check whether an item is new, modified or deleted. |
---|
| 506 | // If no item is passed, checks if anything in the store has changed. |
---|
| 507 | |
---|
| 508 | if(item){ |
---|
| 509 | return !!this._modifiedItems[this.getIdentity(item)]; // Boolean |
---|
| 510 | }else{ |
---|
| 511 | var _dirty = false; |
---|
| 512 | for(var nm in this._modifiedItems){ _dirty = true; break; } |
---|
| 513 | return _dirty; // Boolean |
---|
| 514 | } |
---|
| 515 | }, |
---|
| 516 | |
---|
| 517 | |
---|
| 518 | |
---|
| 519 | /* internal API */ |
---|
| 520 | |
---|
| 521 | _makeDirty: function(item){ |
---|
| 522 | // summary: |
---|
| 523 | // Internal method. |
---|
| 524 | // Marks items as modified, deleted or new. |
---|
| 525 | var id = this.getIdentity(item); |
---|
| 526 | this._modifiedItems[id] = item; |
---|
| 527 | }, |
---|
| 528 | |
---|
| 529 | |
---|
| 530 | _makeXmlString: function(obj){ |
---|
| 531 | // summary: |
---|
| 532 | // Internal method. |
---|
| 533 | // Converts an object into an XML string. |
---|
| 534 | |
---|
| 535 | var parseObj = function(obj, name){ |
---|
| 536 | var xmlStr = ""; |
---|
| 537 | var nm; |
---|
| 538 | if(dojo.isArray(obj)){ |
---|
| 539 | for(var i=0;i<obj.length;i++){ |
---|
| 540 | xmlStr += parseObj(obj[i], name); |
---|
| 541 | } |
---|
| 542 | }else if(dojo.isObject(obj)){ |
---|
| 543 | xmlStr += '<'+name+' '; |
---|
| 544 | for(nm in obj){ |
---|
| 545 | if(!dojo.isObject(obj[nm])){ |
---|
| 546 | xmlStr += nm+'="'+obj[nm]+'" '; |
---|
| 547 | } |
---|
| 548 | } |
---|
| 549 | xmlStr +='>'; |
---|
| 550 | for(nm in obj){ |
---|
| 551 | if(dojo.isObject(obj[nm])){ |
---|
| 552 | xmlStr += parseObj(obj[nm], nm); |
---|
| 553 | } |
---|
| 554 | } |
---|
| 555 | xmlStr += '</'+name+'>'; |
---|
| 556 | } |
---|
| 557 | return xmlStr; |
---|
| 558 | }; |
---|
| 559 | return parseObj(obj, "data"); |
---|
| 560 | }, |
---|
| 561 | |
---|
| 562 | /************************************* |
---|
| 563 | * Dojo.data Identity implementation * |
---|
| 564 | *************************************/ |
---|
| 565 | getIdentity: function(/* jsx3.xml.Entity */ item){ |
---|
| 566 | // summary: |
---|
| 567 | // Returns the identifier for an item. |
---|
| 568 | |
---|
| 569 | return this.getValue(item, this.identity); // String |
---|
| 570 | }, |
---|
| 571 | |
---|
| 572 | getIdentityAttributes: function(/* jsx3.xml.Entity */ item){ |
---|
| 573 | // summary: |
---|
| 574 | // Returns the property used for the identity. |
---|
| 575 | |
---|
| 576 | return [this.identity]; // Array |
---|
| 577 | }, |
---|
| 578 | |
---|
| 579 | |
---|
| 580 | fetchItemByIdentity: function(/* Object|String */ args){ |
---|
| 581 | // summary: |
---|
| 582 | // See dojo/data/api/Identity.fetchItemByIdentity(keywordArgs). |
---|
| 583 | // |
---|
| 584 | // Note: |
---|
| 585 | // This method can be synchronous if mode is set. |
---|
| 586 | // Also, there is a more finger friendly alias of this method, byId(); |
---|
| 587 | if(dojo.isString(args)){ |
---|
| 588 | var id = args; |
---|
| 589 | args = {query:"//record[@jsxid='"+id+"']", mode: dojox.data.SYNC_MODE}; |
---|
| 590 | }else{ |
---|
| 591 | if(args){ |
---|
| 592 | args.query = "//record[@jsxid='"+args.identity+"']"; |
---|
| 593 | } |
---|
| 594 | if(!args.mode){args.mode = this.mode;} |
---|
| 595 | } |
---|
| 596 | args.byId = true; |
---|
| 597 | return this.fetch(args); // dojo/_base/Deferred|Array |
---|
| 598 | }, |
---|
| 599 | byId: function(/* Object|String */ args){ |
---|
| 600 | // stub. See fetchItemByIdentity |
---|
| 601 | } |
---|
| 602 | }); |
---|
| 603 | |
---|
| 604 | }); |
---|
| 605 | |
---|