Storage object for managing localStorage and cookies (bug 491800)
This commit is contained in:
Родитель
5979c77d50
Коммит
98ed26bd1b
|
@ -85,12 +85,12 @@ var unique = function(arr, keyfunc) {
|
|||
};
|
||||
|
||||
|
||||
/* Maintains a list of unique objects in localStorage sorted by date-added
|
||||
/* Maintains a list of unique objects in (local)Storage sorted by date-added
|
||||
* (descending).
|
||||
*
|
||||
* Options:
|
||||
* limit: max number of items to keep in localStorage (default: 10)
|
||||
* storageKey: the key used for localStorage (default: "recently-viewed")
|
||||
* limit: max number of items to keep in Storage (default: 10)
|
||||
* storageKey: the key used for Storage (default: "recently-viewed")
|
||||
* uniqueFunc: the function passed to `unique` to determine uniqueness
|
||||
* of items (default: the whole object, without date-added)
|
||||
*/
|
||||
|
@ -123,16 +123,16 @@ RecentlyViewed.prototype = {
|
|||
return $.fmap(this._list(), function(x) { return x[1]; });
|
||||
},
|
||||
|
||||
/* Save an array to localStorage, maintaining the storage limit. */
|
||||
/* Save an array to Storage, maintaining the storage limit. */
|
||||
_save: function(arr) {
|
||||
arr = arr.slice(0, this.limit);
|
||||
localStorage[this.storageKey] = JSON.stringify(arr);
|
||||
Storage.set(this.storageKey, JSON.stringify(arr));
|
||||
return arr;
|
||||
},
|
||||
|
||||
/* Fetch the internal list of (date, object) tuples. */
|
||||
_list: function() {
|
||||
var val = localStorage[this.storageKey];
|
||||
var val = Storage.get(this.storageKey);
|
||||
if (val === null || val === undefined) {
|
||||
return [];
|
||||
} else {
|
||||
|
@ -141,18 +141,12 @@ RecentlyViewed.prototype = {
|
|||
},
|
||||
|
||||
clear: function() {
|
||||
delete localStorage[this.storageKey];
|
||||
Storage.remove(this.storageKey);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
collections.recently_viewed = function() {
|
||||
try {
|
||||
if (!window.localStorage) { return; }
|
||||
} catch(ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
var recentlyViewed = new RecentlyViewed({
|
||||
storageKey: 'recently-viewed-collections',
|
||||
uniqueFunc: function(e) { return e[1].uuid; }
|
||||
|
|
|
@ -194,9 +194,6 @@ function css(el, prop) {
|
|||
})(jQuery);
|
||||
|
||||
|
||||
z.hasLocalStorage = "localStorage" in window && window["localStorage"] !== null;
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
if ($(".detail").length) {
|
||||
initDetail();
|
||||
|
@ -244,13 +241,7 @@ function initDetail() {
|
|||
$(".install-action a").attr("target", "_self");
|
||||
|
||||
// Replace with the URL back to the discovery promo pane.
|
||||
var pane_url;
|
||||
if (z.hasLocalStorage) {
|
||||
pane_url = localStorage.getItem("discopane-url");
|
||||
} else {
|
||||
pane_url = $.cookie("discopane-url");
|
||||
}
|
||||
$("p#back a").attr("href", pane_url);
|
||||
$("p#back a").attr("href", Storage.get("discopane-url"));
|
||||
|
||||
$("#images").fadeIn("slow").addClass("js").jCarouselLite({
|
||||
btnNext: "#images .nav-next a",
|
||||
|
|
|
@ -47,11 +47,7 @@ function getGuids() {
|
|||
|
||||
function storePaneLink() {
|
||||
// Store the pane URL so we can link back from the add-on detail pages.
|
||||
if (z.hasLocalStorage) {
|
||||
localStorage.setItem("discopane-url", location);
|
||||
} else {
|
||||
$.cookie("discopane-url", location, {path: "/"});
|
||||
}
|
||||
Storage.set("discopane-url", location);
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,11 +79,11 @@ function initRecs() {
|
|||
|
||||
var token2;
|
||||
|
||||
if (z.hasLocalStorage && (!location.hash || !guids.length)) {
|
||||
if (!location.hash || !guids.length) {
|
||||
// If the user has opted out of recommendations, clear out any
|
||||
// existing recommendations.
|
||||
localStorage.removeItem("discopane-recs");
|
||||
localStorage.removeItem("discopane-guids");
|
||||
Storage.remove("discopane-recs");
|
||||
Storage.remove("discopane-guids");
|
||||
}
|
||||
|
||||
function populateRecs() {
|
||||
|
@ -151,26 +147,20 @@ function initRecs() {
|
|||
if (showRecs && guids.length > MIN_EXTENSIONS) {
|
||||
$("body").removeClass("no-recs").addClass("recs");
|
||||
|
||||
var cacheObject;
|
||||
if (z.hasLocalStorage) {
|
||||
cacheObject = localStorage.getItem("discopane-recs");
|
||||
var cacheObject = Storage.get("discopane-recs");
|
||||
if (cacheObject) {
|
||||
// Load local data.
|
||||
cacheObject = JSON.parse(cacheObject);
|
||||
if (cacheObject) {
|
||||
// Load local data.
|
||||
cacheObject = JSON.parse(cacheObject);
|
||||
if (cacheObject) {
|
||||
datastore = cacheObject;
|
||||
token2 = cacheObject.token2;
|
||||
}
|
||||
datastore = cacheObject;
|
||||
token2 = cacheObject.token2;
|
||||
}
|
||||
}
|
||||
|
||||
// Get new recommendations if there are no saved recommendations or
|
||||
// if the user has new installed add-ons.
|
||||
var findRecs = !cacheObject;
|
||||
var updateRecs = (
|
||||
cacheObject && z.hasLocalStorage &&
|
||||
localStorage.getItem("discopane-guids") != guids.toString()
|
||||
);
|
||||
var updateRecs = cacheObject && Storage.get("discopane-guids") != guids.toString();
|
||||
if (findRecs || updateRecs) {
|
||||
var msg;
|
||||
if (findRecs) {
|
||||
|
@ -196,19 +186,15 @@ function initRecs() {
|
|||
$("#recs .loading").remove();
|
||||
datastore = JSON.parse(raw_data);
|
||||
populateRecs();
|
||||
if (z.hasLocalStorage) {
|
||||
localStorage.setItem("discopane-updated", new Date());
|
||||
localStorage.setItem("discopane-recs", raw_data);
|
||||
localStorage.setItem("discopane-guids", guids);
|
||||
}
|
||||
Storage.set("discopane-updated", new Date());
|
||||
Storage.set("discopane-recs", raw_data);
|
||||
Storage.set("discopane-guids", guids);
|
||||
},
|
||||
error: function(raw_data) {
|
||||
$("#recs .loading").remove();
|
||||
populateRecs();
|
||||
if (z.hasLocalStorage) {
|
||||
localStorage.setItem("discopane-recs", "{}");
|
||||
localStorage.setItem("discopane-guids", guids);
|
||||
}
|
||||
Storage.remove("discopane-recs");
|
||||
Storage.remove("discopane-guids");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -67,31 +67,19 @@ $(function() {
|
|||
});
|
||||
|
||||
function initDailyMessage(doc) {
|
||||
var canCloseMsg,
|
||||
$motd = $('.daily-message', doc);
|
||||
try {
|
||||
if ('localStorage' in window && window['localStorage'] !== null) {
|
||||
canCloseMsg = true;
|
||||
}
|
||||
} catch(e) {
|
||||
// Exception thrown when cookies are off (bug in older Firefox)
|
||||
canCloseMsg = false;
|
||||
}
|
||||
var $motd = $('.daily-message', doc);
|
||||
if ($('#editor-motd', doc).length) {
|
||||
// The message on the MOTD page should never be closable
|
||||
canCloseMsg = false;
|
||||
}
|
||||
if (!canCloseMsg) {
|
||||
// Don't show close button, don't attach handlers
|
||||
// The message on the MOTD page should never be closable, so don't
|
||||
// show close button nor attach handlers.
|
||||
return;
|
||||
}
|
||||
$motd.find('.close').show();
|
||||
if (window.localStorage['motd_closed'] == $('p', $motd).text()) {
|
||||
if (Storage.get('motd_closed') == $('p', $motd).text()) {
|
||||
$motd.hide();
|
||||
}
|
||||
$motd.find('.close').click(function(e) {
|
||||
e.stopPropagation();
|
||||
window.localStorage['motd_closed'] = $('.daily-message p').text();
|
||||
Storage.set('motd_closed', $('.daily-message p').text());
|
||||
$motd.slideUp();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
var pending_fetches = 0;
|
||||
var page_state = {};
|
||||
var capabilities = {
|
||||
'localStorage' : ('localStorage' in window) && window['localStorage'] !== null,
|
||||
'JSON' : window.JSON && typeof JSON.parse == 'function',
|
||||
'debug' : !(('' + document.location).indexOf("dbg") < 0),
|
||||
'debug_in_page' : !(('' + document.location).indexOf("dbginpage") < 0),
|
||||
|
@ -24,9 +23,9 @@
|
|||
};
|
||||
|
||||
var writeInterval = false;
|
||||
|
||||
|
||||
var hashInterval = false;
|
||||
|
||||
|
||||
function stop_hash_check() {
|
||||
clearInterval(hashInterval);
|
||||
}
|
||||
|
@ -55,7 +54,7 @@
|
|||
// Worker pool for Web Worker management
|
||||
|
||||
var stats_worker_url = z.media_url+"js/zamboni/stats/stats_worker.js";
|
||||
|
||||
|
||||
var StatsWorkerPool = new WorkerPool(4);
|
||||
|
||||
var breakdown_metrics = {
|
||||
|
@ -94,11 +93,11 @@
|
|||
function date(d) {
|
||||
return Date.parse(date_string(d, '-'));
|
||||
}
|
||||
|
||||
|
||||
function date_string(d, del) {
|
||||
return [d.getFullYear(), pad2(d.getMonth()+1), pad2(d.getDate())].join(del);
|
||||
}
|
||||
|
||||
|
||||
function datepicker_format(d) {
|
||||
return [pad2(d.getMonth()+1), pad2(d.getDate()), d.getFullYear()].join('/');
|
||||
}
|
||||
|
@ -111,7 +110,7 @@
|
|||
document.onbeforeunload = function () {
|
||||
AMO.StatsManager.write_local();
|
||||
}
|
||||
|
||||
|
||||
Series = new AsyncCache(
|
||||
function miss(key, set) {
|
||||
if (typeof key.time === "string") {
|
||||
|
@ -191,7 +190,7 @@
|
|||
AMO.StatsManager.getDataRange(key.metric, time.start, time.end, function() {
|
||||
|
||||
var ret = [];
|
||||
|
||||
|
||||
for (var i=time.end; i>time.start; i-= millis("1 day")) {
|
||||
if (ds[i] !== undefined) {
|
||||
var row = (key.metric == 'apps') ? AMO.StatsManager.collapseVersions(ds[i], 1) : ds[i];
|
||||
|
@ -240,54 +239,38 @@
|
|||
AMO.StatsManager = {
|
||||
|
||||
init: function () {
|
||||
if (capabilities.localStorage) {
|
||||
dbg("looking for local data");
|
||||
if (AMO.StatsManager.verify_local()) {
|
||||
var cacheObject = localStorage.getItem("statscache-" + AMO.getAddonId());
|
||||
dbg("looking for local data");
|
||||
if (AMO.StatsManager.verify_local()) {
|
||||
var cacheObject = Storage.get("statscache-" + AMO.getAddonId());
|
||||
if (cacheObject) {
|
||||
dbg("found local data, loading...");
|
||||
cacheObject = JSON.parse(cacheObject);
|
||||
if (cacheObject) {
|
||||
dbg("found local data, loading...");
|
||||
cacheObject = JSON.parse(cacheObject);
|
||||
if (cacheObject) {
|
||||
datastore = cacheObject;
|
||||
}
|
||||
datastore = cacheObject;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dbg("no local storage");
|
||||
}
|
||||
},
|
||||
|
||||
write_local: function () {
|
||||
dbg("saving local data");
|
||||
if (capabilities.localStorage) {
|
||||
dbg("user has local storage");
|
||||
localStorage.setItem("statscache-" + AMO.getAddonId(), JSON.stringify(datastore));
|
||||
localStorage.setItem("stats_version", version);
|
||||
dbg("saved local data");
|
||||
} else {
|
||||
dbg("no local storage");
|
||||
}
|
||||
Storage.set("statscache-" + AMO.getAddonId(), JSON.stringify(datastore));
|
||||
Storage.set("stats_version", version);
|
||||
dbg("saved local data");
|
||||
},
|
||||
|
||||
clear_local: function () {
|
||||
if (capabilities.localStorage) {
|
||||
var local_store = localStorage;
|
||||
local_store.removeItem("statscache-" + AMO.getAddonId());
|
||||
dbg("cleared local data");
|
||||
}
|
||||
Storage.remove("statscache-" + AMO.getAddonId());
|
||||
dbg("cleared local data");
|
||||
},
|
||||
|
||||
verify_local: function () {
|
||||
if (capabilities.localStorage) {
|
||||
var local_store = localStorage;
|
||||
if (local_store.getItem("stats_version") == version) {
|
||||
return true;
|
||||
} else {
|
||||
dbg("wrong offline data verion");
|
||||
return false;
|
||||
}
|
||||
if (Storage.get("stats_version") == version) {
|
||||
return true;
|
||||
} else {
|
||||
dbg("wrong offline data verion");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_fetchData: function (metric, start, end, callback) {
|
||||
|
@ -419,7 +402,7 @@
|
|||
|
||||
finished();
|
||||
},
|
||||
|
||||
|
||||
getDataSlice: function(metric, time, base) {
|
||||
base = base || "";
|
||||
if (typeof time === "string") {
|
||||
|
@ -431,9 +414,9 @@
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var ds = datastore[metric];
|
||||
|
||||
|
||||
var ret = [];
|
||||
|
||||
for (var i=seriesStart; i<seriesEnd; i+= millis("1 day")) {
|
||||
|
@ -456,7 +439,7 @@
|
|||
|
||||
return Math.ceil((ds.maxdate - ds.mindate) / millis("1 day") / size);
|
||||
},
|
||||
|
||||
|
||||
collapseVersions: function(row, precision) {
|
||||
var out = {
|
||||
count : row.count,
|
||||
|
@ -489,7 +472,7 @@
|
|||
},
|
||||
|
||||
getAvailableFields: function(metric, start, end, callback) {
|
||||
|
||||
|
||||
},
|
||||
|
||||
processRange: function(field, start, end, callback) {
|
||||
|
@ -509,7 +492,7 @@
|
|||
chunk.push(ds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var job = {
|
||||
task: "computeAggregates",
|
||||
data: {
|
||||
|
@ -578,12 +561,12 @@
|
|||
return val;
|
||||
|
||||
},
|
||||
|
||||
|
||||
getPrettyName: function(metric, field) {
|
||||
var parts = field.split('_');
|
||||
var key = parts[0];
|
||||
parts = parts.slice(1);
|
||||
|
||||
|
||||
if (metric in csv_keys) {
|
||||
if (key in csv_keys[metric]) {
|
||||
return csv_keys[metric][key] + ' ' + parts.join(' ');
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
var Storage = (function() {
|
||||
var cookieStorage = {
|
||||
expires: 30, // Number of days
|
||||
getItem: function(key) {
|
||||
return $.cookie(key);
|
||||
},
|
||||
setItem: function(key, value) {
|
||||
return $.cookie(key, value, {path: "/", expires: this.expires});
|
||||
},
|
||||
removeItem: function(key) {
|
||||
return $.cookie(key, null);
|
||||
}
|
||||
};
|
||||
var engine = cookieStorage;
|
||||
try {
|
||||
if ("localStorage" in window && window["localStorage"] !== null) {
|
||||
engine = window.localStorage;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return {
|
||||
get: function(key) {
|
||||
return engine.getItem(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
return engine.setItem(key, value);
|
||||
},
|
||||
remove: function(key) {
|
||||
return engine.removeItem(key);
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -72,7 +72,7 @@ asyncTest('de-select application', function() {
|
|||
|
||||
module('editors MOTD', {
|
||||
setup: function() {
|
||||
window.localStorage['motd_closed'] = '';
|
||||
Storage.remove('motd_closed');
|
||||
this.sandbox = tests.createSandbox('#editors-motd-template');
|
||||
$('.daily-message .close', this.sandbox).hide();
|
||||
initDailyMessage(this.sandbox);
|
||||
|
@ -116,7 +116,7 @@ test('not closable', function() {
|
|||
|
||||
module('editors MOTD after clicking', {
|
||||
setup: function() {
|
||||
window.localStorage['motd_closed'] = 'This is an announcement';
|
||||
Storage.set('motd_closed', 'This is an announcement');
|
||||
this.sandbox = tests.createSandbox('#editors-motd-template');
|
||||
initDailyMessage(this.sandbox);
|
||||
},
|
||||
|
|
|
@ -403,6 +403,7 @@ MINIFY_BUNDLES = {
|
|||
'js/zamboni/tabs.js',
|
||||
|
||||
'js/jquery.cookie.js',
|
||||
'js/storage.js',
|
||||
'js/zamboni/global.js',
|
||||
'js/amo2009/global.js',
|
||||
'js/jquery-ui/jqModal.js',
|
||||
|
@ -455,6 +456,7 @@ MINIFY_BUNDLES = {
|
|||
|
||||
'js/zamboni/truncation.js',
|
||||
'js/jquery.cookie.js',
|
||||
'js/zamboni/storage.js',
|
||||
'js/zamboni/discovery_addons.js',
|
||||
'js/zamboni/discovery_pane.js',
|
||||
),
|
||||
|
@ -464,6 +466,8 @@ MINIFY_BUNDLES = {
|
|||
'js/zamboni/devhub.js',
|
||||
),
|
||||
'zamboni/editors': (
|
||||
'js/jquery.cookie.js',
|
||||
'js/zamboni/storage.js',
|
||||
'js/zamboni/editors.js',
|
||||
),
|
||||
'zamboni/mobile': (
|
||||
|
|
Загрузка…
Ссылка в новой задаче