]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/data/ObjectStore.js.uncompressed.js
1 define ( "dojo/data/ObjectStore" , [ "../_base/lang" , "../Evented" , "../_base/declare" , "../_base/Deferred" , "../_base/array" ,
2 "../_base/connect" , "../regexp"
3 ], function ( lang
, Evented
, declare
, Deferred
, array
, connect
, regexp
) {
5 // dojo/data/ObjectStore
10 return declare ( "dojo.data.ObjectStore" , [ Evented
],{
12 constructor : function ( options
){
14 // A Dojo Data implementation that wraps Dojo object stores for backwards
17 // The configuration information to pass into the data store.
18 // options.objectStore:
19 // The object store to use as the source provider for this data store
20 lang
. mixin ( this , options
);
22 labelProperty
: "label" ,
24 getValue : function ( /*Object*/ item
, /*String*/ property
, /*value?*/ defaultValue
){
26 // Gets the value of an item's 'property'
29 // The item to get the value from
31 // property to look up value for
35 return typeof item
. get === "function" ? item
. get ( property
) :
37 item
[ property
] : defaultValue
;
39 getValues : function ( item
, property
){
41 // Gets the value of an item's 'property' and returns
42 // it. If this value is an array it is just returned,
43 // if not, the value is added to an array and that is returned.
46 // property: /* string */
47 // property to look up value for
49 var val
= this . getValue ( item
, property
);
50 return val
instanceof Array
? val
: val
=== undefined ? [] : [ val
];
53 getAttributes : function ( item
){
55 // Gets the available attributes of an item's 'property' and returns
62 if ( item
. hasOwnProperty ( i
) && !( i
. charAt ( 0 ) == '_' && i
. charAt ( 1 ) == '_' )){
69 hasAttribute : function ( item
, attribute
){
71 // Checks to see if item has attribute
74 // attribute: /* string */
75 return attribute
in item
;
78 containsValue : function ( item
, attribute
, value
){
80 // Checks to see if 'item' has 'value' at 'attribute'
83 // attribute: /* string */
84 // value: /* anything */
85 return array
. indexOf ( this . getValues ( item
, attribute
), value
) > - 1 ;
89 isItem : function ( item
){
91 // Checks to see if the argument is an item
94 // attribute: /* string */
96 // we have no way of determining if it belongs, we just have object returned from
98 return ( typeof item
== 'object' ) && item
&& !( item
instanceof Date
);
101 isItemLoaded : function ( item
){
103 // Checks to see if the item is loaded.
105 // item: /* object */
107 return item
&& typeof item
. load
!== "function" ;
110 loadItem : function ( args
){
112 // Loads an item and calls the callback handler. Note, that this will call the callback
113 // handler even if the item is loaded. Consequently, you can use loadItem to ensure
114 // that an item is loaded is situations when the item may or may not be loaded yet.
115 // If you access a value directly through property access, you can use this to load
116 // a lazy value as well (doesn't need to be an item).
120 // item: item, // this item may or may not be loaded
121 // onItem: function(item){
122 // // do something with the item
127 if ( typeof args
. item
. load
=== "function" ){
128 Deferred
. when ( args
. item
. load (), function ( result
){
129 item
= result
; // in synchronous mode this can allow loadItem to return the value
130 var func
= result
instanceof Error
? args
. onError
: args
. onItem
;
132 func
. call ( args
. scope
, result
);
135 } else if ( args
. onItem
){
136 // even if it is already loaded, we will use call the callback, this makes it easier to
137 // use when it is not known if the item is loaded (you can always safely call loadItem).
138 args
. onItem
. call ( args
. scope
, args
. item
);
142 close : function ( request
){
143 return request
&& request
. abort
&& request
. abort ();
145 fetch : function ( args
){
147 // See dojo.data.api.Read.fetch
150 args
= lang
. delegate ( args
, args
&& args
. queryOptions
);
152 var scope
= args
. scope
|| self
;
153 var query
= args
. query
;
154 if ( typeof query
== "object" ){ // can be null, but that is ignore by for-in
155 query
= lang
. delegate ( query
); // don't modify the original
157 // find any strings and convert them to regular expressions for wildcard support
158 var required
= query
[ i
];
159 if ( typeof required
== "string" ){
160 query
[ i
] = RegExp ( "^" + regexp
. escapeString ( required
, "*?" ). replace ( /\*/g , '.*' ). replace ( /\?/g , '.' ) + "$" , args
. ignoreCase
? "mi" : "m" );
161 query
[ i
]. toString
= ( function ( original
){
170 var results
= this . objectStore
. query ( query
, args
);
171 Deferred
. when ( results
. total
, function ( totalCount
){
172 Deferred
. when ( results
, function ( results
){
174 args
. onBegin
. call ( scope
, totalCount
|| results
. length
, args
);
177 for ( var i
= 0 ; i
< results
. length
; i
++){
178 args
. onItem
. call ( scope
, results
[ i
], args
);
182 args
. onComplete
. call ( scope
, args
. onItem
? null : results
, args
);
187 function errorHandler ( error
){
189 args
. onError
. call ( scope
, error
, args
);
192 args
. abort = function (){
200 // if we were previously observing, cancel the last time to avoid multiple notifications. Just the best we can do for the impedance mismatch between APIs
201 this . observing
. cancel ();
203 this . observing
= results
. observe ( function ( object
, removedFrom
, insertedInto
){
204 if ( array
. indexOf ( self
. _dirtyObjects
, object
) == - 1 ){
205 if ( removedFrom
== - 1 ){
208 else if ( insertedInto
== - 1 ){
209 self
. onDelete ( object
);
212 for ( var i
in object
){
213 if ( i
!= self
. objectStore
. idProperty
){
214 self
. onSet ( object
, i
, null , object
[ i
]);
221 this . onFetch ( results
);
225 getFeatures : function (){
227 // return the store feature set
230 "dojo.data.api.Read" : !! this . objectStore
. get ,
231 "dojo.data.api.Identity" : true ,
232 "dojo.data.api.Write" : !! this . objectStore
. put
,
233 "dojo.data.api.Notification" : true
237 getLabel : function ( /* item */ item
){
239 // See dojo.data.api.Read.getLabel()
240 if ( this . isItem ( item
)){
241 return this . getValue ( item
, this . labelProperty
); //String
243 return undefined ; //undefined
246 getLabelAttributes : function ( /* item */ item
){
248 // See dojo.data.api.Read.getLabelAttributes()
249 return [ this . labelProperty
]; //array
252 //Identity API Support
255 getIdentity : function ( item
){
256 return this . objectStore
. getIdentity
? this . objectStore
. getIdentity ( item
) : item
[ this . objectStore
. idProperty
|| "id" ];
259 getIdentityAttributes : function ( item
){
261 // returns the attributes which are used to make up the
262 // identity of an item. Basically returns this.objectStore.idProperty
264 return [ this . objectStore
. idProperty
];
267 fetchItemByIdentity : function ( args
){
269 // fetch an item by its identity, by looking in our index of what we have loaded
271 Deferred
. when ( this . objectStore
. get ( args
. identity
),
274 args
. onItem
. call ( args
. scope
, result
);
277 args
. onError
. call ( args
. scope
, error
);
283 newItem : function ( data
, parentInfo
){
285 // adds a new item to the store at the specified point.
286 // Takes two parameters, data, and options.
289 // The data to be added in as an item.
293 // get the previous value or any empty array
294 var values
= this . getValue ( parentInfo
. parent
, parentInfo
. attribute
,[]);
296 values
= values
. concat ([ data
]);
297 data
. __parent
= values
;
298 this . setValue ( parentInfo
. parent
, parentInfo
. attribute
, values
);
300 this . _dirtyObjects
. push ({ object
: data
, save
: true });
304 deleteItem : function ( item
){
306 // deletes item and any references to that item from the store.
312 // If the desire is to delete only one reference, unsetAttribute or
313 // setValue is the way to go.
314 this . changing ( item
, true );
318 setValue : function ( item
, attribute
, value
){
320 // sets 'attribute' on 'item' to 'value'
322 var old
= item
[ attribute
];
324 item
[ attribute
]= value
;
325 this . onSet ( item
, attribute
, old
, value
);
327 setValues : function ( item
, attribute
, values
){
329 // sets 'attribute' on 'item' to 'value' value
332 if (! lang
. isArray ( values
)){
333 throw new Error ( "setValues expects to be passed an Array object as its value" );
335 this . setValue ( item
, attribute
, values
);
338 unsetAttribute : function ( item
, attribute
){
340 // unsets 'attribute' on 'item'
343 var old
= item
[ attribute
];
344 delete item
[ attribute
];
345 this . onSet ( item
, attribute
, old
, undefined );
350 changing : function ( object
, _deleting
){
352 // adds an object to the list of dirty objects. This object
353 // contains a reference to the object itself as well as a
354 // cloned and trimmed version of old object for use with
356 object
. __isDirty
= true ;
357 //if an object is already in the list of dirty objects, don't add it again
358 //or it will overwrite the premodification data set.
359 for ( var i
= 0 ; i
< this . _dirtyObjects
. length
; i
++){
360 var dirty
= this . _dirtyObjects
[ i
];
361 if ( object
== dirty
. object
){
363 // we are deleting, no object is an indicator of deletiong
364 dirty
. object
= false ;
365 if (! this . _saveNotNeeded
){
372 var old
= object
instanceof Array
? [] : {};
374 if ( object
. hasOwnProperty ( i
)){
378 this . _dirtyObjects
. push ({ object
: ! _deleting
&& object
, old
: old
, save
: ! this . _saveNotNeeded
});
381 save : function ( kwArgs
){
383 // Saves the dirty data using object store provider. See dojo.data.api.Write for API.
386 // This will cause the save to commit the dirty data for all
387 // ObjectStores as a single transaction.
389 // kwArgs.revertOnError
390 // This will cause the changes to be reverted if there is an
391 // error on the save. By default a revert is executed unless
392 // a value of false is provide for this parameter.
394 // TODOC: kwArgs pseudo
395 kwArgs
= kwArgs
|| {};
396 var result
, actions
= [];
397 var savingObjects
= [];
399 var dirtyObjects
= this . _dirtyObjects
;
400 var left
= dirtyObjects
. length
; // this is how many changes are remaining to be received from the server
402 connect
. connect ( kwArgs
, "onError" , function (){
403 if ( kwArgs
. revertOnError
!== false ){
404 var postCommitDirtyObjects
= dirtyObjects
;
405 dirtyObjects
= savingObjects
;
406 self
. revert (); // revert if there was an error
407 self
. _dirtyObjects
= postCommitDirtyObjects
;
410 self
. _dirtyObjects
= dirtyObjects
. concat ( savingObjects
);
413 if ( this . objectStore
. transaction
){
414 var transaction
= this . objectStore
. transaction ();
416 for ( var i
= 0 ; i
< dirtyObjects
. length
; i
++){
417 var dirty
= dirtyObjects
[ i
];
418 var object
= dirty
. object
;
420 delete object
. __isDirty
;
422 result
= this . objectStore
. put ( object
, { overwrite
: !! old
});
424 else if ( typeof old
!= "undefined" ){
425 result
= this . objectStore
. remove ( this . getIdentity ( old
));
427 savingObjects
. push ( dirty
);
428 dirtyObjects
. splice ( i
--, 1 );
429 Deferred
. when ( result
, function ( value
){
431 if ( kwArgs
. onComplete
){
432 kwArgs
. onComplete
. call ( kwArgs
. scope
, actions
);
437 // on an error we want to revert, first we want to separate any changes that were made since the commit
438 left
= - 1 ; // first make sure that success isn't called
439 kwArgs
. onError
. call ( kwArgs
. scope
, value
);
444 transaction
. commit ();
447 kwArgs
. onError
. call ( kwArgs
. scope
, value
);
451 revert : function ( kwArgs
){
453 // returns any modified data to its original state prior to a save();
455 var dirtyObjects
= this . _dirtyObjects
;
456 for ( var i
= dirtyObjects
. length
; i
> 0 ;){
458 var dirty
= dirtyObjects
[ i
];
459 var object
= dirty
. object
;
464 if ( old
. hasOwnProperty ( j
) && object
[ j
] !== old
[ j
]){
465 this . onSet ( object
, j
, object
[ j
], old
[ j
]);
470 if (! old
. hasOwnProperty ( j
)){
471 this . onSet ( object
, j
, object
[ j
]);
476 // was an addition, remove it
477 this . onDelete ( object
);
479 // was a deletion, we will add it back
482 delete ( object
|| old
). __isDirty
;
483 dirtyObjects
. splice ( i
, 1 );
487 isDirty : function ( item
){
489 // returns true if the item is marked as dirty or true if there are any dirty items
491 return !! this . _dirtyObjects
. length
;
493 return item
. __isDirty
;
495 //Notifcation Support
499 onDelete : function (){},
500 // an extra to get result sets
501 onFetch : function ( results
){}