source: Dev/trunk/src/client/dojox/storage/Storage.as

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

Added Dojo 1.9.3 release.

File size: 11.8 KB
Line 
1import DojoExternalInterface;
2
3class Storage{
4        public static var SUCCESS = "success";
5        public static var FAILED = "failed";
6        public static var PENDING = "pending";
7       
8        //      Wait the following number of milliseconds before flushing
9        public static var FLUSH_DELAY_DEFAULT = 500;
10       
11        public var flush_delay;
12        public var so;
13        public var timer;
14       
15        private var _NAMESPACE_KEY = "allNamespaces";
16       
17        public function Storage(){
18                flush_delay = Storage.FLUSH_DELAY_DEFAULT;
19       
20                DojoExternalInterface.initialize();
21                DojoExternalInterface.addCallback("put", this, put);
22                DojoExternalInterface.addCallback("putMultiple", this, putMultiple);
23                DojoExternalInterface.addCallback("get", this, get);
24                DojoExternalInterface.addCallback("getMultiple", this, getMultiple);
25                DojoExternalInterface.addCallback("showSettings", this, showSettings);
26                DojoExternalInterface.addCallback("clear", this, clear);
27                DojoExternalInterface.addCallback("getKeys", this, getKeys);
28                DojoExternalInterface.addCallback("getNamespaces", this, getNamespaces);
29                DojoExternalInterface.addCallback("remove", this, remove);
30                DojoExternalInterface.addCallback("removeMultiple", this, removeMultiple);
31                DojoExternalInterface.addCallback("flush", this, flush);
32                DojoExternalInterface.addCallback("setFlushDelay", this, setFlushDelay);
33                DojoExternalInterface.addCallback("getFlushDelay", this, getFlushDelay);
34                DojoExternalInterface.loaded();
35               
36                // preload the System Settings finished button movie for offline
37                // access so it is in the cache
38                _root.createEmptyMovieClip("_settingsBackground", 1);
39                _root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath
40                                                                                                                                                                + "../dojox/storage/storage_dialog.swf");
41        }
42
43  //  FIXME: Whoever added this Flush code did not document why it
44  //  exists. Please also put your name and a bug number so I know
45  //  who to contact. -- Brad Neuberg
46       
47        //      Set a new value for the flush delay timer.
48        //      Possible values:
49        //        0 : Perform the flush synchronously after each "put" request
50        //      > 0 : Wait until 'newDelay' ms have passed without any "put" request to flush
51        //       -1 : Do not automatically flush
52        public function setFlushDelay(newDelay){
53                flush_delay = Number(newDelay);
54        }
55       
56        public function getFlushDelay(){
57                return String(flush_delay);
58        }
59       
60        public function flush(namespace){
61                if(timer){
62                        _global.clearTimeout(timer);
63                        delete timer;
64                }
65       
66                var so = SharedObject.getLocal(namespace);
67                var flushResults = so.flush();
68
69                // return results of this command to JavaScript
70                var statusResults;
71                if(flushResults == true){
72                        statusResults = Storage.SUCCESS;
73                }else if(flushResults == "pending"){
74                        statusResults = Storage.PENDING;
75                }else{
76                        statusResults = Storage.FAILED;
77                }
78               
79                DojoExternalInterface.call("dojox.storage._onStatus", statusResults,
80                                            null, namespace);
81        }
82
83        public function put(keyName, keyValue, namespace){
84                // Get the SharedObject for these values and save it
85                so = SharedObject.getLocal(namespace);
86               
87                //  Save the key and value
88                so.data[keyName] = keyValue;
89               
90                // Save the namespace
91                // FIXME: Tie this into the flush/no-flush stuff below; right now
92                // we immediately write out this namespace. -- Brad Neuberg
93    addNamespace(namespace, keyName);
94
95                //      Do all the flush/no-flush stuff
96                var keyNames = new Array();
97                keyNames[0] = keyName;
98                postWrite(so, keyNames, namespace);
99        }
100       
101        public function putMultiple(metaKey, metaValue, metaLengths, namespace){
102                // Get the SharedObject for these values and save it
103                so = SharedObject.getLocal(namespace);
104               
105                //      Create array of keys and value lengths
106                var keys = metaKey.split(",");
107                var lengths = metaLengths.split(",");
108               
109                //      Loop through the array and write the values
110                for(var i = 0; i < keys.length; i++){
111                        so.data[keys[i]] = metaValue.slice(0,lengths[i]);
112                        metaValue = metaValue.slice(lengths[i]);
113                }
114               
115                // Save the namespace
116                // FIXME: Tie this into the flush/no-flush stuff below; right now
117                // we immediately write out this namespace. -- Brad Neuberg
118    addNamespace(namespace, null);
119               
120                //      Do all the flush/no-flush stuff
121                postWrite(so, keys, namespace);
122        }
123
124        public function postWrite(so, keyNames, namespace){
125                //      TODO: Review all this 'handler' stuff. In particular, the flush
126                //  could now be with keys pending from several different requests, not
127                //  only the ones passed in this method call
128
129                // prepare a storage status handler
130                var self = this;
131                so.onStatus = function(infoObject:Object){
132                        //trace("onStatus, infoObject="+infoObject.code);
133                       
134                        // delete the data value if the request was denied
135                        if(infoObject.code == "SharedObject.Flush.Failed"){
136                                for(var i=0;i<keyNames.length;i++){
137                                        delete self.so.data[keyNames[i]];
138                                }
139                        }
140                       
141                        var statusResults;
142                        if(infoObject.code == "SharedObject.Flush.Failed"){
143                                statusResults = Storage.FAILED;
144                        }else if(infoObject.code == "SharedObject.Flush.Pending"){
145                                statusResults = Storage.PENDING;
146                        }else if(infoObject.code == "SharedObject.Flush.Success"){
147                                // if we have succeeded saving our value, see if we
148                                // need to update our list of namespaces
149                                if(self.hasNamespace(namespace) == true){
150                                        statusResults = Storage.SUCCESS;
151                                }else{
152                                        // we have a new namespace we must store
153                                        self.addNamespace(namespace, keyNames[0]);
154                                        return;
155                                }
156                        }
157                        //trace("onStatus, statusResults="+statusResults);
158                       
159                        // give the status results to JavaScript
160                        DojoExternalInterface.call("dojox.storage._onStatus", statusResults,
161                                                    keyNames[0], namespace);
162                }
163               
164                //      Clear any pending flush timers
165                if(timer){
166                        _global.clearTimeout(timer);
167                }
168               
169                //      If we have a flush delay set, set a timer for its execution
170                if(flush_delay > 0){
171                        timer = _global.setTimeout(flush, flush_delay, namespace);
172                //      With a flush_delay value of 0, execute the flush request synchronously
173                }else if(flush_delay == 0){
174                        flush(namespace);
175                }
176                //      Otherwise just don't flush - will be probably be flushed manually
177        }
178
179        public function get(keyName, namespace){
180                // Get the SharedObject for these values and save it
181                so = SharedObject.getLocal(namespace);
182                var results = so.data[keyName];
183               
184                return results;
185        }
186       
187        //      Returns an array with the contents of each key value on the metaKeys array
188        public function getMultiple(metaKeys, namespace){
189                //      get the storage object
190                so = SharedObject.getLocal(namespace);
191               
192                //      Create array of keys to read
193                var keys = metaKeys.split(",");
194                var results = new Array();
195               
196                //      Read from storage into results array
197                for(var i = 0;i < keys.length;i++){
198                        var val = so.data[keys[i]];
199                        val = val.split("\\").join("\\\\");
200                        val = val.split('"').join('\\"');
201                        results.push( val);
202                }
203                       
204                //      Make the results array into a string
205                var metaResults = '["' + results.join('","') + '"]';
206               
207                return metaResults;
208        }       
209       
210        public function showSettings(){
211                // Show the configuration options for the Flash player, opened to the
212                // section for local storage controls (pane 1)
213                System.showSettings(1);
214               
215                // there is no way we can intercept when the Close button is pressed, allowing us
216                // to hide the Flash dialog. Instead, we need to load a movie in the
217                // background that we can show a close button on.
218                _root.createEmptyMovieClip("_settingsBackground", 1);
219                _root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath
220                                                                                                                                                                + "../dojox/storage/storage_dialog.swf");
221        }
222       
223        public function clear(namespace){
224                so = SharedObject.getLocal(namespace);
225                so.clear();
226                so.flush();
227               
228                // remove this namespace entry now
229                removeNamespace(namespace);
230        }
231       
232        public function getKeys(namespace) : String{
233                // Returns a list of the available keys in this namespace
234               
235                // get the storage object
236                so = SharedObject.getLocal(namespace);
237                // get all of the keys
238                var results = [];
239                for(var i in so.data){
240                        results.push(i);       
241                }
242               
243                // remove our key that records our list of namespaces
244                for(var i = 0; i < results.length; i++){
245                        if(results[i] == _NAMESPACE_KEY){
246                                results.splice(i, 1);
247                                break;
248                        }
249                }
250               
251                // a bug in ExternalInterface transforms Arrays into
252                // Strings, so we can't use those here! -- BradNeuberg
253                results = results.join(",");
254               
255                return results;
256        }
257       
258        public function getNamespaces() : String{
259                var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY);
260                var results = [];
261               
262                for(var i in allNamespaces.data){
263                        results.push(i);
264                }
265               
266                // a bug in ExternalInterface transforms Arrays into
267                // Strings, so we can use those here! -- BradNeuberg
268                results = results.join(",");
269               
270                return results;
271        }
272       
273        public function remove(keyName, namespace){
274                // Removes a key
275
276                // get the storage object
277                so = SharedObject.getLocal(namespace);
278               
279                // delete this value
280                delete so.data[keyName];
281               
282                // save the changes
283                so.flush();
284               
285                // see if we are the last entry for this namespace
286                var availableKeys = getKeys(namespace);
287                if(availableKeys == ""){
288                        // we are empty
289                        removeNamespace(namespace);
290                }
291        }
292       
293        //      Removes all the values for each keys on the metaKeys array
294        public function removeMultiple(metaKeys, namespace){           
295                //      get the storage object
296                so = SharedObject.getLocal(namespace);
297               
298                //      Create array of keys to read
299                var keys = metaKeys.split(",");
300                var results = new Array();
301
302                //      Delete elements
303                for(var i=0;i<keys.length;i++){
304                        delete so.data[keys[i]];
305                }
306
307                // see if there are no more entries for this namespace
308                var availableKeys = getKeys(namespace);
309                if(availableKeys == ""){
310                        // we are empty
311                        removeNamespace(namespace);
312                }
313        }
314       
315        private function hasNamespace(namespace):Boolean{
316                // Get the SharedObject for the namespace list
317                var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY);
318               
319                var results = false;
320                for(var i in allNamespaces.data){
321                        if(i == namespace){
322                                results = true;
323                                break;
324                        }
325                }
326               
327                return results;
328        }
329       
330        // FIXME: This code has gotten ugly -- refactor
331        private function addNamespace(namespace, keyName){
332                if(hasNamespace(namespace) == true){
333                        return;
334                }
335               
336                // Get the SharedObject for the namespace list
337                var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY);
338               
339                // prepare a storage status handler if the keyName is
340                // not null
341                if(keyName != null && typeof keyName != "undefined"){
342                        var self = this;
343                        allNamespaces.onStatus = function(infoObject:Object){
344                                // delete the data value if the request was denied
345                                if(infoObject.code == "SharedObject.Flush.Failed"){
346                                        delete self.so.data[keyName];
347                                }
348                               
349                                var statusResults;
350                                if(infoObject.code == "SharedObject.Flush.Failed"){
351                                        statusResults = Storage.FAILED;
352                                }else if(infoObject.code == "SharedObject.Flush.Pending"){
353                                        statusResults = Storage.PENDING;
354                                }else if(infoObject.code == "SharedObject.Flush.Success"){
355                                        statusResults = Storage.SUCCESS;
356                                }
357                               
358                                // give the status results to JavaScript
359                                DojoExternalInterface.call("dojox.storage._onStatus", statusResults,
360                                                            keyName, namespace);
361                        }
362                }
363               
364                // save the namespace list
365                allNamespaces.data[namespace] = true;
366                var flushResults = allNamespaces.flush();
367               
368                // return results of this command to JavaScript
369                if(keyName != null && typeof keyName != "undefined"){
370                        var statusResults;
371                        if(flushResults == true){
372                                statusResults = Storage.SUCCESS;
373                        }else if(flushResults == "pending"){
374                                statusResults = Storage.PENDING;
375                        }else{
376                                statusResults = Storage.FAILED;
377                        }
378                       
379                        DojoExternalInterface.call("dojox.storage._onStatus", statusResults,
380                                                    keyName, namespace);
381                }
382        }
383       
384        // FIXME: This code has gotten ugly -- refactor
385        private function removeNamespace(namespace){
386                if(hasNamespace(namespace) == false){
387                        return;
388                }
389               
390                // try to save the namespace list; don't have a return
391                // callback; if we fail on this, the worst that will happen
392                // is that we have a spurious namespace entry
393                var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY);
394                delete allNamespaces.data[namespace];
395                allNamespaces.flush();
396        }
397
398        static function main(mc){
399                _root.app = new Storage();
400        }
401}
402
Note: See TracBrowser for help on using the repository browser.