aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dojox/off/offline.js.uncompressed.js
diff options
context:
space:
mode:
authormensonge <mensonge@b3834d28-1941-0410-a4f8-b48e95affb8f>2008-11-14 15:39:19 +0000
committermensonge <mensonge@b3834d28-1941-0410-a4f8-b48e95affb8f>2008-11-14 15:39:19 +0000
commit1c5685d68f1b73270fb814fe04cbb490eb90ba5f (patch)
tree3d3ada08a934b96fc31531f1327690d7edc6f766 /includes/js/dojox/off/offline.js.uncompressed.js
parent104d59099e048688c4dbac37d72137006e396558 (diff)
downloadsemanticscuttle-1c5685d68f1b73270fb814fe04cbb490eb90ba5f.tar.gz
semanticscuttle-1c5685d68f1b73270fb814fe04cbb490eb90ba5f.tar.bz2
Minor fix: Remove DOJO library (60Mo) replaced by link to Google CDN (online DOJO library)
git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@159 b3834d28-1941-0410-a4f8-b48e95affb8f
Diffstat (limited to 'includes/js/dojox/off/offline.js.uncompressed.js')
-rw-r--r--includes/js/dojox/off/offline.js.uncompressed.js5910
1 files changed, 0 insertions, 5910 deletions
diff --git a/includes/js/dojox/off/offline.js.uncompressed.js b/includes/js/dojox/off/offline.js.uncompressed.js
deleted file mode 100644
index aa2866d..0000000
--- a/includes/js/dojox/off/offline.js.uncompressed.js
+++ /dev/null
@@ -1,5910 +0,0 @@
-/*
- Copyright (c) 2004-2008, The Dojo Foundation
- All Rights Reserved.
-
- Licensed under the Academic Free License version 2.1 or above OR the
- modified BSD license. For more information on Dojo licensing, see:
-
- http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing
-*/
-
-/*
- This is a compiled version of Dojo, built for deployment and not for
- development. To get an editable version, please visit:
-
- http://dojotoolkit.org
-
- for documentation and information on getting the source.
-*/
-
-if(!dojo._hasResource["dojox.storage.Provider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage.Provider"] = true;
-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){
- // 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.
- // 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
-
- console.warn("dojox.storage.putMultiple not implemented");
- // JAC: We could implement a 'default' puMultiple here by just doing
- // each put individually
- },
-
- 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
-
- console.warn("dojox.storage.getMultiple not implemented");
- // JAC: We could implement a 'default' getMultiple here by just
- // doing each get individually
- },
-
- removeMultiple: function(/*array*/ keys, /*string?*/ namespace) {
- // summary: Removes the given keys from this storage system.
-
- // JAC: We could implement a 'default' removeMultiple here by just
- // doing each remove individually
- console.warn("dojox.storage.remove not implemented");
- },
-
- 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);
- }); // 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 [];
- }
-});
-
-}
-
-if(!dojo._hasResource["dojox.storage.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage.manager"] = true;
-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 = 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;
- }
-};
-
-}
-
-if(!dojo._hasResource["dojox._sql._crypto"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox._sql._crypto"] = true;
-// Taken from http://www.movable-type.co.uk/scripts/aes.html by
-// Chris Veness (CLA signed); adapted for Dojo and Google Gears Worker Pool
-// by Brad Neuberg, bkn3@columbia.edu
-
-dojo.provide("dojox._sql._crypto");
-
-dojo.mixin(dojox._sql._crypto,{
- // _POOL_SIZE:
- // Size of worker pool to create to help with crypto
- _POOL_SIZE: 100,
-
- encrypt: function(plaintext, password, callback){
- // summary:
- // Use Corrected Block TEA to encrypt plaintext using password
- // (note plaintext & password must be strings not string objects).
- // Results will be returned to the 'callback' asychronously.
- this._initWorkerPool();
-
- var msg ={plaintext: plaintext, password: password};
- msg = dojo.toJson(msg);
- msg = "encr:" + String(msg);
-
- this._assignWork(msg, callback);
- },
-
- decrypt: function(ciphertext, password, callback){
- // summary:
- // Use Corrected Block TEA to decrypt ciphertext using password
- // (note ciphertext & password must be strings not string objects).
- // Results will be returned to the 'callback' asychronously.
- this._initWorkerPool();
-
- var msg ={ciphertext: ciphertext, password: password};
- msg = dojo.toJson(msg);
- msg = "decr:" + String(msg);
-
- this._assignWork(msg, callback);
- },
-
- _initWorkerPool: function(){
- // bugs in Google Gears prevents us from dynamically creating
- // and destroying workers as we need them -- the worker
- // pool functionality stops working after a number of crypto
- // cycles (probably related to a memory leak in Google Gears).
- // this is too bad, since it results in much simpler code.
-
- // instead, we have to create a pool of workers and reuse them. we
- // keep a stack of 'unemployed' Worker IDs that are currently not working.
- // if a work request comes in, we pop off the 'unemployed' stack
- // and put them to work, storing them in an 'employed' hashtable,
- // keyed by their Worker ID with the value being the callback function
- // that wants the result. when an employed worker is done, we get
- // a message in our 'manager' which adds this worker back to the
- // unemployed stack and routes the result to the callback that
- // wanted it. if all the workers were employed in the past but
- // more work needed to be done (i.e. it's a tight labor pool ;)
- // then the work messages are pushed onto
- // a 'handleMessage' queue as an object tuple{msg: msg, callback: callback}
-
- if(!this._manager){
- try{
- this._manager = google.gears.factory.create("beta.workerpool", "1.0");
- this._unemployed = [];
- this._employed ={};
- this._handleMessage = [];
-
- var self = this;
- this._manager.onmessage = function(msg, sender){
- // get the callback necessary to serve this result
- var callback = self._employed["_" + sender];
-
- // make this worker unemployed
- self._employed["_" + sender] = undefined;
- self._unemployed.push("_" + sender);
-
- // see if we need to assign new work
- // that was queued up needing to be done
- if(self._handleMessage.length){
- var handleMe = self._handleMessage.shift();
- self._assignWork(handleMe.msg, handleMe.callback);
- }
-
- // return results
- callback(msg);
- }
-
- var workerInit = "function _workerInit(){"
- + "gearsWorkerPool.onmessage = "
- + String(this._workerHandler)
- + ";"
- + "}";
-
- var code = workerInit + " _workerInit();";
-
- // create our worker pool
- for(var i = 0; i < this._POOL_SIZE; i++){
- this._unemployed.push("_" + this._manager.createWorker(code));
- }
- }catch(exp){
- throw exp.message||exp;
- }
- }
- },
-
- _assignWork: function(msg, callback){
- // can we immediately assign this work?
- if(!this._handleMessage.length && this._unemployed.length){
- // get an unemployed worker
- var workerID = this._unemployed.shift().substring(1); // remove _
-
- // list this worker as employed
- this._employed["_" + workerID] = callback;
-
- // do the worke
- this._manager.sendMessage(msg, workerID);
- }else{
- // we have to queue it up
- this._handleMessage ={msg: msg, callback: callback};
- }
- },
-
- _workerHandler: function(msg, sender){
-
- /* Begin AES Implementation */
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
- var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
- 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
- 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
- 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
- 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
- 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
- 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
- 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
- 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
- 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
- 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
- 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
- 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
- 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
- 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
- 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
-
- // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
- var Rcon = [ [0x00, 0x00, 0x00, 0x00],
- [0x01, 0x00, 0x00, 0x00],
- [0x02, 0x00, 0x00, 0x00],
- [0x04, 0x00, 0x00, 0x00],
- [0x08, 0x00, 0x00, 0x00],
- [0x10, 0x00, 0x00, 0x00],
- [0x20, 0x00, 0x00, 0x00],
- [0x40, 0x00, 0x00, 0x00],
- [0x80, 0x00, 0x00, 0x00],
- [0x1b, 0x00, 0x00, 0x00],
- [0x36, 0x00, 0x00, 0x00] ];
-
- /*
- * AES Cipher function: encrypt 'input' with Rijndael algorithm
- *
- * takes byte-array 'input' (16 bytes)
- * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
- *
- * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
- *
- * returns byte-array encrypted value (16 bytes)
- */
- function Cipher(input, w) { // main Cipher function [§5.1]
- var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
- var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
-
- var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4]
- for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
-
- state = AddRoundKey(state, w, 0, Nb);
-
- for (var round=1; round<Nr; round++) {
- state = SubBytes(state, Nb);
- state = ShiftRows(state, Nb);
- state = MixColumns(state, Nb);
- state = AddRoundKey(state, w, round, Nb);
- }
-
- state = SubBytes(state, Nb);
- state = ShiftRows(state, Nb);
- state = AddRoundKey(state, w, Nr, Nb);
-
- var output = new Array(4*Nb); // convert state to 1-d array before returning [§3.4]
- for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
- return output;
- }
-
-
- function SubBytes(s, Nb) { // apply SBox to state S [§5.1.1]
- for (var r=0; r<4; r++) {
- for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
- }
- return s;
- }
-
-
- function ShiftRows(s, Nb) { // shift row r of state S left by r bytes [§5.1.2]
- var t = new Array(4);
- for (var r=1; r<4; r++) {
- for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb]; // shift into temp copy
- for (var c=0; c<4; c++) s[r][c] = t[c]; // and copy back
- } // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
- return s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
- }
-
-
- function MixColumns(s, Nb) { // combine bytes of each col of state S [§5.1.3]
- for (var c=0; c<4; c++) {
- var a = new Array(4); // 'a' is a copy of the current column from 's'
- var b = new Array(4); // 'b' is a•{02} in GF(2^8)
- for (var i=0; i<4; i++) {
- a[i] = s[i][c];
- b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
- }
- // a[n] ^ b[n] is a•{03} in GF(2^8)
- s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
- s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
- s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
- s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
- }
- return s;
- }
-
-
- function AddRoundKey(state, w, rnd, Nb) { // xor Round Key into state S [§5.1.4]
- for (var r=0; r<4; r++) {
- for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
- }
- return state;
- }
-
-
- function KeyExpansion(key) { // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
- var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
- var Nk = key.length/4 // key length (in words): 4/6/8 for 128/192/256-bit keys
- var Nr = Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
-
- var w = new Array(Nb*(Nr+1));
- var temp = new Array(4);
-
- for (var i=0; i<Nk; i++) {
- var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
- w[i] = r;
- }
-
- for (var i=Nk; i<(Nb*(Nr+1)); i++) {
- w[i] = new Array(4);
- for (var t=0; t<4; t++) temp[t] = w[i-1][t];
- if (i % Nk == 0) {
- temp = SubWord(RotWord(temp));
- for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
- } else if (Nk > 6 && i%Nk == 4) {
- temp = SubWord(temp);
- }
- for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
- }
-
- return w;
- }
-
- function SubWord(w) { // apply SBox to 4-byte word w
- for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
- return w;
- }
-
- function RotWord(w) { // rotate 4-byte word w left by one byte
- w[4] = w[0];
- for (var i=0; i<4; i++) w[i] = w[i+1];
- return w;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /*
- * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation
- * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
- * for each block
- * - outputblock = cipher(counter, key)
- * - cipherblock = plaintext xor outputblock
- */
- function AESEncryptCtr(plaintext, password, nBits) {
- if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
-
- // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password;
- // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1
- var nBytes = nBits/8; // no bytes in key
- var pwBytes = new Array(nBytes);
- for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
-
- var key = Cipher(pwBytes, KeyExpansion(pwBytes));
-
- key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
-
- // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
- // block counter in 2nd 8 bytes
- var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
- var counterBlock = new Array(blockSize); // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
- var nonce = (new Date()).getTime(); // milliseconds since 1-Jan-1970
-
- // encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
- for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
- for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff;
-
- // generate key schedule - an expansion of the key into distinct Key Rounds for each round
- var keySchedule = KeyExpansion(key);
-
- var blockCount = Math.ceil(plaintext.length/blockSize);
- var ciphertext = new Array(blockCount); // ciphertext as array of strings
-
- for (var b=0; b<blockCount; b++) {
- // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
- // again done in two stages for 32-bit ops
- for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
- for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
-
- var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block --
-
- // calculate length of final block:
- var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
-
- var ct = '';
- for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter byte-by-byte --
- var plaintextByte = plaintext.charCodeAt(b*blockSize+i);
- var cipherByte = plaintextByte ^ cipherCntr[i];
- ct += String.fromCharCode(cipherByte);
- }
- // ct is now ciphertext for this block
-
- ciphertext[b] = escCtrlChars(ct); // escape troublesome characters in ciphertext
- }
-
- // convert the nonce to a string to go on the front of the ciphertext
- var ctrTxt = '';
- for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
- ctrTxt = escCtrlChars(ctrTxt);
-
- // use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
- return ctrTxt + '-' + ciphertext.join('-');
- }
-
-
- /*
- * Use AES to decrypt 'ciphertext' with 'password' using 'nBits' key, in Counter mode of operation
- *
- * for each block
- * - outputblock = cipher(counter, key)
- * - cipherblock = plaintext xor outputblock
- */
- function AESDecryptCtr(ciphertext, password, nBits) {
- if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
-
- var nBytes = nBits/8; // no bytes in key
- var pwBytes = new Array(nBytes);
- for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
- var pwKeySchedule = KeyExpansion(pwBytes);
- var key = Cipher(pwBytes, pwKeySchedule);
- key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
-
- var keySchedule = KeyExpansion(key);
-
- ciphertext = ciphertext.split('-'); // split ciphertext into array of block-length strings
-
- // recover nonce from 1st element of ciphertext
- var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
- var counterBlock = new Array(blockSize);
- var ctrTxt = unescCtrlChars(ciphertext[0]);
- for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
-
- var plaintext = new Array(ciphertext.length-1);
-
- for (var b=1; b<ciphertext.length; b++) {
- // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
- for (var c=0; c<4; c++) counterBlock[15-c] = ((b-1) >>> c*8) & 0xff;
- for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff;
-
- var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block
-
- ciphertext[b] = unescCtrlChars(ciphertext[b]);
-
- var pt = '';
- for (var i=0; i<ciphertext[b].length; i++) {
- // -- xor plaintext with ciphered counter byte-by-byte --
- var ciphertextByte = ciphertext[b].charCodeAt(i);
- var plaintextByte = ciphertextByte ^ cipherCntr[i];
- pt += String.fromCharCode(plaintextByte);
- }
- // pt is now plaintext for this block
-
- plaintext[b-1] = pt; // b-1 'cos no initial nonce block in plaintext
- }
-
- return plaintext.join('');
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- function escCtrlChars(str) { // escape control chars which might cause problems handling ciphertext
- return str.replace(/[\0\t\n\v\f\r\xa0!-]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
- } // \xa0 to cater for bug in Firefox; include '-' to leave it free for use as a block marker
-
- function unescCtrlChars(str) { // unescape potentially problematic control characters
- return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- function encrypt(plaintext, password){
- return AESEncryptCtr(plaintext, password, 256);
- }
-
- function decrypt(ciphertext, password){
- return AESDecryptCtr(ciphertext, password, 256);
- }
-
- /* End AES Implementation */
-
- var cmd = msg.substr(0,4);
- var arg = msg.substr(5);
- if(cmd == "encr"){
- arg = eval("(" + arg + ")");
- var plaintext = arg.plaintext;
- var password = arg.password;
- var results = encrypt(plaintext, password);
- gearsWorkerPool.sendMessage(String(results), sender);
- }else if(cmd == "decr"){
- arg = eval("(" + arg + ")");
- var ciphertext = arg.ciphertext;
- var password = arg.password;
- var results = decrypt(ciphertext, password);
- gearsWorkerPool.sendMessage(String(results), sender);
- }
- }
-});
-
-}
-
-if(!dojo._hasResource["dojox._sql.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox._sql.common"] = true;
-dojo.provide("dojox._sql.common");
-
-
-
-// summary:
-// Executes a SQL expression.
-// description:
-// There are four ways to call this:
-// 1) Straight SQL: dojox.sql("SELECT * FROM FOOBAR");
-// 2) SQL with parameters: dojox.sql("INSERT INTO FOOBAR VALUES (?)", someParam)
-// 3) Encrypting particular values:
-// dojox.sql("INSERT INTO FOOBAR VALUES (ENCRYPT(?))", someParam, "somePassword", callback)
-// 4) Decrypting particular values:
-// dojox.sql("SELECT DECRYPT(SOMECOL1), DECRYPT(SOMECOL2) FROM
-// FOOBAR WHERE SOMECOL3 = ?", someParam,
-// "somePassword", callback)
-//
-// For encryption and decryption the last two values should be the the password for
-// encryption/decryption, and the callback function that gets the result set.
-//
-// Note: We only support ENCRYPT(?) statements, and
-// and DECRYPT(*) statements for now -- you can not have a literal string
-// inside of these, such as ENCRYPT('foobar')
-//
-// Note: If you have multiple columns to encrypt and decrypt, you can use the following
-// convenience form to not have to type ENCRYPT(?)/DECRYPT(*) many times:
-//
-// dojox.sql("INSERT INTO FOOBAR VALUES (ENCRYPT(?, ?, ?))",
-// someParam1, someParam2, someParam3,
-// "somePassword", callback)
-//
-// dojox.sql("SELECT DECRYPT(SOMECOL1, SOMECOL2) FROM
-// FOOBAR WHERE SOMECOL3 = ?", someParam,
-// "somePassword", callback)
-dojox.sql = new Function("return dojox.sql._exec(arguments);");
-
-dojo.mixin(dojox.sql, {
- dbName: null,
-
- // summary:
- // If true, then we print out any SQL that is executed
- // to the debug window
- debug: (dojo.exists("dojox.sql.debug")?dojox.sql.debug:false),
-
- open: function(dbName){
- if(this._dbOpen && (!dbName || dbName == this.dbName)){
- return;
- }
-
- if(!this.dbName){
- this.dbName = "dot_store_"
- + window.location.href.replace(/[^0-9A-Za-z_]/g, "_");
- // database names in Gears are limited to 64 characters long
- if(this.dbName.length > 63){
- this.dbName = this.dbName.substring(0, 63);
- }
- }
-
- if(!dbName){
- dbName = this.dbName;
- }
-
- try{
- this._initDb();
- this.db.open(dbName);
- this._dbOpen = true;
- }catch(exp){
- throw exp.message||exp;
- }
- },
-
- close: function(dbName){
- // on Internet Explorer, Google Gears throws an exception
- // "Object not a collection", when we try to close the
- // database -- just don't close it on this platform
- // since we are running into a Gears bug; the Gears team
- // said it's ok to not close a database connection
- if(dojo.isIE){ return; }
-
- if(!this._dbOpen && (!dbName || dbName == this.dbName)){
- return;
- }
-
- if(!dbName){
- dbName = this.dbName;
- }
-
- try{
- this.db.close(dbName);
- this._dbOpen = false;
- }catch(exp){
- throw exp.message||exp;
- }
- },
-
- _exec: function(params){
- try{
- // get the Gears Database object
- this._initDb();
-
- // see if we need to open the db; if programmer
- // manually called dojox.sql.open() let them handle
- // it; otherwise we open and close automatically on
- // each SQL execution
- if(!this._dbOpen){
- this.open();
- this._autoClose = true;
- }
-
- // determine our parameters
- var sql = null;
- var callback = null;
- var password = null;
-
- var args = dojo._toArray(params);
-
- sql = args.splice(0, 1)[0];
-
- // does this SQL statement use the ENCRYPT or DECRYPT
- // keywords? if so, extract our callback and crypto
- // password
- if(this._needsEncrypt(sql) || this._needsDecrypt(sql)){
- callback = args.splice(args.length - 1, 1)[0];
- password = args.splice(args.length - 1, 1)[0];
- }
-
- // 'args' now just has the SQL parameters
-
- // print out debug SQL output if the developer wants that
- if(this.debug){
- this._printDebugSQL(sql, args);
- }
-
- // handle SQL that needs encryption/decryption differently
- // do we have an ENCRYPT SQL statement? if so, handle that first
- if(this._needsEncrypt(sql)){
- var crypto = new dojox.sql._SQLCrypto("encrypt", sql,
- password, args,
- callback);
- return; // encrypted results will arrive asynchronously
- }else if(this._needsDecrypt(sql)){ // otherwise we have a DECRYPT statement
- var crypto = new dojox.sql._SQLCrypto("decrypt", sql,
- password, args,
- callback);
- return; // decrypted results will arrive asynchronously
- }
-
- // execute the SQL and get the results
- var rs = this.db.execute(sql, args);
-
- // Gears ResultSet object's are ugly -- normalize
- // these into something JavaScript programmers know
- // how to work with, basically an array of
- // JavaScript objects where each property name is
- // simply the field name for a column of data
- rs = this._normalizeResults(rs);
-
- if(this._autoClose){
- this.close();
- }
-
- return rs;
- }catch(exp){
- exp = exp.message||exp;
-
- console.debug("SQL Exception: " + exp);
-
- if(this._autoClose){
- try{
- this.close();
- }catch(e){
- console.debug("Error closing database: "
- + e.message||e);
- }
- }
-
- throw exp;
- }
- },
-
- _initDb: function(){
- if(!this.db){
- try{
- this.db = google.gears.factory.create('beta.database', '1.0');
- }catch(exp){
- dojo.setObject("google.gears.denied", true);
- dojox.off.onFrameworkEvent("coreOperationFailed");
- throw "Google Gears must be allowed to run";
- }
- }
- },
-
- _printDebugSQL: function(sql, args){
- var msg = "dojox.sql(\"" + sql + "\"";
- for(var i = 0; i < args.length; i++){
- if(typeof args[i] == "string"){
- msg += ", \"" + args[i] + "\"";
- }else{
- msg += ", " + args[i];
- }
- }
- msg += ")";
-
- console.debug(msg);
- },
-
- _normalizeResults: function(rs){
- var results = [];
- if(!rs){ return []; }
-
- while(rs.isValidRow()){
- var row = {};
-
- for(var i = 0; i < rs.fieldCount(); i++){
- var fieldName = rs.fieldName(i);
- var fieldValue = rs.field(i);
- row[fieldName] = fieldValue;
- }
-
- results.push(row);
-
- rs.next();
- }
-
- rs.close();
-
- return results;
- },
-
- _needsEncrypt: function(sql){
- return /encrypt\([^\)]*\)/i.test(sql);
- },
-
- _needsDecrypt: function(sql){
- return /decrypt\([^\)]*\)/i.test(sql);
- }
-});
-
-// summary:
-// A private class encapsulating any cryptography that must be done
-// on a SQL statement. We instantiate this class and have it hold
-// it's state so that we can potentially have several encryption
-// operations happening at the same time by different SQL statements.
-dojo.declare("dojox.sql._SQLCrypto", null, {
- constructor: function(action, sql, password, args, callback){
- if(action == "encrypt"){
- this._execEncryptSQL(sql, password, args, callback);
- }else{
- this._execDecryptSQL(sql, password, args, callback);
- }
- },
-
- _execEncryptSQL: function(sql, password, args, callback){
- // strip the ENCRYPT/DECRYPT keywords from the SQL
- var strippedSQL = this._stripCryptoSQL(sql);
-
- // determine what arguments need encryption
- var encryptColumns = this._flagEncryptedArgs(sql, args);
-
- // asynchronously encrypt each argument that needs it
- var self = this;
- this._encrypt(strippedSQL, password, args, encryptColumns, function(finalArgs){
- // execute the SQL
- var error = false;
- var resultSet = [];
- var exp = null;
- try{
- resultSet = dojox.sql.db.execute(strippedSQL, finalArgs);
- }catch(execError){
- error = true;
- exp = execError.message||execError;
- }
-
- // was there an error during SQL execution?
- if(exp != null){
- if(dojox.sql._autoClose){
- try{ dojox.sql.close(); }catch(e){}
- }
-
- callback(null, true, exp.toString());
- return;
- }
-
- // normalize SQL results into a JavaScript object
- // we can work with
- resultSet = dojox.sql._normalizeResults(resultSet);
-
- if(dojox.sql._autoClose){
- dojox.sql.close();
- }
-
- // are any decryptions necessary on the result set?
- if(dojox.sql._needsDecrypt(sql)){
- // determine which of the result set columns needs decryption
- var needsDecrypt = self._determineDecryptedColumns(sql);
-
- // now decrypt columns asynchronously
- // decrypt columns that need it
- self._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){
- callback(finalResultSet, false, null);
- });
- }else{
- callback(resultSet, false, null);
- }
- });
- },
-
- _execDecryptSQL: function(sql, password, args, callback){
- // strip the ENCRYPT/DECRYPT keywords from the SQL
- var strippedSQL = this._stripCryptoSQL(sql);
-
- // determine which columns needs decryption; this either
- // returns the value *, which means all result set columns will
- // be decrypted, or it will return the column names that need
- // decryption set on a hashtable so we can quickly test a given
- // column name; the key is the column name that needs
- // decryption and the value is 'true' (i.e. needsDecrypt["someColumn"]
- // would return 'true' if it needs decryption, and would be 'undefined'
- // or false otherwise)
- var needsDecrypt = this._determineDecryptedColumns(sql);
-
- // execute the SQL
- var error = false;
- var resultSet = [];
- var exp = null;
- try{
- resultSet = dojox.sql.db.execute(strippedSQL, args);
- }catch(execError){
- error = true;
- exp = execError.message||execError;
- }
-
- // was there an error during SQL execution?
- if(exp != null){
- if(dojox.sql._autoClose){
- try{ dojox.sql.close(); }catch(e){}
- }
-
- callback(resultSet, true, exp.toString());
- return;
- }
-
- // normalize SQL results into a JavaScript object
- // we can work with
- resultSet = dojox.sql._normalizeResults(resultSet);
-
- if(dojox.sql._autoClose){
- dojox.sql.close();
- }
-
- // decrypt columns that need it
- this._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){
- callback(finalResultSet, false, null);
- });
- },
-
- _encrypt: function(sql, password, args, encryptColumns, callback){
- //console.debug("_encrypt, sql="+sql+", password="+password+", encryptColumns="+encryptColumns+", args="+args);
-
- this._totalCrypto = 0;
- this._finishedCrypto = 0;
- this._finishedSpawningCrypto = false;
- this._finalArgs = args;
-
- for(var i = 0; i < args.length; i++){
- if(encryptColumns[i]){
- // we have an encrypt() keyword -- get just the value inside
- // the encrypt() parantheses -- for now this must be a ?
- var sqlParam = args[i];
- var paramIndex = i;
-
- // update the total number of encryptions we know must be done asynchronously
- this._totalCrypto++;
-
- // FIXME: This currently uses DES as a proof-of-concept since the
- // DES code used is quite fast and was easy to work with. Modify dojox.sql
- // to be able to specify a different encryption provider through a
- // a SQL-like syntax, such as dojox.sql("SET ENCRYPTION BLOWFISH"),
- // and modify the dojox.crypto.Blowfish code to be able to work using
- // a Google Gears Worker Pool
-
- // do the actual encryption now, asychronously on a Gears worker thread
- dojox._sql._crypto.encrypt(sqlParam, password, dojo.hitch(this, function(results){
- // set the new encrypted value
- this._finalArgs[paramIndex] = results;
- this._finishedCrypto++;
- // are we done with all encryption?
- if(this._finishedCrypto >= this._totalCrypto
- && this._finishedSpawningCrypto){
- callback(this._finalArgs);
- }
- }));
- }
- }
-
- this._finishedSpawningCrypto = true;
- },
-
- _decrypt: function(resultSet, needsDecrypt, password, callback){
- //console.debug("decrypt, resultSet="+resultSet+", needsDecrypt="+needsDecrypt+", password="+password);
-
- this._totalCrypto = 0;
- this._finishedCrypto = 0;
- this._finishedSpawningCrypto = false;
- this._finalResultSet = resultSet;
-
- for(var i = 0; i < resultSet.length; i++){
- var row = resultSet[i];
-
- // go through each of the column names in row,
- // seeing if they need decryption
- for(var columnName in row){
- if(needsDecrypt == "*" || needsDecrypt[columnName]){
- this._totalCrypto++;
- var columnValue = row[columnName];
-
- // forming a closure here can cause issues, with values not cleanly
- // saved on Firefox/Mac OS X for some of the values above that
- // are needed in the callback below; call a subroutine that will form
- // a closure inside of itself instead
- this._decryptSingleColumn(columnName, columnValue, password, i,
- function(finalResultSet){
- callback(finalResultSet);
- });
- }
- }
- }
-
- this._finishedSpawningCrypto = true;
- },
-
- _stripCryptoSQL: function(sql){
- // replace all DECRYPT(*) occurrences with a *
- sql = sql.replace(/DECRYPT\(\*\)/ig, "*");
-
- // match any ENCRYPT(?, ?, ?, etc) occurrences,
- // then replace with just the question marks in the
- // middle
- var matches = sql.match(/ENCRYPT\([^\)]*\)/ig);
- if(matches != null){
- for(var i = 0; i < matches.length; i++){
- var encryptStatement = matches[i];
- var encryptValue = encryptStatement.match(/ENCRYPT\(([^\)]*)\)/i)[1];
- sql = sql.replace(encryptStatement, encryptValue);
- }
- }
-
- // match any DECRYPT(COL1, COL2, etc) occurrences,
- // then replace with just the column names
- // in the middle
- matches = sql.match(/DECRYPT\([^\)]*\)/ig);
- if(matches != null){
- for(var i = 0; i < matches.length; i++){
- var decryptStatement = matches[i];
- var decryptValue = decryptStatement.match(/DECRYPT\(([^\)]*)\)/i)[1];
- sql = sql.replace(decryptStatement, decryptValue);
- }
- }
-
- return sql;
- },
-
- _flagEncryptedArgs: function(sql, args){
- // capture literal strings that have question marks in them,
- // and also capture question marks that stand alone
- var tester = new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig);
- var matches;
- var currentParam = 0;
- var results = [];
- while((matches = tester.exec(sql)) != null){
- var currentMatch = RegExp.lastMatch+"";
-
- // are we a literal string? then ignore it
- if(/^[\"\']/.test(currentMatch)){
- continue;
- }
-
- // do we have an encrypt keyword to our left?
- var needsEncrypt = false;
- if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){
- needsEncrypt = true;
- }
-
- // set the encrypted flag
- results[currentParam] = needsEncrypt;
-
- currentParam++;
- }
-
- return results;
- },
-
- _determineDecryptedColumns: function(sql){
- var results = {};
-
- if(/DECRYPT\(\*\)/i.test(sql)){
- results = "*";
- }else{
- var tester = /DECRYPT\((?:\s*\w*\s*\,?)*\)/ig;
- var matches;
- while(matches = tester.exec(sql)){
- var lastMatch = new String(RegExp.lastMatch);
- var columnNames = lastMatch.replace(/DECRYPT\(/i, "");
- columnNames = columnNames.replace(/\)/, "");
- columnNames = columnNames.split(/\s*,\s*/);
- dojo.forEach(columnNames, function(column){
- if(/\s*\w* AS (\w*)/i.test(column)){
- column = column.match(/\s*\w* AS (\w*)/i)[1];
- }
- results[column] = true;
- });
- }
- }
-
- return results;
- },
-
- _decryptSingleColumn: function(columnName, columnValue, password, currentRowIndex,
- callback){
- //console.debug("decryptSingleColumn, columnName="+columnName+", columnValue="+columnValue+", currentRowIndex="+currentRowIndex)
- dojox._sql._crypto.decrypt(columnValue, password, dojo.hitch(this, function(results){
- // set the new decrypted value
- this._finalResultSet[currentRowIndex][columnName] = results;
- this._finishedCrypto++;
-
- // are we done with all encryption?
- if(this._finishedCrypto >= this._totalCrypto
- && this._finishedSpawningCrypto){
- //console.debug("done with all decrypts");
- callback(this._finalResultSet);
- }
- }));
- }
-});
-
-}
-
-if(!dojo._hasResource["dojox.sql"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.sql"] = true;
-
-dojo.provide("dojox.sql");
-
-}
-
-if(!dojo._hasResource["dojox.storage.GearsStorageProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage.GearsStorageProvider"] = true;
-dojo.provide("dojox.storage.GearsStorageProvider");
-
-
-
-
-if(dojo.isGears){
-
- (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,
-
- 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";
-
- // 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.initialize:", e);
-
- this.initialized = false; // we were unable to initialize
- dojox.storage.manager.loaded();
- return;
- }
-
- // 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.isGears;
- },
-
- put: function(key, value, resultsHandler, namespace){
- if(this.isValidKey(key) == false){
- throw new Error("Invalid key given: " + key);
- }
- namespace = namespace||this.DEFAULT_NAMESPACE;
-
- // 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());
- return;
- }
-
- if(resultsHandler){
- resultsHandler(dojox.storage.SUCCESS, key, null);
- }
- },
-
- get: function(key, namespace){
- if(this.isValidKey(key) == false){
- throw new Error("Invalid key given: " + key);
- }
- namespace = namespace||this.DEFAULT_NAMESPACE;
-
- // 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(){
- 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){
- namespace = namespace||this.DEFAULT_NAMESPACE;
- if(this.isValidKey(namespace) == false){
- 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){
- if(this.isValidKey(namespace) == false){
- throw new Error("Invalid namespace given: " + namespace);
- }
- namespace = namespace||this.DEFAULT_NAMESPACE;
-
- dojox.sql("DELETE FROM " + this.TABLE_NAME
- + " WHERE namespace = ?",
- namespace);
- },
-
- remove: function(key, namespace){
- namespace = namespace||this.DEFAULT_NAMESPACE;
-
- dojox.sql("DELETE FROM " + this.TABLE_NAME
- + " WHERE namespace = ? AND"
- + " key = ?",
- 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 = dojox.storage.DEFAULT_NAMESPACE;
- }
-
- if(this.isValidKey(namespace) == false){
- 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());
- }
- return;
- }
-
- if(resultsHandler){
- resultsHandler(dojox.storage.SUCCESS, key, null);
- }
- },
-
- getMultiple: function(keys, namespace){
- // TODO: Maybe use SELECT IN instead
-
- if(this.isValidKeyArray(keys) === false){
- throw new ("Invalid key array given: " + keys);
- }
-
- if(namespace == null || typeof namespace == "undefined"){
- namespace = dojox.storage.DEFAULT_NAMESPACE;
- }
-
- if(this.isValidKey(namespace) == false){
- 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){
- namespace = namespace||this.DEFAULT_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");
- }
- });
-
- // register the existence of our storage providers
- dojox.storage.manager.register("dojox.storage.GearsStorageProvider",
- new dojox.storage.GearsStorageProvider());
- })();
-}
-
-}
-
-if(!dojo._hasResource["dojox.storage.WhatWGStorageProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage.WhatWGStorageProvider"] = true;
-dojo.provide("dojox.storage.WhatWGStorageProvider");
-
-
-
-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
- // see: https://bugzilla.mozilla.org/show_bug.cgi?id=357323
- this._domain = (location.hostname == "localhost") ? "localhost.localdomain" : location.hostname;
- // console.debug(this._domain);
-
- // indicate that this storage provider is now loaded
- this.initialized = true;
- dojox.storage.manager.loaded();
- },
-
- isAvailable: function(){
- try{
- // see: https://bugzilla.mozilla.org/show_bug.cgi?id=357323
- var myStorage = globalStorage[((location.hostname == "localhost") ? "localhost.localdomain" : 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);
- }
- });
-
- 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());
- }
- },
-
- 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());
-
-}
-
-if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit._base.place"] = true;
-dojo.provide("dijit._base.place");
-
-// ported from dojo.html.util
-
-dijit.getViewport = function(){
- // summary
- // Returns the dimensions and scroll position of the viewable area of a browser window
-
- var _window = dojo.global;
- var _document = dojo.doc;
-
- // get viewport size
- var w = 0, h = 0;
- var de = _document.documentElement;
- var dew = de.clientWidth, deh = de.clientHeight;
- if(dojo.isMozilla){
- // mozilla
- // _window.innerHeight includes the height taken by the scroll bar
- // clientHeight is ideal but has DTD issues:
- // #4539: FF reverses the roles of body.clientHeight/Width and documentElement.clientHeight/Width based on the DTD!
- // check DTD to see whether body or documentElement returns the viewport dimensions using this algorithm:
- var minw, minh, maxw, maxh;
- var dbw = _document.body.clientWidth;
- if(dbw > dew){
- minw = dew;
- maxw = dbw;
- }else{
- maxw = dew;
- minw = dbw;
- }
- var dbh = _document.body.clientHeight;
- if(dbh > deh){
- minh = deh;
- maxh = dbh;
- }else{
- maxh = deh;
- minh = dbh;
- }
- w = (maxw > _window.innerWidth) ? minw : maxw;
- h = (maxh > _window.innerHeight) ? minh : maxh;
- }else if(!dojo.isOpera && _window.innerWidth){
- //in opera9, dojo.body().clientWidth should be used, instead
- //of window.innerWidth/document.documentElement.clientWidth
- //so we have to check whether it is opera
- w = _window.innerWidth;
- h = _window.innerHeight;
- }else if(dojo.isIE && de && deh){
- w = dew;
- h = deh;
- }else if(dojo.body().clientWidth){
- // IE5, Opera
- w = dojo.body().clientWidth;
- h = dojo.body().clientHeight;
- }
-
- // get scroll position
- var scroll = dojo._docScroll();
-
- return { w: w, h: h, l: scroll.x, t: scroll.y }; // object
-};
-
-dijit.placeOnScreen = function(
- /* DomNode */ node,
- /* Object */ pos,
- /* Object */ corners,
- /* boolean? */ tryOnly){
- // summary:
- // Keeps 'node' in the visible area of the screen while trying to
- // place closest to pos.x, pos.y. The input coordinates are
- // expected to be the desired document position.
- //
- // Set which corner(s) you want to bind to, such as
- //
- // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
- //
- // The desired x/y will be treated as the topleft(TL)/topright(TR) or
- // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
- // and if a perfect match is found, it will be used. Otherwise, it goes through
- // all of the specified corners, and choose the most appropriate one.
- //
- // NOTE: node is assumed to be absolutely or relatively positioned.
-
- var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; });
-
- return dijit._place(node, choices);
-}
-
-dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
- // summary:
- // Given a list of spots to put node, put it at the first spot where it fits,
- // of if it doesn't fit anywhere then the place with the least overflow
- // choices: Array
- // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
- // Above example says to put the top-left corner of the node at (10,20)
- // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
- // for things like tooltip, they are displayed differently (and have different dimensions)
- // based on their orientation relative to the parent. This adjusts the popup based on orientation.
-
- // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
- // viewport over document
- var view = dijit.getViewport();
-
- // This won't work if the node is inside a <div style="position: relative">,
- // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong
- // and also it might get cutoff)
- if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
- dojo.body().appendChild(node);
- }
-
- var best = null;
- dojo.some(choices, function(choice){
- var corner = choice.corner;
- var pos = choice.pos;
-
- // configure node to be displayed in given position relative to button
- // (need to do this in order to get an accurate size for the node, because
- // a tooltips size changes based on position, due to triangle)
- if(layoutNode){
- layoutNode(node, choice.aroundCorner, corner);
- }
-
- // get node's size
- var style = node.style;
- var oldDisplay = style.display;
- var oldVis = style.visibility;
- style.visibility = "hidden";
- style.display = "";
- var mb = dojo.marginBox(node);
- style.display = oldDisplay;
- style.visibility = oldVis;
-
- // coordinates and size of node with specified corner placed at pos,
- // and clipped by viewport
- var startX = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l, pos.x - mb.w)),
- startY = (corner.charAt(0) == 'T' ? pos.y : Math.max(view.t, pos.y - mb.h)),
- endX = (corner.charAt(1) == 'L' ? Math.min(view.l + view.w, startX + mb.w) : pos.x),
- endY = (corner.charAt(0) == 'T' ? Math.min(view.t + view.h, startY + mb.h) : pos.y),
- width = endX - startX,
- height = endY - startY,
- overflow = (mb.w - width) + (mb.h - height);
-
- if(best == null || overflow < best.overflow){
- best = {
- corner: corner,
- aroundCorner: choice.aroundCorner,
- x: startX,
- y: startY,
- w: width,
- h: height,
- overflow: overflow
- };
- }
- return !overflow;
- });
-
- node.style.left = best.x + "px";
- node.style.top = best.y + "px";
- if(best.overflow && layoutNode){
- layoutNode(node, best.aroundCorner, best.corner);
- }
- return best;
-}
-
-dijit.placeOnScreenAroundElement = function(
- /* DomNode */ node,
- /* DomNode */ aroundNode,
- /* Object */ aroundCorners,
- /* Function */ layoutNode){
-
- // summary
- // Like placeOnScreen, except it accepts aroundNode instead of x,y
- // and attempts to place node around it. Uses margin box dimensions.
- //
- // aroundCorners
- // specify Which corner of aroundNode should be
- // used to place the node => which corner(s) of node to use (see the
- // corners parameter in dijit.placeOnScreen)
- // e.g. {'TL': 'BL', 'BL': 'TL'}
- //
- // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
- // for things like tooltip, they are displayed differently (and have different dimensions)
- // based on their orientation relative to the parent. This adjusts the popup based on orientation.
-
-
- // get coordinates of aroundNode
- aroundNode = dojo.byId(aroundNode);
- var oldDisplay = aroundNode.style.display;
- aroundNode.style.display="";
- // #3172: use the slightly tighter border box instead of marginBox
- var aroundNodeW = aroundNode.offsetWidth; //mb.w;
- var aroundNodeH = aroundNode.offsetHeight; //mb.h;
- var aroundNodePos = dojo.coords(aroundNode, true);
- aroundNode.style.display=oldDisplay;
-
- // Generate list of possible positions for node
- var choices = [];
- for(var nodeCorner in aroundCorners){
- choices.push( {
- aroundCorner: nodeCorner,
- corner: aroundCorners[nodeCorner],
- pos: {
- x: aroundNodePos.x + (nodeCorner.charAt(1) == 'L' ? 0 : aroundNodeW),
- y: aroundNodePos.y + (nodeCorner.charAt(0) == 'T' ? 0 : aroundNodeH)
- }
- });
- }
-
- return dijit._place(node, choices, layoutNode);
-}
-
-}
-
-if(!dojo._hasResource["dojox.flash._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.flash._base"] = true;
-dojo.provide("dojox.flash._base");
-
-// for dijit.getViewport(), needed by dojox.flash.Embed.center()
-
-
-dojox.flash = function(){
- // summary:
- // The goal of dojox.flash is to make it easy to extend Flash's capabilities
- // into an Ajax/DHTML environment.
- //
- // dojox.flash provides an easy object for interacting with the Flash plugin.
- // This object provides methods to determine the current version of the Flash
- // plugin (dojox.flash.info); write out the necessary markup to
- // dynamically insert a Flash object into the page (dojox.flash.Embed; and
- // do dynamic installation and upgrading of the current Flash plugin in
- // use (dojox.flash.Install). If you want to call methods on the Flash object
- // embedded into the page it is your responsibility to use Flash's ExternalInterface
- // API and get a reference to the Flash object yourself.
- //
- // To use dojox.flash, you must first wait until Flash is finished loading
- // and initializing before you attempt communication or interaction.
- // To know when Flash is finished use dojo.connect:
- //
- // dojo.connect(dojox.flash, "loaded", myInstance, "myCallback");
- //
- // Then, while the page is still loading provide the file name:
- //
- // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf"));
- //
- // If no SWF files are specified, then Flash is not initialized.
- //
- // Your Flash must use Flash's ExternalInterface to expose Flash methods and
- // to call JavaScript.
- //
- // setSwf can take an optional 'visible' attribute to control whether
- // the Flash object is visible or not on the page; the default is visible:
- //
- // dojox.flash.setSwf(dojo.moduleUrl("dojox", "_storage/storage.swf"),
- // false);
- //
- // Once finished, you can query Flash version information:
- //
- // dojox.flash.info.version
- //
- // Or can communicate with Flash methods that were exposed:
- //
- // var f = dojox.flash.get();
- // var results = f.sayHello("Some Message");
- //
- // Your Flash files should use DojoExternalInterface.as to register methods;
- // this file wraps Flash's normal ExternalInterface but correct various
- // serialization bugs that ExternalInterface has.
- //
- // Note that dojox.flash is not meant to be a generic Flash embedding
- // mechanism; it is as generic as necessary to make Dojo Storage's
- // Flash Storage Provider as clean and modular as possible. If you want
- // a generic Flash embed mechanism see SWFObject
- // (http://blog.deconcept.com/swfobject/).
- //
- // Notes:
- // Note that dojox.flash can currently only work with one Flash object
- // on the page; it does not yet support multiple Flash objects on
- // the same page.
- //
- // Your code can detect whether the Flash player is installing or having
- // its version revved in two ways. First, if dojox.flash detects that
- // Flash installation needs to occur, it sets dojox.flash.info.installing
- // to true. Second, you can detect if installation is necessary with the
- // following callback:
- //
- // dojo.connect(dojox.flash, "installing", myInstance, "myCallback");
- //
- // You can use this callback to delay further actions that might need Flash;
- // when installation is finished the full page will be refreshed and the
- // user will be placed back on your page with Flash installed.
- //
- // -------------------
- // Todo/Known Issues
- // -------------------
- // * On Internet Explorer, after doing a basic install, the page is
- // not refreshed or does not detect that Flash is now available. The way
- // to fix this is to create a custom small Flash file that is pointed to
- // during installation; when it is finished loading, it does a callback
- // that says that Flash installation is complete on IE, and we can proceed
- // to initialize the dojox.flash subsystem.
- // * Things aren't super tested for sending complex objects to Flash
- // methods, since Dojo Storage only needs strings
- //
- // Author- Brad Neuberg, http://codinginparadise.org
-}
-
-dojox.flash = {
- ready: false,
- url: null,
-
- _visible: true,
- _loadedListeners: new Array(),
- _installingListeners: new Array(),
-
- setSwf: function(/* String */ url, /* boolean? */ visible){
- // summary: Sets the SWF files and versions we are using.
- // url: String
- // The URL to this Flash file.
- // visible: boolean?
- // Whether the Flash file is visible or not. If it is not visible we hide it off the
- // screen. This defaults to true (i.e. the Flash file is visible).
- this.url = url;
-
- if(typeof visible != "undefined"){
- this._visible = visible;
- }
-
- // initialize ourselves
- this._initialize();
- },
-
- addLoadedListener: function(/* Function */ listener){
- // summary:
- // Adds a listener to know when Flash is finished loading.
- // Useful if you don't want a dependency on dojo.event.
- // listener: Function
- // A function that will be called when Flash is done loading.
-
- this._loadedListeners.push(listener);
- },
-
- addInstallingListener: function(/* Function */ listener){
- // summary:
- // Adds a listener to know if Flash is being installed.
- // Useful if you don't want a dependency on dojo.event.
- // listener: Function
- // A function that will be called if Flash is being
- // installed
-
- this._installingListeners.push(listener);
- },
-
- loaded: function(){
- // summary: Called back when the Flash subsystem is finished loading.
- // description:
- // A callback when the Flash subsystem is finished loading and can be
- // worked with. To be notified when Flash is finished loading, add a
- // loaded listener:
- //
- // dojox.flash.addLoadedListener(loadedListener);
-
- dojox.flash.ready = true;
- if(dojox.flash._loadedListeners.length > 0){
- for(var i = 0;i < dojox.flash._loadedListeners.length; i++){
- dojox.flash._loadedListeners[i].call(null);
- }
- }
- },
-
- installing: function(){
- // summary: Called if Flash is being installed.
- // description:
- // A callback to know if Flash is currently being installed or
- // having its version revved. To be notified if Flash is installing, connect
- // your callback to this method using the following:
- //
- // dojo.event.connect(dojox.flash, "installing", myInstance, "myCallback");
-
- if(dojox.flash._installingListeners.length > 0){
- for(var i = 0; i < dojox.flash._installingListeners.length; i++){
- dojox.flash._installingListeners[i].call(null);
- }
- }
- },
-
- // Initializes dojox.flash.
- _initialize: function(){
- //console.debug("dojox.flash._initialize");
- // see if we need to rev or install Flash on this platform
- var installer = new dojox.flash.Install();
- dojox.flash.installer = installer;
-
- if(installer.needed() == true){
- installer.install();
- }else{
- // write the flash object into the page
- dojox.flash.obj = new dojox.flash.Embed(this._visible);
- dojox.flash.obj.write();
-
- // setup the communicator
- dojox.flash.comm = new dojox.flash.Communicator();
- }
- }
-};
-
-
-dojox.flash.Info = function(){
- // summary: A class that helps us determine whether Flash is available.
- // description:
- // A class that helps us determine whether Flash is available,
- // it's major and minor versions, and what Flash version features should
- // be used for Flash/JavaScript communication. Parts of this code
- // are adapted from the automatic Flash plugin detection code autogenerated
- // by the Macromedia Flash 8 authoring environment.
- //
- // An instance of this class can be accessed on dojox.flash.info after
- // the page is finished loading.
- //
- // This constructor must be called before the page is finished loading.
-
- // Visual basic helper required to detect Flash Player ActiveX control
- // version information on Internet Explorer
- if(dojo.isIE){
- document.write([
- '<script language="VBScript" type="text/vbscript"\>',
- 'Function VBGetSwfVer(i)',
- ' on error resume next',
- ' Dim swControl, swVersion',
- ' swVersion = 0',
- ' set swControl = CreateObject("ShockwaveFlash.ShockwaveFlash." + CStr(i))',
- ' if (IsObject(swControl)) then',
- ' swVersion = swControl.GetVariable("$version")',
- ' end if',
- ' VBGetSwfVer = swVersion',
- 'End Function',
- '</script\>'].join("\r\n"));
- }
-
- this._detectVersion();
-}
-
-dojox.flash.Info.prototype = {
- // version: String
- // The full version string, such as "8r22".
- version: -1,
-
- // versionMajor, versionMinor, versionRevision: String
- // The major, minor, and revisions of the plugin. For example, if the
- // plugin is 8r22, then the major version is 8, the minor version is 0,
- // and the revision is 22.
- versionMajor: -1,
- versionMinor: -1,
- versionRevision: -1,
-
- // capable: Boolean
- // Whether this platform has Flash already installed.
- capable: false,
-
- // installing: Boolean
- // Set if we are in the middle of a Flash installation session.
- installing: false,
-
- isVersionOrAbove: function(
- /* int */ reqMajorVer,
- /* int */ reqMinorVer,
- /* int */ reqVer){ /* Boolean */
- // summary:
- // Asserts that this environment has the given major, minor, and revision
- // numbers for the Flash player.
- // description:
- // Asserts that this environment has the given major, minor, and revision
- // numbers for the Flash player.
- //
- // Example- To test for Flash Player 7r14:
- //
- // dojox.flash.info.isVersionOrAbove(7, 0, 14)
- // returns:
- // Returns true if the player is equal
- // or above the given version, false otherwise.
-
- // make the revision a decimal (i.e. transform revision 14 into
- // 0.14
- reqVer = parseFloat("." + reqVer);
-
- if(this.versionMajor >= reqMajorVer && this.versionMinor >= reqMinorVer
- && this.versionRevision >= reqVer){
- return true;
- }else{
- return false;
- }
- },
-
- _detectVersion: function(){
- var versionStr;
-
- // loop backwards through the versions until we find the newest version
- for(var testVersion = 25; testVersion > 0; testVersion--){
- if(dojo.isIE){
- versionStr = VBGetSwfVer(testVersion);
- }else{
- versionStr = this._JSFlashInfo(testVersion);
- }
-
- if(versionStr == -1 ){
- this.capable = false;
- return;
- }else if(versionStr != 0){
- var versionArray;
- if(dojo.isIE){
- var tempArray = versionStr.split(" ");
- var tempString = tempArray[1];
- versionArray = tempString.split(",");
- }else{
- versionArray = versionStr.split(".");
- }
-
- this.versionMajor = versionArray[0];
- this.versionMinor = versionArray[1];
- this.versionRevision = versionArray[2];
-
- // 7.0r24 == 7.24
- var versionString = this.versionMajor + "." + this.versionRevision;
- this.version = parseFloat(versionString);
-
- this.capable = true;
-
- break;
- }
- }
- },
-
- // JavaScript helper required to detect Flash Player PlugIn version
- // information. Internet Explorer uses a corresponding Visual Basic
- // version to interact with the Flash ActiveX control.
- _JSFlashInfo: function(testVersion){
- // NS/Opera version >= 3 check for Flash plugin in plugin array
- if(navigator.plugins != null && navigator.plugins.length > 0){
- if(navigator.plugins["Shockwave Flash 2.0"] ||
- navigator.plugins["Shockwave Flash"]){
- var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
- var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
- var descArray = flashDescription.split(" ");
- var tempArrayMajor = descArray[2].split(".");
- var versionMajor = tempArrayMajor[0];
- var versionMinor = tempArrayMajor[1];
- if(descArray[3] != ""){
- var tempArrayMinor = descArray[3].split("r");
- }else{
- var tempArrayMinor = descArray[4].split("r");
- }
- var versionRevision = tempArrayMinor[1] > 0 ? tempArrayMinor[1] : 0;
- var version = versionMajor + "." + versionMinor + "."
- + versionRevision;
-
- return version;
- }
- }
-
- return -1;
- }
-};
-
-dojox.flash.Embed = function(visible){
- // summary: A class that is used to write out the Flash object into the page.
- // description:
- // Writes out the necessary tags to embed a Flash file into the page. Note that
- // these tags are written out as the page is loaded using document.write, so
- // you must call this class before the page has finished loading.
-
- this._visible = visible;
-}
-
-dojox.flash.Embed.prototype = {
- // width: int
- // The width of this Flash applet. The default is the minimal width
- // necessary to show the Flash settings dialog. Current value is
- // 215 pixels.
- width: 215,
-
- // height: int
- // The height of this Flash applet. The default is the minimal height
- // necessary to show the Flash settings dialog. Current value is
- // 138 pixels.
- height: 138,
-
- // id: String
- // The id of the Flash object. Current value is 'flashObject'.
- id: "flashObject",
-
- // Controls whether this is a visible Flash applet or not.
- _visible: true,
-
- protocol: function(){
- switch(window.location.protocol){
- case "https:":
- return "https";
- break;
- default:
- return "http";
- break;
- }
- },
-
- write: function(/* Boolean? */ doExpressInstall){
- // summary: Writes the Flash into the page.
- // description:
- // This must be called before the page
- // is finished loading.
- // doExpressInstall: Boolean
- // Whether to write out Express Install
- // information. Optional value; defaults to false.
-
- // determine our container div's styling
- var containerStyle = "";
- containerStyle += ("width: " + this.width + "px; ");
- containerStyle += ("height: " + this.height + "px; ");
- if(!this._visible){
- containerStyle += "position: absolute; z-index: 10000; top: -1000px; left: -1000px; ";
- }
-
- // figure out the SWF file to get and how to write out the correct HTML
- // for this Flash version
- var objectHTML;
- var swfloc = dojox.flash.url;
- var swflocObject = swfloc;
- var swflocEmbed = swfloc;
- var dojoUrl = dojo.baseUrl;
- if(doExpressInstall){
- // the location to redirect to after installing
- var redirectURL = escape(window.location);
- document.title = document.title.slice(0, 47) + " - Flash Player Installation";
- var docTitle = escape(document.title);
- swflocObject += "?MMredirectURL=" + redirectURL
- + "&MMplayerType=ActiveX"
- + "&MMdoctitle=" + docTitle
- + "&baseUrl=" + escape(dojoUrl);
- swflocEmbed += "?MMredirectURL=" + redirectURL
- + "&MMplayerType=PlugIn"
- + "&baseUrl=" + escape(dojoUrl);
- }else{
- // IE/Flash has an evil bug that shows up some time: if we load the
- // Flash and it isn't in the cache, ExternalInterface works fine --
- // however, the second time when its loaded from the cache a timing
- // bug can keep ExternalInterface from working. The trick below
- // simply invalidates the Flash object in the cache all the time to
- // keep it loading fresh. -- Brad Neuberg
- swflocObject += "?cachebust=" + new Date().getTime();
- }
-
- if(swflocEmbed.indexOf("?") == -1){
- swflocEmbed += '?baseUrl='+escape(dojoUrl);
- }else{
- swflocEmbed += '&baseUrl='+escape(dojoUrl);
- }
-
- objectHTML =
- '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '
- + 'codebase="'
- + this.protocol()
- + '://fpdownload.macromedia.com/pub/shockwave/cabs/flash/'
- + 'swflash.cab#version=8,0,0,0"\n '
- + 'width="' + this.width + '"\n '
- + 'height="' + this.height + '"\n '
- + 'id="' + this.id + '"\n '
- + 'name="' + this.id + '"\n '
- + 'align="middle">\n '
- + '<param name="allowScriptAccess" value="sameDomain"></param>\n '
- + '<param name="movie" value="' + swflocObject + '"></param>\n '
- + '<param name="quality" value="high"></param>\n '
- + '<param name="bgcolor" value="#ffffff"></param>\n '
- + '<embed src="' + swflocEmbed + '" '
- + 'quality="high" '
- + 'bgcolor="#ffffff" '
- + 'width="' + this.width + '" '
- + 'height="' + this.height + '" '
- + 'id="' + this.id + 'Embed' + '" '
- + 'name="' + this.id + '" '
- + 'swLiveConnect="true" '
- + 'align="middle" '
- + 'allowScriptAccess="sameDomain" '
- + 'type="application/x-shockwave-flash" '
- + 'pluginspage="'
- + this.protocol()
- +'://www.macromedia.com/go/getflashplayer" '
- + '></embed>\n'
- + '</object>\n';
-
- // using same mechanism on all browsers now to write out
- // Flash object into page
-
- // document.write no longer works correctly
- // due to Eolas patent workaround in IE;
- // nothing happens (i.e. object doesn't
- // go into page if we use it)
- dojo.connect(dojo, "loaded", dojo.hitch(this, function(){
- var div = document.createElement("div");
- div.setAttribute("id", this.id + "Container");
- div.setAttribute("style", containerStyle);
- div.innerHTML = objectHTML;
-
- var body = document.getElementsByTagName("body");
- if(!body || !body.length){
- throw new Error("No body tag for this page");
- }
- body = body[0];
- body.appendChild(div);
- }));
- },
-
- get: function(){ /* Object */
- // summary: Gets the Flash object DOM node.
- if(dojo.isIE || dojo.isSafari){
- return document.getElementById(this.id);
- }else{
- // different IDs on OBJECT and EMBED tags or
- // else Firefox will return wrong one and
- // communication won't work;
- // also, document.getElementById() returns a
- // plugin but ExternalInterface calls don't
- // work on it so we have to use
- // document[id] instead
- return document[this.id + "Embed"];
- }
- },
-
- setVisible: function(/* Boolean */ visible){
- //console.debug("setVisible, visible="+visible);
-
- // summary: Sets the visibility of this Flash object.
- var container = dojo.byId(this.id + "Container");
- if(visible == true){
- container.style.position = "absolute"; // IE -- Brad Neuberg
- container.style.visibility = "visible";
- }else{
- container.style.position = "absolute";
- container.style.x = "-1000px";
- container.style.y = "-1000px";
- container.style.visibility = "hidden";
- }
- },
-
- center: function(){
- // summary: Centers the flash applet on the page.
-
- var elementWidth = this.width;
- var elementHeight = this.height;
-
- var viewport = dijit.getViewport();
-
- // compute the centered position
- var x = viewport.l + (viewport.w - elementWidth) / 2;
- var y = viewport.t + (viewport.h - elementHeight) / 2;
-
- // set the centered position
- var container = dojo.byId(this.id + "Container");
- container.style.top = y + "px";
- container.style.left = x + "px";
- }
-};
-
-
-dojox.flash.Communicator = function(){
- // summary:
- // A class that is used to communicate between Flash and JavaScript.
- // description:
- // This class helps mediate Flash and JavaScript communication. Internally
- // it uses Flash 8's ExternalInterface API, but adds functionality to fix
- // various encoding bugs that ExternalInterface has.
-}
-
-dojox.flash.Communicator.prototype = {
- // Registers the existence of a Flash method that we can call with
- // JavaScript, using Flash 8's ExternalInterface.
- _addExternalInterfaceCallback: function(methodName){
- var wrapperCall = dojo.hitch(this, function(){
- // some browsers don't like us changing values in the 'arguments' array, so
- // make a fresh copy of it
- var methodArgs = new Array(arguments.length);
- for(var i = 0; i < arguments.length; i++){
- methodArgs[i] = this._encodeData(arguments[i]);
- }
-
- var results = this._execFlash(methodName, methodArgs);
- results = this._decodeData(results);
-
- return results;
- });
-
- this[methodName] = wrapperCall;
- },
-
- // Encodes our data to get around ExternalInterface bugs that are still
- // present even in Flash 9.
- _encodeData: function(data){
- if(!data || typeof data != "string"){
- return data;
- }
-
- // double encode all entity values, or they will be mis-decoded
- // by Flash when returned
- var entityRE = /\&([^;]*)\;/g;
- data = data.replace(entityRE, "&amp;$1;");
-
- // entity encode XML-ish characters, or Flash's broken XML serializer
- // breaks
- data = data.replace(/</g, "&lt;");
- data = data.replace(/>/g, "&gt;");
-
- // transforming \ into \\ doesn't work; just use a custom encoding
- data = data.replace("\\", "&custom_backslash;");
-
- data = data.replace(/\0/g, "\\0"); // null character
- data = data.replace(/\"/g, "&quot;");
-
- return data;
- },
-
- // Decodes our data to get around ExternalInterface bugs that are still
- // present even in Flash 9.
- _decodeData: function(data){
- // wierdly enough, Flash sometimes returns the result as an
- // 'object' that is actually an array, rather than as a String;
- // detect this by looking for a length property; for IE
- // we also make sure that we aren't dealing with a typeof string
- // since string objects have length property there
- if(data && data.length && typeof data != "string"){
- data = data[0];
- }
-
- if(!data || typeof data != "string"){
- return data;
- }
-
- // certain XMLish characters break Flash's wire serialization for
- // ExternalInterface; these are encoded on the
- // DojoExternalInterface side into a custom encoding, rather than
- // the standard entity encoding, because otherwise we won't be able to
- // differentiate between our own encoding and any entity characters
- // that are being used in the string itself
- data = data.replace(/\&custom_lt\;/g, "<");
- data = data.replace(/\&custom_gt\;/g, ">");
- data = data.replace(/\&custom_backslash\;/g, '\\');
-
- // needed for IE; \0 is the NULL character
- data = data.replace(/\\0/g, "\0");
-
- return data;
- },
-
- // Executes a Flash method; called from the JavaScript wrapper proxy we
- // create on dojox.flash.comm.
- _execFlash: function(methodName, methodArgs){
- var plugin = dojox.flash.obj.get();
- methodArgs = (methodArgs) ? methodArgs : [];
-
- // encode arguments that are strings
- for(var i = 0; i < methodArgs; i++){
- if(typeof methodArgs[i] == "string"){
- methodArgs[i] = this._encodeData(methodArgs[i]);
- }
- }
-
- // we use this gnarly hack below instead of
- // plugin[methodName] for two reasons:
- // 1) plugin[methodName] has no call() method, which
- // means we can't pass in multiple arguments dynamically
- // to a Flash method -- we can only have one
- // 2) On IE plugin[methodName] returns undefined --
- // plugin[methodName] used to work on IE when we
- // used document.write but doesn't now that
- // we use dynamic DOM insertion of the Flash object
- // -- Brad Neuberg
- var flashExec = function(){
- return eval(plugin.CallFunction(
- "<invoke name=\"" + methodName
- + "\" returntype=\"javascript\">"
- + __flash__argumentsToXML(methodArgs, 0)
- + "</invoke>"));
- };
- var results = flashExec.call(methodArgs);
-
- if(typeof results == "string"){
- results = this._decodeData(results);
- }
-
- return results;
- }
-}
-
-// FIXME: dojo.declare()-ify this
-
-// TODO: I did not test the Install code when I refactored Dojo Flash from 0.4 to
-// 1.0, so am not sure if it works. If Flash is not present I now prefer
-// that Gears is installed instead of Flash because GearsStorageProvider is
-// much easier to work with than Flash's hacky ExternalInteface.
-// -- Brad Neuberg
-dojox.flash.Install = function(){
- // summary: Helps install Flash plugin if needed.
- // description:
- // Figures out the best way to automatically install the Flash plugin
- // for this browser and platform. Also determines if installation or
- // revving of the current plugin is needed on this platform.
-}
-
-dojox.flash.Install.prototype = {
- needed: function(){ /* Boolean */
- // summary:
- // Determines if installation or revving of the current plugin is
- // needed.
-
- // do we even have flash?
- if(dojox.flash.info.capable == false){
- return true;
- }
-
- // Must have ExternalInterface which came in Flash 8
- if(!dojox.flash.info.isVersionOrAbove(8, 0, 0)){
- return true;
- }
-
- // otherwise we don't need installation
- return false;
- },
-
- install: function(){
- // summary: Performs installation or revving of the Flash plugin.
-
- // indicate that we are installing
- dojox.flash.info.installing = true;
- dojox.flash.installing();
-
- if(dojox.flash.info.capable == false){ // we have no Flash at all
- // write out a simple Flash object to force the browser to prompt
- // the user to install things
- var installObj = new dojox.flash.Embed(false);
- installObj.write(); // write out HTML for Flash
- }else if(dojox.flash.info.isVersionOrAbove(6, 0, 65)){ // Express Install
- var installObj = new dojox.flash.Embed(false);
- installObj.write(true); // write out HTML for Flash 8 version+
- installObj.setVisible(true);
- installObj.center();
- }else{ // older Flash install than version 6r65
- alert("This content requires a more recent version of the Macromedia "
- +" Flash Player.");
- window.location.href = + dojox.flash.Embed.protocol() +
- "://www.macromedia.com/go/getflashplayer";
- }
- },
-
- // Called when the Express Install is either finished, failed, or was
- // rejected by the user.
- _onInstallStatus: function(msg){
- if (msg == "Download.Complete"){
- // Installation is complete.
- dojox.flash._initialize();
- }else if(msg == "Download.Cancelled"){
- alert("This content requires a more recent version of the Macromedia "
- +" Flash Player.");
- window.location.href = dojox.flash.Embed.protocol() +
- "://www.macromedia.com/go/getflashplayer";
- }else if (msg == "Download.Failed"){
- // The end user failed to download the installer due to a network failure
- alert("There was an error downloading the Flash Player update. "
- + "Please try again later, or visit macromedia.com to download "
- + "the latest version of the Flash plugin.");
- }
- }
-}
-
-// find out if Flash is installed
-dojox.flash.info = new dojox.flash.Info();
-
-// vim:ts=4:noet:tw=0:
-
-}
-
-if(!dojo._hasResource["dojox.flash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.flash"] = true;
-dojo.provide("dojox.flash");
-
-
-}
-
-if(!dojo._hasResource["dojox.storage.FlashStorageProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage.FlashStorageProvider"] = true;
-dojo.provide("dojox.storage.FlashStorageProvider");
-
-
-
-
-
-// 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, this.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, this.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, this.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, namespace);
- }
- }
- }
-);
-
-dojox.storage.manager.register("dojox.storage.FlashStorageProvider",
- new dojox.storage.FlashStorageProvider());
-
-}
-
-if(!dojo._hasResource["dojox.storage._common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage._common"] = true;
-dojo.provide("dojox.storage._common");
-
-
-
-/*
- 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
-*/
-
-
-
-
-// now that we are loaded and registered tell the storage manager to
-// initialize itself
-dojox.storage.manager.initialize();
-
-}
-
-if(!dojo._hasResource["dojox.storage"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.storage"] = true;
-dojo.provide("dojox.storage");
-
-
-}
-
-if(!dojo._hasResource["dojox.off.files"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off.files"] = true;
-dojo.provide("dojox.off.files");
-
-// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
-
-// summary:
-// Helps maintain resources that should be
-// available offline, such as CSS files.
-// description:
-// dojox.off.files makes it easy to indicate
-// what resources should be available offline,
-// such as CSS files, JavaScript, HTML, etc.
-dojox.off.files = {
- // versionURL: String
- // An optional file, that if present, records the version
- // of our bundle of files to make available offline. If this
- // file is present, and we are not currently debugging,
- // then we only refresh our offline files if the version has
- // changed.
- versionURL: "version.js",
-
- // listOfURLs: Array
- // For advanced usage; most developers can ignore this.
- // Our list of URLs that will be cached and made available
- // offline.
- listOfURLs: [],
-
- // refreshing: boolean
- // For advanced usage; most developers can ignore this.
- // Whether we are currently in the middle
- // of refreshing our list of offline files.
- refreshing: false,
-
- _cancelID: null,
-
- _error: false,
- _errorMessages: [],
- _currentFileIndex: 0,
- _store: null,
- _doSlurp: false,
-
- slurp: function(){
- // summary:
- // Autoscans the page to find all resources to
- // cache. This includes scripts, images, CSS, and hyperlinks
- // to pages that are in the same scheme/port/host as this
- // page. We also scan the embedded CSS of any stylesheets
- // to find @import statements and url()'s.
- // You should call this method from the top-level, outside of
- // any functions and before the page loads:
- //
- // <script>
- //
- //
- //
- //
- //
- // // configure how we should work offline
- //
- // // set our application name
- // dojox.off.ui.appName = "Moxie";
- //
- // // automatically "slurp" the page and
- // // capture the resources we need offline
- // dojox.off.files.slurp();
- //
- // // tell Dojo Offline we are ready for it to initialize itself now
- // // that we have finished configuring it for our application
- // dojox.off.initialize();
- // </script>
- //
- // Note that inline styles on elements are not handled (i.e.
- // if you somehow have an inline style that uses a URL);
- // object and embed tags are not scanned since their format
- // differs based on type; and elements created by JavaScript
- // after page load are not found. For these you must manually
- // add them with a dojox.off.files.cache() method call.
-
- // just schedule the slurp once the page is loaded and
- // Dojo Offline is ready to slurp; dojox.off will call
- // our _slurp() method before indicating it is finished
- // loading
- this._doSlurp = true;
- },
-
- cache: function(urlOrList){ /* void */
- // summary:
- // Caches a file or list of files to be available offline. This
- // can either be a full URL, such as http://foobar.com/index.html,
- // or a relative URL, such as ../index.html. This URL is not
- // actually cached until dojox.off.sync.synchronize() is called.
- // urlOrList: String or Array[]
- // A URL of a file to cache or an Array of Strings of files to
- // cache
-
- //console.debug("dojox.off.files.cache, urlOrList="+urlOrList);
-
- if(dojo.isString(urlOrList)){
- var url = this._trimAnchor(urlOrList+"");
- if(!this.isAvailable(url)){
- this.listOfURLs.push(url);
- }
- }else if(urlOrList instanceof dojo._Url){
- var url = this._trimAnchor(urlOrList.uri);
- if(!this.isAvailable(url)){
- this.listOfURLs.push(url);
- }
- }else{
- dojo.forEach(urlOrList, function(url){
- url = this._trimAnchor(url);
- if(!this.isAvailable(url)){
- this.listOfURLs.push(url);
- }
- }, this);
- }
- },
-
- printURLs: function(){
- // summary:
- // A helper function that will dump and print out
- // all of the URLs that are cached for offline
- // availability. This can help with debugging if you
- // are trying to make sure that all of your URLs are
- // available offline
- console.debug("The following URLs are cached for offline use:");
- dojo.forEach(this.listOfURLs, function(i){
- console.debug(i);
- });
- },
-
- remove: function(url){ /* void */
- // summary:
- // Removes a URL from the list of files to cache.
- // description:
- // Removes a URL from the list of URLs to cache. Note that this
- // does not actually remove the file from the offline cache;
- // instead, it just prevents us from refreshing this file at a
- // later time, so that it will naturally time out and be removed
- // from the offline cache
- // url: String
- // The URL to remove
- for(var i = 0; i < this.listOfURLs.length; i++){
- if(this.listOfURLs[i] == url){
- this.listOfURLs = this.listOfURLs.splice(i, 1);
- break;
- }
- }
- },
-
- isAvailable: function(url){ /* boolean */
- // summary:
- // Determines whether the given resource is available offline.
- // url: String
- // The URL to check
- for(var i = 0; i < this.listOfURLs.length; i++){
- if(this.listOfURLs[i] == url){
- return true;
- }
- }
-
- return false;
- },
-
- refresh: function(callback){ /* void */
- //console.debug("dojox.off.files.refresh");
- // summary:
- // For advanced usage; most developers can ignore this.
- // Refreshes our list of offline resources,
- // making them available offline.
- // callback: Function
- // A callback that receives two arguments: whether an error
- // occurred, which is a boolean; and an array of error message strings
- // with details on errors encountered. If no error occured then message is
- // empty array with length 0.
- try{
- if(dojo.config.isDebug){
- this.printURLs();
- }
-
- this.refreshing = true;
-
- if(this.versionURL){
- this._getVersionInfo(function(oldVersion, newVersion, justDebugged){
- //console.warn("getVersionInfo, oldVersion="+oldVersion+", newVersion="+newVersion
- // + ", justDebugged="+justDebugged+", isDebug="+dojo.config.isDebug);
- if(dojo.config.isDebug || !newVersion || justDebugged
- || !oldVersion || oldVersion != newVersion){
- console.warn("Refreshing offline file list");
- this._doRefresh(callback, newVersion);
- }else{
- console.warn("No need to refresh offline file list");
- callback(false, []);
- }
- });
- }else{
- console.warn("Refreshing offline file list");
- this._doRefresh(callback);
- }
- }catch(e){
- this.refreshing = false;
-
- // can't refresh files -- core operation --
- // fail fast
- dojox.off.coreOpFailed = true;
- dojox.off.enabled = false;
- dojox.off.onFrameworkEvent("coreOperationFailed");
- }
- },
-
- abortRefresh: function(){
- // summary:
- // For advanced usage; most developers can ignore this.
- // Aborts and cancels a refresh.
- if(!this.refreshing){
- return;
- }
-
- this._store.abortCapture(this._cancelID);
- this.refreshing = false;
- },
-
- _slurp: function(){
- if(!this._doSlurp){
- return;
- }
-
- var handleUrl = dojo.hitch(this, function(url){
- if(this._sameLocation(url)){
- this.cache(url);
- }
- });
-
- handleUrl(window.location.href);
-
- dojo.query("script").forEach(function(i){
- try{
- handleUrl(i.getAttribute("src"));
- }catch(exp){
- //console.debug("dojox.off.files.slurp 'script' error: "
- // + exp.message||exp);
- }
- });
-
- dojo.query("link").forEach(function(i){
- try{
- if(!i.getAttribute("rel")
- || i.getAttribute("rel").toLowerCase() != "stylesheet"){
- return;
- }
-
- handleUrl(i.getAttribute("href"));
- }catch(exp){
- //console.debug("dojox.off.files.slurp 'link' error: "
- // + exp.message||exp);
- }
- });
-
- dojo.query("img").forEach(function(i){
- try{
- handleUrl(i.getAttribute("src"));
- }catch(exp){
- //console.debug("dojox.off.files.slurp 'img' error: "
- // + exp.message||exp);
- }
- });
-
- dojo.query("a").forEach(function(i){
- try{
- handleUrl(i.getAttribute("href"));
- }catch(exp){
- //console.debug("dojox.off.files.slurp 'a' error: "
- // + exp.message||exp);
- }
- });
-
- // FIXME: handle 'object' and 'embed' tag
-
- // parse our style sheets for inline URLs and imports
- dojo.forEach(document.styleSheets, function(sheet){
- try{
- if(sheet.cssRules){ // Firefox
- dojo.forEach(sheet.cssRules, function(rule){
- var text = rule.cssText;
- if(text){
- var matches = text.match(/url\(\s*([^\) ]*)\s*\)/i);
- if(!matches){
- return;
- }
-
- for(var i = 1; i < matches.length; i++){
- handleUrl(matches[i])
- }
- }
- });
- }else if(sheet.cssText){ // IE
- var matches;
- var text = sheet.cssText.toString();
- // unfortunately, using RegExp.exec seems to be flakey
- // for looping across multiple lines on IE using the
- // global flag, so we have to simulate it
- var lines = text.split(/\f|\r|\n/);
- for(var i = 0; i < lines.length; i++){
- matches = lines[i].match(/url\(\s*([^\) ]*)\s*\)/i);
- if(matches && matches.length){
- handleUrl(matches[1]);
- }
- }
- }
- }catch(exp){
- //console.debug("dojox.off.files.slurp stylesheet parse error: "
- // + exp.message||exp);
- }
- });
-
- //this.printURLs();
- },
-
- _sameLocation: function(url){
- if(!url){ return false; }
-
- // filter out anchors
- if(url.length && url.charAt(0) == "#"){
- return false;
- }
-
- // FIXME: dojo._Url should be made public;
- // it's functionality is very useful for
- // parsing URLs correctly, which is hard to
- // do right
- url = new dojo._Url(url);
-
- // totally relative -- ../../someFile.html
- if(!url.scheme && !url.port && !url.host){
- return true;
- }
-
- // scheme relative with port specified -- brad.com:8080
- if(!url.scheme && url.host && url.port
- && window.location.hostname == url.host
- && window.location.port == url.port){
- return true;
- }
-
- // scheme relative with no-port specified -- brad.com
- if(!url.scheme && url.host && !url.port
- && window.location.hostname == url.host
- && window.location.port == 80){
- return true;
- }
-
- // else we have everything
- return window.location.protocol == (url.scheme + ":")
- && window.location.hostname == url.host
- && (window.location.port == url.port || !window.location.port && !url.port);
- },
-
- _trimAnchor: function(url){
- return url.replace(/\#.*$/, "");
- },
-
- _doRefresh: function(callback, newVersion){
- // get our local server
- var localServer;
- try{
- localServer = google.gears.factory.create("beta.localserver", "1.0");
- }catch(exp){
- dojo.setObject("google.gears.denied", true);
- dojox.off.onFrameworkEvent("coreOperationFailed");
- throw "Google Gears must be allowed to run";
- }
-
- var storeName = "dot_store_"
- + window.location.href.replace(/[^0-9A-Za-z_]/g, "_");
-
- // clip at 64 characters, the max length of a resource store name
- if(storeName.length >= 64){
- storeName = storeName.substring(0, 63);
- }
-
- // refresh everything by simply removing
- // any older stores
- localServer.removeStore(storeName);
-
- // open/create the resource store
- localServer.openStore(storeName);
- var store = localServer.createStore(storeName);
- this._store = store;
-
- // add our list of files to capture
- var self = this;
- this._currentFileIndex = 0;
- this._cancelID = store.capture(this.listOfURLs, function(url, success, captureId){
- //console.debug("store.capture, url="+url+", success="+success);
- if(!success && self.refreshing){
- self._cancelID = null;
- self.refreshing = false;
- var errorMsgs = [];
- errorMsgs.push("Unable to capture: " + url);
- callback(true, errorMsgs);
- return;
- }else if(success){
- self._currentFileIndex++;
- }
-
- if(success && self._currentFileIndex >= self.listOfURLs.length){
- self._cancelID = null;
- self.refreshing = false;
- if(newVersion){
- dojox.storage.put("oldVersion", newVersion, null,
- dojox.off.STORAGE_NAMESPACE);
- }
- dojox.storage.put("justDebugged", dojo.config.isDebug, null,
- dojox.off.STORAGE_NAMESPACE);
- callback(false, []);
- }
- });
- },
-
- _getVersionInfo: function(callback){
- var justDebugged = dojox.storage.get("justDebugged",
- dojox.off.STORAGE_NAMESPACE);
- var oldVersion = dojox.storage.get("oldVersion",
- dojox.off.STORAGE_NAMESPACE);
- var newVersion = null;
-
- callback = dojo.hitch(this, callback);
-
- dojo.xhrGet({
- url: this.versionURL + "?browserbust=" + new Date().getTime(),
- timeout: 5 * 1000,
- handleAs: "javascript",
- error: function(err){
- //console.warn("dojox.off.files._getVersionInfo, err=",err);
- dojox.storage.remove("oldVersion", dojox.off.STORAGE_NAMESPACE);
- dojox.storage.remove("justDebugged", dojox.off.STORAGE_NAMESPACE);
- callback(oldVersion, newVersion, justDebugged);
- },
- load: function(data){
- //console.warn("dojox.off.files._getVersionInfo, load=",data);
-
- // some servers incorrectly return 404's
- // as a real page
- if(data){
- newVersion = data;
- }
-
- callback(oldVersion, newVersion, justDebugged);
- }
- });
- }
-}
-
-}
-
-if(!dojo._hasResource["dojox.off.sync"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off.sync"] = true;
-dojo.provide("dojox.off.sync");
-
-
-
-
-
-// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
-
-// summary:
-// Exposes syncing functionality to offline applications
-dojo.mixin(dojox.off.sync, {
- // isSyncing: boolean
- // Whether we are in the middle of a syncing session.
- isSyncing: false,
-
- // cancelled: boolean
- // Whether we were cancelled during our last sync request or not. If
- // we are cancelled, then successful will be false.
- cancelled: false,
-
- // successful: boolean
- // Whether the last sync was successful or not. If false, an error
- // occurred.
- successful: true,
-
- // details: String[]
- // Details on the sync. If the sync was successful, this will carry
- // any conflict or merging messages that might be available; if the
- // sync was unsuccessful, this will have an error message. For both
- // of these, this should be an array of Strings, where each string
- // carries details on the sync.
- // Example:
- // dojox.off.sync.details = ["The document 'foobar' had conflicts - yours one",
- // "The document 'hello world' was automatically merged"];
- details: [],
-
- // error: boolean
- // Whether an error occurred during the syncing process.
- error: false,
-
- // actions: dojox.off.sync.ActionLog
- // Our ActionLog that we store offline actions into for later
- // replaying when we go online
- actions: null,
-
- // autoSync: boolean
- // For advanced usage; most developers can ignore this.
- // Whether we do automatically sync on page load or when we go online.
- // If true we do, if false syncing must be manually initiated.
- // Defaults to true.
- autoSync: true,
-
- // summary:
- // An event handler that is called during the syncing process with
- // the state of syncing. It is important that you connect to this
- // method and respond to certain sync events, especially the
- // "download" event.
- // description:
- // This event handler is called during the syncing process. You can
- // do a dojo.connect to receive sync feedback:
- //
- // dojo.connect(dojox.off.sync, "onSync", someFunc);
- //
- // You will receive one argument, which is the type of the event
- // and which can have the following values.
- //
- // The most common two types that you need to care about are "download"
- // and "finished", especially if you are using the default
- // Dojo Offline UI widget that does the hard work of informing
- // the user through the UI about what is occuring during syncing.
- //
- // If you receive the "download" event, you should make a network call
- // to retrieve and store your data somehow for offline access. The
- // "finished" event indicates that syncing is done. An example:
- //
- // dojo.connect(dojox.off.sync, "onSync", function(type){
- // if(type == "download"){
- // // make a network call to download some data
- // // for use offline
- // dojo.xhrGet({
- // url: "downloadData.php",
- // handleAs: "javascript",
- // error: function(err){
- // dojox.off.sync.finishedDownloading(false, "Can't download data");
- // },
- // load: function(data){
- // // store our data
- // dojox.storage.put("myData", data);
- //
- // // indicate we are finished downloading
- // dojox.off.sync.finishedDownloading(true);
- // }
- // });
- // }else if(type == "finished"){
- // // update UI somehow to indicate we are finished,
- // // such as using the download data to change the
- // // available data
- // }
- // })
- //
- // Here is the full list of event types if you want to do deep
- // customization, such as updating your UI to display the progress
- // of syncing (note that the default Dojo Offline UI widget does
- // this for you if you choose to pull that in). Most of these
- // are only appropriate for advanced usage and can be safely
- // ignored:
- //
- // * "start"
- // syncing has started
- // * "refreshFiles"
- // syncing will begin refreshing
- // our offline file cache
- // * "upload"
- // syncing will begin uploading
- // any local data changes we have on the client.
- // This event is fired before we fire
- // the dojox.off.sync.actions.onReplay event for
- // each action to replay; use it to completely
- // over-ride the replaying behavior and prevent
- // it entirely, perhaps rolling your own sync
- // protocol if needed.
- // * "download"
- // syncing will begin downloading any new data that is
- // needed into persistent storage. Applications are required to
- // implement this themselves, storing the required data into
- // persistent local storage using Dojo Storage.
- // * "finished"
- // syncing is finished; this
- // will be called whether an error ocurred or not; check
- // dojox.off.sync.successful and dojox.off.sync.error for sync details
- // * "cancel"
- // Fired when canceling has been initiated; canceling will be
- // attempted, followed by the sync event "finished".
- onSync: function(/* String */ type){},
-
- synchronize: function(){ /* void */
- // summary: Starts synchronizing
-
- //dojo.debug("synchronize");
- if(this.isSyncing || dojox.off.goingOnline || (!dojox.off.isOnline)){
- return;
- }
-
- this.isSyncing = true;
- this.successful = false;
- this.details = [];
- this.cancelled = false;
-
- this.start();
- },
-
- cancel: function(){ /* void */
- // summary:
- // Attempts to cancel this sync session
-
- if(!this.isSyncing){ return; }
-
- this.cancelled = true;
- if(dojox.off.files.refreshing){
- dojox.off.files.abortRefresh();
- }
-
- this.onSync("cancel");
- },
-
- finishedDownloading: function(successful /* boolean? */,
- errorMessage /* String? */){
- // summary:
- // Applications call this method from their
- // after getting a "download" event in
- // dojox.off.sync.onSync to signal that
- // they are finished downloading any data
- // that should be available offline
- // successful: boolean?
- // Whether our downloading was successful or not.
- // If not present, defaults to true.
- // errorMessage: String?
- // If unsuccessful, a message explaining why
- if(typeof successful == "undefined"){
- successful = true;
- }
-
- if(!successful){
- this.successful = false;
- this.details.push(errorMessage);
- this.error = true;
- }
-
- this.finished();
- },
-
- start: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Called at the start of the syncing process. Advanced
- // developers can over-ride this method to use their
- // own sync mechanism to start syncing.
-
- if(this.cancelled){
- this.finished();
- return;
- }
- this.onSync("start");
- this.refreshFiles();
- },
-
- refreshFiles: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Called when we are going to refresh our list
- // of offline files during syncing. Advanced developers
- // can over-ride this method to do some advanced magic related to
- // refreshing files.
-
- //dojo.debug("refreshFiles");
- if(this.cancelled){
- this.finished();
- return;
- }
-
- this.onSync("refreshFiles");
-
- dojox.off.files.refresh(dojo.hitch(this, function(error, errorMessages){
- if(error){
- this.error = true;
- this.successful = false;
- for(var i = 0; i < errorMessages.length; i++){
- this.details.push(errorMessages[i]);
- }
-
- // even if we get an error while syncing files,
- // keep syncing so we can upload and download
- // data
- }
-
- this.upload();
- }));
- },
-
- upload: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Called when syncing wants to upload data. Advanced
- // developers can over-ride this method to completely
- // throw away the Action Log and replaying system
- // and roll their own advanced sync mechanism if needed.
-
- if(this.cancelled){
- this.finished();
- return;
- }
-
- this.onSync("upload");
-
- // when we are done uploading start downloading
- dojo.connect(this.actions, "onReplayFinished", this, this.download);
-
- // replay the actions log
- this.actions.replay();
- },
-
- download: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Called when syncing wants to download data. Advanced
- // developers can over-ride this method to use their
- // own sync mechanism.
-
- if(this.cancelled){
- this.finished();
- return;
- }
-
- // apps should respond to the "download"
- // event to download their data; when done
- // they must call dojox.off.sync.finishedDownloading()
- this.onSync("download");
- },
-
- finished: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Called when syncing is finished. Advanced
- // developers can over-ride this method to clean
- // up after finishing their own sync
- // mechanism they might have rolled.
- this.isSyncing = false;
-
- this.successful = (!this.cancelled && !this.error);
-
- this.onSync("finished");
- },
-
- _save: function(callback){
- this.actions._save(function(){
- callback();
- });
- },
-
- _load: function(callback){
- this.actions._load(function(){
- callback();
- });
- }
-});
-
-
-// summary:
-// A class that records actions taken by a user when they are offline,
-// suitable for replaying when the network reappears.
-// description:
-// The basic idea behind this method is to record user actions that would
-// normally have to contact a server into an action log when we are
-// offline, so that later when we are online we can simply replay this log
-// in the order user actions happened so that they can be executed against
-// the server, causing synchronization to happen.
-//
-// When we replay, for each of the actions that were added, we call a
-// method named onReplay that applications should connect to and
-// which will be called over and over for each of our actions --
-// applications should take the offline action
-// information and use it to talk to a server to have this action
-// actually happen online, 'syncing' themselves with the server.
-//
-// For example, if the action was "update" with the item that was updated, we
-// might call some RESTian server API that exists for updating an item in
-// our application. The server could either then do sophisticated merging
-// and conflict resolution on the server side, for example, allowing you
-// to pop up a custom merge UI, or could do automatic merging or nothing
-// of the sort. When you are finished with this particular action, your
-// application is then required to call continueReplay() on the actionLog object
-// passed to onReplay() to continue replaying the action log, or haltReplay()
-// with the reason for halting to completely stop the syncing/replaying
-// process.
-//
-// For example, imagine that we have a web application that allows us to add
-// contacts. If we are offline, and we update a contact, we would add an action;
-// imagine that the user has to click an Update button after changing the values
-// for a given contact:
-//
-// dojox.off.whenOffline(dojo.byId("updateButton"), "onclick", function(evt){
-// // get the updated customer values
-// var customer = getCustomerValues();
-//
-// // we are offline -- just record this action
-// var action = {name: "update", customer: customer};
-// dojox.off.sync.actions.add(action)
-//
-// // persist this customer data into local storage as well
-// dojox.storage.put(customer.name, customer);
-// })
-//
-// Then, when we go back online, the dojox.off.sync.actions.onReplay event
-// will fire over and over, once for each action that was recorded while offline:
-//
-// dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){
-// // called once for each action we added while offline, in the order
-// // they were added
-// if(action.name == "update"){
-// var customer = action.customer;
-//
-// // call some network service to update this customer
-// dojo.xhrPost({
-// url: "updateCustomer.php",
-// content: {customer: dojo.toJson(customer)},
-// error: function(err){
-// actionLog.haltReplay(err);
-// },
-// load: function(data){
-// actionLog.continueReplay();
-// }
-// })
-// }
-// })
-//
-// Note that the actions log is always automatically persisted locally while using it, so
-// that if the user closes the browser or it crashes the actions will safely be stored
-// for later replaying.
-dojo.declare("dojox.off.sync.ActionLog", null, {
- // entries: Array
- // An array of our action entries, where each one is simply a custom
- // object literal that were passed to add() when this action entry
- // was added.
- entries: [],
-
- // reasonHalted: String
- // If we halted, the reason why
- reasonHalted: null,
-
- // isReplaying: boolean
- // If true, we are in the middle of replaying a command log; if false,
- // then we are not
- isReplaying: false,
-
- // autoSave: boolean
- // Whether we automatically save the action log after each call to
- // add(); defaults to true. For applications that are rapidly adding
- // many action log entries in a short period of time, it can be
- // useful to set this to false and simply call save() yourself when
- // you are ready to persist your command log -- otherwise performance
- // could be slow as the default action is to attempt to persist the
- // actions log constantly with calls to add().
- autoSave: true,
-
- add: function(action /* Object */){ /* void */
- // summary:
- // Adds an action to our action log
- // description:
- // This method will add an action to our
- // action log, later to be replayed when we
- // go from offline to online. 'action'
- // will be available when this action is
- // replayed and will be passed to onReplay.
- //
- // Example usage:
- //
- // dojox.off.sync.log.add({actionName: "create", itemType: "document",
- // {title: "Message", content: "Hello World"}});
- //
- // The object literal is simply a custom object appropriate
- // for our application -- it can be anything that preserves the state
- // of a user action that will be executed when we go back online
- // and replay this log. In the above example,
- // "create" is the name of this action; "documents" is the
- // type of item this command is operating on, such as documents, contacts,
- // tasks, etc.; and the final argument is the document that was created.
-
- if(this.isReplaying){
- throw "Programming error: you can not call "
- + "dojox.off.sync.actions.add() while "
- + "we are replaying an action log";
- }
-
- this.entries.push(action);
-
- // save our updated state into persistent
- // storage
- if(this.autoSave){
- this._save();
- }
- },
-
- onReplay: function(action /* Object */,
- actionLog /* dojox.off.sync.ActionLog */){ /* void */
- // summary:
- // Called when we replay our log, for each of our action
- // entries.
- // action: Object
- // A custom object literal representing an action for this
- // application, such as
- // {actionName: "create", item: {title: "message", content: "hello world"}}
- // actionLog: dojox.off.sync.ActionLog
- // A reference to the dojox.off.sync.actions log so that developers
- // can easily call actionLog.continueReplay() or actionLog.haltReplay().
- // description:
- // This callback should be connected to by applications so that
- // they can sync themselves when we go back online:
- //
- // dojo.connect(dojox.off.sync.actions, "onReplay", function(action, actionLog){
- // // do something
- // })
- //
- // When we replay our action log, this callback is called for each
- // of our action entries in the order they were added. The
- // 'action' entry that was passed to add() for this action will
- // also be passed in to onReplay, so that applications can use this information
- // to do their syncing, such as contacting a server web-service
- // to create a new item, for example.
- //
- // Inside the method you connected to onReplay, you should either call
- // actionLog.haltReplay(reason) if an error occurred and you would like to halt
- // action replaying or actionLog.continueReplay() to have the action log
- // continue replaying its log and proceed to the next action;
- // the reason you must call these is the action you execute inside of
- // onAction will probably be asynchronous, since it will be talking on
- // the network, and you should call one of these two methods based on
- // the result of your network call.
- },
-
- length: function(){ /* Number */
- // summary:
- // Returns the length of this
- // action log
- return this.entries.length;
- },
-
- haltReplay: function(reason /* String */){ /* void */
- // summary: Halts replaying this command log.
- // reason: String
- // The reason we halted.
- // description:
- // This method is called as we are replaying an action log; it
- // can be called from dojox.off.sync.actions.onReplay, for
- // example, for an application to indicate an error occurred
- // while replaying this action, halting further processing of
- // the action log. Note that any action log entries that
- // were processed before have their effects retained (i.e.
- // they are not rolled back), while the action entry that was
- // halted stays in our list of actions to later be replayed.
- if(!this.isReplaying){
- return;
- }
-
- if(reason){
- this.reasonHalted = reason.toString();
- }
-
- // save the state of our action log, then
- // tell anyone who is interested that we are
- // done when we are finished saving
- if(this.autoSave){
- var self = this;
- this._save(function(){
- self.isReplaying = false;
- self.onReplayFinished();
- });
- }else{
- this.isReplaying = false;
- this.onReplayFinished();
- }
- },
-
- continueReplay: function(){ /* void */
- // summary:
- // Indicates that we should continue processing out list of
- // actions.
- // description:
- // This method is called by applications that have overridden
- // dojox.off.sync.actions.onReplay() to continue replaying our
- // action log after the application has finished handling the
- // current action.
- if(!this.isReplaying){
- return;
- }
-
- // shift off the old action we just ran
- this.entries.shift();
-
- // are we done?
- if(!this.entries.length){
- // save the state of our action log, then
- // tell anyone who is interested that we are
- // done when we are finished saving
- if(this.autoSave){
- var self = this;
- this._save(function(){
- self.isReplaying = false;
- self.onReplayFinished();
- });
- return;
- }else{
- this.isReplaying = false;
- this.onReplayFinished();
- return;
- }
- }
-
- // get the next action
- var nextAction = this.entries[0];
- this.onReplay(nextAction, this);
- },
-
- clear: function(){ /* void */
- // summary:
- // Completely clears this action log of its entries
-
- if(this.isReplaying){
- return;
- }
-
- this.entries = [];
-
- // save our updated state into persistent
- // storage
- if(this.autoSave){
- this._save();
- }
- },
-
- replay: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Replays all of the commands that have been
- // cached in this command log when we go back online;
- // onCommand will be called for each command we have
-
- if(this.isReplaying){
- return;
- }
-
- this.reasonHalted = null;
-
- if(!this.entries.length){
- this.onReplayFinished();
- return;
- }
-
- this.isReplaying = true;
-
- var nextAction = this.entries[0];
- this.onReplay(nextAction, this);
- },
-
- // onReplayFinished: Function
- // For advanced usage; most developers can ignore this.
- // Called when we are finished replaying our commands;
- // called if we have successfully exhausted all of our
- // commands, or if an error occurred during replaying.
- // The default implementation simply continues the
- // synchronization process. Connect to this to register
- // for the event:
- //
- // dojo.connect(dojox.off.sync.actions, "onReplayFinished",
- // someFunc)
- onReplayFinished: function(){
- },
-
- toString: function(){
- var results = "";
- results += "[";
-
- for(var i = 0; i < this.entries.length; i++){
- results += "{";
- for(var j in this.entries[i]){
- results += j + ": \"" + this.entries[i][j] + "\"";
- results += ", ";
- }
- results += "}, ";
- }
-
- results += "]";
-
- return results;
- },
-
- _save: function(callback){
- if(!callback){
- callback = function(){};
- }
-
- try{
- var self = this;
- var resultsHandler = function(status, key, message){
- //console.debug("resultsHandler, status="+status+", key="+key+", message="+message);
- if(status == dojox.storage.FAILED){
- dojox.off.onFrameworkEvent("save",
- {status: dojox.storage.FAILED,
- isCoreSave: true,
- key: key,
- value: message,
- namespace: dojox.off.STORAGE_NAMESPACE});
- callback();
- }else if(status == dojox.storage.SUCCESS){
- callback();
- }
- };
-
- dojox.storage.put("actionlog", this.entries, resultsHandler,
- dojox.off.STORAGE_NAMESPACE);
- }catch(exp){
- console.debug("dojox.off.sync._save: " + exp.message||exp);
- dojox.off.onFrameworkEvent("save",
- {status: dojox.storage.FAILED,
- isCoreSave: true,
- key: "actionlog",
- value: this.entries,
- namespace: dojox.off.STORAGE_NAMESPACE});
- callback();
- }
- },
-
- _load: function(callback){
- var entries = dojox.storage.get("actionlog", dojox.off.STORAGE_NAMESPACE);
-
- if(!entries){
- entries = [];
- }
-
- this.entries = entries;
-
- callback();
- }
- }
-);
-
-dojox.off.sync.actions = new dojox.off.sync.ActionLog();
-
-}
-
-if(!dojo._hasResource["dojox.off._common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off._common"] = true;
-dojo.provide("dojox.off._common");
-
-
-
-
-
-// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
-
-// summary:
-// dojox.off is the main object for offline applications.
-dojo.mixin(dojox.off, {
- // isOnline: boolean
- // true if we are online, false if not
- isOnline: false,
-
- // NET_CHECK: int
- // For advanced usage; most developers can ignore this.
- // Time in seconds on how often we should check the status of the
- // network with an automatic background timer. The current default
- // is 5 seconds.
- NET_CHECK: 5,
-
- // STORAGE_NAMESPACE: String
- // For advanced usage; most developers can ignore this.
- // The namespace we use to save core data into Dojo Storage.
- STORAGE_NAMESPACE: "_dot",
-
- // enabled: boolean
- // For advanced usage; most developers can ignore this.
- // Whether offline ability is enabled or not. Defaults to true.
- enabled: true,
-
- // availabilityURL: String
- // For advanced usage; most developers can ignore this.
- // The URL to check for site availability. We do a GET request on
- // this URL to check for site availability. By default we check for a
- // simple text file in src/off/network_check.txt that has one value
- // it, the value '1'.
- availabilityURL: dojo.moduleUrl("dojox", "off/network_check.txt"),
-
- // goingOnline: boolean
- // For advanced usage; most developers can ignore this.
- // True if we are attempting to go online, false otherwise
- goingOnline: false,
-
- // coreOpFailed: boolean
- // For advanced usage; most developers can ignore this.
- // A flag set by the Dojo Offline framework that indicates that the
- // user denied some operation that required the offline cache or an
- // operation failed in some critical way that was unrecoverable. For
- // example, if the offline cache is Google Gears and we try to get a
- // Gears database, a popup window appears asking the user whether they
- // will approve or deny this request. If the user denies the request,
- // and we are doing some operation that is core to Dojo Offline, then
- // we set this flag to 'true'. This flag causes a 'fail fast'
- // condition, turning off offline ability.
- coreOpFailed: false,
-
- // doNetChecking: boolean
- // For advanced usage; most developers can ignore this.
- // Whether to have a timing interval in the background doing automatic
- // network checks at regular intervals; the length of time between
- // checks is controlled by dojox.off.NET_CHECK. Defaults to true.
- doNetChecking: true,
-
- // hasOfflineCache: boolean
- // For advanced usage; most developers can ignore this.
- // Determines if an offline cache is available or installed; an
- // offline cache is a facility that can truely cache offline
- // resources, such as JavaScript, HTML, etc. in such a way that they
- // won't be removed from the cache inappropriately like a browser
- // cache would. If this is false then an offline cache will be
- // installed. Only Google Gears is currently supported as an offline
- // cache. Future possible offline caches include Firefox 3.
- hasOfflineCache: null,
-
- // browserRestart: boolean
- // For advanced usage; most developers can ignore this.
- // If true, the browser must be restarted to register the existence of
- // a new host added offline (from a call to addHostOffline); if false,
- // then nothing is needed.
- browserRestart: false,
-
- _STORAGE_APP_NAME: window.location.href.replace(/[^0-9A-Za-z_]/g, "_"),
-
- _initializeCalled: false,
- _storageLoaded: false,
- _pageLoaded: false,
-
- onLoad: function(){
- // summary:
- // Called when Dojo Offline can be used.
- // description:
- // Do a dojo.connect to this to know when you can
- // start using Dojo Offline:
- // dojo.connect(dojox.off, "onLoad", myFunc);
- },
-
- onNetwork: function(type){
- // summary:
- // Called when our on- or offline- status changes.
- // description:
- // If we move online, then this method is called with the
- // value "online". If we move offline, then this method is
- // called with the value "offline". You can connect to this
- // method to do add your own behavior:
- //
- // dojo.connect(dojox.off, "onNetwork", someFunc)
- //
- // Note that if you are using the default Dojo Offline UI
- // widget that most of the on- and off-line notification
- // and syncing is automatically handled and provided to the
- // user.
- // type: String
- // Either "online" or "offline".
- },
-
- initialize: function(){ /* void */
- // summary:
- // Called when a Dojo Offline-enabled application is finished
- // configuring Dojo Offline, and is ready for Dojo Offline to
- // initialize itself.
- // description:
- // When an application has finished filling out the variables Dojo
- // Offline needs to work, such as dojox.off.ui.appName, it must
- // this method to tell Dojo Offline to initialize itself.
-
- // Note:
- // This method is needed for a rare edge case. In some conditions,
- // especially if we are dealing with a compressed Dojo build, the
- // entire Dojo Offline subsystem might initialize itself and be
- // running even before the JavaScript for an application has had a
- // chance to run and configure Dojo Offline, causing Dojo Offline
- // to have incorrect initialization parameters for a given app,
- // such as no value for dojox.off.ui.appName. This method is
- // provided to prevent this scenario, to slightly 'slow down' Dojo
- // Offline so it can be configured before running off and doing
- // its thing.
-
- //console.debug("dojox.off.initialize");
- this._initializeCalled = true;
-
- if(this._storageLoaded && this._pageLoaded){
- this._onLoad();
- }
- },
-
- goOffline: function(){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Manually goes offline, away from the network.
- if((dojox.off.sync.isSyncing)||(this.goingOnline)){ return; }
-
- this.goingOnline = false;
- this.isOnline = false;
- },
-
- goOnline: function(callback){ /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Attempts to go online.
- // description:
- // Attempts to go online, making sure this web application's web
- // site is available. 'callback' is called asychronously with the
- // result of whether we were able to go online or not.
- // callback: Function
- // An optional callback function that will receive one argument:
- // whether the site is available or not and is boolean. If this
- // function is not present we call dojo.xoff.onOnline instead if
- // we are able to go online.
-
- //console.debug("goOnline");
-
- if(dojox.off.sync.isSyncing || dojox.off.goingOnline){
- return;
- }
-
- this.goingOnline = true;
- this.isOnline = false;
-
- // see if can reach our web application's web site
- this._isSiteAvailable(callback);
- },
-
- onFrameworkEvent: function(type /* String */, saveData /* Object? */){
- // summary:
- // For advanced usage; most developers can ignore this.
- // A standard event handler that can be attached to to find out
- // about low-level framework events. Most developers will not need to
- // attach to this method; it is meant for low-level information
- // that can be useful for updating offline user-interfaces in
- // exceptional circumstances. The default Dojo Offline UI
- // widget takes care of most of these situations.
- // type: String
- // The type of the event:
- //
- // * "offlineCacheInstalled"
- // An event that is fired when a user
- // has installed an offline cache after the page has been loaded.
- // If a user didn't have an offline cache when the page loaded, a
- // UI of some kind might have prompted them to download one. This
- // method is called if they have downloaded and installed an
- // offline cache so a UI can reinitialize itself to begin using
- // this offline cache.
- // * "coreOperationFailed"
- // Fired when a core operation during interaction with the
- // offline cache is denied by the user. Some offline caches, such
- // as Google Gears, prompts the user to approve or deny caching
- // files, using the database, and more. If the user denies a
- // request that is core to Dojo Offline's operation, we set
- // dojox.off.coreOpFailed to true and call this method for
- // listeners that would like to respond some how to Dojo Offline
- // 'failing fast'.
- // * "save"
- // Called whenever the framework saves data into persistent
- // storage. This could be useful for providing save feedback
- // or providing appropriate error feedback if saving fails
- // due to a user not allowing the save to occur
- // saveData: Object?
- // If the type was 'save', then a saveData object is provided with
- // further save information. This object has the following properties:
- //
- // * status - dojox.storage.SUCCESS, dojox.storage.PENDING, dojox.storage.FAILED
- // Whether the save succeeded, whether it is pending based on a UI
- // dialog asking the user for permission, or whether it failed.
- //
- // * isCoreSave - boolean
- // If true, then this save was for a core piece of data necessary
- // for the functioning of Dojo Offline. If false, then it is a
- // piece of normal data being saved for offline access. Dojo
- // Offline will 'fail fast' if some core piece of data could not
- // be saved, automatically setting dojox.off.coreOpFailed to
- // 'true' and dojox.off.enabled to 'false'.
- //
- // * key - String
- // The key that we are attempting to persist
- //
- // * value - Object
- // The object we are trying to persist
- //
- // * namespace - String
- // The Dojo Storage namespace we are saving this key/value pair
- // into, such as "default", "Documents", "Contacts", etc.
- // Optional.
- if(type == "save"){
- if(saveData.isCoreSave && (saveData.status == dojox.storage.FAILED)){
- dojox.off.coreOpFailed = true;
- dojox.off.enabled = false;
-
- // FIXME: Stop the background network thread
- dojox.off.onFrameworkEvent("coreOperationFailed");
- }
- }else if(type == "coreOperationFailed"){
- dojox.off.coreOpFailed = true;
- dojox.off.enabled = false;
- // FIXME: Stop the background network thread
- }
- },
-
- _checkOfflineCacheAvailable: function(callback){
- // is a true, offline cache running on this machine?
- this.hasOfflineCache = dojo.isGears;
-
- callback();
- },
-
- _onLoad: function(){
- //console.debug("dojox.off._onLoad");
-
- // both local storage and the page are finished loading
-
- // cache the Dojo JavaScript -- just use the default dojo.js
- // name for the most common scenario
- // FIXME: TEST: Make sure syncing doesn't break if dojo.js
- // can't be found, or report an error to developer
- dojox.off.files.cache(dojo.moduleUrl("dojo", "dojo.js"));
-
- // pull in the files needed by Dojo
- this._cacheDojoResources();
-
- // FIXME: need to pull in the firebug lite files here!
- // workaround or else we will get an error on page load
- // from Dojo that it can't find 'console.debug' for optimized builds
- // dojox.off.files.cache(dojo.config.baseRelativePath + "src/debug.js");
-
- // make sure that resources needed by all of our underlying
- // Dojo Storage storage providers will be available
- // offline
- dojox.off.files.cache(dojox.storage.manager.getResourceList());
-
- // slurp the page if the end-developer wants that
- dojox.off.files._slurp();
-
- // see if we have an offline cache; when done, move
- // on to the rest of our startup tasks
- this._checkOfflineCacheAvailable(dojo.hitch(this, "_onOfflineCacheChecked"));
- },
-
- _onOfflineCacheChecked: function(){
- // this method is part of our _onLoad series of startup tasks
-
- // if we have an offline cache, see if we have been added to the
- // list of available offline web apps yet
- if(this.hasOfflineCache && this.enabled){
- // load framework data; when we are finished, continue
- // initializing ourselves
- this._load(dojo.hitch(this, "_finishStartingUp"));
- }else if(this.hasOfflineCache && !this.enabled){
- // we have an offline cache, but it is disabled for some reason
- // perhaps due to the user denying a core operation
- this._finishStartingUp();
- }else{
- this._keepCheckingUntilInstalled();
- }
- },
-
- _keepCheckingUntilInstalled: function(){
- // this method is part of our _onLoad series of startup tasks
-
- // kick off a background interval that keeps
- // checking to see if an offline cache has been
- // installed since this page loaded
-
- // FIXME: Gears: See if we are installed somehow after the
- // page has been loaded
-
- // now continue starting up
- this._finishStartingUp();
- },
-
- _finishStartingUp: function(){
- //console.debug("dojox.off._finishStartingUp");
-
- // this method is part of our _onLoad series of startup tasks
-
- if(!this.hasOfflineCache){
- this.onLoad();
- }else if(this.enabled){
- // kick off a thread to check network status on
- // a regular basis
- this._startNetworkThread();
-
- // try to go online
- this.goOnline(dojo.hitch(this, function(){
- //console.debug("Finished trying to go online");
- // indicate we are ready to be used
- dojox.off.onLoad();
- }));
- }else{ // we are disabled or a core operation failed
- if(this.coreOpFailed){
- this.onFrameworkEvent("coreOperationFailed");
- }else{
- this.onLoad();
- }
- }
- },
-
- _onPageLoad: function(){
- //console.debug("dojox.off._onPageLoad");
- this._pageLoaded = true;
-
- if(this._storageLoaded && this._initializeCalled){
- this._onLoad();
- }
- },
-
- _onStorageLoad: function(){
- //console.debug("dojox.off._onStorageLoad");
- this._storageLoaded = true;
-
- // were we able to initialize storage? if
- // not, then this is a core operation, and
- // let's indicate we will need to fail fast
- if(!dojox.storage.manager.isAvailable()
- && dojox.storage.manager.isInitialized()){
- this.coreOpFailed = true;
- this.enabled = false;
- }
-
- if(this._pageLoaded && this._initializeCalled){
- this._onLoad();
- }
- },
-
- _isSiteAvailable: function(callback){
- // summary:
- // Determines if our web application's website is available.
- // description:
- // This method will asychronously determine if our web
- // application's web site is available, which is a good proxy for
- // network availability. The URL dojox.off.availabilityURL is
- // used, which defaults to this site's domain name (ex:
- // foobar.com). We check for dojox.off.AVAILABILITY_TIMEOUT (in
- // seconds) and abort after that
- // callback: Function
- // An optional callback function that will receive one argument:
- // whether the site is available or not and is boolean. If this
- // function is not present we call dojox.off.onNetwork instead if we
- // are able to go online.
- dojo.xhrGet({
- url: this._getAvailabilityURL(),
- handleAs: "text",
- timeout: this.NET_CHECK * 1000,
- error: dojo.hitch(this, function(err){
- //console.debug("dojox.off._isSiteAvailable.error: " + err);
- this.goingOnline = false;
- this.isOnline = false;
- if(callback){ callback(false); }
- }),
- load: dojo.hitch(this, function(data){
- //console.debug("dojox.off._isSiteAvailable.load, data="+data);
- this.goingOnline = false;
- this.isOnline = true;
-
- if(callback){ callback(true);
- }else{ this.onNetwork("online"); }
- })
- });
- },
-
- _startNetworkThread: function(){
- //console.debug("startNetworkThread");
-
- // kick off a thread that does periodic
- // checks on the status of the network
- if(!this.doNetChecking){
- return;
- }
-
- window.setInterval(dojo.hitch(this, function(){
- var d = dojo.xhrGet({
- url: this._getAvailabilityURL(),
- handleAs: "text",
- timeout: this.NET_CHECK * 1000,
- error: dojo.hitch(this,
- function(err){
- if(this.isOnline){
- this.isOnline = false;
-
- // FIXME: xhrGet() is not
- // correctly calling abort
- // on the XHR object when
- // it times out; fix inside
- // there instead of externally
- // here
- try{
- if(typeof d.ioArgs.xhr.abort == "function"){
- d.ioArgs.xhr.abort();
- }
- }catch(e){}
-
- // if things fell in the middle of syncing,
- // stop syncing
- dojox.off.sync.isSyncing = false;
-
- this.onNetwork("offline");
- }
- }
- ),
- load: dojo.hitch(this,
- function(data){
- if(!this.isOnline){
- this.isOnline = true;
- this.onNetwork("online");
- }
- }
- )
- });
-
- }), this.NET_CHECK * 1000);
- },
-
- _getAvailabilityURL: function(){
- var url = this.availabilityURL.toString();
-
- // bust the browser's cache to make sure we are really talking to
- // the server
- if(url.indexOf("?") == -1){
- url += "?";
- }else{
- url += "&";
- }
- url += "browserbust=" + new Date().getTime();
-
- return url;
- },
-
- _onOfflineCacheInstalled: function(){
- this.onFrameworkEvent("offlineCacheInstalled");
- },
-
- _cacheDojoResources: function(){
- // if we are a non-optimized build, then the core Dojo bootstrap
- // system was loaded as separate JavaScript files;
- // add these to our offline cache list. these are
- // loaded before the dojo.require() system exists
-
- // FIXME: create a better mechanism in the Dojo core to
- // expose whether you are dealing with an optimized build;
- // right now we just scan the SCRIPT tags attached to this
- // page and see if there is one for _base/_loader/bootstrap.js
- var isOptimizedBuild = true;
- dojo.forEach(dojo.query("script"), function(i){
- var src = i.getAttribute("src");
- if(!src){ return; }
-
- if(src.indexOf("_base/_loader/bootstrap.js") != -1){
- isOptimizedBuild = false;
- }
- });
-
- if(!isOptimizedBuild){
- dojox.off.files.cache(dojo.moduleUrl("dojo", "_base.js").uri);
- dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/loader.js").uri);
- dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/bootstrap.js").uri);
-
- // FIXME: pull in the host environment file in a more generic way
- // for other host environments
- dojox.off.files.cache(dojo.moduleUrl("dojo", "_base/_loader/hostenv_browser.js").uri);
- }
-
- // add anything that was brought in with a
- // dojo.require() that resulted in a JavaScript
- // URL being fetched
-
- // FIXME: modify dojo/_base/_loader/loader.js to
- // expose a public API to get this information
-
- for(var i = 0; i < dojo._loadedUrls.length; i++){
- dojox.off.files.cache(dojo._loadedUrls[i]);
- }
-
- // FIXME: add the standard Dojo CSS file
- },
-
- _save: function(){
- // summary:
- // Causes the Dojo Offline framework to save its configuration
- // data into local storage.
- },
-
- _load: function(callback){
- // summary:
- // Causes the Dojo Offline framework to load its configuration
- // data from local storage
- dojox.off.sync._load(callback);
- }
-});
-
-
-// wait until the storage system is finished loading
-dojox.storage.manager.addOnLoad(dojo.hitch(dojox.off, "_onStorageLoad"));
-
-// wait until the page is finished loading
-dojo.addOnLoad(dojox.off, "_onPageLoad");
-
-}
-
-if(!dojo._hasResource["dojox.off"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off"] = true;
-dojo.provide("dojox.off");
-
-
-}
-
-if(!dojo._hasResource["dojox.off.ui"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off.ui"] = true;
-dojo.provide("dojox.off.ui");
-
-
-
-
-
-// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
-
-// summary:
-// dojox.off.ui provides a standard,
-// default user-interface for a
-// Dojo Offline Widget that can easily
-// be dropped into applications that would
-// like to work offline.
-dojo.mixin(dojox.off.ui, {
- // appName: String
- // This application's name, such as "Foobar". Note that
- // this is a string, not HTML, so embedded markup will
- // not work, including entities. Only the following
- // characters are allowed: numbers, letters, and spaces.
- // You must set this property.
- appName: "setme",
-
- // autoEmbed: boolean
- // For advanced usage; most developers can ignore this.
- // Whether to automatically auto-embed the default Dojo Offline
- // widget into this page; default is true.
- autoEmbed: true,
-
- // autoEmbedID: String
- // For advanced usage; most developers can ignore this.
- // The ID of the DOM element that will contain our
- // Dojo Offline widget; defaults to the ID 'dot-widget'.
- autoEmbedID: "dot-widget",
-
- // runLink: String
- // For advanced usage; most developers can ignore this.
- // The URL that should be navigated to to run this
- // application offline; this will be placed inside of a
- // link that the user can drag to their desktop and double
- // click. Note that this URL must exactly match the URL
- // of the main page of our resource that is offline for
- // it to be retrieved from the offline cache correctly.
- // For example, if you have cached your main page as
- // http://foobar.com/index.html, and you set this to
- // http://www.foobar.com/index.html, the run link will
- // not work. By default this value is automatically set to
- // the URL of this page, so it does not need to be set
- // manually unless you have unusual needs.
- runLink: window.location.href,
-
- // runLinkTitle: String
- // For advanced usage; most developers can ignore this.
- // The text that will be inside of the link that a user
- // can drag to their desktop to run this application offline.
- // By default this is automatically set to "Run " plus your
- // application's name.
- runLinkTitle: "Run Application",
-
- // learnHowPath: String
- // For advanced usage; most developers can ignore this.
- // The path to a web page that has information on
- // how to use this web app offline; defaults to
- // src/off/ui-template/learnhow.html, relative to
- // your Dojo installation. Make sure to set
- // dojo.to.ui.customLearnHowPath to true if you want
- // a custom Learn How page.
- learnHowPath: dojo.moduleUrl("dojox", "off/resources/learnhow.html"),
-
- // customLearnHowPath: boolean
- // For advanced usage; most developers can ignore this.
- // Whether the developer is using their own custom page
- // for the Learn How instructional page; defaults to false.
- // Use in conjunction with dojox.off.ui.learnHowPath.
- customLearnHowPath: false,
-
- htmlTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.html").uri,
- cssTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.css").uri,
- onlineImagePath: dojo.moduleUrl("dojox", "off/resources/greenball.png").uri,
- offlineImagePath: dojo.moduleUrl("dojox", "off/resources/redball.png").uri,
- rollerImagePath: dojo.moduleUrl("dojox", "off/resources/roller.gif").uri,
- checkmarkImagePath: dojo.moduleUrl("dojox", "off/resources/checkmark.png").uri,
- learnHowJSPath: dojo.moduleUrl("dojox", "off/resources/learnhow.js").uri,
-
- _initialized: false,
-
- onLoad: function(){
- // summary:
- // A function that should be connected to allow your
- // application to know when Dojo Offline, the page, and
- // the Offline Widget are all initialized and ready to be
- // used:
- //
- // dojo.connect(dojox.off.ui, "onLoad", someFunc)
- },
-
- _initialize: function(){
- //console.debug("dojox.off.ui._initialize");
-
- // make sure our app name is correct
- if(this._validateAppName(this.appName) == false){
- alert("You must set dojox.off.ui.appName; it can only contain "
- + "letters, numbers, and spaces; right now it "
- + "is incorrectly set to '" + dojox.off.ui.appName + "'");
- dojox.off.enabled = false;
- return;
- }
-
- // set our run link text to its default
- this.runLinkText = "Run " + this.appName;
-
- // setup our event listeners for Dojo Offline events
- // to update our UI
- dojo.connect(dojox.off, "onNetwork", this, "_onNetwork");
- dojo.connect(dojox.off.sync, "onSync", this, "_onSync");
-
- // cache our default UI resources
- dojox.off.files.cache([
- this.htmlTemplatePath,
- this.cssTemplatePath,
- this.onlineImagePath,
- this.offlineImagePath,
- this.rollerImagePath,
- this.checkmarkImagePath
- ]);
-
- // embed the offline widget UI
- if(this.autoEmbed){
- this._doAutoEmbed();
- }
- },
-
- _doAutoEmbed: function(){
- // fetch our HTML for the offline widget
-
- // dispatch the request
- dojo.xhrGet({
- url: this.htmlTemplatePath,
- handleAs: "text",
- error: function(err){
- dojox.off.enabled = false;
- err = err.message||err;
- alert("Error loading the Dojo Offline Widget from "
- + this.htmlTemplatePath + ": " + err);
- },
- load: dojo.hitch(this, this._templateLoaded)
- });
- },
-
- _templateLoaded: function(data){
- //console.debug("dojox.off.ui._templateLoaded");
- // inline our HTML
- var container = dojo.byId(this.autoEmbedID);
- if(container){ container.innerHTML = data; }
-
- // fill out our image paths
- this._initImages();
-
- // update our network indicator status ball
- this._updateNetIndicator();
-
- // update our 'Learn How' text
- this._initLearnHow();
-
- this._initialized = true;
-
- // check offline cache settings
- if(!dojox.off.hasOfflineCache){
- this._showNeedsOfflineCache();
- return;
- }
-
- // check to see if we need a browser restart
- // to be able to use this web app offline
- if(dojox.off.hasOfflineCache && dojox.off.browserRestart){
- this._needsBrowserRestart();
- return;
- }else{
- var browserRestart = dojo.byId("dot-widget-browser-restart");
- if(browserRestart){ browserRestart.style.display = "none"; }
- }
-
- // update our sync UI
- this._updateSyncUI();
-
- // register our event listeners for our main buttons
- this._initMainEvtHandlers();
-
- // if offline functionality is disabled, disable everything
- this._setOfflineEnabled(dojox.off.enabled);
-
- // update our UI based on the state of the network
- this._onNetwork(dojox.off.isOnline ? "online" : "offline");
-
- // try to go online
- this._testNet();
- },
-
- _testNet: function(){
- dojox.off.goOnline(dojo.hitch(this, function(isOnline){
- //console.debug("testNet callback, isOnline="+isOnline);
-
- // display our online/offline results
- this._onNetwork(isOnline ? "online" : "offline");
-
- // indicate that our default UI
- // and Dojo Offline are now ready to
- // be used
- this.onLoad();
- }));
- },
-
- _updateNetIndicator: function(){
- var onlineImg = dojo.byId("dot-widget-network-indicator-online");
- var offlineImg = dojo.byId("dot-widget-network-indicator-offline");
- var titleText = dojo.byId("dot-widget-title-text");
-
- if(onlineImg && offlineImg){
- if(dojox.off.isOnline == true){
- onlineImg.style.display = "inline";
- offlineImg.style.display = "none";
- }else{
- onlineImg.style.display = "none";
- offlineImg.style.display = "inline";
- }
- }
-
- if(titleText){
- if(dojox.off.isOnline){
- titleText.innerHTML = "Online";
- }else{
- titleText.innerHTML = "Offline";
- }
- }
- },
-
- _initLearnHow: function(){
- var learnHow = dojo.byId("dot-widget-learn-how-link");
-
- if(!learnHow){ return; }
-
- if(!this.customLearnHowPath){
- // add parameters to URL so the Learn How page
- // can customize itself and display itself
- // correctly based on framework settings
- var dojoPath = dojo.config.baseRelativePath;
- this.learnHowPath += "?appName=" + encodeURIComponent(this.appName)
- + "&hasOfflineCache=" + dojox.off.hasOfflineCache
- + "&runLink=" + encodeURIComponent(this.runLink)
- + "&runLinkText=" + encodeURIComponent(this.runLinkText)
- + "&baseRelativePath=" + encodeURIComponent(dojoPath);
-
- // cache our Learn How JavaScript page and
- // the HTML version with full query parameters
- // so it is available offline without a cache miss
- dojox.off.files.cache(this.learnHowJSPath);
- dojox.off.files.cache(this.learnHowPath);
- }
-
- learnHow.setAttribute("href", this.learnHowPath);
-
- var appName = dojo.byId("dot-widget-learn-how-app-name");
-
- if(!appName){ return; }
-
- appName.innerHTML = "";
- appName.appendChild(document.createTextNode(this.appName));
- },
-
- _validateAppName: function(appName){
- if(!appName){ return false; }
-
- return (/^[a-z0-9 ]*$/i.test(appName));
- },
-
- _updateSyncUI: function(){
- var roller = dojo.byId("dot-roller");
- var checkmark = dojo.byId("dot-success-checkmark");
- var syncMessages = dojo.byId("dot-sync-messages");
- var details = dojo.byId("dot-sync-details");
- var cancel = dojo.byId("dot-sync-cancel");
-
- if(dojox.off.sync.isSyncing){
- this._clearSyncMessage();
-
- if(roller){ roller.style.display = "inline"; }
-
- if(checkmark){ checkmark.style.display = "none"; }
-
- if(syncMessages){
- dojo.removeClass(syncMessages, "dot-sync-error");
- }
-
- if(details){ details.style.display = "none"; }
-
- if(cancel){ cancel.style.display = "inline"; }
- }else{
- if(roller){ roller.style.display = "none"; }
-
- if(cancel){ cancel.style.display = "none"; }
-
- if(syncMessages){
- dojo.removeClass(syncMessages, "dot-sync-error");
- }
- }
- },
-
- _setSyncMessage: function(message){
- var syncMessage = dojo.byId("dot-sync-messages");
- if(syncMessage){
- // when used with Google Gears pre-release in Firefox/Mac OS X,
- // the browser would crash when testing in Moxie
- // if we set the message this way for some reason.
- // Brad Neuberg, bkn3@columbia.edu
- //syncMessage.innerHTML = message;
-
- while(syncMessage.firstChild){
- syncMessage.removeChild(syncMessage.firstChild);
- }
- syncMessage.appendChild(document.createTextNode(message));
- }
- },
-
- _clearSyncMessage: function(){
- this._setSyncMessage("");
- },
-
- _initImages: function(){
- var onlineImg = dojo.byId("dot-widget-network-indicator-online");
- if(onlineImg){
- onlineImg.setAttribute("src", this.onlineImagePath);
- }
-
- var offlineImg = dojo.byId("dot-widget-network-indicator-offline");
- if(offlineImg){
- offlineImg.setAttribute("src", this.offlineImagePath);
- }
-
- var roller = dojo.byId("dot-roller");
- if(roller){
- roller.setAttribute("src", this.rollerImagePath);
- }
-
- var checkmark = dojo.byId("dot-success-checkmark");
- if(checkmark){
- checkmark.setAttribute("src", this.checkmarkImagePath);
- }
- },
-
- _showDetails: function(evt){
- // cancel the button's default behavior
- evt.preventDefault();
- evt.stopPropagation();
-
- if(!dojox.off.sync.details.length){
- return;
- }
-
- // determine our HTML message to display
- var html = "";
- html += "<html><head><title>Sync Details</title><head><body>";
- html += "<h1>Sync Details</h1>\n";
- html += "<ul>\n";
- for(var i = 0; i < dojox.off.sync.details.length; i++){
- html += "<li>";
- html += dojox.off.sync.details[i];
- html += "</li>";
- }
- html += "</ul>\n";
- html += "<a href='javascript:window.close()' "
- + "style='text-align: right; padding-right: 2em;'>"
- + "Close Window"
- + "</a>\n";
- html += "</body></html>";
-
- // open a popup window with this message
- var windowParams = "height=400,width=600,resizable=true,"
- + "scrollbars=true,toolbar=no,menubar=no,"
- + "location=no,directories=no,dependent=yes";
-
- var popup = window.open("", "SyncDetails", windowParams);
-
- if(!popup){ // aggressive popup blocker
- alert("Please allow popup windows for this domain; can't display sync details window");
- return;
- }
-
- popup.document.open();
- popup.document.write(html);
- popup.document.close();
-
- // put the focus on the popup window
- if(popup.focus){
- popup.focus();
- }
- },
-
- _cancel: function(evt){
- // cancel the button's default behavior
- evt.preventDefault();
- evt.stopPropagation();
-
- dojox.off.sync.cancel();
- },
-
- _needsBrowserRestart: function(){
- var browserRestart = dojo.byId("dot-widget-browser-restart");
- if(browserRestart){
- dojo.addClass(browserRestart, "dot-needs-browser-restart");
- }
-
- var appName = dojo.byId("dot-widget-browser-restart-app-name");
- if(appName){
- appName.innerHTML = "";
- appName.appendChild(document.createTextNode(this.appName));
- }
-
- var status = dojo.byId("dot-sync-status");
- if(status){
- status.style.display = "none";
- }
- },
-
- _showNeedsOfflineCache: function(){
- var widgetContainer = dojo.byId("dot-widget-container");
- if(widgetContainer){
- dojo.addClass(widgetContainer, "dot-needs-offline-cache");
- }
- },
-
- _hideNeedsOfflineCache: function(){
- var widgetContainer = dojo.byId("dot-widget-container");
- if(widgetContainer){
- dojo.removeClass(widgetContainer, "dot-needs-offline-cache");
- }
- },
-
- _initMainEvtHandlers: function(){
- var detailsButton = dojo.byId("dot-sync-details-button");
- if(detailsButton){
- dojo.connect(detailsButton, "onclick", this, this._showDetails);
- }
- var cancelButton = dojo.byId("dot-sync-cancel-button");
- if(cancelButton){
- dojo.connect(cancelButton, "onclick", this, this._cancel);
- }
- },
-
- _setOfflineEnabled: function(enabled){
- var elems = [];
- elems.push(dojo.byId("dot-sync-status"));
-
- for(var i = 0; i < elems.length; i++){
- if(elems[i]){
- elems[i].style.visibility =
- (enabled ? "visible" : "hidden");
- }
- }
- },
-
- _syncFinished: function(){
- this._updateSyncUI();
-
- var checkmark = dojo.byId("dot-success-checkmark");
- var details = dojo.byId("dot-sync-details");
-
- if(dojox.off.sync.successful == true){
- this._setSyncMessage("Sync Successful");
- if(checkmark){ checkmark.style.display = "inline"; }
- }else if(dojox.off.sync.cancelled == true){
- this._setSyncMessage("Sync Cancelled");
-
- if(checkmark){ checkmark.style.display = "none"; }
- }else{
- this._setSyncMessage("Sync Error");
-
- var messages = dojo.byId("dot-sync-messages");
- if(messages){
- dojo.addClass(messages, "dot-sync-error");
- }
-
- if(checkmark){ checkmark.style.display = "none"; }
- }
-
- if(dojox.off.sync.details.length && details){
- details.style.display = "inline";
- }
- },
-
- _onFrameworkEvent: function(type, saveData){
- if(type == "save"){
- if(saveData.status == dojox.storage.FAILED && !saveData.isCoreSave){
- alert("Please increase the amount of local storage available "
- + "to this application");
- if(dojox.storage.hasSettingsUI()){
- dojox.storage.showSettingsUI();
- }
-
- // FIXME: Be able to know if storage size has changed
- // due to user configuration
- }
- }else if(type == "coreOperationFailed"){
- console.log("Application does not have permission to use Dojo Offline");
-
- if(!this._userInformed){
- alert("This application will not work if Google Gears is not allowed to run");
- this._userInformed = true;
- }
- }else if(type == "offlineCacheInstalled"){
- // clear out the 'needs offline cache' info
- this._hideNeedsOfflineCache();
-
- // check to see if we need a browser restart
- // to be able to use this web app offline
- if(dojox.off.hasOfflineCache == true
- && dojox.off.browserRestart == true){
- this._needsBrowserRestart();
- return;
- }else{
- var browserRestart = dojo.byId("dot-widget-browser-restart");
- if(browserRestart){
- browserRestart.style.display = "none";
- }
- }
-
- // update our sync UI
- this._updateSyncUI();
-
- // register our event listeners for our main buttons
- this._initMainEvtHandlers();
-
- // if offline is disabled, disable everything
- this._setOfflineEnabled(dojox.off.enabled);
-
- // try to go online
- this._testNet();
- }
- },
-
- _onSync: function(type){
- //console.debug("ui, onSync="+type);
- switch(type){
- case "start":
- this._updateSyncUI();
- break;
-
- case "refreshFiles":
- this._setSyncMessage("Downloading UI...");
- break;
-
- case "upload":
- this._setSyncMessage("Uploading new data...");
- break;
-
- case "download":
- this._setSyncMessage("Downloading new data...");
- break;
-
- case "finished":
- this._syncFinished();
- break;
-
- case "cancel":
- this._setSyncMessage("Canceling Sync...");
- break;
-
- default:
- dojo.warn("Programming error: "
- + "Unknown sync type in dojox.off.ui: " + type);
- break;
- }
- },
-
- _onNetwork: function(type){
- // summary:
- // Called when we go on- or off-line
- // description:
- // When we go online or offline, this method is called to update
- // our UI. Default behavior is to update the Offline
- // Widget UI and to attempt a synchronization.
- // type: String
- // "online" if we just moved online, and "offline" if we just
- // moved offline.
-
- if(!this._initialized){ return; }
-
- // update UI
- this._updateNetIndicator();
-
- if(type == "offline"){
- this._setSyncMessage("You are working offline");
-
- // clear old details
- var details = dojo.byId("dot-sync-details");
- if(details){ details.style.display = "none"; }
-
- // if we fell offline during a sync, hide
- // the sync info
- this._updateSyncUI();
- }else{ // online
- // synchronize, but pause for a few seconds
- // so that the user can orient themselves
- if(dojox.off.sync.autoSync){
- if(dojo.isAIR){
- window.setTimeout(function(){dojox.off.sync.synchronize();}, 1000);
- }else{
- window.setTimeout(dojox._scopeName + ".off.sync.synchronize()", 1000);
- }
- }
- }
- }
-});
-
-// register ourselves for low-level framework events
-dojo.connect(dojox.off, "onFrameworkEvent", dojox.off.ui, "_onFrameworkEvent");
-
-// start our magic when the Dojo Offline framework is ready to go
-dojo.connect(dojox.off, "onLoad", dojox.off.ui, dojox.off.ui._initialize);
-
-}
-
-if(!dojo._hasResource["dojox.off.offline"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojox.off.offline"] = true;
-dojo.provide("dojox.off.offline");
-
-
-
-
-
-
-
-}
-