summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/storage
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/storage')
-rw-r--r--js/dojo/dojox/storage/AirDBStorageProvider.js252
-rw-r--r--js/dojo/dojox/storage/AirEncryptedLocalStorageProvider.js221
-rw-r--r--js/dojo/dojox/storage/AirFileStorageProvider.js232
-rw-r--r--js/dojo/dojox/storage/BehaviorStorageProvider.js241
-rw-r--r--js/dojo/dojox/storage/CookieStorageProvider.js207
-rw-r--r--js/dojo/dojox/storage/FlashStorageProvider.js347
-rw-r--r--js/dojo/dojox/storage/GearsStorageProvider.js388
-rw-r--r--js/dojo/dojox/storage/LocalStorageProvider.js209
-rw-r--r--js/dojo/dojox/storage/Provider.js345
-rw-r--r--js/dojo/dojox/storage/README115
-rw-r--r--js/dojo/dojox/storage/Storage.as402
-rw-r--r--js/dojo/dojox/storage/Storage.swfbin0 -> 3325 bytes
-rw-r--r--js/dojo/dojox/storage/WhatWGStorageProvider.js277
-rw-r--r--js/dojo/dojox/storage/_common.js24
-rw-r--r--js/dojo/dojox/storage/buildFlashStorage.sh4
-rw-r--r--js/dojo/dojox/storage/demos/helloworld.html90
-rw-r--r--js/dojo/dojox/storage/manager.js262
-rw-r--r--js/dojo/dojox/storage/storage_dialog.flabin0 -> 344064 bytes
-rw-r--r--js/dojo/dojox/storage/storage_dialog.swfbin0 -> 26980 bytes
19 files changed, 3616 insertions, 0 deletions
diff --git a/js/dojo/dojox/storage/AirDBStorageProvider.js b/js/dojo/dojox/storage/AirDBStorageProvider.js
new file mode 100644
index 0000000..71b6cbe
--- /dev/null
+++ b/js/dojo/dojox/storage/AirDBStorageProvider.js
@@ -0,0 +1,252 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/AirDBStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/manager,dojox/storage/Provider"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.AirDBStorageProvider");
+dojo.require("dojox.storage.manager");
+dojo.require("dojox.storage.Provider");
+
+if (dojo.isAIR) {
+ (function(){
+
+ if (!air) {
+ var air = {};
+ }
+ air.File = window.runtime.flash.filesystem.File;
+ air.SQLConnection = window.runtime.flash.data.SQLConnection;
+ air.SQLStatement = window.runtime.flash.data.SQLStatement;
+
+ // summary:
+ // Storage provider that uses features in the Adobe AIR runtime to achieve
+ // permanent storage
+ dojo.declare("dojox.storage.AirDBStorageProvider", [ dojox.storage.Provider ], {
+ DATABASE_FILE: "dojo.db",
+ TABLE_NAME: "__DOJO_STORAGE",
+ initialized: false,
+
+ _db: null,
+
+ initialize: function(){
+ this.initialized = false;
+
+ // need to initialize our storage database
+ try{
+ this._db = new air.SQLConnection();
+ this._db.open(air.File.applicationStorageDirectory.resolvePath(this.DATABASE_FILE));
+
+ this._sql("CREATE TABLE IF NOT EXISTS " + this.TABLE_NAME + "(namespace TEXT, key TEXT, value TEXT)");
+ this._sql("CREATE UNIQUE INDEX IF NOT EXISTS namespace_key_index ON " + this.TABLE_NAME + " (namespace, key)");
+
+ this.initialized = true;
+ }catch(e){
+ console.debug("dojox.storage.AirDBStorageProvider.initialize:", e);
+ }
+
+ // indicate that this storage provider is now loaded
+ dojox.storage.manager.loaded();
+ },
+
+ _sql: function(query, params){
+ var stmt = new air.SQLStatement();
+ stmt.sqlConnection = this._db;
+ stmt.text = query;
+ if (params){
+ for (var param in params){
+ stmt.parameters[param] = params[param];
+ }
+ }
+ stmt.execute();
+ return stmt.getResult();
+ },
+
+ _beginTransaction: function(){
+ this._db.begin();
+ },
+
+ _commitTransaction: function(){
+ this._db.commit();
+ },
+
+ isAvailable: function(){
+ return true;
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // try to store the value
+ try{
+ this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":key });
+ this._sql("INSERT INTO " + this.TABLE_NAME + " VALUES (:namespace, :key, :value)",
+ { ":namespace":namespace, ":key":key, ":value":value });
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirDBStorageProvider.put:", e);
+ resultsHandler(this.FAILED, key, e.toString());
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, key, null, namespace);
+ }
+ },
+
+ get: function(key, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ var results = this._sql("SELECT * FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":key });
+
+ if(results.data && results.data.length){
+ return results.data[0].value;
+ }
+
+ return null;
+ },
+
+ getNamespaces: function(){
+ var results = [ this.DEFAULT_NAMESPACE ];
+ var rs = this._sql("SELECT namespace FROM " + this.TABLE_NAME + " DESC GROUP BY namespace");
+ if (rs.data){
+ for(var i = 0; i < rs.data.length; i++){
+ if(rs.data[i].namespace != this.DEFAULT_NAMESPACE){
+ results.push(rs.data[i].namespace);
+ }
+ }
+ }
+ return results;
+ },
+
+ getKeys: function(namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ var rs = this._sql("SELECT key FROM " + this.TABLE_NAME + " WHERE namespace = :namespace", { ":namespace":namespace });
+ if (rs.data){
+ for(var i = 0; i < rs.data.length; i++){
+ results.push(rs.data[i].key);
+ }
+ }
+ return results;
+ },
+
+ clear: function(namespace){
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace", { ":namespace":namespace });
+ },
+
+ remove: function(key, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":key });
+ },
+
+ putMultiple: function(keys, values, resultsHandler, namespace) {
+ if(this.isValidKeyArray(keys) === false
+ || ! values instanceof Array
+ || keys.length != values.length){
+ throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]");
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // try to store the value
+ try{
+ this._beginTransaction();
+ for(var i=0;i<keys.length;i++) {
+ this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":keys[i] });
+ this._sql("INSERT INTO " + this.TABLE_NAME + " VALUES (:namespace, :key, :value)",
+ { ":namespace":namespace, ":key":keys[i], ":value":values[i] });
+ }
+ this._commitTransaction();
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirDBStorageProvider.putMultiple:", e);
+ if(resultsHandler){
+ resultsHandler(this.FAILED, keys, e.toString(), namespace);
+ }
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, keys, null);
+ }
+ },
+
+ getMultiple: function(keys, namespace){
+ if(this.isValidKeyArray(keys) === false){
+ throw new Error("Invalid key array given: " + keys);
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ for(var i=0;i<keys.length;i++){
+ var result = this._sql("SELECT * FROM " + this.TABLE_NAME + " WHERE namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":keys[i] });
+ results[i] = result.data && result.data.length ? result.data[0].value : null;
+ }
+
+ return results;
+ },
+
+ removeMultiple: function(keys, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ this._beginTransaction();
+ for(var i=0;i<keys.length;i++){
+ this._sql("DELETE FROM " + this.TABLE_NAME + " WHERE namespace = namespace = :namespace AND key = :key",
+ { ":namespace":namespace, ":key":keys[i] });
+ }
+ this._commitTransaction();
+ },
+
+ isPermanent: function(){ return true; },
+
+ getMaximumSize: function(){ return this.SIZE_NO_LIMIT; },
+
+ hasSettingsUI: function(){ return false; },
+
+ showSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ },
+
+ hideSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ }
+ });
+
+ dojox.storage.manager.register("dojox.storage.AirDBStorageProvider", new dojox.storage.AirDBStorageProvider());
+ dojox.storage.manager.initialize();
+ })();
+}
+});
diff --git a/js/dojo/dojox/storage/AirEncryptedLocalStorageProvider.js b/js/dojo/dojox/storage/AirEncryptedLocalStorageProvider.js
new file mode 100644
index 0000000..6e5f4a5
--- /dev/null
+++ b/js/dojo/dojox/storage/AirEncryptedLocalStorageProvider.js
@@ -0,0 +1,221 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/AirEncryptedLocalStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/manager,dojox/storage/Provider"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.AirEncryptedLocalStorageProvider");
+dojo.require("dojox.storage.manager");
+dojo.require("dojox.storage.Provider");
+
+if (dojo.isAIR) {
+ (function(){
+
+ if (!air) {
+ var air = {};
+ }
+ air.ByteArray = window.runtime.flash.utils.ByteArray;
+ air.EncryptedLocalStore = window.runtime.flash.data.EncryptedLocalStore,
+
+ // summary:
+ // Storage provider that uses features in the Adobe AIR runtime to achieve
+ // permanent storage
+ dojo.declare("dojox.storage.AirEncryptedLocalStorageProvider", [ dojox.storage.Provider ], {
+ initialize: function(){
+ // indicate that this storage provider is now loaded
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){
+ return true;
+ },
+
+ _getItem: function(key){
+ var storedValue = air.EncryptedLocalStore.getItem("__dojo_" + key);
+ return storedValue ? storedValue.readUTFBytes(storedValue.length) : "";
+ },
+
+ _setItem: function(key, value){
+ var bytes = new air.ByteArray();
+ bytes.writeUTFBytes(value);
+ air.EncryptedLocalStore.setItem("__dojo_" + key, bytes);
+ },
+
+ _removeItem: function(key){
+ air.EncryptedLocalStore.removeItem("__dojo_" + key);
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // try to store the value
+ try{
+ var namespaces = this._getItem("namespaces")||'|';
+ if(namespaces.indexOf('|'+namespace+'|')==-1){
+ this._setItem("namespaces", namespaces + namespace + '|');
+ }
+ var keys = this._getItem(namespace + "_keys")||'|';
+ if(keys.indexOf('|'+key+'|')==-1){
+ this._setItem(namespace + "_keys", keys + key + '|');
+ }
+ this._setItem('_' + namespace + '_' + key, value);
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirEncryptedLocalStorageProvider.put:", e);
+ resultsHandler(this.FAILED, key, e.toString(), namespace);
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, key, null, namespace);
+ }
+ },
+
+ get: function(key, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ return this._getItem('_' + namespace + '_' + key);
+ },
+
+ getNamespaces: function(){
+ var results = [ this.DEFAULT_NAMESPACE ];
+ var namespaces = (this._getItem("namespaces")||'|').split('|');
+ for (var i=0;i<namespaces.length;i++){
+ if(namespaces[i].length && namespaces[i] != this.DEFAULT_NAMESPACE){
+ results.push(namespaces[i]);
+ }
+ }
+ return results;
+ },
+
+ getKeys: function(namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ var keys = (this._getItem(namespace + "_keys")||'|').split('|');
+ for (var i=0;i<keys.length;i++){
+ if (keys[i].length){
+ results.push(keys[i]);
+ }
+ }
+ return results;
+ },
+
+ clear: function(namespace){
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ var namespaces = this._getItem("namespaces")||'|';
+ if(namespaces.indexOf('|'+namespace+'|')!=-1){
+ this._setItem("namespaces", namespaces.replace('|' + namespace + '|', '|'));
+ }
+ var keys = (this._getItem(namespace + "_keys")||'|').split('|');
+ for (var i=0;i<keys.length;i++){
+ if (keys[i].length){
+ this._removeItem(namespace + "_" + keys[i]);
+ }
+ }
+ this._removeItem(namespace + "_keys");
+ },
+
+ remove: function(key, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ var keys = this._getItem(namespace + "_keys")||'|';
+ if(keys.indexOf('|'+key+'|')!=-1){
+ this._setItem(namespace + "_keys", keys.replace('|' + key + '|', '|'));
+ }
+ this._removeItem('_' + namespace + '_' + key);
+ },
+
+ putMultiple: function(keys, values, resultsHandler, namespace) {
+ if(this.isValidKeyArray(keys) === false
+ || ! values instanceof Array
+ || keys.length != values.length){
+ throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]");
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // try to store the value
+ try{
+ for(var i=0;i<keys.length;i++) {
+ this.put(keys[i], values[i], null, namespace);
+ }
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirEncryptedLocalStorageProvider.putMultiple:", e);
+ if(resultsHandler){
+ resultsHandler(this.FAILED, keys, e.toString(), namespace);
+ }
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, keys, null);
+ }
+ },
+
+ getMultiple: function(keys, namespace){
+ if(this.isValidKeyArray(keys) === false){
+ throw new Error("Invalid key array given: " + keys);
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ for(var i=0;i<keys.length;i++){
+ results[i] = this.get(keys[i], namespace);
+ }
+ return results;
+ },
+
+ removeMultiple: function(keys, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ for(var i=0;i<keys.length;i++){
+ this.remove(keys[i], namespace);
+ }
+ },
+
+ isPermanent: function(){ return true; },
+
+ getMaximumSize: function(){ return this.SIZE_NO_LIMIT; },
+
+ hasSettingsUI: function(){ return false; },
+
+ showSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ },
+
+ hideSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ }
+ });
+
+ dojox.storage.manager.register("dojox.storage.AirEncryptedLocalStorageProvider", new dojox.storage.AirEncryptedLocalStorageProvider());
+ dojox.storage.manager.initialize();
+ })();
+}
+});
diff --git a/js/dojo/dojox/storage/AirFileStorageProvider.js b/js/dojo/dojox/storage/AirFileStorageProvider.js
new file mode 100644
index 0000000..9749913
--- /dev/null
+++ b/js/dojo/dojox/storage/AirFileStorageProvider.js
@@ -0,0 +1,232 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/AirFileStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/manager,dojox/storage/Provider"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.AirFileStorageProvider");
+dojo.require("dojox.storage.manager");
+dojo.require("dojox.storage.Provider");
+
+if (dojo.isAIR) {
+ (function(){
+
+ if (!air) {
+ var air = {};
+ }
+ air.File = window.runtime.flash.filesystem.File;
+ air.FileStream = window.runtime.flash.filesystem.FileStream;
+ air.FileMode = window.runtime.flash.filesystem.FileMode;
+
+ // summary:
+ // Storage provider that uses features in the Adobe AIR runtime to achieve
+ // permanent storage
+ dojo.declare("dojox.storage.AirFileStorageProvider", [ dojox.storage.Provider ], {
+ initialized: false,
+
+ _storagePath: "__DOJO_STORAGE/",
+
+ initialize: function(){
+ this.initialized = false;
+
+ // need to initialize our storage directory
+ try{
+ var dir = air.File.applicationStorageDirectory.resolvePath(this._storagePath);
+ if (!dir.exists){
+ dir.createDirectory();
+ }
+ this.initialized = true;
+ }catch(e){
+ console.debug("dojox.storage.AirFileStorageProvider.initialize:", e);
+ }
+
+ // indicate that this storage provider is now loaded
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){
+ return true;
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // try to store the value
+ try{
+ this.remove(key, namespace);
+
+ var dir = air.File.applicationStorageDirectory.resolvePath(this._storagePath + namespace);
+ if (!dir.exists){
+ dir.createDirectory();
+ }
+
+ var file = dir.resolvePath(key);
+ var stream = new air.FileStream();
+ stream.open(file, air.FileMode.WRITE);
+ stream.writeObject(value);
+ stream.close();
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirFileStorageProvider.put:", e);
+ resultsHandler(this.FAILED, key, e.toString(), namespace);
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, key, null, namespace);
+ }
+ },
+
+ get: function(key, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ var results = null;
+
+ var file = air.File.applicationStorageDirectory.resolvePath(this._storagePath + namespace + '/' + key);
+ if (file.exists && !file.isDirectory){
+ var stream = new air.FileStream();
+ stream.open(file, air.FileMode.READ);
+ results = stream.readObject();
+ stream.close();
+ }
+
+ return results;
+ },
+
+ getNamespaces: function(){
+ var results = [ this.DEFAULT_NAMESPACE ];
+ var dir = air.File.applicationStorageDirectory.resolvePath(this._storagePath);
+ var files = dir.getDirectoryListing(), i;
+ for (i = 0; i < files.length; i++) {
+ if(files[i].isDirectory && files[i].name != this.DEFAULT_NAMESPACE){
+ results.push(files[i].name);
+ }
+ }
+ return results;
+ },
+
+ getKeys: function(namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ var dir = air.File.applicationStorageDirectory.resolvePath(this._storagePath + namespace);
+ if (dir.exists && dir.isDirectory){
+ var files = dir.getDirectoryListing(), i;
+ for (i = 0; i < files.length; i++) {
+ results.push(files[i].name);
+ }
+ }
+ return results;
+ },
+
+ clear: function(namespace){
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ var dir = air.File.applicationStorageDirectory.resolvePath(this._storagePath + namespace);
+ if (dir.exists && dir.isDirectory){
+ dir.deleteDirectory(true);
+ }
+ },
+
+ remove: function(key, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ var file = air.File.applicationStorageDirectory.resolvePath(this._storagePath + namespace + '/' + key);
+ if (file.exists && !file.isDirectory){
+ file.deleteFile();
+ }
+ },
+
+ putMultiple: function(keys, values, resultsHandler, namespace) {
+ if(this.isValidKeyArray(keys) === false
+ || ! values instanceof Array
+ || keys.length != values.length){
+ throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]");
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // try to store the value
+ try{
+ for(var i=0;i<keys.length;i++) {
+ this.put(keys[i], values[i], null, namespace);
+ }
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.AirFileStorageProvider.putMultiple:", e);
+ if(resultsHandler){
+ resultsHandler(this.FAILED, keys, e.toString(), namespace);
+ }
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, keys, null, namespace);
+ }
+ },
+
+ getMultiple: function(keys, namespace){
+ if(this.isValidKeyArray(keys) === false){
+ throw new Error("Invalid key array given: " + keys);
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = this.DEFAULT_NAMESPACE;
+ }
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = [];
+ for(var i=0;i<keys.length;i++){
+ results[i] = this.get(keys[i], namespace);
+ }
+ return results;
+ },
+
+ removeMultiple: function(keys, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ for(var i=0;i<keys.length;i++){
+ this.remove(keys[i], namespace);
+ }
+ },
+
+ isPermanent: function(){ return true; },
+
+ getMaximumSize: function(){ return this.SIZE_NO_LIMIT; },
+
+ hasSettingsUI: function(){ return false; },
+
+ showSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ },
+
+ hideSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ }
+ });
+
+ dojox.storage.manager.register("dojox.storage.AirFileStorageProvider", new dojox.storage.AirFileStorageProvider());
+ dojox.storage.manager.initialize();
+ })();
+}
+});
diff --git a/js/dojo/dojox/storage/BehaviorStorageProvider.js b/js/dojo/dojox/storage/BehaviorStorageProvider.js
new file mode 100644
index 0000000..6ab2211
--- /dev/null
+++ b/js/dojo/dojox/storage/BehaviorStorageProvider.js
@@ -0,0 +1,241 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/BehaviorStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/Provider,dojox/storage/manager"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.BehaviorStorageProvider");
+
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+
+dojo.declare(
+ "dojox.storage.BehaviorStorageProvider",
+ [dojox.storage.Provider],
+ {
+ store: null,
+
+ storeName: '__dojox_BehaviorStorage',
+
+ keys: [],
+
+ initialize: function(){
+ try{
+ this.store = this._createStore();
+ this.store.load(this.storeName);
+ }catch(e){
+ throw new Error("Store is not available: " + e);
+ }
+
+ var keys = this.get('keys','dojoxSystemNS');
+ this.keys = keys || [];
+
+ this.initialized = true;
+ dojox.storage.manager.loaded();
+
+ },
+
+ isAvailable: function(){ /*Boolean*/
+ // This is not completely true. UserData may
+ // be disabled in security settings. To *really*
+ // check if this is available, one needs to wait
+ // until the store is successfully initialized...
+ return dojo.isIE && dojo.isIE >= 5;
+ },
+
+ _createStore: function() {
+ var storeNode = dojo.create(
+ 'link',
+ {id: this.storeName + 'Node', style: {'display':'none'}},
+ dojo.query('head')[0]
+ );
+ storeNode.addBehavior('#default#userdata');
+
+ return storeNode;
+ },
+
+ put: function( /*string*/ key,
+ /*object*/ value,
+ /*function*/ resultsHandler,
+ /*string?*/ namespace){
+
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ var fullKey = this.getFullKey(key,namespace);
+ value = dojo.toJson(value);
+
+ this.store.setAttribute(fullKey, value);
+ this.store.save(this.storeName);
+
+ var success = this.store.getAttribute(fullKey) === value;
+ if(success){
+ this._addKey(fullKey);
+ this.store.setAttribute('__dojoxSystemNS_keys', dojo.toJson(this.keys));
+ this.store.save(this.storeName);
+ }
+
+ if(resultsHandler){
+ resultsHandler(success ? this.SUCCESS : this.FAILED, key, null, namespace);
+ }
+ },
+
+ get: function(/*string*/ key, /*string?*/ namespace){ /*Object*/
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ key = this.getFullKey(key, namespace);
+
+ return dojo.fromJson(this.store.getAttribute(key));
+ },
+
+ getKeys: function(/*string?*/ namespace){ /*Array*/
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_';
+
+ var keys = [];
+ for(var i = 0; i < this.keys.length; i++){
+ var currentKey = this.keys[i];
+ if(this._beginsWith(currentKey,namespace)){
+ currentKey = currentKey.substring(namespace.length);
+ keys.push(currentKey);
+ }
+ }
+
+ return keys;
+ },
+
+ clear: function(/*string?*/ namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_';
+
+ var keys = [];
+ for(var i = 0; i < this.keys.length; i++){
+ var currentKey = this.keys[i];
+ if(this._beginsWith(currentKey,namespace)){
+ keys.push(currentKey);
+ }
+ }
+
+ dojo.forEach(keys, function(key){
+ this.store.removeAttribute(key);
+ this._removeKey(key);
+ }, this);
+
+ this.put('keys', this.keys, null, 'dojoxSystemNS');
+ this.store.save(this.storeName);
+ },
+
+ remove: function(/*string*/ key, /*string?*/ namespace){
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ key = this.getFullKey(key, namespace);
+ this.store.removeAttribute(key);
+
+ this._removeKey(key);
+ this.put('keys', this.keys, null, 'dojoxSystemNS');
+ this.store.save(this.storeName);
+
+ },
+
+ getNamespaces: function(){ /*string[]*/
+
+
+ var results = [ this.DEFAULT_NAMESPACE];
+
+ var found = {};
+ found[this.DEFAULT_NAMESPACE] = true;
+ var tester = /^__([^_]*)_/;
+
+ for(var i = 0; i < this.keys.length; i++){
+ var currentKey = this.keys[i];
+ if(tester.test(currentKey) == true){
+ var currentNS = currentKey.match(tester)[1];
+ if(typeof found[currentNS] == "undefined"){
+ found[currentNS] = true;
+ results.push(currentNS);
+ }
+ }
+ }
+
+ return results;
+
+ },
+
+ isPermanent: function(){ /*Boolean*/
+ return true;
+ },
+
+ getMaximumSize: function(){ /* mixed */
+ // this *might* be more, depending on the zone
+ // of the current site. But 64k is guaranteed.
+ return 64;
+ },
+
+ hasSettingsUI: function(){ /*Boolean*/
+ return false;
+ },
+
+ isValidKey: function(/*string*/ keyName){ /*Boolean*/
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z_-]*$/.test(keyName);
+ },
+
+ isValidNamespace: function(/*string*/ keyName){ /*Boolean*/
+
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z-]*$/.test(keyName);
+ },
+
+ getFullKey: function(key, namespace){
+ // checks for valid namespace and
+ // key are already performed.
+ return "__" + namespace + "_" + key;
+ },
+
+ _beginsWith: function(/* string */ haystack, /* string */ needle) {
+ if(needle.length > haystack.length) {
+ return false;
+ }
+ return haystack.substring(0,needle.length) === needle;
+ },
+
+ _assertIsValidNamespace: function(/* string */ namespace){
+ if(this.isValidNamespace(namespace) === false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ },
+
+ _assertIsValidKey: function(/* string */ key){
+ if(this.isValidKey(key) === false){
+ throw new Error("Invalid key given: " + key);
+ }
+ },
+
+ _addKey: function(key){
+ this._removeKey(key);
+ this.keys.push(key);
+ },
+
+ _removeKey: function(key){
+ this.keys = dojo.filter(this.keys,function(item){ return item !== key;},this);
+ }
+ }
+);
+
+dojox.storage.manager.register("dojox.storage.BehaviorStorageProvider", new dojox.storage.BehaviorStorageProvider());
+});
diff --git a/js/dojo/dojox/storage/CookieStorageProvider.js b/js/dojo/dojox/storage/CookieStorageProvider.js
new file mode 100644
index 0000000..292a347
--- /dev/null
+++ b/js/dojo/dojox/storage/CookieStorageProvider.js
@@ -0,0 +1,207 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/CookieStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/Provider,dojox/storage/manager,dojo/cookie"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.CookieStorageProvider");
+
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+dojo.require("dojo.cookie");
+
+dojo.declare(
+ "dojox.storage.CookieStorageProvider",
+ [dojox.storage.Provider],
+ {
+ store: null,
+
+ cookieName: 'dojoxStorageCookie',
+
+ storageLife: 730, // in days
+
+ initialize: function(){
+
+ this.store = dojo.fromJson(dojo.cookie(this.cookieName)) || {};
+
+ this.initialized = true;
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){ /*Boolean*/
+ return dojo.cookie.isSupported();
+ },
+
+ put: function( /*string*/ key,
+ /*object*/ value,
+ /*function*/ resultsHandler,
+ /*string?*/ namespace){
+
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ fullKey = this.getFullKey(key,namespace);
+
+ this.store[fullKey] = dojo.toJson(value);
+ this._save();
+
+ var success = dojo.toJson(this.store) === dojo.cookie(this.cookieName);
+
+ if(!success){
+ this.remove(key,namespace);
+ }
+
+ if(resultsHandler){
+ resultsHandler(success ? this.SUCCESS : this.FAILED, key, null, namespace);
+ }
+
+ },
+
+ get: function(/*string*/ key, /*string?*/ namespace){ /*Object*/
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ // get our full key name, which is namespace + key
+ key = this.getFullKey(key, namespace);
+
+ return this.store[key] ? dojo.fromJson(this.store[key]) : null;
+ },
+
+ getKeys: function(/*string?*/ namespace){ /*Array*/
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_';
+
+ var keys = [];
+ for(var currentKey in this.store){
+ if(this._beginsWith(currentKey,namespace)){
+ currentKey = currentKey.substring(namespace.length);
+ keys.push(currentKey);
+ }
+ }
+
+ return keys;
+ },
+
+ clear: function(/*string?*/ namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_';
+
+ for(var currentKey in this.store){
+ if(this._beginsWith(currentKey,namespace)){
+ delete(this.store[currentKey]);
+ }
+ }
+
+ this._save();
+ },
+
+ remove: function(/*string*/ key, /*string?*/ namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ this._assertIsValidKey(key);
+ key = this.getFullKey(key, namespace);
+
+ delete this.store[key];
+ this._save();
+ },
+
+ getNamespaces: function(){ /*string[]*/
+ // There must be a better way than
+ // to execute a regex on *every*
+ // item in the store.
+
+ var results = [this.DEFAULT_NAMESPACE];
+
+ var found = {};
+ found[this.DEFAULT_NAMESPACE] = true;
+ var tester = /^__([^_]*)_/;
+
+ for(var currentKey in this.store){
+ if(tester.test(currentKey) == true){
+ var currentNS = currentKey.match(tester)[1];
+ if(typeof found[currentNS] == "undefined"){
+ found[currentNS] = true;
+ results.push(currentNS);
+ }
+ }
+ }
+
+ return results;
+ },
+
+ isPermanent: function(){ /*Boolean*/
+ return true;
+ },
+
+ getMaximumSize: function(){ /* mixed */
+ return 4;
+ },
+
+ hasSettingsUI: function(){ /*Boolean*/
+ return false;
+ },
+
+ isValidKey: function(/*string*/ keyName){ /*Boolean*/
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z_-]*$/.test(keyName);
+ },
+
+ isValidNamespace: function(/*string*/ keyName){ /*Boolean*/
+ // we *must* prevent namespaces from having
+ // underscores - else lookup of namespaces
+ // via RegEx (e.g. in getNamespaces ) would
+ // return wrong results.
+ //
+ // The only way around this would be to
+ // disallow underscores in keys.
+
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z-]*$/.test(keyName);
+ },
+
+ getFullKey: function(key, namespace){
+ // checks for valid namespace and
+ // key are already performed.
+ return "__" + namespace + "_" + key;
+ },
+
+ _save: function(){
+ dojo.cookie(this.cookieName,dojo.toJson(this.store),{expires: this.storageLife});
+ },
+
+ _beginsWith: function(/* string */ haystack, /* string */ needle) {
+ if(needle.length > haystack.length) {
+ return false;
+ }
+ return haystack.substring(0,needle.length) === needle;
+ },
+
+ _assertIsValidNamespace: function(/* string */ namespace){
+ if(this.isValidNamespace(namespace) === false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ },
+
+ _assertIsValidKey: function(/* string */ key){
+ if(this.isValidKey(key) === false){
+ throw new Error("Invalid key given: " + key);
+ }
+ }
+ }
+);
+
+dojox.storage.manager.register("dojox.storage.CookieStorageProvider", new dojox.storage.CookieStorageProvider());
+
+});
diff --git a/js/dojo/dojox/storage/FlashStorageProvider.js b/js/dojo/dojox/storage/FlashStorageProvider.js
new file mode 100644
index 0000000..7bc4d9c
--- /dev/null
+++ b/js/dojo/dojox/storage/FlashStorageProvider.js
@@ -0,0 +1,347 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/FlashStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/flash,dojox/storage/manager,dojox/storage/Provider"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.FlashStorageProvider");
+
+dojo.require("dojox.flash");
+dojo.require("dojox.storage.manager");
+dojo.require("dojox.storage.Provider");
+
+// summary:
+// Storage provider that uses features in Flash to achieve permanent
+// storage
+// description:
+// Authors of this storage provider-
+// Brad Neuberg, bkn3@columbia.edu
+dojo.declare("dojox.storage.FlashStorageProvider", dojox.storage.Provider, {
+ initialized: false,
+
+ _available: null,
+ _statusHandler: null,
+ _flashReady: false,
+ _pageReady: false,
+
+ initialize: function(){
+ //console.debug("FlashStorageProvider.initialize");
+ if(dojo.config["disableFlashStorage"] == true){
+ return;
+ }
+
+ // initialize our Flash
+ dojox.flash.addLoadedListener(dojo.hitch(this, function(){
+ //console.debug("flashReady");
+ // indicate our Flash subsystem is now loaded
+ this._flashReady = true;
+ if(this._flashReady && this._pageReady){
+ this._loaded();
+ }
+ }));
+ var swfLoc = dojo.moduleUrl("dojox", "storage/Storage.swf").toString();
+ dojox.flash.setSwf(swfLoc, false);
+
+ // wait till page is finished loading
+ dojo.connect(dojo, "loaded", this, function(){
+ //console.debug("pageReady");
+ this._pageReady = true;
+ if(this._flashReady && this._pageReady){
+ this._loaded();
+ }
+ });
+ },
+
+ // 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
+ setFlushDelay: function(newDelay){
+ if(newDelay === null || typeof newDelay === "undefined" || isNaN(newDelay)){
+ throw new Error("Invalid argunment: " + newDelay);
+ }
+
+ dojox.flash.comm.setFlushDelay(String(newDelay));
+ },
+
+ getFlushDelay: function(){
+ return Number(dojox.flash.comm.getFlushDelay());
+ },
+
+ flush: function(namespace){
+ //FIXME: is this test necessary? Just use !namespace
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+ dojox.flash.comm.flush(namespace);
+ },
+
+ isAvailable: function(){
+ return (this._available = !dojo.config["disableFlashStorage"]);
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ if(!this.isValidKey(key)){
+ throw new Error("Invalid key given: " + key);
+ }
+
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // serialize the value;
+ // handle strings differently so they have better performance
+ if(dojo.isString(value)){
+ value = "string:" + value;
+ }else{
+ value = dojo.toJson(value);
+ }
+
+ dojox.flash.comm.put(key, value, namespace);
+ },
+
+ putMultiple: function(keys, values, resultsHandler, namespace){
+ if(!this.isValidKeyArray(keys) || ! values instanceof Array
+ || keys.length != values.length){
+ throw new Error("Invalid arguments: keys = [" + keys + "], values = [" + values + "]");
+ }
+
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // Convert the arguments on strings we can pass along to Flash
+ var metaKey = keys.join(",");
+ var lengths = [];
+ for(var i=0;i<values.length;i++){
+ if(dojo.isString(values[i])){
+ values[i] = "string:" + values[i];
+ }else{
+ values[i] = dojo.toJson(values[i]);
+ }
+ lengths[i] = values[i].length;
+ }
+ var metaValue = values.join("");
+ var metaLengths = lengths.join(",");
+
+ dojox.flash.comm.putMultiple(metaKey, metaValue, metaLengths, namespace);
+ },
+
+ get: function(key, namespace){
+ if(!this.isValidKey(key)){
+ throw new Error("Invalid key given: " + key);
+ }
+
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = dojox.flash.comm.get(key, namespace);
+
+ if(results == ""){
+ return null;
+ }
+
+ return this._destringify(results);
+ },
+
+ getMultiple: function(/*array*/ keys, /*string?*/ namespace){ /*Object*/
+ if(!this.isValidKeyArray(keys)){
+ throw new ("Invalid key array given: " + keys);
+ }
+
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var metaKey = keys.join(",");
+ var metaResults = dojox.flash.comm.getMultiple(metaKey, namespace);
+ var results = eval("(" + metaResults + ")");
+
+ // destringify each entry back into a real JS object
+ //FIXME: use dojo.map
+ for(var i = 0; i < results.length; i++){
+ results[i] = (results[i] == "") ? null : this._destringify(results[i]);
+ }
+
+ return results;
+ },
+
+ _destringify: function(results){
+ // destringify the content back into a
+ // real JavaScript object;
+ // handle strings differently so they have better performance
+ if(dojo.isString(results) && (/^string:/.test(results))){
+ results = results.substring("string:".length);
+ }else{
+ results = dojo.fromJson(results);
+ }
+
+ return results;
+ },
+
+ getKeys: function(namespace){
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var results = dojox.flash.comm.getKeys(namespace);
+
+ // Flash incorrectly returns an empty string as "null"
+ if(results == null || results == "null"){
+ results = "";
+ }
+
+ results = results.split(",");
+ results.sort();
+
+ return results;
+ },
+
+ getNamespaces: function(){
+ var results = dojox.flash.comm.getNamespaces();
+
+ // Flash incorrectly returns an empty string as "null"
+ if(results == null || results == "null"){
+ results = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ results = results.split(",");
+ results.sort();
+
+ return results;
+ },
+
+ clear: function(namespace){
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ dojox.flash.comm.clear(namespace);
+ },
+
+ remove: function(key, namespace){
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ dojox.flash.comm.remove(key, namespace);
+ },
+
+ removeMultiple: function(/*array*/ keys, /*string?*/ namespace){ /*Object*/
+ if(!this.isValidKeyArray(keys)){
+ dojo.raise("Invalid key array given: " + keys);
+ }
+ if(!namespace){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var metaKey = keys.join(",");
+ dojox.flash.comm.removeMultiple(metaKey, namespace);
+ },
+
+ isPermanent: function(){
+ return true;
+ },
+
+ getMaximumSize: function(){
+ return dojox.storage.SIZE_NO_LIMIT;
+ },
+
+ hasSettingsUI: function(){
+ return true;
+ },
+
+ showSettingsUI: function(){
+ dojox.flash.comm.showSettings();
+ dojox.flash.obj.setVisible(true);
+ dojox.flash.obj.center();
+ },
+
+ hideSettingsUI: function(){
+ // hide the dialog
+ dojox.flash.obj.setVisible(false);
+
+ // call anyone who wants to know the dialog is
+ // now hidden
+ if(dojo.isFunction(dojox.storage.onHideSettingsUI)){
+ dojox.storage.onHideSettingsUI.call(null);
+ }
+ },
+
+ getResourceList: function(){ /* Array[] */
+ // Dojo Offline no longer uses the FlashStorageProvider for offline
+ // storage; Gears is now required
+ return [];
+ },
+
+ /** Called when Flash and the page are finished loading. */
+ _loaded: function(){
+ // get available namespaces
+ this._allNamespaces = this.getNamespaces();
+
+ this.initialized = true;
+
+ // indicate that this storage provider is now loaded
+ dojox.storage.manager.loaded();
+ },
+
+ // Called if the storage system needs to tell us about the status
+ // of a put() request.
+ _onStatus: function(statusResult, key, namespace){
+ //console.debug("onStatus, statusResult="+statusResult+", key="+key);
+ var ds = dojox.storage;
+ var dfo = dojox.flash.obj;
+
+ if(statusResult == ds.PENDING){
+ dfo.center();
+ dfo.setVisible(true);
+ }else{
+ dfo.setVisible(false);
+ }
+
+ if(ds._statusHandler){
+ ds._statusHandler.call(null, statusResult, key, null, namespace);
+ }
+ }
+ }
+);
+
+dojox.storage.manager.register("dojox.storage.FlashStorageProvider",
+ new dojox.storage.FlashStorageProvider());
+
+});
diff --git a/js/dojo/dojox/storage/GearsStorageProvider.js b/js/dojo/dojox/storage/GearsStorageProvider.js
new file mode 100644
index 0000000..0ce0461
--- /dev/null
+++ b/js/dojo/dojox/storage/GearsStorageProvider.js
@@ -0,0 +1,388 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/GearsStorageProvider", ["dijit","dojo","dojox","dojo/require!dojo/gears,dojox/storage/Provider,dojox/storage/manager,dojox/sql"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.GearsStorageProvider");
+dojo.require("dojo.gears");
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+dojo.require("dojox.sql");
+
+if(dojo.gears.available){
+
+ (function(){
+ // make sure we don't define the gears provider if we're not gears
+ // enabled
+
+ dojo.declare("dojox.storage.GearsStorageProvider", dojox.storage.Provider, {
+ // summary:
+ // Storage provider that uses the features of Google Gears
+ // to store data (it is saved into the local SQL database
+ // provided by Gears, using dojox.sql)
+ // description:
+ // You can disable this storage provider with the following djConfig
+ // variable:
+ // var djConfig = { disableGearsStorage: true };
+ //
+ // Authors of this storage provider-
+ // Brad Neuberg, bkn3@columbia.edu
+ constructor: function(){
+ },
+ // instance methods and properties
+ TABLE_NAME: "__DOJO_STORAGE",
+ initialized: false,
+
+ _available: null,
+ _storageReady: false,
+
+ initialize: function(){
+ //console.debug("dojox.storage.GearsStorageProvider.initialize");
+ if(dojo.config["disableGearsStorage"] == true){
+ return;
+ }
+
+ // partition our storage data so that multiple apps
+ // on the same host won't collide
+ this.TABLE_NAME = "__DOJO_STORAGE";
+
+ // we delay creating our internal tables until an operation is
+ // actually called, to avoid having a Gears permission dialog
+ // on page load (bug #7538)
+
+ // indicate that this storage provider is now loaded
+ this.initialized = true;
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){
+ // is Google Gears available and defined?
+ return this._available = dojo.gears.available;
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ this._initStorage();
+
+ if(!this.isValidKey(key)){
+ throw new Error("Invalid key given: " + key);
+ }
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + key);
+ }
+
+ // serialize the value;
+ // handle strings differently so they have better performance
+ if(dojo.isString(value)){
+ value = "string:" + value;
+ }else{
+ value = dojo.toJson(value);
+ }
+
+ // try to store the value
+ try{
+ dojox.sql("DELETE FROM " + this.TABLE_NAME
+ + " WHERE namespace = ? AND key = ?",
+ namespace, key);
+ dojox.sql("INSERT INTO " + this.TABLE_NAME
+ + " VALUES (?, ?, ?)",
+ namespace, key, value);
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.GearsStorageProvider.put:", e);
+ resultsHandler(this.FAILED, key, e.toString(), namespace);
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(dojox.storage.SUCCESS, key, null, namespace);
+ }
+ },
+
+ get: function(key, namespace){
+ this._initStorage();
+
+ if(!this.isValidKey(key)){
+ throw new Error("Invalid key given: " + key);
+ }
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + key);
+ }
+
+ // try to find this key in the database
+ var results = dojox.sql("SELECT * FROM " + this.TABLE_NAME
+ + " WHERE namespace = ? AND "
+ + " key = ?",
+ namespace, key);
+ if(!results.length){
+ return null;
+ }else{
+ results = results[0].value;
+ }
+
+ // destringify the content back into a
+ // real JavaScript object;
+ // handle strings differently so they have better performance
+ if(dojo.isString(results) && (/^string:/.test(results))){
+ results = results.substring("string:".length);
+ }else{
+ results = dojo.fromJson(results);
+ }
+
+ return results;
+ },
+
+ getNamespaces: function(){
+ this._initStorage();
+
+ var results = [ dojox.storage.DEFAULT_NAMESPACE ];
+
+ var rs = dojox.sql("SELECT namespace FROM " + this.TABLE_NAME
+ + " DESC GROUP BY namespace");
+ for(var i = 0; i < rs.length; i++){
+ if(rs[i].namespace != dojox.storage.DEFAULT_NAMESPACE){
+ results.push(rs[i].namespace);
+ }
+ }
+
+ return results;
+ },
+
+ getKeys: function(namespace){
+ this._initStorage();
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var rs = dojox.sql("SELECT key FROM " + this.TABLE_NAME
+ + " WHERE namespace = ?",
+ namespace);
+
+ var results = [];
+ for(var i = 0; i < rs.length; i++){
+ results.push(rs[i].key);
+ }
+
+ return results;
+ },
+
+ clear: function(namespace){
+ this._initStorage();
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ dojox.sql("DELETE FROM " + this.TABLE_NAME
+ + " WHERE namespace = ?",
+ namespace);
+ },
+
+ remove: function(key, namespace){
+ this._initStorage();
+
+ if(!this.isValidKey(key)){
+ throw new Error("Invalid key given: " + key);
+ }
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + key);
+ }
+
+ dojox.sql("DELETE FROM " + this.TABLE_NAME
+ + " WHERE namespace = ? AND"
+ + " key = ?",
+ namespace,
+ key);
+ },
+
+ putMultiple: function(keys, values, resultsHandler, namespace) {
+ this._initStorage();
+
+ if(!this.isValidKeyArray(keys)
+ || ! values instanceof Array
+ || keys.length != values.length){
+ throw new Error("Invalid arguments: keys = ["
+ + keys + "], values = [" + values + "]");
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ this._statusHandler = resultsHandler;
+
+ // try to store the value
+ try{
+ dojox.sql.open();
+ dojox.sql.db.execute("BEGIN TRANSACTION");
+ var _stmt = "REPLACE INTO " + this.TABLE_NAME + " VALUES (?, ?, ?)";
+ for(var i=0;i<keys.length;i++) {
+ // serialize the value;
+ // handle strings differently so they have better performance
+ var value = values[i];
+ if(dojo.isString(value)){
+ value = "string:" + value;
+ }else{
+ value = dojo.toJson(value);
+ }
+
+ dojox.sql.db.execute( _stmt,
+ [namespace, keys[i], value]);
+ }
+ dojox.sql.db.execute("COMMIT TRANSACTION");
+ dojox.sql.close();
+ }catch(e){
+ // indicate we failed
+ console.debug("dojox.storage.GearsStorageProvider.putMultiple:", e);
+ if(resultsHandler){
+ resultsHandler(this.FAILED, keys, e.toString(), namespace);
+ }
+ return;
+ }
+
+ if(resultsHandler){
+ resultsHandler(dojox.storage.SUCCESS, keys, null, namespace);
+ }
+ },
+
+ getMultiple: function(keys, namespace){
+ // TODO: Maybe use SELECT IN instead
+ this._initStorage();
+
+ if(!this.isValidKeyArray(keys)){
+ throw new ("Invalid key array given: " + keys);
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ var _stmt = "SELECT * FROM " + this.TABLE_NAME
+ + " WHERE namespace = ? AND " + " key = ?";
+
+ var results = [];
+ for(var i=0;i<keys.length;i++){
+ var result = dojox.sql( _stmt, namespace, keys[i]);
+
+ if( ! result.length){
+ results[i] = null;
+ }else{
+ result = result[0].value;
+
+ // destringify the content back into a
+ // real JavaScript object;
+ // handle strings differently so they have better performance
+ if(dojo.isString(result) && (/^string:/.test(result))){
+ results[i] = result.substring("string:".length);
+ }else{
+ results[i] = dojo.fromJson(result);
+ }
+ }
+ }
+
+ return results;
+ },
+
+ removeMultiple: function(keys, namespace){
+ this._initStorage();
+
+ if(!this.isValidKeyArray(keys)){
+ throw new Error("Invalid arguments: keys = [" + keys + "]");
+ }
+
+ if(namespace == null || typeof namespace == "undefined"){
+ namespace = dojox.storage.DEFAULT_NAMESPACE;
+ }
+ if(!this.isValidKey(namespace)){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ dojox.sql.open();
+ dojox.sql.db.execute("BEGIN TRANSACTION");
+ var _stmt = "DELETE FROM " + this.TABLE_NAME
+ + " WHERE namespace = ? AND key = ?";
+
+ for(var i=0;i<keys.length;i++){
+ dojox.sql.db.execute( _stmt,
+ [namespace, keys[i]]);
+ }
+ dojox.sql.db.execute("COMMIT TRANSACTION");
+ dojox.sql.close();
+ },
+
+ isPermanent: function(){ return true; },
+
+ getMaximumSize: function(){ return this.SIZE_NO_LIMIT; },
+
+ hasSettingsUI: function(){ return false; },
+
+ showSettingsUI: function(){
+ throw new Error(this.declaredClass
+ + " does not support a storage settings user-interface");
+ },
+
+ hideSettingsUI: function(){
+ throw new Error(this.declaredClass
+ + " does not support a storage settings user-interface");
+ },
+
+ _initStorage: function(){
+ // we delay creating the tables until an operation is actually
+ // called so that we don't give a Gears dialog right on page
+ // load (bug #7538)
+ if (this._storageReady) {
+ return;
+ }
+
+ if (!google.gears.factory.hasPermission) {
+ var siteName = null;
+ var icon = null;
+ var msg = 'This site would like to use Google Gears to enable '
+ + 'enhanced functionality.';
+ var allowed = google.gears.factory.getPermission(siteName, icon, msg);
+ if (!allowed) {
+ throw new Error('You must give permission to use Gears in order to '
+ + 'store data');
+ }
+ }
+
+ // create the table that holds our data
+ try{
+ dojox.sql("CREATE TABLE IF NOT EXISTS " + this.TABLE_NAME + "( "
+ + " namespace TEXT, "
+ + " key TEXT, "
+ + " value TEXT "
+ + ")"
+ );
+ dojox.sql("CREATE UNIQUE INDEX IF NOT EXISTS namespace_key_index"
+ + " ON " + this.TABLE_NAME
+ + " (namespace, key)");
+ }catch(e){
+ console.debug("dojox.storage.GearsStorageProvider._createTables:", e);
+ throw new Error('Unable to create storage tables for Gears in '
+ + 'Dojo Storage');
+ }
+
+ this._storageReady = true;
+ }
+ });
+
+ // register the existence of our storage providers
+ dojox.storage.manager.register("dojox.storage.GearsStorageProvider",
+ new dojox.storage.GearsStorageProvider());
+ })();
+}
+
+});
diff --git a/js/dojo/dojox/storage/LocalStorageProvider.js b/js/dojo/dojox/storage/LocalStorageProvider.js
new file mode 100644
index 0000000..d4a139b
--- /dev/null
+++ b/js/dojo/dojox/storage/LocalStorageProvider.js
@@ -0,0 +1,209 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/LocalStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/Provider,dojox/storage/manager"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.LocalStorageProvider");
+
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+
+dojo.declare(
+ "dojox.storage.LocalStorageProvider",
+ [dojox.storage.Provider],
+ {
+ store: null,
+
+ initialize: function(){
+
+ this.store = localStorage;
+
+ this.initialized = true;
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){ /*Boolean*/
+ return typeof localStorage != 'undefined';
+ },
+
+ put: function( /*string*/ key,
+ /*object*/ value,
+ /*function*/ resultsHandler,
+ /*string?*/ namespace){
+
+ // TODO: Use the events as specified in http://dev.w3.org/html5/webstorage/#the-storage-event ?
+ // Currently, the storage event is not reliable around browsers.
+
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ var fullKey = this.getFullKey(key,namespace);
+
+ // prepending a prefix to a string value
+ // will result in that prefix not being
+ // usable as a value, so we better use
+ // toJson() always.
+ value = dojo.toJson(value);
+
+ try { // ua may raise an QUOTA_EXCEEDED_ERR exception
+ this.store.setItem(fullKey,value);
+
+ if(resultsHandler){
+ resultsHandler(this.SUCCESS, key, null, namespace);
+ }
+ } catch(e) {
+ if(resultsHandler){
+ resultsHandler(this.FAILED, key, e.toString(), namespace);
+ }
+ }
+ },
+
+ get: function(/*string*/ key, /*string?*/ namespace){ /*Object*/
+ this._assertIsValidKey(key);
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ // get our full key name, which is namespace + key
+ key = this.getFullKey(key, namespace);
+
+ return dojo.fromJson(this.store.getItem(key));
+ },
+
+ getKeys: function(/*string?*/ namespace){ /*Array*/
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_'
+
+ var keys = [];
+ for(var i = 0; i < this.store.length; i++){
+ var currentKey = this.store.key(i);
+ if(this._beginsWith(currentKey,namespace)){
+ currentKey = currentKey.substring(namespace.length);
+ keys.push(currentKey);
+ }
+ }
+
+ return keys;
+ },
+
+ clear: function(/*string?*/ namespace){
+ // Um, well, the 'specs' in Provider.js say that if
+ // no namespace is given, this method should nuke
+ // the *complete* storage. As other components might
+ // be using localStorage too, this might not be a
+ // good idea, so this method won't do it.
+
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ namespace = '__'+namespace+'_';
+
+ var keys = [];
+ for(var i = 0; i < this.store.length; i++){
+ if(this._beginsWith(this.store.key(i),namespace)){
+ keys.push(this.store.key(i));
+ }
+ }
+
+ dojo.forEach(keys, dojo.hitch(this.store, "removeItem"));
+ },
+
+ remove: function(/*string*/ key, /*string?*/ namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+ this._assertIsValidNamespace(namespace);
+
+ this.store.removeItem(this.getFullKey(key, namespace));
+ },
+
+ getNamespaces: function(){ /*string[]*/
+ // There must be a better way than
+ // to execute a regex on *every*
+ // item in the store.
+
+ var results = [ this.DEFAULT_NAMESPACE];
+
+ var found = {};
+ found[this.DEFAULT_NAMESPACE] = true;
+ var tester = /^__([^_]*)_/;
+
+ for(var i = 0; i < this.store.length; i++){
+ var currentKey = this.store.key(i);
+ if(tester.test(currentKey) == true){
+ var currentNS = currentKey.match(tester)[1];
+ if(typeof found[currentNS] == "undefined"){
+ found[currentNS] = true;
+ results.push(currentNS);
+ }
+ }
+ }
+
+ return results;
+ },
+
+ isPermanent: function(){ /*Boolean*/
+ return true;
+ },
+
+ getMaximumSize: function(){ /* mixed */
+ return dojox.storage.SIZE_NO_LIMIT;
+ },
+
+ hasSettingsUI: function(){ /*Boolean*/
+ return false;
+ },
+
+ isValidKey: function(/*string*/ keyName){ /*Boolean*/
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z_-]*$/.test(keyName);
+ },
+
+ isValidNamespace: function(/*string*/ keyName){ /*Boolean*/
+ // we *must* prevent namespaces from having
+ // underscores - else lookup of namespaces
+ // via RegEx (e.g. in getNamespaces ) would
+ // return wrong results.
+ //
+ // The only way around this would be to
+ // disallow underscores in keys.
+
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z-]*$/.test(keyName);
+ },
+
+ getFullKey: function(key, namespace){
+ // checks for valid namespace and
+ // key are already performed.
+ return "__" + namespace + "_" + key;
+ },
+
+ _beginsWith: function(/* string */ haystack, /* string */ needle) {
+ if(needle.length > haystack.length) {
+ return false;
+ }
+ return haystack.substring(0,needle.length) === needle;
+ },
+
+ _assertIsValidNamespace: function(/* string */ namespace){
+ if(this.isValidNamespace(namespace) === false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+ },
+
+ _assertIsValidKey: function(/* string */ key){
+ if(this.isValidKey(key) === false){
+ throw new Error("Invalid key given: " + key);
+ }
+ }
+ }
+);
+
+dojox.storage.manager.register("dojox.storage.LocalStorageProvider", new dojox.storage.LocalStorageProvider());
+});
diff --git a/js/dojo/dojox/storage/Provider.js b/js/dojo/dojox/storage/Provider.js
new file mode 100644
index 0000000..1847e12
--- /dev/null
+++ b/js/dojo/dojox/storage/Provider.js
@@ -0,0 +1,345 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/Provider", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.Provider");
+
+dojo.declare("dojox.storage.Provider", null, {
+ // summary: A singleton for working with dojox.storage.
+ // description:
+ // dojox.storage exposes the current available storage provider on this
+ // platform. It gives you methods such as dojox.storage.put(),
+ // dojox.storage.get(), etc.
+ //
+ // For more details on dojox.storage, see the primary documentation
+ // page at
+ // http://manual.dojotoolkit.org/storage.html
+ //
+ // Note for storage provider developers who are creating subclasses-
+ // This is the base class for all storage providers Specific kinds of
+ // Storage Providers should subclass this and implement these methods.
+ // You should avoid initialization in storage provider subclass's
+ // constructor; instead, perform initialization in your initialize()
+ // method.
+ constructor: function(){
+ },
+
+ // SUCCESS: String
+ // Flag that indicates a put() call to a
+ // storage provider was succesful.
+ SUCCESS: "success",
+
+ // FAILED: String
+ // Flag that indicates a put() call to
+ // a storage provider failed.
+ FAILED: "failed",
+
+ // PENDING: String
+ // Flag that indicates a put() call to a
+ // storage provider is pending user approval.
+ PENDING: "pending",
+
+ // SIZE_NOT_AVAILABLE: String
+ // Returned by getMaximumSize() if this storage provider can not determine
+ // the maximum amount of data it can support.
+ SIZE_NOT_AVAILABLE: "Size not available",
+
+ // SIZE_NO_LIMIT: String
+ // Returned by getMaximumSize() if this storage provider has no theoretical
+ // limit on the amount of data it can store.
+ SIZE_NO_LIMIT: "No size limit",
+
+ // DEFAULT_NAMESPACE: String
+ // The namespace for all storage operations. This is useful if several
+ // applications want access to the storage system from the same domain but
+ // want different storage silos.
+ DEFAULT_NAMESPACE: "default",
+
+ // onHideSettingsUI: Function
+ // If a function is assigned to this property, then when the settings
+ // provider's UI is closed this function is called. Useful, for example,
+ // if the user has just cleared out all storage for this provider using
+ // the settings UI, and you want to update your UI.
+ onHideSettingsUI: null,
+
+ initialize: function(){
+ // summary:
+ // Allows this storage provider to initialize itself. This is
+ // called after the page has finished loading, so you can not do
+ // document.writes(). Storage Provider subclasses should initialize
+ // themselves inside of here rather than in their function
+ // constructor.
+ console.warn("dojox.storage.initialize not implemented");
+ },
+
+ isAvailable: function(){ /*Boolean*/
+ // summary:
+ // Returns whether this storage provider is available on this
+ // platform.
+ console.warn("dojox.storage.isAvailable not implemented");
+ },
+
+ put: function( /*string*/ key,
+ /*object*/ value,
+ /*function*/ resultsHandler,
+ /*string?*/ namespace){
+ // summary:
+ // Puts a key and value into this storage system.
+ // description:
+ // Example-
+ // var resultsHandler = function(status, key, message, namespace){
+ // alert("status="+status+", key="+key+", message="+message);
+ // };
+ // dojox.storage.put("test", "hello world", resultsHandler);
+ //
+ // Arguments:
+ //
+ // status - The status of the put operation, given by
+ // dojox.storage.FAILED, dojox.storage.SUCCEEDED, or
+ // dojox.storage.PENDING
+ // key - The key that was used for the put
+ // message - An optional message if there was an error or things failed.
+ // namespace - The namespace of the key. This comes at the end since
+ // it was added later.
+ //
+ // Important note: if you are using Dojo Storage in conjunction with
+ // Dojo Offline, then you don't need to provide
+ // a resultsHandler; this is because for Dojo Offline we
+ // use Google Gears to persist data, which has unlimited data
+ // once the user has given permission. If you are using Dojo
+ // Storage apart from Dojo Offline, then under the covers hidden
+ // Flash might be used, which is both asychronous and which might
+ // get denied; in this case you must provide a resultsHandler.
+ // key:
+ // A string key to use when retrieving this value in the future.
+ // value:
+ // A value to store; this can be any JavaScript type.
+ // resultsHandler:
+ // A callback function that will receive three arguments. The
+ // first argument is one of three values: dojox.storage.SUCCESS,
+ // dojox.storage.FAILED, or dojox.storage.PENDING; these values
+ // determine how the put request went. In some storage systems
+ // users can deny a storage request, resulting in a
+ // dojox.storage.FAILED, while in other storage systems a storage
+ // request must wait for user approval, resulting in a
+ // dojox.storage.PENDING status until the request is either
+ // approved or denied, resulting in another call back with
+ // dojox.storage.SUCCESS.
+ // The second argument in the call back is the key name that was being stored.
+ // The third argument in the call back is an optional message that
+ // details possible error messages that might have occurred during
+ // the storage process.
+ // namespace:
+ // Optional string namespace that this value will be placed into;
+ // if left off, the value will be placed into dojox.storage.DEFAULT_NAMESPACE
+
+ console.warn("dojox.storage.put not implemented");
+ },
+
+ get: function(/*string*/ key, /*string?*/ namespace){ /*Object*/
+ // summary:
+ // Gets the value with the given key. Returns null if this key is
+ // not in the storage system.
+ // key:
+ // A string key to get the value of.
+ // namespace:
+ // Optional string namespace that this value will be retrieved from;
+ // if left off, the value will be retrieved from dojox.storage.DEFAULT_NAMESPACE
+ // return: Returns any JavaScript object type; null if the key is not present
+ console.warn("dojox.storage.get not implemented");
+ },
+
+ hasKey: function(/*string*/ key, /*string?*/ namespace){
+ // summary: Determines whether the storage has the given key.
+ return !!this.get(key, namespace); // Boolean
+ },
+
+ getKeys: function(/*string?*/ namespace){ /*Array*/
+ // summary: Enumerates all of the available keys in this storage system.
+ // return: Array of available keys
+ console.warn("dojox.storage.getKeys not implemented");
+ },
+
+ clear: function(/*string?*/ namespace){
+ // summary:
+ // Completely clears this storage system of all of it's values and
+ // keys. If 'namespace' is provided just clears the keys in that
+ // namespace.
+ console.warn("dojox.storage.clear not implemented");
+ },
+
+ remove: function(/*string*/ key, /*string?*/ namespace){
+ // summary: Removes the given key from this storage system.
+ console.warn("dojox.storage.remove not implemented");
+ },
+
+ getNamespaces: function(){ /*string[]*/
+ console.warn("dojox.storage.getNamespaces not implemented");
+ },
+
+ isPermanent: function(){ /*Boolean*/
+ // summary:
+ // Returns whether this storage provider's values are persisted
+ // when this platform is shutdown.
+ console.warn("dojox.storage.isPermanent not implemented");
+ },
+
+ getMaximumSize: function(){ /* mixed */
+ // summary: The maximum storage allowed by this provider
+ // returns:
+ // Returns the maximum storage size
+ // supported by this provider, in
+ // thousands of bytes (i.e., if it
+ // returns 60 then this means that 60K
+ // of storage is supported).
+ //
+ // If this provider can not determine
+ // it's maximum size, then
+ // dojox.storage.SIZE_NOT_AVAILABLE is
+ // returned; if there is no theoretical
+ // limit on the amount of storage
+ // this provider can return, then
+ // dojox.storage.SIZE_NO_LIMIT is
+ // returned
+ console.warn("dojox.storage.getMaximumSize not implemented");
+ },
+
+ putMultiple: function( /*array*/ keys,
+ /*array*/ values,
+ /*function*/ resultsHandler,
+ /*string?*/ namespace){
+ // summary:
+ // Puts multiple keys and values into this storage system.
+ // description:
+ // Example-
+ // var resultsHandler = function(status, key, message){
+ // alert("status="+status+", key="+key+", message="+message);
+ // };
+ // dojox.storage.put(["test"], ["hello world"], resultsHandler);
+ //
+ // Important note: if you are using Dojo Storage in conjunction with
+ // Dojo Offline, then you don't need to provide
+ // a resultsHandler; this is because for Dojo Offline we
+ // use Google Gears to persist data, which has unlimited data
+ // once the user has given permission. If you are using Dojo
+ // Storage apart from Dojo Offline, then under the covers hidden
+ // Flash might be used, which is both asychronous and which might
+ // get denied; in this case you must provide a resultsHandler.
+ // keys:
+ // An array of string keys to use when retrieving this value in the future,
+ // one per value to be stored
+ // values:
+ // An array of values to store; this can be any JavaScript type, though the
+ // performance of plain strings is considerably better
+ // resultsHandler:
+ // A callback function that will receive three arguments. The
+ // first argument is one of three values: dojox.storage.SUCCESS,
+ // dojox.storage.FAILED, or dojox.storage.PENDING; these values
+ // determine how the put request went. In some storage systems
+ // users can deny a storage request, resulting in a
+ // dojox.storage.FAILED, while in other storage systems a storage
+ // request must wait for user approval, resulting in a
+ // dojox.storage.PENDING status until the request is either
+ // approved or denied, resulting in another call back with
+ // dojox.storage.SUCCESS.
+ // The second argument in the call back is the key name that was being stored.
+ // The third argument in the call back is an optional message that
+ // details possible error messages that might have occurred during
+ // the storage process.
+ // namespace:
+ // Optional string namespace that this value will be placed into;
+ // if left off, the value will be placed into dojox.storage.DEFAULT_NAMESPACE
+
+ for(var i = 0; i < keys.length; i++){
+ dojox.storage.put(keys[i], values[i], resultsHandler, namespace);
+ }
+ },
+
+ getMultiple: function(/*array*/ keys, /*string?*/ namespace){ /*Object*/
+ // summary:
+ // Gets the valuse corresponding to each of the given keys.
+ // Returns a null array element for each given key that is
+ // not in the storage system.
+ // keys:
+ // An array of string keys to get the value of.
+ // namespace:
+ // Optional string namespace that this value will be retrieved from;
+ // if left off, the value will be retrieved from dojox.storage.DEFAULT_NAMESPACE
+ // return: Returns any JavaScript object type; null if the key is not present
+
+ var results = [];
+ for(var i = 0; i < keys.length; i++){
+ results.push(dojox.storage.get(keys[i], namespace));
+ }
+
+ return results;
+ },
+
+ removeMultiple: function(/*array*/ keys, /*string?*/ namespace) {
+ // summary: Removes the given keys from this storage system.
+
+ for(var i = 0; i < keys.length; i++){
+ dojox.storage.remove(keys[i], namespace);
+ }
+ },
+
+ isValidKeyArray: function( keys) {
+ if(keys === null || keys === undefined || !dojo.isArray(keys)){
+ return false;
+ }
+
+ // JAC: This could be optimized by running the key validity test
+ // directly over a joined string
+ return !dojo.some(keys, function(key){
+ return !this.isValidKey(key);
+ }, this); // Boolean
+ },
+
+ hasSettingsUI: function(){ /*Boolean*/
+ // summary: Determines whether this provider has a settings UI.
+ return false;
+ },
+
+ showSettingsUI: function(){
+ // summary: If this provider has a settings UI, determined
+ // by calling hasSettingsUI(), it is shown.
+ console.warn("dojox.storage.showSettingsUI not implemented");
+ },
+
+ hideSettingsUI: function(){
+ // summary: If this provider has a settings UI, hides it.
+ console.warn("dojox.storage.hideSettingsUI not implemented");
+ },
+
+ isValidKey: function(/*string*/ keyName){ /*Boolean*/
+ // summary:
+ // Subclasses can call this to ensure that the key given is valid
+ // in a consistent way across different storage providers. We use
+ // the lowest common denominator for key values allowed: only
+ // letters, numbers, and underscores are allowed. No spaces.
+ if(keyName === null || keyName === undefined){
+ return false;
+ }
+
+ return /^[0-9A-Za-z_]*$/.test(keyName);
+ },
+
+ getResourceList: function(){ /* Array[] */
+ // summary:
+ // Returns a list of URLs that this
+ // storage provider might depend on.
+ // description:
+ // This method returns a list of URLs that this
+ // storage provider depends on to do its work.
+ // This list is used by the Dojo Offline Toolkit
+ // to cache these resources to ensure the machinery
+ // used by this storage provider is available offline.
+ // What is returned is an array of URLs.
+ // Note that Dojo Offline uses Gears as its native
+ // storage provider, and does not support using other
+ // kinds of storage providers while offline anymore.
+
+ return [];
+ }
+});
+
+});
diff --git a/js/dojo/dojox/storage/README b/js/dojo/dojox/storage/README
new file mode 100644
index 0000000..7acf9b0
--- /dev/null
+++ b/js/dojo/dojox/storage/README
@@ -0,0 +1,115 @@
+-------------------------------------------------------------------------------
+Dojo Storage
+-------------------------------------------------------------------------------
+Version X.XXX (does not have separate versioning -- versioned by release date)
+Last Release date: January 2010
+-------------------------------------------------------------------------------
+Project state:
+experimental
+-------------------------------------------------------------------------------
+Credits
+ Brad Neuberg
+ Alex Russell
+
+LocalStorage, BehaviorStorage, CookieStorage:
+ Jens Arps
+-------------------------------------------------------------------------------
+Project description
+
+dojox.storage provides a JavaScript abstraction for persistent storage
+as well as pluggable implementations which typically use native browser
+extensions (e.g. Flash player, Gears)
+
+-------------------------------------------------------------------------------
+Dependencies:
+
+FlashStorageProvider requires the Flash player
+GearsStorageProvider requires the Gears extension
+LocalStorageProvider does not require any plugins but will run only in certain
+browsers (see below)
+BehaviorStorageProvider does not require any plugins but will run only in IE 5+
+CookieStorageProvider has no requirements
+The various Air*StorageProviders require Adobe's AIR software
+
+The open source mtasc compiler (www.mtasc.org) is needed to build the
+ActionScript into SWF format. The SWF object is maintained within svn, so
+this step is only necessary if Storage.as is modified. A sample build script
+is provided (buildFlashStorage.sh)
+
+-------------------------------------------------------------------------------
+Documentation
+
+See http://dojotoolkit.org/reference-guide/dojox/storage.html for Dojo Storage docs.
+
+See dojox/storage/demos/helloworld.html for a simple Hello World example
+you can base your code off of.
+
+-------------------------------------------------------------------------------
+Installation instructions
+
+If you want to use Dojo Storage in a web browser:
+
+These installation instructions are to use Dojo Storage in a web browser; at
+runtime, Dojo Storage will autodetect and use the best available storage
+option. This includes:
+
+ * localStorage: HTML 5 Web Browsers (Firefox 3+, Safari 4+, IE 8+)
+ * Google Gears (Plugin)
+ * globalStorage (Firefox 2+)
+ * userData Behavior (IE 5+)
+ * Hidden Flash (Plugin)
+ * Cookies
+
+To have access to Dojo Storage, require "dojox.storage":
+
+dojo.require("dojox.storage");
+
+
+If you want to use Dojo Storage with Adobe AIR:
+
+[TBD! Why don't you write this and contribute!]
+
+-------------------------------------------------------------------------------
+Additional Notes
+
+
+STORAGE TABLE
+-------------
+
+
+Browser Used StorageProvider, in order of preference
+
+IE 6 / IE7 GearsStorageProvider
+ FlashStorageProvider
+ BehaviorStorageProvider
+ CookieStorageProvider
+
+IE 8 LocalStorageProvider
+ GearsStorageProvider
+ FlashStorageProvider
+ BehaviorStorageProvider
+ CookieStorageProvider
+
+Safari 3 FlashStorageProvider
+ CookieStorageProvider
+
+Safari 4 LocalStorageProvider
+ FlashStorageProvider
+ CookieStorageProvider
+
+Chromium 4 FlashStorageProvider
+(Mac OS) CookieStorageProvider
+
+Firefox 2 WhatWGStorageProvider (= globalStorage)
+ GearsStorageProvider
+ FlashStorageProvider
+ CookieStorageProvider
+
+Firefox 3 LocalStorageProvider
+ GearsStorageProvider
+ FlashStorageProvider
+ CookieStorageProvider
+
+Opera 10 LocalStorageProvider
+ FlashStorageProvider
+ CookieStorageProvider
diff --git a/js/dojo/dojox/storage/Storage.as b/js/dojo/dojox/storage/Storage.as
new file mode 100644
index 0000000..89ec67d
--- /dev/null
+++ b/js/dojo/dojox/storage/Storage.as
@@ -0,0 +1,402 @@
+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;
+
+ 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);
+ _root._settingsBackground.loadMovie(DojoExternalInterface.dojoPath
+ + "../dojox/storage/storage_dialog.swf");
+ }
+
+ // FIXME: Whoever added this Flush code did not document why it
+ // exists. Please also put your name and a bug number so I know
+ // who to contact. -- Brad Neuberg
+
+ // 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 flushResults = so.flush();
+
+ // 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", statusResults,
+ null, namespace);
+ }
+
+ 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;
+
+ // Save the namespace
+ // FIXME: Tie this into the flush/no-flush stuff below; right now
+ // we immediately write out this namespace. -- Brad Neuberg
+ addNamespace(namespace, keyName);
+
+ // 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]);
+ }
+
+ // Save the namespace
+ // FIXME: Tie this into the flush/no-flush stuff below; right now
+ // we immediately write out this namespace. -- Brad Neuberg
+ addNamespace(namespace, null);
+
+ // 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){
+ //trace("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;
+ }
+ }
+ //trace("onStatus, statusResults="+statusResults);
+
+ // give the status results to JavaScript
+ DojoExternalInterface.call("dojox.storage._onStatus", statusResults,
+ keyNames[0], namespace);
+ }
+
+ // Clear any pending flush timers
+ if(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){
+ 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
+ + "../dojox/storage/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) : String{
+ // 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 = [];
+ 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;
+ }
+ }
+
+ // a bug in ExternalInterface transforms Arrays into
+ // Strings, so we can't use those here! -- BradNeuberg
+ results = results.join(",");
+
+ return results;
+ }
+
+ public function getNamespaces() : String{
+ var allNamespaces = SharedObject.getLocal(_NAMESPACE_KEY);
+ var results = [];
+
+ for(var i in allNamespaces.data){
+ results.push(i);
+ }
+
+ // a bug in ExternalInterface transforms Arrays into
+ // Strings, so we can use those here! -- BradNeuberg
+ results = results.join(",");
+
+ return results;
+ }
+
+ 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", statusResults,
+ keyName, namespace);
+ }
+ }
+
+ // 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", statusResults,
+ keyName, namespace);
+ }
+ }
+
+ // 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){
+ _root.app = new Storage();
+ }
+}
+
diff --git a/js/dojo/dojox/storage/Storage.swf b/js/dojo/dojox/storage/Storage.swf
new file mode 100644
index 0000000..9a09f70
--- /dev/null
+++ b/js/dojo/dojox/storage/Storage.swf
Binary files differ
diff --git a/js/dojo/dojox/storage/WhatWGStorageProvider.js b/js/dojo/dojox/storage/WhatWGStorageProvider.js
new file mode 100644
index 0000000..61b9e57
--- /dev/null
+++ b/js/dojo/dojox/storage/WhatWGStorageProvider.js
@@ -0,0 +1,277 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/WhatWGStorageProvider", ["dijit","dojo","dojox","dojo/require!dojox/storage/Provider,dojox/storage/manager"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.WhatWGStorageProvider");
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+
+dojo.declare("dojox.storage.WhatWGStorageProvider", [ dojox.storage.Provider ], {
+ // summary:
+ // Storage provider that uses WHAT Working Group features in Firefox 2
+ // to achieve permanent storage.
+ // description:
+ // The WHAT WG storage API is documented at
+ // http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
+ //
+ // You can disable this storage provider with the following djConfig
+ // variable:
+ // var djConfig = { disableWhatWGStorage: true };
+ //
+ // Authors of this storage provider-
+ // JB Boisseau, jb.boisseau@eutech-ssii.com
+ // Brad Neuberg, bkn3@columbia.edu
+
+ initialized: false,
+
+ _domain: null,
+ _available: null,
+ _statusHandler: null,
+ _allNamespaces: null,
+ _storageEventListener: null,
+
+ initialize: function(){
+ if(dojo.config["disableWhatWGStorage"] == true){
+ return;
+ }
+
+ // get current domain
+ this._domain = location.hostname;
+ // console.debug(this._domain);
+
+ // indicate that this storage provider is now loaded
+ this.initialized = true;
+ dojox.storage.manager.loaded();
+ },
+
+ isAvailable: function(){
+ try{
+ var myStorage = globalStorage[location.hostname];
+ }catch(e){
+ this._available = false;
+ return this._available;
+ }
+
+ this._available = true;
+ return this._available;
+ },
+
+ put: function(key, value, resultsHandler, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ // get our full key name, which is namespace + key
+ key = this.getFullKey(key, namespace);
+
+ this._statusHandler = resultsHandler;
+
+ // serialize the value;
+ // handle strings differently so they have better performance
+ if(dojo.isString(value)){
+ value = "string:" + value;
+ }else{
+ value = dojo.toJson(value);
+ }
+
+ // register for successful storage events.
+ var storageListener = dojo.hitch(this, function(evt){
+ // remove any old storage event listener we might have added
+ // to the window on old put() requests; Firefox has a bug
+ // where it can occassionaly go into infinite loops calling
+ // our storage event listener over and over -- this is a
+ // workaround
+ // FIXME: Simplify this into a test case and submit it
+ // to Firefox
+ window.removeEventListener("storage", storageListener, false);
+
+ // indicate we succeeded
+ if(resultsHandler){
+ resultsHandler.call(null, this.SUCCESS, key, null, namespace);
+ }
+ });
+
+ window.addEventListener("storage", storageListener, false);
+
+ // try to store the value
+ try{
+ var myStorage = globalStorage[this._domain];
+ myStorage.setItem(key, value);
+ }catch(e){
+ // indicate we failed
+ this._statusHandler.call(null, this.FAILED, key, e.toString(), namespace);
+ }
+ },
+
+ get: function(key, namespace){
+ if(this.isValidKey(key) == false){
+ throw new Error("Invalid key given: " + key);
+ }
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ // get our full key name, which is namespace + key
+ key = this.getFullKey(key, namespace);
+
+ // sometimes, even if a key doesn't exist, Firefox
+ // will return a blank string instead of a null --
+ // this _might_ be due to having underscores in the
+ // keyname, but I am not sure.
+
+ // FIXME: Simplify this bug into a testcase and
+ // submit it to Firefox
+ var myStorage = globalStorage[this._domain];
+ var results = myStorage.getItem(key);
+
+ if(results == null || results == ""){
+ return null;
+ }
+
+ results = results.value;
+
+ // destringify the content back into a
+ // real JavaScript object;
+ // handle strings differently so they have better performance
+ if(dojo.isString(results) && (/^string:/.test(results))){
+ results = results.substring("string:".length);
+ }else{
+ results = dojo.fromJson(results);
+ }
+
+ return results;
+ },
+
+ getNamespaces: function(){
+ var results = [ this.DEFAULT_NAMESPACE ];
+
+ // simply enumerate through our array and save any string
+ // that starts with __
+ var found = {};
+ var myStorage = globalStorage[this._domain];
+ var tester = /^__([^_]*)_/;
+ for(var i = 0; i < myStorage.length; i++){
+ var currentKey = myStorage.key(i);
+ if(tester.test(currentKey) == true){
+ var currentNS = currentKey.match(tester)[1];
+ // have we seen this namespace before?
+ if(typeof found[currentNS] == "undefined"){
+ found[currentNS] = true;
+ results.push(currentNS);
+ }
+ }
+ }
+
+ return results;
+ },
+
+ getKeys: function(namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // create a regular expression to test the beginning
+ // of our key names to see if they match our namespace;
+ // if it is the default namespace then test for the presence
+ // of no namespace for compatibility with older versions
+ // of dojox.storage
+ var namespaceTester;
+ if(namespace == this.DEFAULT_NAMESPACE){
+ namespaceTester = new RegExp("^([^_]{2}.*)$");
+ }else{
+ namespaceTester = new RegExp("^__" + namespace + "_(.*)$");
+ }
+
+ var myStorage = globalStorage[this._domain];
+ var keysArray = [];
+ for(var i = 0; i < myStorage.length; i++){
+ var currentKey = myStorage.key(i);
+ if(namespaceTester.test(currentKey) == true){
+ // strip off the namespace portion
+ currentKey = currentKey.match(namespaceTester)[1];
+ keysArray.push(currentKey);
+ }
+ }
+
+ return keysArray;
+ },
+
+ clear: function(namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // create a regular expression to test the beginning
+ // of our key names to see if they match our namespace;
+ // if it is the default namespace then test for the presence
+ // of no namespace for compatibility with older versions
+ // of dojox.storage
+ var namespaceTester;
+ if(namespace == this.DEFAULT_NAMESPACE){
+ namespaceTester = new RegExp("^[^_]{2}");
+ }else{
+ namespaceTester = new RegExp("^__" + namespace + "_");
+ }
+
+ var myStorage = globalStorage[this._domain];
+ var keys = [];
+ for(var i = 0; i < myStorage.length; i++){
+ if(namespaceTester.test(myStorage.key(i)) == true){
+ keys[keys.length] = myStorage.key(i);
+ }
+ }
+
+ dojo.forEach(keys, dojo.hitch(myStorage, "removeItem"));
+ },
+
+ remove: function(key, namespace){
+ // get our full key name, which is namespace + key
+ key = this.getFullKey(key, namespace);
+
+ var myStorage = globalStorage[this._domain];
+ myStorage.removeItem(key);
+ },
+
+ isPermanent: function(){
+ return true;
+ },
+
+ getMaximumSize: function(){
+ return this.SIZE_NO_LIMIT;
+ },
+
+ hasSettingsUI: function(){
+ return false;
+ },
+
+ showSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ },
+
+ hideSettingsUI: function(){
+ throw new Error(this.declaredClass + " does not support a storage settings user-interface");
+ },
+
+ getFullKey: function(key, namespace){
+ namespace = namespace||this.DEFAULT_NAMESPACE;
+
+ if(this.isValidKey(namespace) == false){
+ throw new Error("Invalid namespace given: " + namespace);
+ }
+
+ // don't append a namespace string for the default namespace,
+ // for compatibility with older versions of dojox.storage
+ if(namespace == this.DEFAULT_NAMESPACE){
+ return key;
+ }else{
+ return "__" + namespace + "_" + key;
+ }
+ }
+});
+
+dojox.storage.manager.register("dojox.storage.WhatWGStorageProvider",
+ new dojox.storage.WhatWGStorageProvider());
+
+});
diff --git a/js/dojo/dojox/storage/_common.js b/js/dojo/dojox/storage/_common.js
new file mode 100644
index 0000000..0c766ca
--- /dev/null
+++ b/js/dojo/dojox/storage/_common.js
@@ -0,0 +1,24 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/_common", ["dijit","dojo","dojox","dojo/require!dojox/storage/Provider,dojox/storage/manager,dojox/storage/LocalStorageProvider,dojox/storage/GearsStorageProvider,dojox/storage/WhatWGStorageProvider,dojox/storage/FlashStorageProvider,dojox/storage/BehaviorStorageProvider,dojox/storage/CookieStorageProvider"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage._common");
+dojo.require("dojox.storage.Provider");
+dojo.require("dojox.storage.manager");
+
+/*
+ Note: if you are doing Dojo Offline builds you _must_
+ have offlineProfile=true when you run the build script:
+ ./build.sh action=release profile=offline offlineProfile=true
+*/
+dojo.require("dojox.storage.LocalStorageProvider");
+dojo.require("dojox.storage.GearsStorageProvider");
+dojo.require("dojox.storage.WhatWGStorageProvider");
+dojo.require("dojox.storage.FlashStorageProvider");
+dojo.require("dojox.storage.BehaviorStorageProvider");
+dojo.require("dojox.storage.CookieStorageProvider");
+
+// now that we are loaded and registered tell the storage manager to
+// initialize itself
+dojox.storage.manager.initialize();
+
+});
diff --git a/js/dojo/dojox/storage/buildFlashStorage.sh b/js/dojo/dojox/storage/buildFlashStorage.sh
new file mode 100644
index 0000000..892dca1
--- /dev/null
+++ b/js/dojo/dojox/storage/buildFlashStorage.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# TODO: FIXME: Get rid of this and hook it into Dojo's general build script
+# You must have mtasc to run this
+mtasc -trace DojoExternalInterface.trace -main -cp ../flash -swf Storage.swf -version 8 -header 215:138:10 Storage.as
diff --git a/js/dojo/dojox/storage/demos/helloworld.html b/js/dojo/dojox/storage/demos/helloworld.html
new file mode 100644
index 0000000..44fd739
--- /dev/null
+++ b/js/dojo/dojox/storage/demos/helloworld.html
@@ -0,0 +1,90 @@
+<html>
+ <head>
+ <script src="../../../dojo/dojo.js"></script>
+ <script src="../storage-browser.js"></script>
+
+ <script>
+ dojo.require("dojox.storage");
+
+ function runDemo(){
+ // setup event handlers
+ dojo.byId("saveButton").onclick = saveValue;
+
+ // write out what our storage provider is for debugging
+ dojo.byId("currentProvider").innerHTML =
+ dojox.storage.manager.currentProvider.declaredClass;
+
+ loadValues();
+ }
+
+ function loadValues(){
+ // get any values that were saved before and write them into the page
+ var results = dojox.storage.get("myValues");
+
+ if(results){
+ var printMe = "<ul>";
+ for(var i = 0; i < results.length; i++){
+ printMe += "<li>" + results[i] + "</li>";
+ }
+ printMe += "</ul>";
+ dojo.byId("allValues").innerHTML = printMe;
+ }
+ }
+
+ function saveValue(){
+ var value = dojo.byId("saveValue").value;
+ if(value == undefined || value === ""){
+ alert("Please enter a correct value");
+ return;
+ }
+
+ // get the old values first, since we are saving everything
+ // as one key
+ var results = dojox.storage.get("myValues");
+ if(!results){
+ results = new Array();
+ }
+
+ // add new value
+ results.push(value);
+
+ dojox.storage.put("myValues", results, function(status, keyName){
+ if(status == dojox.storage.FAILED){
+ alert("You do not have permission to store data for this web site.");
+ }else if(status == dojox.storage.SUCCESS){
+ loadValues();
+ }
+ });
+ }
+
+ // wait until the storage system is finished loading
+ if(!dojox.storage.manager.isInitialized()){
+ dojo.connect(dojox.storage.manager, "loaded", runDemo);
+ }else{
+ dojo.connect(dojo, "loaded", runDemo);
+ }
+ </script>
+ </head>
+
+ <body>
+ <h1>Dojo Storage Hello World</h1>
+
+ <p>Simple Dojo Storage example. Enter values below to have them
+ persisted in Dojo Storage; refresh browser page or close browser
+ and then return to this page to see the values again. Note that
+ Dojo Storage will not work from file:// URLs.</p>
+
+ <h2>Save Values:</h2>
+ <div>
+ <input id="saveValue" type="text"></input>
+ <button id="saveButton">Save Value</button>
+ </div>
+
+ <h2>All Saved Values:</h2>
+ <p id="allValues"></p>
+
+ <p>Using Dojo Storage Provider (autodetected):
+ <span id="currentProvider"></span>
+ <p>
+ </body>
+</html> \ No newline at end of file
diff --git a/js/dojo/dojox/storage/manager.js b/js/dojo/dojox/storage/manager.js
new file mode 100644
index 0000000..5d47296
--- /dev/null
+++ b/js/dojo/dojox/storage/manager.js
@@ -0,0 +1,262 @@
+//>>built
+// wrapped by build app
+define("dojox/storage/manager", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
+dojo.provide("dojox.storage.manager");
+//dojo.require("dojo.AdapterRegistry");
+// FIXME: refactor this to use an AdapterRegistry
+
+dojox.storage.manager = new function(){
+ // summary: A singleton class in charge of the dojox.storage system
+ // description:
+ // Initializes the storage systems and figures out the best available
+ // storage options on this platform.
+
+ // currentProvider: Object
+ // The storage provider that was automagically chosen to do storage
+ // on this platform, such as dojox.storage.FlashStorageProvider.
+ this.currentProvider = null;
+
+ // available: Boolean
+ // Whether storage of some kind is available.
+ this.available = false;
+
+ // providers: Array
+ // Array of all the static provider instances, useful if you want to
+ // loop through and see what providers have been registered.
+ this.providers = [];
+
+ this._initialized = false;
+
+ this._onLoadListeners = [];
+
+ this.initialize = function(){
+ // summary:
+ // Initializes the storage system and autodetects the best storage
+ // provider we can provide on this platform
+ this.autodetect();
+ };
+
+ this.register = function(/*string*/ name, /*Object*/ instance){
+ // summary:
+ // Registers the existence of a new storage provider; used by
+ // subclasses to inform the manager of their existence. The
+ // storage manager will select storage providers based on
+ // their ordering, so the order in which you call this method
+ // matters.
+ // name:
+ // The full class name of this provider, such as
+ // "dojox.storage.FlashStorageProvider".
+ // instance:
+ // An instance of this provider, which we will use to call
+ // isAvailable() on.
+
+ // keep list of providers as a list so that we can know what order
+ // storage providers are preferred; also, store the providers hashed
+ // by name in case someone wants to get a provider that uses
+ // a particular storage backend
+ this.providers.push(instance);
+ this.providers[name] = instance;
+ };
+
+ this.setProvider = function(storageClass){
+ // summary:
+ // Instructs the storageManager to use the given storage class for
+ // all storage requests.
+ // description:
+ // Example-
+ // dojox.storage.setProvider(
+ // dojox.storage.IEStorageProvider)
+
+ };
+
+ this.autodetect = function(){
+ // summary:
+ // Autodetects the best possible persistent storage provider
+ // available on this platform.
+
+ //console.debug("dojox.storage.manager.autodetect");
+
+ if(this._initialized){ // already finished
+ return;
+ }
+
+ // a flag to force the storage manager to use a particular
+ // storage provider type, such as
+ // djConfig = {forceStorageProvider: "dojox.storage.WhatWGStorageProvider"};
+ var forceProvider = dojo.config["forceStorageProvider"] || false;
+
+ // go through each provider, seeing if it can be used
+ var providerToUse;
+ //FIXME: use dojo.some
+ for(var i = 0; i < this.providers.length; i++){
+ providerToUse = this.providers[i];
+ if(forceProvider && forceProvider == providerToUse.declaredClass){
+ // still call isAvailable for this provider, since this helps some
+ // providers internally figure out if they are available
+ // FIXME: This should be refactored since it is non-intuitive
+ // that isAvailable() would initialize some state
+ providerToUse.isAvailable();
+ break;
+ }else if(!forceProvider && providerToUse.isAvailable()){
+ break;
+ }
+ }
+
+ if(!providerToUse){ // no provider available
+ this._initialized = true;
+ this.available = false;
+ this.currentProvider = null;
+ console.warn("No storage provider found for this platform");
+ this.loaded();
+ return;
+ }
+
+ // create this provider and mix in it's properties
+ // so that developers can do dojox.storage.put rather
+ // than dojox.storage.currentProvider.put, for example
+ this.currentProvider = providerToUse;
+ dojo.mixin(dojox.storage, this.currentProvider);
+
+ // have the provider initialize itself
+ dojox.storage.initialize();
+
+ this._initialized = true;
+ this.available = true;
+ };
+
+ this.isAvailable = function(){ /*Boolean*/
+ // summary: Returns whether any storage options are available.
+ return this.available;
+ };
+
+ this.addOnLoad = function(func){ /* void */
+ // summary:
+ // Adds an onload listener to know when Dojo Offline can be used.
+ // description:
+ // Adds a listener to know when Dojo Offline can be used. This
+ // ensures that the Dojo Offline framework is loaded and that the
+ // local dojox.storage system is ready to be used. This method is
+ // useful if you don't want to have a dependency on Dojo Events
+ // when using dojox.storage.
+ // func: Function
+ // A function to call when Dojo Offline is ready to go
+ this._onLoadListeners.push(func);
+
+ if(this.isInitialized()){
+ this._fireLoaded();
+ }
+ };
+
+ this.removeOnLoad = function(func){ /* void */
+ // summary: Removes the given onLoad listener
+ for(var i = 0; i < this._onLoadListeners.length; i++){
+ if(func == this._onLoadListeners[i]){
+ this._onLoadListeners.splice(i, 1);
+ break;
+ }
+ }
+ };
+
+ this.isInitialized = function(){ /*Boolean*/
+ // summary:
+ // Returns whether the storage system is initialized and ready to
+ // be used.
+
+ // FIXME: This should REALLY not be in here, but it fixes a tricky
+ // Flash timing bug.
+ // Confirm that this is still needed with the newly refactored Dojo
+ // Flash. Used to be for Internet Explorer. -- Brad Neuberg
+ if(this.currentProvider != null
+ && this.currentProvider.declaredClass == "dojox.storage.FlashStorageProvider"
+ && dojox.flash.ready == false){
+ return false;
+ }else{
+ return this._initialized;
+ }
+ };
+
+ this.supportsProvider = function(/*string*/ storageClass){ /* Boolean */
+ // summary: Determines if this platform supports the given storage provider.
+ // description:
+ // Example-
+ // dojox.storage.manager.supportsProvider(
+ // "dojox.storage.InternetExplorerStorageProvider");
+
+ // construct this class dynamically
+ try{
+ // dynamically call the given providers class level isAvailable()
+ // method
+ var provider = eval("new " + storageClass + "()");
+ var results = provider.isAvailable();
+ if(!results){ return false; }
+ return results;
+ }catch(e){
+ return false;
+ }
+ };
+
+ this.getProvider = function(){ /* Object */
+ // summary: Gets the current provider
+ return this.currentProvider;
+ };
+
+ this.loaded = function(){
+ // summary:
+ // The storage provider should call this method when it is loaded
+ // and ready to be used. Clients who will use the provider will
+ // connect to this method to know when they can use the storage
+ // system. You can either use dojo.connect to connect to this
+ // function, or can use dojox.storage.manager.addOnLoad() to add
+ // a listener that does not depend on the dojo.event package.
+ // description:
+ // Example 1-
+ // if(dojox.storage.manager.isInitialized() == false){
+ // dojo.connect(dojox.storage.manager, "loaded", TestStorage, "initialize");
+ // }else{
+ // dojo.connect(dojo, "loaded", TestStorage, "initialize");
+ // }
+ // Example 2-
+ // dojox.storage.manager.addOnLoad(someFunction);
+
+
+ // FIXME: we should just provide a Deferred for this. That way you
+ // don't care when this happens or has happened. Deferreds are in Base
+ this._fireLoaded();
+ };
+
+ this._fireLoaded = function(){
+ //console.debug("dojox.storage.manager._fireLoaded");
+
+ dojo.forEach(this._onLoadListeners, function(i){
+ try{
+ i();
+ }catch(e){ console.debug(e); }
+ });
+ };
+
+ this.getResourceList = function(){
+ // summary:
+ // Returns a list of whatever resources are necessary for storage
+ // providers to work.
+ // description:
+ // This will return all files needed by all storage providers for
+ // this particular environment type. For example, if we are in the
+ // browser environment, then this will return the hidden SWF files
+ // needed by the FlashStorageProvider, even if we don't need them
+ // for the particular browser we are working within. This is meant
+ // to faciliate Dojo Offline, which must retrieve all resources we
+ // need offline into the offline cache -- we retrieve everything
+ // needed, in case another browser that requires different storage
+ // mechanisms hits the local offline cache. For example, if we
+ // were to sync against Dojo Offline on Firefox 2, then we would
+ // not grab the FlashStorageProvider resources needed for Safari.
+ var results = [];
+ dojo.forEach(dojox.storage.manager.providers, function(currentProvider){
+ results = results.concat(currentProvider.getResourceList());
+ });
+
+ return results;
+ }
+};
+
+});
diff --git a/js/dojo/dojox/storage/storage_dialog.fla b/js/dojo/dojox/storage/storage_dialog.fla
new file mode 100644
index 0000000..8e9a093
--- /dev/null
+++ b/js/dojo/dojox/storage/storage_dialog.fla
Binary files differ
diff --git a/js/dojo/dojox/storage/storage_dialog.swf b/js/dojo/dojox/storage/storage_dialog.swf
new file mode 100644
index 0000000..db6b217
--- /dev/null
+++ b/js/dojo/dojox/storage/storage_dialog.swf
Binary files differ