[76] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.4.0 |
---|
| 3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
| 4 | * licensing@sencha.com |
---|
| 5 | * http://www.sencha.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Ext.state.Provider |
---|
| 9 | * Abstract base class for state provider implementations. This class provides methods |
---|
| 10 | * for encoding and decoding <b>typed</b> variables including dates and defines the |
---|
| 11 | * Provider interface. |
---|
| 12 | */ |
---|
| 13 | Ext.state.Provider = Ext.extend(Ext.util.Observable, { |
---|
| 14 | |
---|
| 15 | constructor : function(){ |
---|
| 16 | /** |
---|
| 17 | * @event statechange |
---|
| 18 | * Fires when a state change occurs. |
---|
| 19 | * @param {Provider} this This state provider |
---|
| 20 | * @param {String} key The state key which was changed |
---|
| 21 | * @param {String} value The encoded value for the state |
---|
| 22 | */ |
---|
| 23 | this.addEvents("statechange"); |
---|
| 24 | this.state = {}; |
---|
| 25 | Ext.state.Provider.superclass.constructor.call(this); |
---|
| 26 | }, |
---|
| 27 | |
---|
| 28 | /** |
---|
| 29 | * Returns the current value for a key |
---|
| 30 | * @param {String} name The key name |
---|
| 31 | * @param {Mixed} defaultValue A default value to return if the key's value is not found |
---|
| 32 | * @return {Mixed} The state data |
---|
| 33 | */ |
---|
| 34 | get : function(name, defaultValue){ |
---|
| 35 | return typeof this.state[name] == "undefined" ? |
---|
| 36 | defaultValue : this.state[name]; |
---|
| 37 | }, |
---|
| 38 | |
---|
| 39 | /** |
---|
| 40 | * Clears a value from the state |
---|
| 41 | * @param {String} name The key name |
---|
| 42 | */ |
---|
| 43 | clear : function(name){ |
---|
| 44 | delete this.state[name]; |
---|
| 45 | this.fireEvent("statechange", this, name, null); |
---|
| 46 | }, |
---|
| 47 | |
---|
| 48 | /** |
---|
| 49 | * Sets the value for a key |
---|
| 50 | * @param {String} name The key name |
---|
| 51 | * @param {Mixed} value The value to set |
---|
| 52 | */ |
---|
| 53 | set : function(name, value){ |
---|
| 54 | this.state[name] = value; |
---|
| 55 | this.fireEvent("statechange", this, name, value); |
---|
| 56 | }, |
---|
| 57 | |
---|
| 58 | /** |
---|
| 59 | * Decodes a string previously encoded with {@link #encodeValue}. |
---|
| 60 | * @param {String} value The value to decode |
---|
| 61 | * @return {Mixed} The decoded value |
---|
| 62 | */ |
---|
| 63 | decodeValue : function(cookie){ |
---|
| 64 | /** |
---|
| 65 | * a -> Array |
---|
| 66 | * n -> Number |
---|
| 67 | * d -> Date |
---|
| 68 | * b -> Boolean |
---|
| 69 | * s -> String |
---|
| 70 | * o -> Object |
---|
| 71 | * -> Empty (null) |
---|
| 72 | */ |
---|
| 73 | var re = /^(a|n|d|b|s|o|e)\:(.*)$/, |
---|
| 74 | matches = re.exec(unescape(cookie)), |
---|
| 75 | all, |
---|
| 76 | type, |
---|
| 77 | v, |
---|
| 78 | kv; |
---|
| 79 | if(!matches || !matches[1]){ |
---|
| 80 | return; // non state cookie |
---|
| 81 | } |
---|
| 82 | type = matches[1]; |
---|
| 83 | v = matches[2]; |
---|
| 84 | switch(type){ |
---|
| 85 | case 'e': |
---|
| 86 | return null; |
---|
| 87 | case 'n': |
---|
| 88 | return parseFloat(v); |
---|
| 89 | case 'd': |
---|
| 90 | return new Date(Date.parse(v)); |
---|
| 91 | case 'b': |
---|
| 92 | return (v == '1'); |
---|
| 93 | case 'a': |
---|
| 94 | all = []; |
---|
| 95 | if(v != ''){ |
---|
| 96 | Ext.each(v.split('^'), function(val){ |
---|
| 97 | all.push(this.decodeValue(val)); |
---|
| 98 | }, this); |
---|
| 99 | } |
---|
| 100 | return all; |
---|
| 101 | case 'o': |
---|
| 102 | all = {}; |
---|
| 103 | if(v != ''){ |
---|
| 104 | Ext.each(v.split('^'), function(val){ |
---|
| 105 | kv = val.split('='); |
---|
| 106 | all[kv[0]] = this.decodeValue(kv[1]); |
---|
| 107 | }, this); |
---|
| 108 | } |
---|
| 109 | return all; |
---|
| 110 | default: |
---|
| 111 | return v; |
---|
| 112 | } |
---|
| 113 | }, |
---|
| 114 | |
---|
| 115 | /** |
---|
| 116 | * Encodes a value including type information. Decode with {@link #decodeValue}. |
---|
| 117 | * @param {Mixed} value The value to encode |
---|
| 118 | * @return {String} The encoded value |
---|
| 119 | */ |
---|
| 120 | encodeValue : function(v){ |
---|
| 121 | var enc, |
---|
| 122 | flat = '', |
---|
| 123 | i = 0, |
---|
| 124 | len, |
---|
| 125 | key; |
---|
| 126 | if(v == null){ |
---|
| 127 | return 'e:1'; |
---|
| 128 | }else if(typeof v == 'number'){ |
---|
| 129 | enc = 'n:' + v; |
---|
| 130 | }else if(typeof v == 'boolean'){ |
---|
| 131 | enc = 'b:' + (v ? '1' : '0'); |
---|
| 132 | }else if(Ext.isDate(v)){ |
---|
| 133 | enc = 'd:' + v.toGMTString(); |
---|
| 134 | }else if(Ext.isArray(v)){ |
---|
| 135 | for(len = v.length; i < len; i++){ |
---|
| 136 | flat += this.encodeValue(v[i]); |
---|
| 137 | if(i != len - 1){ |
---|
| 138 | flat += '^'; |
---|
| 139 | } |
---|
| 140 | } |
---|
| 141 | enc = 'a:' + flat; |
---|
| 142 | }else if(typeof v == 'object'){ |
---|
| 143 | for(key in v){ |
---|
| 144 | if(typeof v[key] != 'function' && v[key] !== undefined){ |
---|
| 145 | flat += key + '=' + this.encodeValue(v[key]) + '^'; |
---|
| 146 | } |
---|
| 147 | } |
---|
| 148 | enc = 'o:' + flat.substring(0, flat.length-1); |
---|
| 149 | }else{ |
---|
| 150 | enc = 's:' + v; |
---|
| 151 | } |
---|
| 152 | return escape(enc); |
---|
| 153 | } |
---|
| 154 | }); |
---|
| 155 | /** |
---|
| 156 | * @class Ext.state.Manager |
---|
| 157 | * This is the global state manager. By default all components that are "state aware" check this class |
---|
| 158 | * for state information if you don't pass them a custom state provider. In order for this class |
---|
| 159 | * to be useful, it must be initialized with a provider when your application initializes. Example usage: |
---|
| 160 | <pre><code> |
---|
| 161 | // in your initialization function |
---|
| 162 | init : function(){ |
---|
| 163 | Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); |
---|
| 164 | var win = new Window(...); |
---|
| 165 | win.restoreState(); |
---|
| 166 | } |
---|
| 167 | </code></pre> |
---|
| 168 | * @singleton |
---|
| 169 | */ |
---|
| 170 | Ext.state.Manager = function(){ |
---|
| 171 | var provider = new Ext.state.Provider(); |
---|
| 172 | |
---|
| 173 | return { |
---|
| 174 | /** |
---|
| 175 | * Configures the default state provider for your application |
---|
| 176 | * @param {Provider} stateProvider The state provider to set |
---|
| 177 | */ |
---|
| 178 | setProvider : function(stateProvider){ |
---|
| 179 | provider = stateProvider; |
---|
| 180 | }, |
---|
| 181 | |
---|
| 182 | /** |
---|
| 183 | * Returns the current value for a key |
---|
| 184 | * @param {String} name The key name |
---|
| 185 | * @param {Mixed} defaultValue The default value to return if the key lookup does not match |
---|
| 186 | * @return {Mixed} The state data |
---|
| 187 | */ |
---|
| 188 | get : function(key, defaultValue){ |
---|
| 189 | return provider.get(key, defaultValue); |
---|
| 190 | }, |
---|
| 191 | |
---|
| 192 | /** |
---|
| 193 | * Sets the value for a key |
---|
| 194 | * @param {String} name The key name |
---|
| 195 | * @param {Mixed} value The state data |
---|
| 196 | */ |
---|
| 197 | set : function(key, value){ |
---|
| 198 | provider.set(key, value); |
---|
| 199 | }, |
---|
| 200 | |
---|
| 201 | /** |
---|
| 202 | * Clears a value from the state |
---|
| 203 | * @param {String} name The key name |
---|
| 204 | */ |
---|
| 205 | clear : function(key){ |
---|
| 206 | provider.clear(key); |
---|
| 207 | }, |
---|
| 208 | |
---|
| 209 | /** |
---|
| 210 | * Gets the currently configured state provider |
---|
| 211 | * @return {Provider} The state provider |
---|
| 212 | */ |
---|
| 213 | getProvider : function(){ |
---|
| 214 | return provider; |
---|
| 215 | } |
---|
| 216 | }; |
---|
| 217 | }(); |
---|
| 218 | /** |
---|
| 219 | * @class Ext.state.CookieProvider |
---|
| 220 | * @extends Ext.state.Provider |
---|
| 221 | * The default Provider implementation which saves state via cookies. |
---|
| 222 | * <br />Usage: |
---|
| 223 | <pre><code> |
---|
| 224 | var cp = new Ext.state.CookieProvider({ |
---|
| 225 | path: "/cgi-bin/", |
---|
| 226 | expires: new Date(new Date().getTime()+(1000*60*60*24*30)), //30 days |
---|
| 227 | domain: "extjs.com" |
---|
| 228 | }); |
---|
| 229 | Ext.state.Manager.setProvider(cp); |
---|
| 230 | </code></pre> |
---|
| 231 | * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site) |
---|
| 232 | * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now) |
---|
| 233 | * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than |
---|
| 234 | * your page is on, but you can specify a sub-domain, or simply the domain itself like 'extjs.com' to include |
---|
| 235 | * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same |
---|
| 236 | * domain the page is running on including the 'www' like 'www.extjs.com') |
---|
| 237 | * @cfg {Boolean} secure True if the site is using SSL (defaults to false) |
---|
| 238 | * @constructor |
---|
| 239 | * Create a new CookieProvider |
---|
| 240 | * @param {Object} config The configuration object |
---|
| 241 | */ |
---|
| 242 | Ext.state.CookieProvider = Ext.extend(Ext.state.Provider, { |
---|
| 243 | |
---|
| 244 | constructor : function(config){ |
---|
| 245 | Ext.state.CookieProvider.superclass.constructor.call(this); |
---|
| 246 | this.path = "/"; |
---|
| 247 | this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days |
---|
| 248 | this.domain = null; |
---|
| 249 | this.secure = false; |
---|
| 250 | Ext.apply(this, config); |
---|
| 251 | this.state = this.readCookies(); |
---|
| 252 | }, |
---|
| 253 | |
---|
| 254 | // private |
---|
| 255 | set : function(name, value){ |
---|
| 256 | if(typeof value == "undefined" || value === null){ |
---|
| 257 | this.clear(name); |
---|
| 258 | return; |
---|
| 259 | } |
---|
| 260 | this.setCookie(name, value); |
---|
| 261 | Ext.state.CookieProvider.superclass.set.call(this, name, value); |
---|
| 262 | }, |
---|
| 263 | |
---|
| 264 | // private |
---|
| 265 | clear : function(name){ |
---|
| 266 | this.clearCookie(name); |
---|
| 267 | Ext.state.CookieProvider.superclass.clear.call(this, name); |
---|
| 268 | }, |
---|
| 269 | |
---|
| 270 | // private |
---|
| 271 | readCookies : function(){ |
---|
| 272 | var cookies = {}, |
---|
| 273 | c = document.cookie + ";", |
---|
| 274 | re = /\s?(.*?)=(.*?);/g, |
---|
| 275 | matches, |
---|
| 276 | name, |
---|
| 277 | value; |
---|
| 278 | while((matches = re.exec(c)) != null){ |
---|
| 279 | name = matches[1]; |
---|
| 280 | value = matches[2]; |
---|
| 281 | if(name && name.substring(0,3) == "ys-"){ |
---|
| 282 | cookies[name.substr(3)] = this.decodeValue(value); |
---|
| 283 | } |
---|
| 284 | } |
---|
| 285 | return cookies; |
---|
| 286 | }, |
---|
| 287 | |
---|
| 288 | // private |
---|
| 289 | setCookie : function(name, value){ |
---|
| 290 | document.cookie = "ys-"+ name + "=" + this.encodeValue(value) + |
---|
| 291 | ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) + |
---|
| 292 | ((this.path == null) ? "" : ("; path=" + this.path)) + |
---|
| 293 | ((this.domain == null) ? "" : ("; domain=" + this.domain)) + |
---|
| 294 | ((this.secure == true) ? "; secure" : ""); |
---|
| 295 | }, |
---|
| 296 | |
---|
| 297 | // private |
---|
| 298 | clearCookie : function(name){ |
---|
| 299 | document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" + |
---|
| 300 | ((this.path == null) ? "" : ("; path=" + this.path)) + |
---|
| 301 | ((this.domain == null) ? "" : ("; domain=" + this.domain)) + |
---|
| 302 | ((this.secure == true) ? "; secure" : ""); |
---|
| 303 | } |
---|
| 304 | }); |
---|