diff options
Diffstat (limited to 'includes/js/dojox/off/offline.js.uncompressed.js')
-rw-r--r-- | includes/js/dojox/off/offline.js.uncompressed.js | 5910 |
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, "&$1;"); - - // entity encode XML-ish characters, or Flash's broken XML serializer - // breaks - data = data.replace(/</g, "<"); - data = data.replace(/>/g, ">"); - - // 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, """); - - 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"); - - - - - - - -} - |