1 /**
  2  * The Render Engine
  3  * CookieStorage
  4  *
  5  * @fileoverview A storage object where data is maintained in a cookie that stores data
  6  *               as a JSON object.
  7  *
  8  * @author: Brett Fattori (brettf@renderengine.com)
  9  * @author: $Author: bfattori@gmail.com $
 10  * @version: $Revision: 1567 $
 11  *
 12  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 13  *
 14  * Permission is hereby granted, free of charge, to any person obtaining a copy
 15  * of this software and associated documentation files (the "Software"), to deal
 16  * in the Software without restriction, including without limitation the rights
 17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 18  * copies of the Software, and to permit persons to whom the Software is
 19  * furnished to do so, subject to the following conditions:
 20  *
 21  * The above copyright notice and this permission notice shall be included in
 22  * all copies or substantial portions of the Software.
 23  *
 24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 30  * THE SOFTWARE.
 31  *
 32  */
 33 
 34 // The class this file defines and its required classes
 35 R.Engine.define({
 36     "class":"R.storage.CookieStorage",
 37     "requires":[
 38         "R.storage.AbstractStorage"
 39     ]
 40 });
 41 
 42 /**
 43  * @class <tt>R.storage.CookieStorage</tt> is used to maintain data in a
 44  *    cookie using a JSON object.  If cookies are not supported, the methods
 45  *    will have no effect.
 46  *
 47  * @param name {String} The name of the cookie
 48  * @param options {Object} An object which contains any of the following: path, domain, secure (boolean),
 49  *    and expires (number).  Any of the values can be left off, in which case defaults will be used.
 50  * @extends R.storage.AbstractStorage
 51  * @constructor
 52  * @description This class of storage is used to persist data in a cookie.
 53  */
 54 R.storage.CookieStorage = function () {
 55     return R.storage.AbstractStorage.extend(/** @scope R.storage.CookieStorage.prototype */{
 56 
 57         enabled:null,
 58         cookieName:null,
 59         options:null,
 60         hash:null,
 61 
 62         /** @private */
 63         constructor:function (name, options) {
 64             this.enabled = R.engine.Support.sysInfo().support.storage.cookie;
 65             AssertWarn(this.enabled, "CookieStorage is not supported by browser - DISABLED");
 66             this.base(name);
 67             this.cookieName = name;
 68             this.options = $.extend({
 69                 path:"/",
 70                 domain:null,
 71                 secure:null,
 72                 expires:null
 73             }, options);
 74             this.hash = this.loadData() || {};
 75         },
 76 
 77         destroy:function () {
 78             this.dispose();
 79             this.base();
 80         },
 81 
 82         /**
 83          * Release the object back into the object pool.
 84          */
 85         release:function () {
 86             this.base();
 87             this.cookieName = null;
 88             this.options = null;
 89             this.hash = null;
 90         },
 91 
 92         /**
 93          * Initialize the storage object to the document.cookie object
 94          * @return {Object} The <tt>localStorage</tt> object
 95          */
 96         initStorageObject:function () {
 97             return window.document.cookie;
 98         },
 99 
100         /**
101          * Save a value to cookie storage.
102          * @param key {String} The key to store the data with
103          * @param value {Object} The value to store with the key
104          */
105         save:function (key, value) {
106             if (!this.enabled) {
107                 return;
108             }
109 
110             if (typeof key === "object" && !R.isArray(key)) {
111                 // Set the entire hash
112                 this.hash = key;
113             } else {
114                 this.hash[key] = value;
115             }
116             this.saveData(JSON.stringify(this.hash));
117         },
118 
119         /**
120          * Get the value associated with the key from cookie storage.
121          * @param key {String} The key to retrieve data for
122          * @return {Object} The value that was stored with the key, or <tt>null</tt>
123          */
124         load:function (key) {
125             if (!this.enabled) {
126                 return null;
127             }
128 
129             if (!key) {
130                 return this.hash();
131             }
132             return this.hash[key];
133         },
134 
135         /**
136          * Dispose of the cookie (remove it from the user's browser).
137          */
138         dispose:function () {
139             if (!this.enabled) {
140                 return;
141             }
142 
143             var oldExpires = this.options.expires;
144             $.extend(this.options, {
145                 expires:-1
146             });
147             this.saveData("");
148             $.extend(this.options, {
149                 expires:oldExpires
150             });
151         },
152 
153         /**
154          * Clear all of the data stored in the cookie.
155          */
156         clear:function () {
157             if (!this.enabled) {
158                 return;
159             }
160 
161             this.saveData("{}");
162         },
163 
164         /**
165          * Saves the data object into the cookie.
166          * @param data
167          * @private
168          */
169         saveData:function (data) {
170             AssertWarn(data.length < R.engine.Support.sysInfo().support.storage.cookie.maxLength,
171                 "Data to save to cookie is larger than supported size - will be truncated");
172 
173             var p = "";
174             $.each(this.options, function (k, v) {
175                 if (v) {
176                     p += (p.length > 0 ? ";" : "") + k + (function (o) {
177                         switch (o) {
178                             case "secure":
179                                 return "";
180                             case "expires":
181                                 return "=" + new Date(R.now() + v).toGMTString();
182                             default:
183                                 return "=" + v;
184                         }
185                     })(k);
186                 }
187             });
188 
189             // Save the cookie
190             this.getStorageObject() = this.cookieName + "=" + data + ";" + p;
191         },
192 
193         /**
194          * Loads the data object from the cookie
195          * @private
196          */
197         loadData:function () {
198             if (!this.enabled) {
199                 return null;
200             }
201 
202             var va = this.getStorageObject().match('(?:^|;)\\s*' + this.cookieName + '=([^;]*)');
203             var value = (va) ? va[1] : null;
204             return JSON.parse(value);
205         }
206 
207     }, /** @scope R.storage.CookieStorage.prototype */ {
208 
209         /**
210          * Get the class name of this object
211          *
212          * @return {String} "R.storage.CookieStorage"
213          */
214         getClassName:function () {
215             return "R.storage.CookieStorage";
216         }
217 
218     });
219 };
220