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