vendor: 7,785 bytes, lines 1-269
1;(function(root) { 2 var CrossStorageHub = {}; 3 4 /** 5 * Accepts an array of objects with two keys: origin and allow. The value 6 * of origin is expected to be a RegExp, and allow, an array of strings. 7 * The cross storage hub is then initialized to accept requests from any of 8 * the matching origins, allowing access to the associated lists of methods. 9 * Methods may include any of: get, set, del, getKeys and clear. A 'ready' 10 * message is sent to the parent window once complete. 11 * 12 * @example 13 * // Subdomain can get, but only root domain can set and del 14 * CrossStorageHub.init([ 15 * {origin: /\.example.com$/, allow: ['get']}, 16 * {origin: /:(www\.)?example.com$/, allow: ['get', 'set', 'del']} 17 * ]); 18 * 19 * @param {array} permissions An array of objects with origin and allow 20 */ 21 CrossStorageHub.init = function(permissions) { 22 var available = true; 23 24 // Return if localStorage is unavailable, or third party 25 // access is disabled 26 try { 27 if (!window.localStorage) available = false; 28 } catch (e) { 29 available = false; 30 } 31 32 if (!available) { 33 try { 34 return window.parent.postMessage('cross-storage:unavailable', '*'); 35 } catch (e) { 36 return; 37 } 38 } 39 40 CrossStorageHub._permissions = permissions || []; 41 CrossStorageHub._installListener(); 42 window.parent.postMessage('cross-storage:ready', '*'); 43 }; 44 45 /** 46 * Installs the necessary listener for the window message event. Accommodates 47 * IE8 and up. 48 * 49 * @private 50 */ 51 CrossStorageHub._installListener = function() { 52 var listener = CrossStorageHub._listener; 53 if (window.addEventListener) { 54 window.addEventListener('message', listener, false); 55 } else { 56 window.attachEvent('onmessage', listener); 57 } 58 }; 59 60 /** 61 * The message handler for all requests posted to the window. It ignores any 62 * messages having an origin that does not match the originally supplied 63 * pattern. Given a JSON object with one of get, set, del or getKeys as the 64 * method, the function performs the requested action and returns its result. 65 * 66 * @param {MessageEvent} message A message to be processed 67 */ 68 CrossStorageHub._listener = function(message) { 69 var origin, targetOrigin, request, method, error, result, response; 70 71 // postMessage returns the string "null" as the origin for "file://" 72 origin = (message.origin === 'null') ? 'file://' : message.origin; 73 74 // Handle polling for a ready message 75 if (message.data === 'cross-storage:poll') { 76 return window.parent.postMessage('cross-storage:ready', message.origin); 77 } 78 79 // Ignore the ready message when viewing the hub directly 80 if (message.data === 'cross-storage:ready') return; 81 82 // Check whether message.data is a valid json 83 try { 84 request = JSON.parse(message.data); 85 } catch (err) { 86 return; 87 } 88 89 // Check whether request.method is a string 90 if (!request || typeof request.method !== 'string') { 91 return; 92 } 93 94 method = request.method.split('cross-storage:')[1]; 95 96 if (!method) { 97 return; 98 } else if (!CrossStorageHub._permitted(origin, method)) { 99 error = 'Invalid permissions for ' + method; 100 } else { 101 try { 102 result = CrossStorageHub['_' + method](request.params); 103 } catch (err) { 104 error = err.message; 105 } 106 } 107 108 response = JSON.stringify({ 109 id: request.id, 110 error: error, 111 result: result 112 }); 113 114 // postMessage requires that the target origin be set to "*" for "file://" 115 targetOrigin = (origin === 'file://') ? '*' : origin; 116 117 window.parent.postMessage(response, targetOrigin); 118 }; 119 120 /** 121 * Returns a boolean indicating whether or not the requested method is 122 * permitted for the given origin. The argument passed to method is expected 123 * to be one of 'get', 'set', 'del' or 'getKeys'. 124 * 125 * @param {string} origin The origin for which to determine permissions 126 * @param {string} method Requested action 127 * @returns {bool} Whether or not the request is permitted 128 */ 129 CrossStorageHub._permitted = function(origin, method) { 130 var available, i, entry, match; 131 132 available = ['get', 'set', 'del', 'clear', 'getKeys']; 133 if (!CrossStorageHub._inArray(method, available)) { 134 return false; 135 } 136 137 for (i = 0; i < CrossStorageHub._permissions.length; i++) { 138 entry = CrossStorageHub._permissions[i]; 139 if (!(entry.origin instanceof RegExp) || !(entry.allow instanceof Array)) { 140 continue; 141 } 142 143 match = entry.origin.test(origin); 144 if (match && CrossStorageHub._inArray(method, entry.allow)) { 145 return true; 146 } 147 } 148 149 return false; 150 }; 151 152 /** 153 * Sets a key to the specified value. 154 * 155 * @param {object} params An object with key and value 156 */ 157 CrossStorageHub._set = function(params) { 158 window.localStorage.setItem(params.key, params.value); 159 }; 160 161 /** 162 * Accepts an object with an array of keys for which to retrieve their values. 163 * Returns a single value if only one key was supplied, otherwise it returns 164 * an array. Any keys not set result in a null element in the resulting array. 165 * 166 * @param {object} params An object with an array of keys 167 * @returns {*|*[]} Either a single value, or an array 168 */ 169 CrossStorageHub._get = function(params) { 170 var storage, result, i, value; 171 172 storage = window.localStorage; 173 result = []; 174 175 for (i = 0; i < params.keys.length; i++) { 176 try { 177 value = storage.getItem(params.keys[i]); 178 } catch (e) { 179 value = null; 180 } 181 182 result.push(value); 183 } 184 185 return (result.length > 1) ? result : result[0]; 186 }; 187 188 /** 189 * Deletes all keys specified in the array found at params.keys. 190 * 191 * @param {object} params An object with an array of keys 192 */ 193 CrossStorageHub._del = function(params) { 194 for (var i = 0; i < params.keys.length; i++) { 195 window.localStorage.removeItem(params.keys[i]); 196 } 197 }; 198 199 /** 200 * Clears localStorage. 201 */ 202 CrossStorageHub._clear = function() { 203 window.localStorage.clear(); 204 }; 205 206 /** 207 * Returns an array of all keys stored in localStorage. 208 * 209 * @returns {string[]} The array of keys 210 */ 211 CrossStorageHub._getKeys = function(params) { 212 var i, length, keys; 213 214 keys = []; 215 length = window.localStorage.length; 216 217 for (i = 0; i < length; i++) { 218 keys.push(window.localStorage.key(i)); 219 } 220 221 return keys; 222 }; 223 224 /** 225 * Returns whether or not a value is present in the array. Consists of an 226 * alternative to extending the array prototype for indexOf, since it's 227 * unavailable for IE8. 228 * 229 * @param {*} value The value to find 230 * @parma {[]*} array The array in which to search 231 * @returns {bool} Whether or not the value was found 232 */ 233 CrossStorageHub._inArray = function(value, array) { 234 for (var i = 0; i < array.length; i++) { 235 if (value === array[i]) return true; 236 } 237 238 return false; 239 }; 240 241 /** 242 * A cross-browser version of Date.now compatible with IE8 that avoids 243 * modifying the Date object. 244 * 245 * @return {int} The current timestamp in milliseconds 246 */ 247 CrossStorageHub._now = function() { 248 if (typeof Date.now === 'function') { 249 return Date.now(); 250 } 251 252 return new Date().getTime(); 253 }; 254 255 /** 256 * Export for various environments. 257 */ 258 if (typeof module !== 'undefined' && module.exports) { 259 module.exports = CrossStorageHub; 260 } else if (typeof exports !== 'undefined') { 261 exports.CrossStorageHub = CrossStorageHub; 262 } else if (typeof define === 'function' && define.amd) { 263 define([], function() { 264 return CrossStorageHub; 265 }); 266 } else { 267 root.CrossStorageHub = CrossStorageHub; 268 } 269}(this));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.