Storage object for managing localStorage and cookies (bug 491800)

This commit is contained in:
Chris Van 2011-03-17 20:01:40 -04:00
Родитель 5979c77d50
Коммит 98ed26bd1b
8 изменённых файлов: 99 добавлений и 121 удалений

Просмотреть файл

@ -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': (