SwfStore

A JavaScript library for cross-domain flash cookies - made by Nfriedly

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/11847/77621/SwfStore.js

  1. /**
  2. * SwfStore - a JavaScript library for cross-domain flash cookies
  3. *
  4. * http://github.com/nfriedly/Javascript-Flash-Cookies
  5. *
  6. * Copyright (c) 2010 by Nathan Friedly - http://nfriedly.com
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26.  
  27. /*jslint browser: true, devel: true, vars: true, white: true, nomen: true, plusplus: true, regexp: true */
  28. /*globals define:false, module:false */
  29.  
  30. (function() {
  31.  
  32. "use strict"; // http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
  33.  
  34. var counter = 0; // a counter for element id's and whatnot
  35.  
  36. var reNamespace = /[^a-z0-9_\/]/ig; //a regex to find anything that's not letters, numbers underscore and forward slash
  37. var reId = /[^a-z0-9_]/ig; // same as above except no forward slashes
  38. /**
  39. * SwfStore constructor - creates a new SwfStore object and embeds the .swf into the web page.
  40. *
  41. * usage:
  42. * var mySwfStore = new SwfStore({
  43. * namespace: "my_cool_app",
  44. * swf_url: "http://example.com/path/to/storage.swf",
  45. * onready: function() {
  46. * console.log('ready!', mySwfStore.get('my_key'));
  47. * },
  48. * onerror: function() {
  49. * console.error('swfStore failed to load :(');
  50. * }
  51. * });
  52. *
  53. * @param {object} config
  54. * @param {string} [config.swf_url=storage.swf] - Url to storage.swf. Must be an absolute url (with http:// and all) to work cross-domain
  55. * @param {functon} [config.onready] Callback function that is fired when the SwfStore is loaded. Recommended.
  56. * @param {function} [config.onerror] Callback function that is fired if the SwfStore fails to load. Recommended.
  57. * @param {string} [config.namespace="swfstore"] The namespace to use in both JS and the SWF. Allows a page to have more than one instance of SwfStore.
  58. * @param {integer} [config.timeout=10] The number of seconds to wait before assuming the user does not have flash.
  59. * @param {boolean} [config.debug=false] Is debug mode enabled? If so, mesages will be logged to the console and the .swf will be rendered on the page (although it will be an empty white box unless it cannot communicate with JS. Then it will log errors to the .swf)
  60. */
  61. function SwfStore(config) {
  62. // make sure we have something of a configuration
  63. config = config || {};
  64. var defaults = {
  65. swf_url: 'storage.swf', // this should be a complete protocol-relative url (//example.com/path/to/storage.swf) for cross-domain, cross-protocol usage
  66. namespace: 'swfstore',
  67. debug: false,
  68. timeout: 10, // number of seconds to wait before concluding there was an error
  69. onready: null,
  70. onerror: null
  71. };
  72. var key;
  73. for (key in defaults) {
  74. if (defaults.hasOwnProperty(key)) {
  75. if (!config.hasOwnProperty(key)) {
  76. config[key] = defaults[key];
  77. }
  78. }
  79. }
  80. config.namespace = config.namespace.replace(reNamespace, '_');
  81.  
  82. if (window.SwfStore[config.namespace]) {
  83. throw "There is already an instance of SwfStore using the '" + config.namespace + "' namespace. Use that instance or specify an alternate namespace in the config.";
  84. }
  85.  
  86. this.config = config;
  87.  
  88. // a couple of basic timesaver functions
  89. function id() {
  90. return "SwfStore_" + config.namespace.replace(reId, "_") + "_" + (counter++);
  91. }
  92.  
  93. function div(visible) {
  94. var d = document.createElement('div');
  95. document.body.appendChild(d);
  96. d.id = id();
  97. if (!visible) {
  98. // setting display:none causes the .swf to not render at all
  99. d.style.position = "absolute";
  100. d.style.top = "-2000px";
  101. d.style.left = "-2000px";
  102. }
  103. return d;
  104. }
  105.  
  106. // get a logger ready
  107. // if we're in a browser that doesn't have a console, build one
  108. if (typeof console === "undefined") {
  109. var loggerOutput = div(true);
  110. this.console = {
  111. log: function(msg) {
  112. var m = div(true);
  113. m.innerHTML = msg;
  114. loggerOutput.appendChild(m);
  115. }
  116. };
  117. } else {
  118. this.console = console;
  119. }
  120. this.log = function(type, source, msg) {
  121. if (config.debug) {
  122. // only output to log if debug is currently enabled
  123. source = (source === 'swfStore') ? 'swf' : source;
  124. if (typeof(this.console[type]) !== "undefined") {
  125. this.console[type]('SwfStore - ' + config.namespace + ' (' + source + '): ' + msg);
  126. } else {
  127. this.console.log('SwfStore - ' + config.namespace + ": " + type + ' (' + source + '): ' + msg);
  128. }
  129. }
  130. };
  131.  
  132. this.log('info', 'js', 'Initializing...');
  133.  
  134. // the callback functions that javascript provides to flash must be globally accessible
  135. SwfStore[config.namespace] = this;
  136.  
  137. var swfContainer = div(config.debug);
  138.  
  139. var swfName = id();
  140.  
  141. var flashvars = "namespace=" + encodeURIComponent(config.namespace);
  142.  
  143. swfContainer.innerHTML = '<object height="100" width="500" codebase="https://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="' +
  144. swfName + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">' +
  145. ' <param value="' + config.swf_url + '" name="movie">' +
  146. ' <param value="' + flashvars + '" name="FlashVars">' +
  147. ' <param value="always" name="allowScriptAccess">' +
  148. ' <embed height="375" align="middle" width="500" pluginspage="https://www.macromedia.com/go/getflashplayer" ' +
  149. 'flashvars="' + flashvars + '" type="application/x-shockwave-flash" allowscriptaccess="always" quality="high" loop="false" play="true" ' +
  150. 'name="' + swfName + '" bgcolor="#ffffff" src="' + config.swf_url + '">' +
  151. '</object>';
  152.  
  153. this.swf = document[swfName] || window[swfName];
  154.  
  155. this._timeout = setTimeout(function() {
  156. SwfStore[config.namespace].onerror(new Error(config.swf_url + ' failed to load within ' + config.timeout + ' seconds.'), 'js');
  157. }, config.timeout * 1000);
  158. }
  159.  
  160. // we need to check everything we send to flash because it can't take functions as arguments
  161. function checkData(data) {
  162. if (typeof data === "function") {
  163. throw new Error('SwfStore Error: Functions cannot be used as keys or values.');
  164. }
  165. }
  166.  
  167. SwfStore.prototype = {
  168.  
  169. /**
  170. * This is an indicator of whether or not the SwfStore is initialized.
  171. * Use the onready and onerror config options rather than checking this variable.
  172. */
  173. ready: false,
  174.  
  175. /**
  176. * Sets the given key to the given value in the swf
  177. * @param {string} key
  178. * @param {string} value
  179. */
  180. set: function(key, value) {
  181. this._checkReady();
  182. checkData(key);
  183. checkData(value);
  184. if (value === null || typeof value == "undefined") {
  185. this.swf.clear(key);
  186. } else {
  187. this.swf.set(key, value);
  188. }
  189. },
  190.  
  191. /**
  192. * Retrieves the specified value from the swf.
  193. * @param {string} key
  194. * @return {string} value
  195. */
  196. get: function(key) {
  197. this._checkReady();
  198. checkData(key);
  199. //this.log('debug', 'js', 'Reading ' + key);
  200. return this.swf.get(key);
  201. },
  202.  
  203. /**
  204. * Retrieves all stored values from the swf.
  205. * @return {object}
  206. */
  207. getAll: function() {
  208. this._checkReady();
  209. var pairs = this.swf.getAll();
  210. var data = {};
  211. for (var i = 0, len = pairs.length, pair; i < len; i++) {
  212. pair = pairs[i];
  213. data[pair.key] = pair.value;
  214. }
  215. return data;
  216. },
  217.  
  218. clearAll: function() {
  219. var all = this.getAll();
  220. for (var key in all) {
  221. if (all.hasOwnProperty(key)) {
  222. this.clear(key);
  223. }
  224. }
  225. },
  226.  
  227. /**
  228. * Delete the specified key from the swf
  229. *
  230. * @param {string} key
  231. */
  232. clear: function(key) {
  233. this._checkReady();
  234. checkData(key);
  235. this.swf.clear(key);
  236. },
  237.  
  238. /**
  239. * We need to run this check before tying to work with the swf
  240. *
  241. * @private
  242. */
  243. _checkReady: function() {
  244. if (!this.ready) {
  245. throw 'SwfStore is not yet finished initializing. Pass a config.onready callback or wait until this.ready is true before trying to use a SwfStore instance.';
  246. }
  247. },
  248.  
  249. /**
  250. * This is the function that the swf calls to announce that it has loaded.
  251. * This function in turn fires the onready function if provided in the config.
  252. *
  253. * @private
  254. */
  255. onload: function() {
  256. // deal with scope the easy way
  257. var that = this;
  258. // wrapping everything in a timeout so that the JS can finish initializing first
  259. // (If the .swf is cached in IE, it fires the callback *immediately* before JS has
  260. // finished executing. setTimeout(function, 0) fixes that)
  261. setTimeout(function() {
  262. clearTimeout(that._timeout);
  263. that.ready = true;
  264.  
  265. //this.log('info', 'js', 'Ready!')
  266. if (that.config.onready) {
  267. that.config.onready();
  268. }
  269. }, 0);
  270. },
  271.  
  272.  
  273. /**
  274. * If the swf had an error but is still able to communicate with JavaScript, it will call this function.
  275. * This function is also called if the time limit is reached and flash has not yet loaded.
  276. * This function is most commonly called when either flash is not installed or local storage has been disabled.
  277. * If an onerror function was provided in the config, this function will fire it.
  278. *
  279. * @private
  280. */
  281. onerror: function(err, source) {
  282. clearTimeout(this._timeout);
  283. if (!(err instanceof Error)) {
  284. err = new Error(err);
  285. }
  286. this.log('error', source || 'swf', err.message);
  287. if (this.config.onerror) {
  288. this.config.onerror(err);
  289. }
  290. }
  291. };
  292.  
  293. // UMD for working with requirejs / browserify
  294. if (typeof define === 'function' && define.amd) {
  295. // AMD. Register as an anonymous module.
  296. define([], SwfStore);
  297. } else if (typeof module === 'object' && module.exports) {
  298. // Browserify
  299. module.exports = SwfStore;
  300. }
  301.  
  302. // reguardless of UMD, SwfStore must be a global for flash to communicate with it
  303. window.SwfStore = SwfStore;
  304.  
  305. }());