New file |
0,0 → 1,386 |
import DojoExternalInterface; |
|
class Storage { |
public static var SUCCESS = "success"; |
public static var FAILED = "failed"; |
public static var PENDING = "pending"; |
|
// Wait the following number of milliseconds before flushing |
public static var FLUSH_DELAY_DEFAULT = 500; |
|
public var flush_delay; |
public var so; |
public var timer; |
|
private var _NAMESPACE_KEY = "allNamespaces"; |
|
public function Storage(){ |
flush_delay = Storage.FLUSH_DELAY_DEFAULT; |
|
//getURL("javascript:console.debug('FLASH:Storage constructor')"); |
DojoExternalInterface.initialize(); |
DojoExternalInterface.addCallback("put", this, put); |
DojoExternalInterface.addCallback("putMultiple", this, putMultiple); |
DojoExternalInterface.addCallback("get", this, get); |
DojoExternalInterface.addCallback("getMultiple", this, getMultiple); |
DojoExternalInterface.addCallback("showSettings", this, showSettings); |
DojoExternalInterface.addCallback("clear", this, clear); |
DojoExternalInterface.addCallback("getKeys", this, getKeys); |
DojoExternalInterface.addCallback("getNamespaces", this, getNamespaces); |
DojoExternalInterface.addCallback("remove", this, remove); |
DojoExternalInterface.addCallback("removeMultiple", this, removeMultiple); |
DojoExternalInterface.addCallback("flush", this, flush); |
DojoExternalInterface.addCallback("setFlushDelay", this, setFlushDelay); |
DojoExternalInterface.addCallback("getFlushDelay", this, getFlushDelay); |
DojoExternalInterface.loaded(); |
|
// preload the System Settings finished button movie for offline |
// access so it is in the cache |
_root.createEmptyMovieClip("_settingsBackground", 1); |
// getURL("javascript:alert('"+DojoExternalInterface.dojoPath+"');"); |
_root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf"); |
} |
|
// Set a new value for the flush delay timer. |
// Possible values: |
// 0 : Perform the flush synchronously after each "put" request |
// > 0 : Wait until 'newDelay' ms have passed without any "put" request to flush |
// -1 : Do not automatically flush |
public function setFlushDelay(newDelay){ |
flush_delay = Number(newDelay); |
} |
public function getFlushDelay(){ |
return String(flush_delay); |
} |
|
public function flush(namespace){ |
if(timer){ |
_global.clearTimeout(timer); |
delete timer; |
} |
|
var so = SharedObject.getLocal(namespace); |
|
//var st = (new Date()).getTime(); |
var flushResults = so.flush(); |
//var end = (new Date()).getTime(); |
//getURL("javascript:dojo.debug('FLASH: flush - not a word game - took " + (end - st) + "ms')"); |
|
// return results of this command to JavaScript |
var statusResults; |
if(flushResults == true){ |
statusResults = Storage.SUCCESS; |
}else if(flushResults == "pending"){ |
statusResults = Storage.PENDING; |
}else{ |
statusResults = Storage.FAILED; |
} |
|
DojoExternalInterface.call("dojox.storage._onStatus", null, statusResults, null); |
} |
|
// FIXME: This code has gotten ugly -- refactor |
public function put(keyName, keyValue, namespace){ |
// Get the SharedObject for these values and save it |
so = SharedObject.getLocal(namespace); |
|
// Save the key and value |
so.data[keyName] = keyValue; |
|
// Do all the flush/no-flush stuff |
var keyNames = new Array(); keyNames[0] = keyName; |
postWrite( so, keyNames, namespace); |
} |
|
public function putMultiple(metaKey, metaValue, metaLengths, namespace){ |
// Get the SharedObject for these values and save it |
so = SharedObject.getLocal(namespace); |
|
// Create array of keys and value lengths |
var keys = metaKey.split(","); |
var lengths = metaLengths.split(","); |
|
// Loop through the array and write the values |
for(var i=0;i<keys.length;i++){ |
so.data[keys[i]] = metaValue.slice(0,lengths[i]); |
metaValue = metaValue.slice(lengths[i]); |
} |
|
// Do all the flush/no-flush stuff |
postWrite( so, keys, namespace); |
} |
|
public function postWrite( so, keyNames, namespace){ |
// TODO: Review all this 'handler' stuff. In particular, the flush could now be with keys pending |
// from several different requests, not only the ones passed in this method call |
|
// prepare a storage status handler |
var self = this; |
so.onStatus = function(infoObject:Object){ |
//getURL("javascript:console.debug('FLASH: onStatus, infoObject="+infoObject.code+"')"); |
|
// delete the data value if the request was denied |
if(infoObject.code == "SharedObject.Flush.Failed"){ |
for(var i=0;i<keyNames.length;i++){ |
delete self.so.data[keyNames[i]]; |
} |
} |
|
var statusResults; |
if(infoObject.code == "SharedObject.Flush.Failed"){ |
statusResults = Storage.FAILED; |
}else if(infoObject.code == "SharedObject.Flush.Pending"){ |
statusResults = Storage.PENDING; |
}else if(infoObject.code == "SharedObject.Flush.Success"){ |
// if we have succeeded saving our value, see if we |
// need to update our list of namespaces |
if(self.hasNamespace(namespace) == true){ |
statusResults = Storage.SUCCESS; |
}else{ |
// we have a new namespace we must store |
self.addNamespace(namespace, keyNames[0]); |
return; |
} |
} |
//getURL("javascript:console.debug('FLASH: onStatus, statusResults="+statusResults+"')"); |
|
// give the status results to JavaScript |
DojoExternalInterface.call("dojox.storage._onStatus", null, statusResults, keyNames[0]); |
} |
|
// Clear any pending flush timers |
if(timer){ |
//getURL("javascript:dojo.debug('FLASH: clearing timer')"); |
_global.clearTimeout( timer); |
} |
|
// If we have a flush delay set, set a timer for its execution |
if(flush_delay > 0){ |
timer = _global.setTimeout( flush, flush_delay, namespace); |
// With a flush_delay value of 0, execute the flush request synchronously |
}else if(flush_delay == 0){ |
//getURL("javascript:dojo.debug('FLASH: calling flush now')"); |
flush(namespace); |
} |
// Otherwise just don't flush - will be probably be flushed manually |
} |
|
public function get(keyName, namespace){ |
// Get the SharedObject for these values and save it |
so = SharedObject.getLocal(namespace); |
var results = so.data[keyName]; |
|
return results; |
} |
|
// Returns an array with the contents of each key value on the metaKeys array |
public function getMultiple(metaKeys, namespace){ |
|
// get the storage object |
so = SharedObject.getLocal(namespace); |
|
// Create array of keys to read |
var keys = metaKeys.split(","); |
var results = new Array(); |
|
// Read from storage into results array |
for(var i=0;i<keys.length;i++){ |
var val = so.data[keys[i]]; |
val = val.split("\\").join("\\\\"); |
val = val.split('"').join('\\"'); |
results.push( val); |
} |
|
// Make the results array into a string |
var metaResults = '["' + results.join('","') + '"]'; |
|
return metaResults; |
} |
|
public function showSettings(){ |
// Show the configuration options for the Flash player, opened to the |
// section for local storage controls (pane 1) |
System.showSettings(1); |
|
// there is no way we can intercept when the Close button is pressed, allowing us |
// to hide the Flash dialog. Instead, we need to load a movie in the |
// background that we can show a close button on. |
_root.createEmptyMovieClip("_settingsBackground", 1); |
_root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath + "storage_dialog.swf"); |
} |
|
public function clear(namespace){ |
so = SharedObject.getLocal(namespace); |
so.clear(); |
so.flush(); |
|
// remove this namespace entry now |
removeNamespace(namespace); |
} |
|
public function getKeys(namespace){ |
// Returns a list of the available keys in this namespace |
|
// get the storage object |
so = SharedObject.getLocal(namespace); |
|
// get all of the keys |
var results = new Array(); |
for(var i in so.data){ |
results.push(i); |
} |
|
// remove our key that records our list of namespaces |
for(var i = 0; i < results.length; i++){ |
if(results[i] == _NAMESPACE_KEY){ |
results.splice(i, 1); |
break; |
} |
} |
|
// join the keys together in a comma seperated string |
results = results.join(","); |
|
return results; |
} |
|
public function getNamespaces(){ |
var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY); |
var results = new Array(); |
for(var i in allNamespaces.data){ |
results.push(i); |
} |
|
return results.join(","); |
} |
|
public function remove(keyName, namespace){ |
// Removes a key |
|
// get the storage object |
so = SharedObject.getLocal(namespace); |
|
// delete this value |
delete so.data[keyName]; |
|
// save the changes |
so.flush(); |
|
// see if we are the last entry for this namespace |
var availableKeys = getKeys(namespace); |
if(availableKeys == ""){ |
// we are empty |
removeNamespace(namespace); |
} |
} |
|
// Removes all the values for each keys on the metaKeys array |
public function removeMultiple(metaKeys, namespace){ |
|
// get the storage object |
so = SharedObject.getLocal(namespace); |
|
// Create array of keys to read |
var keys = metaKeys.split(","); |
var results = new Array(); |
|
// Delete elements |
for(var i=0;i<keys.length;i++){ |
delete so.data[keys[i]]; |
} |
|
// see if there are no more entries for this namespace |
var availableKeys = getKeys(namespace); |
if(availableKeys == ""){ |
// we are empty |
removeNamespace(namespace); |
} |
} |
|
private function hasNamespace(namespace):Boolean{ |
// Get the SharedObject for the namespace list |
var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY); |
|
var results = false; |
for(var i in allNamespaces.data){ |
if(i == namespace){ |
results = true; |
break; |
} |
} |
|
return results; |
} |
|
// FIXME: This code has gotten ugly -- refactor |
private function addNamespace(namespace, keyName){ |
if(hasNamespace(namespace) == true){ |
return; |
} |
|
// Get the SharedObject for the namespace list |
var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY); |
|
// prepare a storage status handler if the keyName is |
// not null |
if(keyName != null && typeof keyName != "undefined"){ |
var self = this; |
allNamespaces.onStatus = function(infoObject:Object){ |
// delete the data value if the request was denied |
if(infoObject.code == "SharedObject.Flush.Failed"){ |
delete self.so.data[keyName]; |
} |
|
var statusResults; |
if(infoObject.code == "SharedObject.Flush.Failed"){ |
statusResults = Storage.FAILED; |
}else if(infoObject.code == "SharedObject.Flush.Pending"){ |
statusResults = Storage.PENDING; |
}else if(infoObject.code == "SharedObject.Flush.Success"){ |
statusResults = Storage.SUCCESS; |
} |
|
// give the status results to JavaScript |
DojoExternalInterface.call("dojox.storage._onStatus", null, statusResults, keyName); |
} |
} |
|
// save the namespace list |
allNamespaces.data[namespace] = true; |
var flushResults = allNamespaces.flush(); |
|
// return results of this command to JavaScript |
if(keyName != null && typeof keyName != "undefined"){ |
var statusResults; |
if(flushResults == true){ |
statusResults = Storage.SUCCESS; |
}else if(flushResults == "pending"){ |
statusResults = Storage.PENDING; |
}else{ |
statusResults = Storage.FAILED; |
} |
|
DojoExternalInterface.call("dojox.storage._onStatus", null, statusResults, keyName); |
} |
} |
|
// FIXME: This code has gotten ugly -- refactor |
private function removeNamespace(namespace){ |
if(hasNamespace(namespace) == false){ |
return; |
} |
|
// try to save the namespace list; don't have a return |
// callback; if we fail on this, the worst that will happen |
// is that we have a spurious namespace entry |
var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY); |
delete allNamespaces.data[namespace]; |
allNamespaces.flush(); |
} |
|
static function main(mc){ |
//getURL("javascript:console.debug('FLASH: storage loaded')"); |
_root.app = new Storage(); |
} |
} |
|