source: Dev/trunk/src/client/dojox/calendar/StoreMixin.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 11.1 KB
Line 
1define(["dojo/_base/declare", "dojo/_base/array", "dojo/_base/html", "dojo/_base/lang", "dojo/dom-class",
2        "dojo/Stateful", "dojo/when"],
3        function(declare, arr, html, lang, domClass, Stateful, when){
4
5        return declare("dojox.calendar.StoreMixin", Stateful, {
6               
7                // summary:
8                //              This mixin contains the store management.
9               
10                // store: dojo.store.Store
11                //              The store that contains the events to display.
12                store: null,
13               
14                // query: Object
15                //              A query that can be passed to when querying the store.
16                query: {},
17
18                // queryOptions: dojo/store/api/Store.QueryOptions?
19                //              Options to be applied when querying the store.
20                queryOptions: null,
21
22                // startTimeAttr: String
23                //              The attribute of the store item that contains the start time of
24                //              the events represented by this item.    Default is "startTime".
25                startTimeAttr: "startTime",
26               
27                // endTimeAttr: String
28                //              The attribute of the store item that contains the end time of
29                //              the events represented by this item.    Default is "endTime".
30                endTimeAttr: "endTime",
31               
32                // summaryAttr: String
33                //              The attribute of the store item that contains the summary of
34                //              the events represented by this item.    Default is "summary".
35                summaryAttr: "summary",
36               
37                // allDayAttr: String
38                //              The attribute of the store item that contains the all day state of
39                //              the events represented by this item.    Default is "allDay".
40                allDayAttr: "allDay",
41       
42                // cssClassFunc: Function
43                //              Optional function that returns a css class name to apply to item renderers that are displaying the specified item in parameter.
44                cssClassFunc: null,             
45                                                       
46                // decodeDate: Function?
47                //              An optional function to transform store date into Date objects. Default is null.
48                decodeDate: null,
49               
50                // encodeDate: Function?
51                //              An optional function to transform Date objects into store date. Default is null.
52                encodeDate: null,
53               
54                // displayedItemsInvalidated: Boolean
55                //              Whether the data items displayed must be recomputed, usually after the displayed
56                //              time range has changed.
57                // tags:
58                //              protected
59                displayedItemsInvalidated: false,
60                                                                       
61                itemToRenderItem: function(item, store){
62                        // summary:
63                        //              Creates the render item based on the dojo.store item. It must be of the form:
64                        //      |       {
65                        //  |           id: Object,
66                        //      |               startTime: Date,
67                        //      |               endTime: Date,
68                        //      |               summary: String
69                        //      |       }
70                        //              By default it is building an object using the store id, the summaryAttr,
71                        //              startTimeAttr and endTimeAttr properties as well as decodeDate property if not null.
72                        //              Other fields or way to query fields can be used if needed.
73                        // item: Object
74                        //              The store item.
75                        // store: dojo.store.api.Store
76                        //              The store.
77                        // returns: Object
78                        if(this.owner){
79                                return this.owner.itemToRenderItem(item, store);
80                        }
81                        return {
82                                id: store.getIdentity(item),
83                                summary: item[this.summaryAttr],
84                                startTime: (this.decodeDate && this.decodeDate(item[this.startTimeAttr])) || this.newDate(item[this.startTimeAttr], this.dateClassObj),
85                                endTime: (this.decodeDate && this.decodeDate(item[this.endTimeAttr])) || this.newDate(item[this.endTimeAttr], this.dateClassObj),
86                                allDay: item[this.allDayAttr] != null ? item[this.allDayAttr] : false,
87                                cssClass: this.cssClassFunc ? this.cssClassFunc(item) : null
88                        };
89                },
90               
91                renderItemToItem: function(/*Object*/ renderItem, /*dojo.store.api.Store*/ store){
92                        // summary:
93                        //              Create a store item based on the render item. It must be of the form:
94                        //      |       {
95                        //      |               id: Object
96                        //      |               startTime: Date,
97                        //      |               endTime: Date,
98                        //      |               summary: String
99                        //      |       }
100                        //              By default it is building an object using the summaryAttr, startTimeAttr and endTimeAttr properties
101                        //              and encodeDate property if not null. If the encodeDate property is null a Date object will be set in the start and end time.
102                        //              When using a JsonRest store, for example, it is recommended to transfer dates using the ISO format (see dojo.date.stamp).
103                        //              In that case, provide a custom function to the encodeDate property that is using the date ISO encoding provided by Dojo.
104                        // renderItem: Object
105                        //              The render item.
106                        // store: dojo.store.api.Store
107                        //              The store.
108                        // returns:Object
109                        if(this.owner){
110                                return this.owner.renderItemToItem(renderItem, store);
111                        }
112                        var item = {};
113                        item[store.idProperty] = renderItem.id;
114                        item[this.summaryAttr] = renderItem.summary;
115                        item[this.startTimeAttr] = (this.encodeDate && this.encodeDate(renderItem.startTime)) || renderItem.startTime;
116                        item[this.endTimeAttr] = (this.encodeDate && this.encodeDate(renderItem.endTime)) || renderItem.endTime;
117                        return this.getItemStoreState(renderItem) == "unstored" ? item : lang.mixin(renderItem._item, item);
118                },                     
119               
120                _computeVisibleItems: function(renderData){
121                        // summary:
122                        //              Computes the data items that are in the displayed interval.
123                        // renderData: Object
124                        //              The renderData that contains the start and end time of the displayed interval.
125                        // tags:
126                        //              protected
127
128                        var startTime = renderData.startTime;
129                        var endTime = renderData.endTime;
130                        if(this.items){
131                                renderData.items = arr.filter(this.items, function(item){
132                                        return this.isOverlapping(renderData, item.startTime, item.endTime, startTime, endTime);
133                                }, this);
134                        }
135                },
136               
137                _initItems: function(items){
138                        // tags:
139                        //              private
140                        this.set("items", items);
141                        return items;
142                },
143               
144                _refreshItemsRendering: function(renderData){
145                },
146               
147                _updateItems: function(object, previousIndex, newIndex){
148                        // as soon as we add a item or remove one layout might change,
149                        // let's make that the default
150                        // TODO: what about items in non visible area...
151                        // tags:
152                        //              private
153                        var layoutCanChange = true;
154                        var oldItem = null;
155                        var newItem = this.itemToRenderItem(object, this.store);
156                        // keep a reference on the store data item.
157                        newItem._item = object;
158                       
159                        // set the item as in the store
160                       
161                        if(previousIndex!=-1){
162                                if(newIndex!=previousIndex){
163                                        // this is a remove or a move
164                                        this.items.splice(previousIndex, 1);
165                                        if(this.setItemSelected && this.isItemSelected(newItem)){
166                                                this.setItemSelected(newItem, false);
167                                                this.dispatchChange(newItem, this.get("selectedItem"), null, null);
168                                        }
169                                }else{
170                                        // this is a put, previous and new index identical
171                                        // check what changed
172                                        oldItem = this.items[previousIndex];
173                                        var cal = this.dateModule;
174                                        layoutCanChange = cal.compare(newItem.startTime, oldItem.startTime) != 0 ||
175                                                cal.compare(newItem.endTime, oldItem.endTime) != 0;
176                                        // we want to keep the same item object and mixin new values
177                                        // into old object
178                                        lang.mixin(oldItem, newItem);
179                                }
180                        }else if(newIndex!=-1){
181                                // this is a add
182                               
183                                var tempId = object.temporaryId;
184                                if(tempId){
185                                        // this item had a temporary id that was changed
186                                        var l = this.items.length;
187                                        for(var i=l-1; i>=0; i--){
188                                                if(this.items[i].id == tempId){
189                                                        this.items[i] = newItem;
190                                                        break;
191                                                }
192                                        }
193                                        this._cleanItemStoreState(tempId);
194                                        this._setItemStoreState(newItem, "storing");
195                                }
196                               
197                                var s = this._getItemStoreStateObj(newItem);
198                                if(s){
199                                        // if the item is at the correct index (creation)
200                                        // we must fix it. Should not occur but ensure integrity.
201                                        if(this.items[newIndex].id != newItem.id){                                             
202                                                var l = this.items.length;
203                                                for(var i=l-1; i>=0; i--){
204                                                        if(this.items[i].id == newItem.id){
205                                                                this.items.splice(i, 1);
206                                                                break;
207                                                        }
208                                                }                                               
209                                                this.items.splice(newIndex, 0, newItem);                                               
210                                        }
211                                        // update with the latest values from the store.
212                                        lang.mixin(s.renderItem, newItem);
213                                }else{
214                                        this.items.splice(newIndex, 0, newItem);                                       
215                                }
216                                this.set("items", this.items);
217                        }       
218                       
219                        this._setItemStoreState(newItem, "stored");
220                       
221                        if(!this._isEditing){
222                                if(layoutCanChange){                           
223                                        this._refreshItemsRendering();                 
224                                }else{
225                                        // just update the item
226                                        this.updateRenderers(oldItem);
227                                }
228                        }
229                },
230               
231                _setStoreAttr: function(value){
232                        this.displayedItemsInvalidated = true;
233                        var r;
234
235                        if(this._observeHandler){
236                                this._observeHandler.remove();
237                                this._observeHandler = null;
238                        }
239                        if(value){                             
240                                var results = value.query(this.query, this.queryOptions);
241                                if(results.observe){
242                                        // user asked us to observe the store
243                                        this._observeHandler = results.observe(lang.hitch(this, this._updateItems), true);
244                                }                               
245                                results = results.map(lang.hitch(this, function(item){
246                                        var renderItem = this.itemToRenderItem(item, value);
247                                        // keep a reference on the store data item.
248                                        renderItem._item = item;
249                                        return renderItem;
250                                }));
251                                r = when(results, lang.hitch(this, this._initItems));
252                        }else{
253                                // we remove the store
254                                r = this._initItems([]);
255                        }
256                        this._set("store", value);
257                        return r;
258                },
259               
260                _getItemStoreStateObj: function(/*Object*/item){
261                        // tags
262                        //              private
263                       
264                        if(this.owner){
265                                return this.owner._getItemStoreStateObj(item);
266                        }
267                       
268                        var store = this.get("store");
269                        if(store != null && this._itemStoreState != null){
270                                var id = item.id == undefined ? store.getIdentity(item) : item.id;
271                                return this._itemStoreState[id];
272                        }
273                        return null;
274                },
275               
276                getItemStoreState: function(item){
277                        //      summary:
278                        //              Returns the creation state of an item.
279                        //              This state is changing during the interactive creation of an item.
280                        //              Valid values are:
281                        //              - "unstored": The event is being interactively created. It is not in the store yet.
282                        //              - "storing": The creation gesture has ended, the event is being added to the store.
283                        //              - "stored": The event is not in the two previous states, and is assumed to be in the store
284                        //              (not checking because of performance reasons, use store API for testing existence in store).
285                        // item: Object
286                        //              The item.
287                        // returns: String
288                       
289                        if(this.owner){
290                                return this.owner.getItemStoreState(item);
291                        }
292
293                        if(this._itemStoreState == null){
294                                return "stored";
295                        }
296                       
297                        var store = this.get("store");
298                        var id = item.id == undefined ? store.getIdentity(item) : item.id;
299                        var s = this._itemStoreState[id];
300                       
301                        if(store != null && s != undefined){                           
302                                return s.state;                                                         
303                        }
304                        return "stored";               
305                },
306               
307                _setItemStoreState: function(/*Object*/item, /*String*/state){
308                        // tags
309                        //              private
310                       
311                        if(this.owner){
312                                this.owner._setItemStoreState(item, state);
313                                return;
314                        }
315                       
316                        if(this._itemStoreState == undefined){
317                                this._itemStoreState = {};
318                        }
319                       
320                        var store = this.get("store");
321                        var id = item.id == undefined ? store.getIdentity(item) : item.id;
322                        var s = this._itemStoreState[id];
323                       
324                                               
325                        if(state == "stored" || state == null){
326                                if(s != undefined){
327                                        delete this._itemStoreState[id];                                       
328                                }
329                                return;
330                        }
331
332                        if(store){                             
333                                this._itemStoreState[id] = {
334                                                id: id,
335                                                item: item,
336                                                renderItem: this.itemToRenderItem(item, store),
337                                                state: state
338                                };                                             
339                        }
340                },
341               
342                _cleanItemStoreState: function(id){ 
343                             
344                        if(this.owner){
345                                return this.owner._cleanItemStoreState(id);       
346                        }                       
347                        var s = this._itemStoreState[id];
348                        if(s){
349                                delete this._itemStoreState[id];
350                                return true;
351                        }
352                        return false;
353                }
354
355        });
356
357});
Note: See TracBrowser for help on using the repository browser.