Provider.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /**
  2. * @class Ext.state.Provider
  3. * <p>Abstract base class for state provider implementations. The provider is responsible
  4. * for setting values and extracting values to/from the underlying storage source. The
  5. * storage source can vary and the details should be implemented in a subclass. For example
  6. * a provider could use a server side database or the browser localstorage where supported.</p>
  7. *
  8. * <p>This class provides methods for encoding and decoding <b>typed</b> variables including
  9. * dates and defines the Provider interface. By default these methods put the value and the
  10. * type information into a delimited string that can be stored. These should be overridden in
  11. * a subclass if you want to change the format of the encoded value and subsequent decoding.</p>
  12. */
  13. Ext.define('Ext.state.Provider', {
  14. mixins: {
  15. observable: 'Ext.util.Observable'
  16. },
  17. /**
  18. * @cfg {String} prefix A string to prefix to items stored in the underlying state store.
  19. * Defaults to <tt>'ext-'</tt>
  20. */
  21. prefix: 'ext-',
  22. constructor : function(config){
  23. config = config || {};
  24. var me = this;
  25. Ext.apply(me, config);
  26. /**
  27. * @event statechange
  28. * Fires when a state change occurs.
  29. * @param {Ext.state.Provider} this This state provider
  30. * @param {String} key The state key which was changed
  31. * @param {String} value The encoded value for the state
  32. */
  33. me.addEvents("statechange");
  34. me.state = {};
  35. me.mixins.observable.constructor.call(me);
  36. },
  37. /**
  38. * Returns the current value for a key
  39. * @param {String} name The key name
  40. * @param {Object} defaultValue A default value to return if the key's value is not found
  41. * @return {Object} The state data
  42. */
  43. get : function(name, defaultValue){
  44. return typeof this.state[name] == "undefined" ?
  45. defaultValue : this.state[name];
  46. },
  47. /**
  48. * Clears a value from the state
  49. * @param {String} name The key name
  50. */
  51. clear : function(name){
  52. var me = this;
  53. delete me.state[name];
  54. me.fireEvent("statechange", me, name, null);
  55. },
  56. /**
  57. * Sets the value for a key
  58. * @param {String} name The key name
  59. * @param {Object} value The value to set
  60. */
  61. set : function(name, value){
  62. var me = this;
  63. me.state[name] = value;
  64. me.fireEvent("statechange", me, name, value);
  65. },
  66. /**
  67. * Decodes a string previously encoded with {@link #encodeValue}.
  68. * @param {String} value The value to decode
  69. * @return {Object} The decoded value
  70. */
  71. decodeValue : function(value){
  72. // a -> Array
  73. // n -> Number
  74. // d -> Date
  75. // b -> Boolean
  76. // s -> String
  77. // o -> Object
  78. // -> Empty (null)
  79. var me = this,
  80. re = /^(a|n|d|b|s|o|e)\:(.*)$/,
  81. matches = re.exec(unescape(value)),
  82. all,
  83. type,
  84. keyValue,
  85. values,
  86. vLen,
  87. v;
  88. if(!matches || !matches[1]){
  89. return; // non state
  90. }
  91. type = matches[1];
  92. value = matches[2];
  93. switch (type) {
  94. case 'e':
  95. return null;
  96. case 'n':
  97. return parseFloat(value);
  98. case 'd':
  99. return new Date(Date.parse(value));
  100. case 'b':
  101. return (value == '1');
  102. case 'a':
  103. all = [];
  104. if(value != ''){
  105. values = value.split('^');
  106. vLen = values.length;
  107. for (v = 0; v < vLen; v++) {
  108. value = values[v];
  109. all.push(me.decodeValue(value));
  110. }
  111. }
  112. return all;
  113. case 'o':
  114. all = {};
  115. if(value != ''){
  116. values = value.split('^');
  117. vLen = values.length;
  118. for (v = 0; v < vLen; v++) {
  119. value = values[v];
  120. keyValue = value.split('=');
  121. all[keyValue[0]] = me.decodeValue(keyValue[1]);
  122. }
  123. }
  124. return all;
  125. default:
  126. return value;
  127. }
  128. },
  129. /**
  130. * Encodes a value including type information. Decode with {@link #decodeValue}.
  131. * @param {Object} value The value to encode
  132. * @return {String} The encoded value
  133. */
  134. encodeValue : function(value){
  135. var flat = '',
  136. i = 0,
  137. enc,
  138. len,
  139. key;
  140. if (value == null) {
  141. return 'e:1';
  142. } else if(typeof value == 'number') {
  143. enc = 'n:' + value;
  144. } else if(typeof value == 'boolean') {
  145. enc = 'b:' + (value ? '1' : '0');
  146. } else if(Ext.isDate(value)) {
  147. enc = 'd:' + value.toGMTString();
  148. } else if(Ext.isArray(value)) {
  149. for (len = value.length; i < len; i++) {
  150. flat += this.encodeValue(value[i]);
  151. if (i != len - 1) {
  152. flat += '^';
  153. }
  154. }
  155. enc = 'a:' + flat;
  156. } else if (typeof value == 'object') {
  157. for (key in value) {
  158. if (typeof value[key] != 'function' && value[key] !== undefined) {
  159. flat += key + '=' + this.encodeValue(value[key]) + '^';
  160. }
  161. }
  162. enc = 'o:' + flat.substring(0, flat.length-1);
  163. } else {
  164. enc = 's:' + value;
  165. }
  166. return escape(enc);
  167. }
  168. });