User:Erutuon/scripts/storageUtils.js

// // implicit dependencies : mediawiki.cookie,mw.storage /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true, sub:true */

/* global mw, $ */

(function StorageUtilsIIFE {

// Lowest level wrapper that wraps `localStorage` or `$.cookie` and // `$.removeCookie`. var StorageWrapper = function { this.cookiePreferences = { expires: 30, path: '/' }; };

StorageWrapper.prototype = { constructor: StorageWrapper, localStorageAvailable: mw.storage.get("localStorageTest") !== false, cookieAvailable: navigator.cookieEnabled, get storageAvailable { return this.localStorageAvailable || this.cookieAvailable; },	set: function(name, value) { if (this.localStorageAvailable) { localStorage[name] = value; } else { mw.cookie.set(name, value, {}); }	},	get: function(name) { if (this.localStorageAvailable) { return localStorage[name]; } else { return mw.cookie.get(name); }	},	remove: function(name) { if (this.localStorageAvailable) { delete localStorage[name]; } else { return $.removeCookie(name); }	}, };

var StorageByAddress = function (path, version) { console.log(arguments); if (typeof path !== "string") throw new TypeError("Expected string"); // Call constructor for StorageWrapper object. StorageWrapper.call(this); this.path = path; this.version = version || 1; };

StorageByAddress.prototype = Object.create(StorageWrapper.prototype, {	constructor: { value: StorageByAddress },	itemAddressPrefix: {		get: function {			return "enwikt/" + this.path + "?v=" + this.version;		},	},	makeAddress: {		value: function(type) {			return this.itemAddressPrefix + "&Type=" + type;		},	},	getByType: {		value: function(type) {			return StorageWrapper.prototype.get.call(this, this.makeAddress(type));		},	},	setByType: {		value: function(type, value) {			return StorageWrapper.prototype.set.call(this, this.makeAddress(type), value);		},	},	removeByType: {		value: function(type) {			return StorageWrapper.prototype.remove.call(this, this.makeAddress(type));		},	} });

// Expirable, lazy object storage. Inherits from `StorageByAddress` and // `StorageWrapper`, but has its own `get` and `remove` methods and a `set` method // that does nothing. var CacheableStorage = function(productName, getProductCallback, expireInDays, version) { StorageByAddress.call(this, "CacheableStorage/" + productName, version); this.expireInDays = expireInDays; this.productName = productName; this.getProductCallback = getProductCallback; this._cachedData = null; };

var secondsPerDay = 24 * 3600;

// callback function that must be bound using `Function.prototype.bind` so that // `this` refers to the correct object CacheableStorage.refreshDataHelper = function (data) { this.setByType("Type", typeof data); this.setByType("Expiration", new Date.toISOString); if (typeof(data) != "string") data = JSON.stringify(data); this.setByType("Data", data); };

CacheableStorage.prototype = Object.create(StorageByAddress.prototype, {	constructor: { value: CacheableStorage },	refreshDataHelper: {		get: function {			if (!this._refreshDataHelper)				this._refreshDataHelper = CacheableStorage.refreshDataHelper.bind(this);			return this._refreshDataHelper;		},	},	refreshData: {		value: function {			this.getProductCallback.then(this.refreshDataHelper);		},	},	get: {		value: function {			if (this._cachedData)				return this._cachedData;			var data = this.getByType("Data");			var type = this.getByType("Type");			var expiration = this.getByType("Expiration");			if (data) {				if (type != "string") data = JSON.parse(data);				if ((new Date - new Date(expiration)) / 1000 > this.expireInDays * secondsPerDay) {					this.refreshData;					return data;				} else {					this._cachedData = data;					return this._cachedData;				}			} else {				this.refreshData; }			return null; },	},	// just to override `StorageWrapper.protoype.set` set: { value: function doesNothing {}, }, remove: { value: function { this.removeByType("Type"); this.removeByType("Expiration"); this.removeByType("Data"); this._cachedData = null; }	},	// For compatibility with old version, which had a different name for // the equivalent method: GetItem: { get: function { return this.get; },	}, });

/* * Not expirable. Inherits from `StorageByAddress` and `StorageWrapper`, but has its * own `get`, `set`, and `remove` methods. */ var ObjectStorage = function(contextName, version) { StorageByAddress.call(this, "CacheableStorage/" + contextName, version); this.contextName = contextName; this._cachedData = null; };

ObjectStorage.prototype = Object.create(StorageByAddress.prototype, {	constructor: { value: ObjectStorage },	set: {		value: function(obj) {			var s = typeof(obj) == "string" ? obj : JSON.stringify(obj);			this.setByType("Data", s);			this.setByType("Type", typeof(obj));			this._cachedData = obj;		},	},	get: {		value: function {			if (this._cachedData)				return this._cachedData;			var data = this.getByType("Data");			var type = this.getByType("Type");			if (data) {				if (type != "string")					data = JSON.parse(data);				this._cachedData = data;				return this._cachedData;			}			return null;		},	},	remove: {		value: function {			this.removeByType("Data");			this.removeByType("Type");			this._cachedData = null;		},	},	// For compatibility with old version, which had different names for	// equivalent methods:	Get: {		get: function  {			return this.get;		},	},	Set: {		get: function  { return this.set; },	}, });

window.MyStorage = { StorageWrapper: StorageWrapper, StorageByAddress: StorageByAddress, CacheableStorage: CacheableStorage, ObjectStorage: ObjectStorage, };

});