source: Dev/trunk/src/client/dojox/mvc/StatefulArray.js @ 529

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

Added Dojo 1.9.3 release.

File size: 7.1 KB
Line 
1define([
2        "dojo/_base/lang",
3        "dojo/Stateful"
4], function(lang, Stateful){
5        function update(/*dojox/mvc/StatefulArray*/ a){
6                // summary:
7                //              Set all array elements as stateful so that watch function runs.
8                // a: dojox/mvc/StatefulArray
9                //              The array.
10
11                // Notify change of elements.
12                if(a._watchElementCallbacks){
13                        a._watchElementCallbacks();
14                }
15
16                return a; // dojox/mvc/StatefulArray
17        }
18
19        var StatefulArray = function(/*Anything[]*/ a){
20                // summary:
21                //              An inheritance of native JavaScript array, that adds dojo/Stateful capability.
22                // description:
23                //              Supported methods are:
24                //
25                //              - pop() - watchElements() notification is done for the removed elements. watch() notification is done for the length.
26                //              - push() - watchElements() notification is done for the added elements. watch() notification is done for the length.
27                //              - reverse() - watchElements() notification is done, indicating that the change affects all elements.
28                //              - shift() - watchElements() notification is done for the removed elements. watch() notification is done for the length.
29                //              - sort() - watchElements() notification is done, indicating that the change affects all elements.
30                //              - splice() - watchElements() notification is done for the removed/added elements. watch() notification is done for the length. Returns an instance of StatefulArray instead of the native array.
31                //              - unshift() - watchElements() notification is done for the added elements. watch() notification is done for the length.
32                //              - concat() - Returns an instance of StatefulArray instead of the native Array.
33                //              - join() - The length as well as the elements are obtained via stateful getters, instead of direct access.
34                //              - slice() - The length as well as the elements are obtained via stateful getters, instead of direct access.
35                //              - Setting an element to this array via set() - watch() notification is done for the new element as well as the new length.
36                //              - Setting a length to this array via set() - watchElements() notification is done for the removed/added elements. watch() notification is done for the new length.
37
38                var array = lang._toArray(a || []);
39                var ctor = StatefulArray;
40                array.constructor = ctor;
41                return lang.mixin(array, {
42                        pop: function(){
43                                return this.splice(this.get("length") - 1, 1)[0];
44                        },
45                        push: function(){
46                                this.splice.apply(this, [this.get("length"), 0].concat(lang._toArray(arguments)));
47                                return this.get("length");
48                        },
49                        reverse: function(){
50                                return update([].reverse.apply(this, lang._toArray(arguments)));
51                        },
52                        shift: function(){
53                                return this.splice(0, 1)[0];
54                        },
55                        sort: function(){
56                                return update([].sort.apply(this, lang._toArray(arguments)));
57                        },
58                        splice: function(/*Number*/ idx, /*Number*/ n){
59                                // summary:
60                                //              Removes and then adds some elements to an array.
61                                //              watchElements() notification is done for the removed/added elements.
62                                //              watch() notification is done for the length.
63                                //              Returns an instance of StatefulArray instead of the native array.
64                                // idx: Number
65                                //              The index where removal/addition should be done.
66                                // n: Number
67                                //              How many elements to be removed at idx.
68                                // varargs: Anything[]
69                                //              The elements to be added to idx.
70                                // returns: dojox/mvc/StatefulArray
71                                //              The removed elements.
72
73                                var l = this.get("length");
74
75                                idx += idx < 0 ? l : 0;
76
77                                var p = Math.min(idx, l),
78                                 removals = this.slice(idx, idx + n),
79                                 adds = lang._toArray(arguments).slice(2);
80
81                                // Do the modification in a native manner except for setting additions
82                                [].splice.apply(this, [idx, n].concat(new Array(adds.length)));
83
84                                // Set additions in a stateful manner
85                                for(var i = 0; i < adds.length; i++){
86                                        this[p + i] = adds[i];
87                                }
88
89                                // Notify change of elements.
90                                if(this._watchElementCallbacks){
91                                        this._watchElementCallbacks(idx, removals, adds);
92                                }
93
94                                // Notify change of length.
95                                // Not calling the setter for "length" though, given removal/addition of array automatically changes the length.
96                                if(this._watchCallbacks){
97                                        this._watchCallbacks("length", l, l - removals.length + adds.length);
98                                }
99
100                                return removals; // dojox/mvc/StatefulArray
101                        },
102                        unshift: function(){
103                                this.splice.apply(this, [0, 0].concat(lang._toArray(arguments)));
104                                return this.get("length");
105                        },
106                        concat: function(/*Array*/ a){
107                                return new StatefulArray([].concat.apply(this, arguments));
108                        },
109                        join: function(/*String*/ sep){
110                                // summary:
111                                //              Returns a string joining string elements in a, with a separator.
112                                // sep: String
113                                //              The separator.
114
115                                var list = [];
116                                for(var l = this.get("length"), i = 0; i < l; i++){
117                                        list.push(this.get(i));
118                                }
119                                return list.join(sep); // String
120                        },
121                        slice: function(/*Number*/ start, /*Number*/ end){
122                                // summary:
123                                //              Returns partial elements of an array.
124                                // start: Number
125                                //              The index to begin with.
126                                // end: Number
127                                //              The index to end at. (a[end] won't be picked up)
128
129                                var l = this.get("length");
130
131                                start += start < 0 ? l : 0;
132                                end = (end === void 0 ? l : end) + (end < 0 ? l : 0);
133
134                                var slice = [];
135                                for(var i = start || 0; i < Math.min(end, this.get("length")); i++){
136                                        slice.push(this.get(i));
137                                }
138                                return new StatefulArray(slice); // dojox/mvc/StatefulArray
139                        },
140                        watchElements: function(/*Function*/ callback){
141                                // summary:
142                                //              Watch for change in array elements.
143                                // callback: Function
144                                //              The callback function, which should take: The array index, the removed elements, and the added elements.
145
146                                var callbacks = this._watchElementCallbacks, _self = this;
147                                if(!callbacks){
148                                        callbacks = this._watchElementCallbacks = function(idx, removals, adds){
149                                                for(var list = [].concat(callbacks.list), i = 0; i < list.length; i++){
150                                                        list[i].call(_self, idx, removals, adds);
151                                                }
152                                        };
153                                        callbacks.list = [];
154                                }
155
156                                callbacks.list.push(callback);
157
158                                var h = {};
159                                h.unwatch = h.remove = function(){
160                                        for(var list = callbacks.list, i = 0; i < list.length; i++){
161                                                if(list[i] == callback){
162                                                        list.splice(i, 1);
163                                                        break;
164                                                }
165                                        }
166                                };
167                                return h; // dojo/handle
168                        }
169                }, Stateful.prototype, {
170                        set: function(/*Number|String*/ name, /*Anything*/ value){
171                                // summary:
172                                //              Sets a new value to an array.
173                                // name: Number|String
174                                //              The property name.
175                                // value: Anything
176                                //              The new value.
177
178                                if(name == "length"){
179                                        var old = this.get("length");
180                                        if(old < value){
181                                                this.splice.apply(this, [old, 0].concat(new Array(value - old)));
182                                        }else if(value < old){
183                                                this.splice.apply(this, [value, old - value]);
184                                        }
185                                        return this;
186                                }else{
187                                        var oldLength = this.length;
188                                        Stateful.prototype.set.call(this, name, value);
189                                        if(oldLength != this.length){
190                                                Stateful.prototype.set.call(this, "length", this.length);
191                                        }
192                                        return this;
193                                }
194                        },
195                        isInstanceOf: function(cls){
196                                return Stateful.prototype.isInstanceOf.apply(this, arguments) || cls == StatefulArray;
197                        }
198                });
199        };
200
201        StatefulArray._meta = {bases: [Stateful]}; // For isInstanceOf()
202        return lang.setObject("dojox.mvc.StatefulArray", StatefulArray);
203});
Note: See TracBrowser for help on using the repository browser.