1 | dojo.provide("dojox.storage.WhatWGStorageProvider"); |
---|
2 | dojo.require("dojox.storage.Provider"); |
---|
3 | dojo.require("dojox.storage.manager"); |
---|
4 | |
---|
5 | dojo.declare("dojox.storage.WhatWGStorageProvider", [ dojox.storage.Provider ], { |
---|
6 | // summary: |
---|
7 | // Storage provider that uses WHAT Working Group features in Firefox 2 |
---|
8 | // to achieve permanent storage. |
---|
9 | // description: |
---|
10 | // The WHAT WG storage API is documented at |
---|
11 | // http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side |
---|
12 | // |
---|
13 | // You can disable this storage provider with the following djConfig variable: |
---|
14 | // | var djConfig = { disableWhatWGStorage: true }; |
---|
15 | // |
---|
16 | // Authors of this storage provider: |
---|
17 | // |
---|
18 | // - JB Boisseau, jb.boisseau@eutech-ssii.com |
---|
19 | // - Brad Neuberg, bkn3@columbia.edu |
---|
20 | |
---|
21 | initialized: false, |
---|
22 | |
---|
23 | _domain: null, |
---|
24 | _available: null, |
---|
25 | _statusHandler: null, |
---|
26 | _allNamespaces: null, |
---|
27 | _storageEventListener: null, |
---|
28 | |
---|
29 | initialize: function(){ |
---|
30 | if(dojo.config["disableWhatWGStorage"] == true){ |
---|
31 | return; |
---|
32 | } |
---|
33 | |
---|
34 | // get current domain |
---|
35 | this._domain = location.hostname; |
---|
36 | // console.debug(this._domain); |
---|
37 | |
---|
38 | // indicate that this storage provider is now loaded |
---|
39 | this.initialized = true; |
---|
40 | dojox.storage.manager.loaded(); |
---|
41 | }, |
---|
42 | |
---|
43 | isAvailable: function(){ |
---|
44 | try{ |
---|
45 | var myStorage = globalStorage[location.hostname]; |
---|
46 | }catch(e){ |
---|
47 | this._available = false; |
---|
48 | return this._available; |
---|
49 | } |
---|
50 | |
---|
51 | this._available = true; |
---|
52 | return this._available; |
---|
53 | }, |
---|
54 | |
---|
55 | put: function(key, value, resultsHandler, namespace){ |
---|
56 | if(this.isValidKey(key) == false){ |
---|
57 | throw new Error("Invalid key given: " + key); |
---|
58 | } |
---|
59 | namespace = namespace||this.DEFAULT_NAMESPACE; |
---|
60 | |
---|
61 | // get our full key name, which is namespace + key |
---|
62 | key = this.getFullKey(key, namespace); |
---|
63 | |
---|
64 | this._statusHandler = resultsHandler; |
---|
65 | |
---|
66 | // serialize the value; |
---|
67 | // handle strings differently so they have better performance |
---|
68 | if(dojo.isString(value)){ |
---|
69 | value = "string:" + value; |
---|
70 | }else{ |
---|
71 | value = dojo.toJson(value); |
---|
72 | } |
---|
73 | |
---|
74 | // register for successful storage events. |
---|
75 | var storageListener = dojo.hitch(this, function(evt){ |
---|
76 | // remove any old storage event listener we might have added |
---|
77 | // to the window on old put() requests; Firefox has a bug |
---|
78 | // where it can occassionaly go into infinite loops calling |
---|
79 | // our storage event listener over and over -- this is a |
---|
80 | // workaround |
---|
81 | // FIXME: Simplify this into a test case and submit it |
---|
82 | // to Firefox |
---|
83 | window.removeEventListener("storage", storageListener, false); |
---|
84 | |
---|
85 | // indicate we succeeded |
---|
86 | if(resultsHandler){ |
---|
87 | resultsHandler.call(null, this.SUCCESS, key, null, namespace); |
---|
88 | } |
---|
89 | }); |
---|
90 | |
---|
91 | window.addEventListener("storage", storageListener, false); |
---|
92 | |
---|
93 | // try to store the value |
---|
94 | try{ |
---|
95 | var myStorage = globalStorage[this._domain]; |
---|
96 | myStorage.setItem(key, value); |
---|
97 | }catch(e){ |
---|
98 | // indicate we failed |
---|
99 | this._statusHandler.call(null, this.FAILED, key, e.toString(), namespace); |
---|
100 | } |
---|
101 | }, |
---|
102 | |
---|
103 | get: function(key, namespace){ |
---|
104 | if(this.isValidKey(key) == false){ |
---|
105 | throw new Error("Invalid key given: " + key); |
---|
106 | } |
---|
107 | namespace = namespace||this.DEFAULT_NAMESPACE; |
---|
108 | |
---|
109 | // get our full key name, which is namespace + key |
---|
110 | key = this.getFullKey(key, namespace); |
---|
111 | |
---|
112 | // sometimes, even if a key doesn't exist, Firefox |
---|
113 | // will return a blank string instead of a null -- |
---|
114 | // this _might_ be due to having underscores in the |
---|
115 | // keyname, but I am not sure. |
---|
116 | |
---|
117 | // FIXME: Simplify this bug into a testcase and |
---|
118 | // submit it to Firefox |
---|
119 | var myStorage = globalStorage[this._domain]; |
---|
120 | var results = myStorage.getItem(key); |
---|
121 | |
---|
122 | if(results == null || results == ""){ |
---|
123 | return null; |
---|
124 | } |
---|
125 | |
---|
126 | results = results.value; |
---|
127 | |
---|
128 | // destringify the content back into a |
---|
129 | // real JavaScript object; |
---|
130 | // handle strings differently so they have better performance |
---|
131 | if(dojo.isString(results) && (/^string:/.test(results))){ |
---|
132 | results = results.substring("string:".length); |
---|
133 | }else{ |
---|
134 | results = dojo.fromJson(results); |
---|
135 | } |
---|
136 | |
---|
137 | return results; |
---|
138 | }, |
---|
139 | |
---|
140 | getNamespaces: function(){ |
---|
141 | var results = [ this.DEFAULT_NAMESPACE ]; |
---|
142 | |
---|
143 | // simply enumerate through our array and save any string |
---|
144 | // that starts with __ |
---|
145 | var found = {}; |
---|
146 | var myStorage = globalStorage[this._domain]; |
---|
147 | var tester = /^__([^_]*)_/; |
---|
148 | for(var i = 0; i < myStorage.length; i++){ |
---|
149 | var currentKey = myStorage.key(i); |
---|
150 | if(tester.test(currentKey) == true){ |
---|
151 | var currentNS = currentKey.match(tester)[1]; |
---|
152 | // have we seen this namespace before? |
---|
153 | if(typeof found[currentNS] == "undefined"){ |
---|
154 | found[currentNS] = true; |
---|
155 | results.push(currentNS); |
---|
156 | } |
---|
157 | } |
---|
158 | } |
---|
159 | |
---|
160 | return results; |
---|
161 | }, |
---|
162 | |
---|
163 | getKeys: function(namespace){ |
---|
164 | namespace = namespace||this.DEFAULT_NAMESPACE; |
---|
165 | |
---|
166 | if(this.isValidKey(namespace) == false){ |
---|
167 | throw new Error("Invalid namespace given: " + namespace); |
---|
168 | } |
---|
169 | |
---|
170 | // create a regular expression to test the beginning |
---|
171 | // of our key names to see if they match our namespace; |
---|
172 | // if it is the default namespace then test for the presence |
---|
173 | // of no namespace for compatibility with older versions |
---|
174 | // of dojox.storage |
---|
175 | var namespaceTester; |
---|
176 | if(namespace == this.DEFAULT_NAMESPACE){ |
---|
177 | namespaceTester = new RegExp("^([^_]{2}.*)$"); |
---|
178 | }else{ |
---|
179 | namespaceTester = new RegExp("^__" + namespace + "_(.*)$"); |
---|
180 | } |
---|
181 | |
---|
182 | var myStorage = globalStorage[this._domain]; |
---|
183 | var keysArray = []; |
---|
184 | for(var i = 0; i < myStorage.length; i++){ |
---|
185 | var currentKey = myStorage.key(i); |
---|
186 | if(namespaceTester.test(currentKey) == true){ |
---|
187 | // strip off the namespace portion |
---|
188 | currentKey = currentKey.match(namespaceTester)[1]; |
---|
189 | keysArray.push(currentKey); |
---|
190 | } |
---|
191 | } |
---|
192 | |
---|
193 | return keysArray; |
---|
194 | }, |
---|
195 | |
---|
196 | clear: function(namespace){ |
---|
197 | namespace = namespace||this.DEFAULT_NAMESPACE; |
---|
198 | |
---|
199 | if(this.isValidKey(namespace) == false){ |
---|
200 | throw new Error("Invalid namespace given: " + namespace); |
---|
201 | } |
---|
202 | |
---|
203 | // create a regular expression to test the beginning |
---|
204 | // of our key names to see if they match our namespace; |
---|
205 | // if it is the default namespace then test for the presence |
---|
206 | // of no namespace for compatibility with older versions |
---|
207 | // of dojox.storage |
---|
208 | var namespaceTester; |
---|
209 | if(namespace == this.DEFAULT_NAMESPACE){ |
---|
210 | namespaceTester = new RegExp("^[^_]{2}"); |
---|
211 | }else{ |
---|
212 | namespaceTester = new RegExp("^__" + namespace + "_"); |
---|
213 | } |
---|
214 | |
---|
215 | var myStorage = globalStorage[this._domain]; |
---|
216 | var keys = []; |
---|
217 | for(var i = 0; i < myStorage.length; i++){ |
---|
218 | if(namespaceTester.test(myStorage.key(i)) == true){ |
---|
219 | keys[keys.length] = myStorage.key(i); |
---|
220 | } |
---|
221 | } |
---|
222 | |
---|
223 | dojo.forEach(keys, dojo.hitch(myStorage, "removeItem")); |
---|
224 | }, |
---|
225 | |
---|
226 | remove: function(key, namespace){ |
---|
227 | // get our full key name, which is namespace + key |
---|
228 | key = this.getFullKey(key, namespace); |
---|
229 | |
---|
230 | var myStorage = globalStorage[this._domain]; |
---|
231 | myStorage.removeItem(key); |
---|
232 | }, |
---|
233 | |
---|
234 | isPermanent: function(){ |
---|
235 | return true; |
---|
236 | }, |
---|
237 | |
---|
238 | getMaximumSize: function(){ |
---|
239 | return this.SIZE_NO_LIMIT; |
---|
240 | }, |
---|
241 | |
---|
242 | hasSettingsUI: function(){ |
---|
243 | return false; |
---|
244 | }, |
---|
245 | |
---|
246 | showSettingsUI: function(){ |
---|
247 | throw new Error(this.declaredClass + " does not support a storage settings user-interface"); |
---|
248 | }, |
---|
249 | |
---|
250 | hideSettingsUI: function(){ |
---|
251 | throw new Error(this.declaredClass + " does not support a storage settings user-interface"); |
---|
252 | }, |
---|
253 | |
---|
254 | getFullKey: function(key, namespace){ |
---|
255 | namespace = namespace||this.DEFAULT_NAMESPACE; |
---|
256 | |
---|
257 | if(this.isValidKey(namespace) == false){ |
---|
258 | throw new Error("Invalid namespace given: " + namespace); |
---|
259 | } |
---|
260 | |
---|
261 | // don't append a namespace string for the default namespace, |
---|
262 | // for compatibility with older versions of dojox.storage |
---|
263 | if(namespace == this.DEFAULT_NAMESPACE){ |
---|
264 | return key; |
---|
265 | }else{ |
---|
266 | return "__" + namespace + "_" + key; |
---|
267 | } |
---|
268 | } |
---|
269 | }); |
---|
270 | |
---|
271 | dojox.storage.manager.register("dojox.storage.WhatWGStorageProvider", |
---|
272 | new dojox.storage.WhatWGStorageProvider()); |
---|