Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / state / Provider.js
index 9bca5e4..81536fb 100644 (file)
@@ -1,33 +1,61 @@
-/*!
- * Ext JS Library 3.1.0
- * Copyright(c) 2006-2009 Ext JS, LLC
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @class Ext.state.Provider
- * Abstract base class for state provider implementations. This class provides methods
- * for encoding and decoding <b>typed</b> variables including dates and defines the
- * Provider interface.
+ * <p>Abstract base class for state provider implementations. The provider is responsible
+ * for setting values  and extracting values to/from the underlying storage source. The 
+ * storage source can vary and the details should be implemented in a subclass. For example
+ * a provider could use a server side database or the browser localstorage where supported.</p>
+ *
+ * <p>This class provides methods for encoding and decoding <b>typed</b> variables including 
+ * dates and defines the Provider interface. By default these methods put the value and the
+ * type information into a delimited string that can be stored. These should be overridden in 
+ * a subclass if you want to change the format of the encoded value and subsequent decoding.</p>
  */
-Ext.state.Provider = function(){
+Ext.define('Ext.state.Provider', {
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
+    
     /**
-     * @event statechange
-     * Fires when a state change occurs.
-     * @param {Provider} this This state provider
-     * @param {String} key The state key which was changed
-     * @param {String} value The encoded value for the state
+     * @cfg {String} prefix A string to prefix to items stored in the underlying state store. 
+     * Defaults to <tt>'ext-'</tt>
      */
-    this.addEvents("statechange");
-    this.state = {};
-    Ext.state.Provider.superclass.constructor.call(this);
-};
-Ext.extend(Ext.state.Provider, Ext.util.Observable, {
+    prefix: 'ext-',
+    
+    constructor : function(config){
+        config = config || {};
+        var me = this;
+        Ext.apply(me, config);
+        /**
+         * @event statechange
+         * Fires when a state change occurs.
+         * @param {Ext.state.Provider} this This state provider
+         * @param {String} key The state key which was changed
+         * @param {String} value The encoded value for the state
+         */
+        me.addEvents("statechange");
+        me.state = {};
+        me.mixins.observable.constructor.call(me);
+    },
+    
     /**
      * Returns the current value for a key
      * @param {String} name The key name
-     * @param {Mixed} defaultValue A default value to return if the key's value is not found
-     * @return {Mixed} The state data
+     * @param {Object} defaultValue A default value to return if the key's value is not found
+     * @return {Object} The state data
      */
     get : function(name, defaultValue){
         return typeof this.state[name] == "undefined" ?
@@ -39,90 +67,119 @@ Ext.extend(Ext.state.Provider, Ext.util.Observable, {
      * @param {String} name The key name
      */
     clear : function(name){
-        delete this.state[name];
-        this.fireEvent("statechange", this, name, null);
+        var me = this;
+        delete me.state[name];
+        me.fireEvent("statechange", me, name, null);
     },
 
     /**
      * Sets the value for a key
      * @param {String} name The key name
-     * @param {Mixed} value The value to set
+     * @param {Object} value The value to set
      */
     set : function(name, value){
-        this.state[name] = value;
-        this.fireEvent("statechange", this, name, value);
+        var me = this;
+        me.state[name] = value;
+        me.fireEvent("statechange", me, name, value);
     },
 
     /**
      * Decodes a string previously encoded with {@link #encodeValue}.
      * @param {String} value The value to decode
-     * @return {Mixed} The decoded value
+     * @return {Object} The decoded value
      */
-    decodeValue : function(cookie){
-        var re = /^(a|n|d|b|s|o)\:(.*)$/;
-        var matches = re.exec(unescape(cookie));
-        if(!matches || !matches[1]) return; // non state cookie
-        var type = matches[1];
-        var v = matches[2];
-        switch(type){
-            case "n":
-                return parseFloat(v);
-            case "d":
-                return new Date(Date.parse(v));
-            case "b":
-                return (v == "1");
-            case "a":
-                var all = [];
-                if(v != ''){
-                    Ext.each(v.split('^'), function(val){
-                        all.push(this.decodeValue(val));
-                    }, this);
+    decodeValue : function(value){
+
+        // a -> Array
+        // n -> Number
+        // d -> Date
+        // b -> Boolean
+        // s -> String
+        // o -> Object
+        // -> Empty (null)
+
+        var me = this,
+            re = /^(a|n|d|b|s|o|e)\:(.*)$/,
+            matches = re.exec(unescape(value)),
+            all,
+            type,
+            value,
+            keyValue;
+            
+        if(!matches || !matches[1]){
+            return; // non state
+        }
+        
+        type = matches[1];
+        value = matches[2];
+        switch (type) {
+            case 'e':
+                return null;
+            case 'n':
+                return parseFloat(value);
+            case 'd':
+                return new Date(Date.parse(value));
+            case 'b':
+                return (value == '1');
+            case 'a':
+                all = [];
+                if(value != ''){
+                    Ext.each(value.split('^'), function(val){
+                        all.push(me.decodeValue(val));
+                    }, me);
                 }
                 return all;
-           case "o":
-                var all = {};
-                if(v != ''){
-                    Ext.each(v.split('^'), function(val){
-                        var kv = val.split('=');
-                        all[kv[0]] = this.decodeValue(kv[1]);
-                    }, this);
+           case 'o':
+                all = {};
+                if(value != ''){
+                    Ext.each(value.split('^'), function(val){
+                        keyValue = val.split('=');
+                        all[keyValue[0]] = me.decodeValue(keyValue[1]);
+                    }, me);
                 }
                 return all;
            default:
-                return v;
+                return value;
         }
     },
 
     /**
      * Encodes a value including type information.  Decode with {@link #decodeValue}.
-     * @param {Mixed} value The value to encode
+     * @param {Object} value The value to encode
      * @return {String} The encoded value
      */
-    encodeValue : function(v){
-        var enc;
-        if(typeof v == "number"){
-            enc = "n:" + v;
-        }else if(typeof v == "boolean"){
-            enc = "b:" + (v ? "1" : "0");
-        }else if(Ext.isDate(v)){
-            enc = "d:" + v.toGMTString();
-        }else if(Ext.isArray(v)){
-            var flat = "";
-            for(var i = 0, len = v.length; i < len; i++){
-                flat += this.encodeValue(v[i]);
-                if(i != len-1) flat += "^";
+    encodeValue : function(value){
+        var flat = '',
+            i = 0,
+            enc,
+            len,
+            key;
+            
+        if (value == null) {
+            return 'e:1';    
+        } else if(typeof value == 'number') {
+            enc = 'n:' + value;
+        } else if(typeof value == 'boolean') {
+            enc = 'b:' + (value ? '1' : '0');
+        } else if(Ext.isDate(value)) {
+            enc = 'd:' + value.toGMTString();
+        } else if(Ext.isArray(value)) {
+            for (len = value.length; i < len; i++) {
+                flat += this.encodeValue(value[i]);
+                if (i != len - 1) {
+                    flat += '^';
+                }
             }
-            enc = "a:" + flat;
-        }else if(typeof v == "object"){
-            var flat = "";
-            for(var key in v){
-                if(typeof v[key] != "function" && v[key] !== undefined){
-                    flat += key + "=" + this.encodeValue(v[key]) + "^";
+            enc = 'a:' + flat;
+        } else if (typeof value == 'object') {
+            for (key in value) {
+                if (typeof value[key] != 'function' && value[key] !== undefined) {
+                    flat += key + '=' + this.encodeValue(value[key]) + '^';
                 }
             }
-            enc = "o:" + flat.substring(0, flat.length-1);
-        }else{
-            enc = "s:" + v;
+            enc = 'o:' + flat.substring(0, flat.length-1);
+        } else {
+            enc = 's:' + value;
         }
         return escape(enc);
     }