]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/store/Observable.js.uncompressed.js
1 define ( "dojo/store/Observable" , [ "../_base/kernel" , "../_base/lang" , "../_base/Deferred" , "../_base/array" /*=====, "./api/Store" =====*/
2 ], function ( kernel
, lang
, Deferred
, array
/*=====, Store =====*/ ){
5 // dojo/store/Observable
7 var Observable = function ( /*Store*/ store
){
9 // The Observable store wrapper takes a store and sets an observe method on query()
10 // results that can be used to monitor results for changes.
13 // Observable wraps an existing store so that notifications can be made when a query
17 // Create a Memory store that returns an observable query, and then log some
18 // information about that query.
20 // | var store = Observable(new Memory({
22 // | {id: 1, name: "one", prime: false},
23 // | {id: 2, name: "two", even: true, prime: true},
24 // | {id: 3, name: "three", prime: true},
25 // | {id: 4, name: "four", even: true, prime: false},
26 // | {id: 5, name: "five", prime: true}
29 // | var changes = [], results = store.query({ prime: true });
30 // | var observer = results.observe(function(object, previousIndex, newIndex){
31 // | changes.push({previousIndex:previousIndex, newIndex:newIndex, object:object});
34 // See the Observable tests for more information.
36 var undef
, queryUpdaters
= [], revision
= 0 ;
37 // a Comet driven store could directly call notify to notify observers when data has
38 // changed on the backend
39 // create a new instance
40 store
= lang
. delegate ( store
);
42 store
. notify = function ( object
, existingId
){
44 var updaters
= queryUpdaters
. slice ();
45 for ( var i
= 0 , l
= updaters
. length
; i
< l
; i
++){
46 updaters
[ i
]( object
, existingId
);
49 var originalQuery
= store
. query
;
50 store
. query = function ( query
, options
){
51 options
= options
|| {};
52 var results
= originalQuery
. apply ( this , arguments
);
53 if ( results
&& results
. forEach
){
54 var nonPagedOptions
= lang
. mixin ({}, options
);
55 delete nonPagedOptions
. start
;
56 delete nonPagedOptions
. count
;
58 var queryExecutor
= store
. queryEngine
&& store
. queryEngine ( query
, nonPagedOptions
);
59 var queryRevision
= revision
;
60 var listeners
= [], queryUpdater
;
61 results
. observe = function ( listener
, includeObjectUpdates
){
62 if ( listeners
. push ( listener
) == 1 ){
63 // first listener was added, create the query checker and updater
64 queryUpdaters
. push ( queryUpdater = function ( changed
, existingId
){
65 Deferred
. when ( results
, function ( resultsArray
){
66 var atEnd
= resultsArray
. length
!= options
. count
;
68 if (++ queryRevision
!= revision
){
69 throw new Error ( "Query is out of date, you must observe() the query prior to any data modifications" );
71 var removedObject
, removedFrom
= - 1 , insertedInto
= - 1 ;
72 if ( existingId
!== undef
){
74 for ( i
= 0 , l
= resultsArray
. length
; i
< l
; i
++){
75 var object
= resultsArray
[ i
];
76 if ( store
. getIdentity ( object
) == existingId
){
77 removedObject
= object
;
79 if ( queryExecutor
|| ! changed
){ // if it was changed and we don't have a queryExecutor, we shouldn't remove it because updated objects would be eliminated
80 resultsArray
. splice ( i
, 1 );
89 // if a matches function exists, use that (probably more efficient)
90 ( queryExecutor
. matches
? queryExecutor
. matches ( changed
) : queryExecutor ([ changed
]). length
)){
92 var firstInsertedInto
= removedFrom
> - 1 ?
93 removedFrom
: // put back in the original slot so it doesn't move unless it needs to (relying on a stable sort below)
95 resultsArray
. splice ( firstInsertedInto
, 0 , changed
); // add the new item
96 insertedInto
= array
. indexOf ( queryExecutor ( resultsArray
), changed
); // sort it
97 // we now need to push the chagne back into the original results array
98 resultsArray
. splice ( firstInsertedInto
, 1 ); // remove the inserted item from the previous index
100 if (( options
. start
&& insertedInto
== 0 ) ||
101 (! atEnd
&& insertedInto
== resultsArray
. length
)){
102 // if it is at the end of the page, assume it goes into the prev or next page
105 resultsArray
. splice ( insertedInto
, 0 , changed
); // and insert into the results array with the correct index
109 // we don't have a queryEngine, so we can't provide any information
110 // about where it was inserted or moved to. If it is an update, we leave it's position alone, other we at least indicate a new object
111 if ( existingId
!== undef
){
112 // an update, keep the index the same
113 insertedInto
= removedFrom
;
114 } else if (! options
. start
){
116 insertedInto
= store
. defaultIndex
|| 0 ;
117 resultsArray
. splice ( insertedInto
, 0 , changed
);
120 if (( removedFrom
> - 1 || insertedInto
> - 1 ) &&
121 ( includeObjectUpdates
|| ! queryExecutor
|| ( removedFrom
!= insertedInto
))){
122 var copyListeners
= listeners
. slice ();
123 for ( i
= 0 ; listener
= copyListeners
[ i
]; i
++){
124 listener ( changed
|| removedObject
, removedFrom
, insertedInto
);
131 // TODO: Remove cancel in 2.0.
132 handle
. remove
= handle
. cancel = function (){
133 // remove this listener
134 var index
= array
. indexOf ( listeners
, listener
);
135 if ( index
> - 1 ){ // check to make sure we haven't already called cancel
136 listeners
. splice ( index
, 1 );
137 if (! listeners
. length
){
138 // no more listeners, remove the query updater too
139 queryUpdaters
. splice ( array
. indexOf ( queryUpdaters
, queryUpdater
), 1 );
149 function whenFinished ( method
, action
){
150 var original
= store
[ method
];
152 store
[ method
] = function ( value
){
154 // if one method calls another (like add() calling put()) we don't want two events
155 return original
. apply ( this , arguments
);
159 var results
= original
. apply ( this , arguments
);
160 Deferred
. when ( results
, function ( results
){
161 action (( typeof results
== "object" && results
) || value
);
170 // monitor for updates by listening to these methods
171 whenFinished ( "put" , function ( object
){
172 store
. notify ( object
, store
. getIdentity ( object
));
174 whenFinished ( "add" , function ( object
){
175 store
. notify ( object
);
177 whenFinished ( "remove" , function ( id
){
178 store
. notify ( undefined , id
);
184 lang
. setObject ( "dojo.store.Observable" , Observable
);