Skip to content

Commit

Permalink
Replace localStorage with indexedDB.
Browse files Browse the repository at this point in the history
  • Loading branch information
dracos committed Feb 14, 2020
1 parent 643d97c commit 4cb4248
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 125 deletions.
1 change: 1 addition & 0 deletions templates/web/base/common_scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
END;
IF c.user.has_body_permission_to('planned_reports');
scripts.push(
'https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js',
version('/cobrands/fixmystreet/offline.js'),
);
END;
Expand Down
269 changes: 144 additions & 125 deletions web/cobrands/fixmystreet/offline.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ fixmystreet.offlineBanner = (function() {
}

// Note this non-global way of handling plurals may need looking at in future
function formText() {
var num = fixmystreet.offlineData.getForms().length;
function formText(num) {
if ( num === 1 ) {
return num + ' ' + translation_strings.offline.update_single;
} else {
return num + ' ' + translation_strings.offline.update_plural;
}
}

function onlineText() {
return sprintf(translation_strings.offline.saved_to_submit, formText());
function onlineText(num) {
return sprintf(translation_strings.offline.saved_to_submit, formText(num));
}

function offlineText() {
return translation_strings.offline.you_are_offline + ' \u2013 ' + sprintf(translation_strings.offline.N_saved, formText());
function offlineText(num) {
return translation_strings.offline.you_are_offline + ' \u2013 ' + sprintf(translation_strings.offline.N_saved, formText(num));
}

function remove() {
Expand All @@ -31,24 +30,29 @@ fixmystreet.offlineBanner = (function() {

return {
make: function(offline) {
var num = fixmystreet.offlineData.getForms().length;
var banner = ['<div class="top_banner top_banner--offline"><p><span id="offline_saving"></span> <span id="offline_forms">'];
if (offline || num > 0) {
banner.push(offline ? offlineText() : onlineText());
}
banner.push('</span></p></div>');
banner = $(banner.join(''));
banner.prependTo('.content');
if (num === 0) {
banner.hide();
}
fixmystreet.offlineData.getFormsLength().then(function(num) {
var banner = ['<div class="top_banner top_banner--offline"><p><span id="offline_saving"></span> <span id="offline_forms">'];
if (offline || num > 0) {
banner.push(offline ? offlineText(num) : onlineText(num));
}
banner.push('</span></p></div>');
banner = $(banner.join(''));
banner.prependTo('.content');
if (num === 0) {
banner.hide();
}
});

window.addEventListener("offline", function(e) {
$('#offline_forms').html(offlineText());
fixmystreet.offlineData.getFormsLength().then(function(num) {
$('#offline_forms').html(offlineText(num));
});
});

window.addEventListener("online", function(e) {
$('#offline_forms').html(onlineText());
fixmystreet.offlineData.getFormsLength().then(function(num) {
$('#offline_forms').html(onlineText(num));
});
});

function nextForm(DataOrJqXHR, textStatus, jqXHROrErrorThrown) {
Expand All @@ -62,37 +66,41 @@ fixmystreet.offlineBanner = (function() {

$(document).on('click', '#oFN', function(e) {
e.preventDefault();
fixmystreet.offlineData.getForms().forEach(function(form) {
$(document).queue('postForm', function() {
postForm(form[0], form[1]).fail(function(jqXHR) {
if (jqXHR.status !== 400) {
return nextForm();
}
// In case the request failed due to out-of-date CSRF token,
// try once more with a new token given in the error response.
var m = jqXHR.responseText.match(/content="([^"]*)" name="csrf-token"/);
if (!m) {
return nextForm();
}
var token = m[1];
if (!token) {
return nextForm();
}
var param = form[1].replace(/&token=[^&]*/, '&token=' + token);
return postForm(form[0], param).fail(nextForm);
fixmystreet.offlineData.getForms().then(function(forms) {
console.log(forms);
forms.forEach(function(form) {
$(document).queue('postForm', function() {
postForm(form[0], form[1]).fail(function(jqXHR) {
if (jqXHR.status !== 400) {
return nextForm();
}
// In case the request failed due to out-of-date CSRF token,
// try once more with a new token given in the error response.
var m = jqXHR.responseText.match(/content="([^"]*)" name="csrf-token"/);
if (!m) {
return nextForm();
}
var token = m[1];
if (!token) {
return nextForm();
}
var param = form[1].replace(/&token=[^&]*/, '&token=' + token);
return postForm(form[0], param).fail(nextForm);
});
});
});
$(document).dequeue('postForm');
});
$(document).dequeue('postForm');
});
},
update: function() {
$('.top_banner--offline').slideDown();
$('#offline_forms span').text(formText());
var num = fixmystreet.offlineData.getForms().length;
if (num === 0) {
window.setTimeout(remove, 3000);
}
fixmystreet.offlineData.getFormsLength().then(function(num) {
$('#offline_forms span').text(formText(num));
if (num === 0) {
window.setTimeout(remove, 3000);
}
});
},
startProgress: function(l) {
$('.top_banner--offline').slideDown();
Expand All @@ -115,61 +123,64 @@ fixmystreet.offlineData = (function() {
var data;

function getData() {
if (data === undefined) {
data = JSON.parse(localStorage.getItem('offlineData'));
if (!data) {
data = { cachedReports: {}, forms: [] };
}
if (data !== undefined) {
return Promise.resolve(data);
}
return data;
return idbKeyval.get('offlineData').then(function(d) {
data = d || { cachedReports: {}, forms: [] };
return data;
});
}

function saveData() {
localStorage.setItem('offlineData', JSON.stringify(getData()));
function updateData(cb) {
getData().then(function(data) {
cb(data);
idbKeyval.set('offlineData', data);
});
}

return {
getFormsLength: function() {
return getData().then(function(data) { return data.forms.length; });
},
getForms: function() {
return getData().forms;
return getData().then(function(data) { return data.forms; });
},
addForm: function(action, formData) {
var forms = getData().forms;
if (!forms.length || formData != forms[forms.length - 1][1]) {
forms.push([action, formData]);
saveData();
}
fixmystreet.offlineBanner.update();
updateData(function(data) {
var forms = data.forms;
if (!forms.length || formData != forms[forms.length - 1][1]) {
forms.push([action, formData]);
}
fixmystreet.offlineBanner.update();
});
},
shiftForm: function(idx) {
getData().forms.shift();
saveData();
fixmystreet.offlineBanner.update();
updateData(function(data) {
data.forms.shift();
fixmystreet.offlineBanner.update();
});
},
clearForms: function(idx) {
getData().forms = [];
saveData();
fixmystreet.offlineBanner.update();
},
getCachedUrls: function() {
return Object.keys(getData().cachedReports);
updateData(function(data) {
data.forms = [];
fixmystreet.offlineBanner.update();
});
},
isIndexed: function(url, lastupdate) {
if (lastupdate) {
return getData().cachedReports[url] === lastupdate;
}
return !!getData().cachedReports[url];
getCachedReports: function() {
return getData().then(function(data) { return data.cachedReports; });
},
add: function(url, lastupdate) {
var data = getData();
data.cachedReports[url] = lastupdate || "-";
saveData();
updateData(function(data) {
data.cachedReports[url] = lastupdate || "-";
});
},
remove: function(urls) {
var data = getData();
urls.forEach(function(url) {
delete data.cachedReports[url];
updateData(function(data) {
urls.forEach(function(url) {
delete data.cachedReports[url];
});
});
saveData();
}
};
})();
Expand Down Expand Up @@ -200,7 +211,7 @@ fixmystreet.cachet = (function(){
item.url + '/map' // Static map image
];
$reportPage.find('img').each(function(i, img) {
if (img.src.indexOf('/photo/') === -1 || fixmystreet.offlineData.isIndexed(img.src) || urlsInProgress[img.src]) {
if (img.src.indexOf('/photo/') === -1 || urlsInProgress[img.src]) {
return;
}
imagesToGet.push(img.src);
Expand Down Expand Up @@ -247,27 +258,30 @@ fixmystreet.offline = (function() {
var toRemove = [];
var shouldBeCached = {};

localStorage.setItem('/my/planned', $('.item-list').html());
idbKeyval.set('/my/planned', $('.item-list').html());

getReportsFromList().forEach(function(item, i) {
if (!fixmystreet.offlineData.isIndexed(item.url, item.lastupdate)) {
toCache.push(item);
}
shouldBeCached[item.url] = 1;
});
fixmystreet.offlineData.getCachedReports().then(function(reports) {
getReportsFromList().forEach(function(item, i) {
var t = reports[item.url];
if (t !== item.lastupdate) {
toCache.push(item);
}
shouldBeCached[item.url] = 1;
});

Object.keys(reports).forEach(function(url) {
if ( !shouldBeCached[url] ) {
toRemove.push(url);
}
});

fixmystreet.offlineData.getCachedUrls().forEach(function(url) {
if ( !shouldBeCached[url] ) {
toRemove.push(url);
if (toRemove[0]) {
removeReports(toRemove);
}
if (toCache[0]) {
fixmystreet.cachet.cacheReports(toCache);
}
});

if (toRemove[0]) {
removeReports(toRemove);
}
if (toCache[0]) {
fixmystreet.cachet.cacheReports(toCache);
}
}

// Remove a list of reports from the offline cache
Expand Down Expand Up @@ -299,20 +313,22 @@ fixmystreet.offline = (function() {
$('.js-back-to-report-list').attr('href', '/my/planned');

// Refill form with saved data if there is any
var savedForm;
fixmystreet.offlineData.getForms().forEach(function(form) {
if (form[0].endsWith(url)) {
savedForm = form[1];
}
});
if (savedForm) {
savedForm.replace(/\+/g, '%20').split('&').forEach(function(kv) {
kv = kv.split('=', 2);
if (kv[0] != 'include_update' && kv[0] != 'public_update' && kv[0] != 'save') {
$('[name=' + kv[0] + ']').val(decodeURIComponent(kv[1]));
fixmystreet.offlineData.getForms().then(function(forms) {
var savedForm;
forms.forEach(function(form) {
if (form[0].endsWith(url)) {
savedForm = form[1];
}
});
}
if (savedForm) {
savedForm.replace(/\+/g, '%20').split('&').forEach(function(kv) {
kv = kv.split('=', 2);
if (kv[0] != 'include_update' && kv[0] != 'public_update' && kv[0] != 'save') {
$('[name=' + kv[0] + ']').val(decodeURIComponent(kv[1]));
}
});
}
});

// If we catch the form submit, e.g. Chrome still seems to
// try and submit and we get the Chrome offline error page
Expand Down Expand Up @@ -343,33 +359,36 @@ if (!navigator.onLine && location.pathname.indexOf('/report') === 0) {

if ($('#offline_list').length) {
// We are OFFLINE
var html = localStorage.getItem('/my/planned');
if (html) {
idbKeyval.get('/my/planned').then(function(html) {
if (!html) { return; }
$('#offline_list').before('<h2>'+translation_strings.offline.your_reports+'</h2>');
$('#offline_list').html(html);
if (location.search.indexOf('saved=1') > 0) {
$('#offline_list').before('<p class="form-success">'+translation_strings.offline.update_saved+'</p>');
}
var offlineForms = fixmystreet.offlineData.getForms();
var savedForms = {};
offlineForms.forEach(function(form) {
savedForms[form[0]] = 1;
});
$('#offline_list a').each(function(i, a) {
if (savedForms[a.href]) {
$(this).find('h3').prepend('<em>'+translation_strings.offline.update_data_saved+'</em> ');
}
fixmystreet.offlineData.getForms().then(function(offlineForms) {
var savedForms = {};
offlineForms.forEach(function(form) {
savedForms[form[0]] = 1;
});
$('#offline_list a').each(function(i, a) {
if (savedForms[a.href]) {
$(this).find('h3').prepend('<em>'+translation_strings.offline.update_data_saved+'</em> ');
}
});
});
$('#offline_clear').css('margin-top', '5em').html('<button id="js-clear-localStorage">'+translation_strings.offline.clear_data+'</button>');
$('#js-clear-localStorage').click(function() {
$('#offline_clear').css('margin-top', '5em').html('<button id="js-clear-storage">'+translation_strings.offline.clear_data+'</button>');
$('#js-clear-storage').click(function() {
if (window.confirm(translation_strings.offline.are_you_sure)) {
fixmystreet.offline.removeReports(fixmystreet.offlineData.getCachedUrls());
fixmystreet.offlineData.getCachedReports().then(function(reports) {
fixmystreet.offline.removeReports(Object.keys(reports));
});
fixmystreet.offlineData.clearForms();
localStorage.removeItem('/my/planned');
idbKeyval.del('/my/planned');
alert(translation_strings.offline.data_cleared);
}
});
}
});
fixmystreet.offlineBanner.make(true);
} else {
fixmystreet.offlineBanner.make(false);
Expand Down

0 comments on commit 4cb4248

Please sign in to comment.