Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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