diff options
author | Matthew Somerville <matthew-github@dracos.co.uk> | 2016-11-29 17:44:04 +0000 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2016-12-16 10:15:35 +0000 |
commit | 34f942d7881451e164431a3231774568421a00f5 (patch) | |
tree | b9ff457f3286413fdd228027b2d4015ef8fd13ff /web | |
parent | fddf7f9585e50a60acca01b84bc8f9cfc267dd0b (diff) |
Store/show shortlisted reports offline.
This:
* On an online visit to /my/planned, caches all shortlisted reports,
their images and static maps in localStorage, with progress banner;
* When a report is added/removed from the shortlist, caches/de-caches
that report;
* When viewing a report page offline, shows that page from the cache
if present (replacing the dynamic map with the cached static map, and
replacing report images with their cached equivalents – it is a shame
to duplicate, but we cannot rely on the browser cache having these images);
* When viewing another page offline, shows an error message but also the
list of shortlisted reports that are cached (again, replacing their
thumbnail images with the cached versions).
Diffstat (limited to 'web')
-rw-r--r-- | web/cobrands/fixmystreet.com/base.scss | 35 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/fixmystreet.js | 3 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/offline.js | 276 | ||||
-rw-r--r-- | web/cobrands/oxfordshire/base.scss | 1 | ||||
-rw-r--r-- | web/cobrands/sass/_top-banner.scss | 49 |
5 files changed, 329 insertions, 35 deletions
diff --git a/web/cobrands/fixmystreet.com/base.scss b/web/cobrands/fixmystreet.com/base.scss index 905f20f41..5b703c3d2 100644 --- a/web/cobrands/fixmystreet.com/base.scss +++ b/web/cobrands/fixmystreet.com/base.scss @@ -7,40 +7,7 @@ @import "../sass/h5bp"; @import "_colours"; @import "../sass/base"; - -.top_banner { - color: $primary_text; - background: $primary; - p { - margin: auto; - padding: 0.5em 2em; - max-width: 50em; - text-align: center; - } - a { - color: $primary_text; - text-decoration: underline; - } -} - -.top_banner--donate { - background: #bef; -} - -// The banner interferes with the map moving/placement on mobile, and the top -// bar navigation on desktop (which both assume that .wrapper is at the top of -// the page) so hide there for now -.mappage .top_banner--donate { - display: none; -} - -// This banner is only shown via JavaScript AJAX call -.top_banner--country { - display: none; -} -.top_banner__close { - float: $right; -} +@import "../sass/top-banner"; #site-logo { background: url('data:image/png;base64,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') no-repeat; diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index cd3b127d6..cd2a066e3 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -316,6 +316,7 @@ $.extend(fixmystreet.set_up, { $change = $form.find("input[name='change']" ), $submit = $form.find("input[type='submit']" ), $labels = $('label[for="' + $submit.attr('id') + '"]'), + problemId = $form.find("input[name='id']").val(), data = $form.serialize() + '&ajax=1', changeValue, buttonLabel, @@ -327,10 +328,12 @@ $.extend(fixmystreet.set_up, { buttonLabel = $submit.data('label-remove'); buttonValue = $submit.data('value-remove'); $('.shortlisted-status').remove(); + $(document).trigger('shortlist-add', problemId); } else if (data.outcome == 'remove') { changeValue = "add"; buttonLabel = $submit.data('label-add'); buttonValue = $submit.data('value-add'); + $(document).trigger('shortlist-remove', problemId); } $change.val(changeValue); $submit.val(buttonValue).attr('aria-label', buttonLabel); diff --git a/web/cobrands/fixmystreet/offline.js b/web/cobrands/fixmystreet/offline.js index 4b3373029..23db5d472 100644 --- a/web/cobrands/fixmystreet/offline.js +++ b/web/cobrands/fixmystreet/offline.js @@ -1,5 +1,279 @@ -if (!$('#offline_list').length) { +fixmystreet.offlineBanner = (function() { + var toCache = 0; + var cachedSoFar = 0; + + return { + make: function(offline) { + var banner = ['<div class="top_banner top_banner--offline"><p><span id="offline_saving">']; + banner.push('</span></p></div>'); + banner = $(banner.join('')); + banner.prependTo('.content'); + banner.hide(); + }, + startProgress: function(l) { + $('.top_banner--offline').slideDown(); + toCache = l; + $('#offline_saving').html('Saving reports offline – <span>0</span>/' + toCache + '.'); + }, + progress: function() { + cachedSoFar += 1; + if (cachedSoFar === toCache) { + $('#offline_saving').text('Reports saved offline.'); + } else { + $('#offline_saving span').text(cachedSoFar); + } + } + }; +})(); + +fixmystreet.offlineData = (function() { + var data; + + function getData() { + if (data === undefined) { + data = JSON.parse(localStorage.getItem('offlineData')); + if (!data) { + data = { cachedReports: {} }; + } + } + return data; + } + + function saveData() { + localStorage.setItem('offlineData', JSON.stringify(getData())); + } + + return { + getCachedUrls: function() { + return Object.keys(getData().cachedReports); + }, + isIndexed: function(url, lastupdate) { + if (lastupdate) { + return getData().cachedReports[url] === lastupdate; + } + return !!getData().cachedReports[url]; + }, + add: function(url, lastupdate) { + var data = getData(); + data.cachedReports[url] = lastupdate || "-"; + saveData(); + }, + remove: function(urls) { + var data = getData(); + urls.forEach(function(url) { + delete data.cachedReports[url]; + }); + saveData(); + } + }; +})(); + +fixmystreet.cachet = (function(){ + var urlsInProgress = {}; + + function cacheURL(url, type) { + urlsInProgress[url] = 1; + + var ret; + if (type === 'image') { + ret = $.Deferred(function(deferred) { + var oReq = new XMLHttpRequest(); + oReq.open("GET", url, true); + oReq.responseType = "blob"; + oReq.onload = function(oEvent) { + var blob = oReq.response; + var reader = new window.FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function() { + localStorage.setItem(url, reader.result); + delete urlsInProgress[url]; + deferred.resolve(blob); + }; + }; + oReq.send(); + }); + } else { + ret = $.ajax(url).pipe(function(content, textStatus, jqXHR) { + localStorage.setItem(url, content); + delete urlsInProgress[url]; + return content; + }); + } + return ret; + } + + function cacheReport(item) { + return cacheURL(item.url, 'html').pipe(function(html) { + var $reportPage = $(html); + var imagesToGet = [ + 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]) { + return; + } + imagesToGet.push(img.src); + imagesToGet.push(img.src.replace('.jpeg', '.fp.jpeg')); + }); + var imagePromises = imagesToGet.map(function(url) { + return cacheURL(url, 'image'); + }); + return $.when.apply(undefined, imagePromises).pipe(function() { + fixmystreet.offlineBanner.progress(); + fixmystreet.offlineData.add(item.url, item.lastupdate); + }, function() { + fixmystreet.offlineBanner.progress(); + fixmystreet.offlineData.add(item.url, item.lastupdate); + }); + }); + } + + // Cache a list of reports offline + // This fetches the HTML and any img elements in that HTML + function cacheReports(items) { + fixmystreet.offlineBanner.startProgress(items.length); + var promises = items.map(function(item) { + return cacheReport(item); + }); + return $.when.apply(undefined, promises); + } + + return { + cacheReports: cacheReports + }; +})(); + +fixmystreet.offline = (function() { + function getReportsFromList() { + var reports = $('.item-list__item').map(function(i, li) { + var $li = $(li), + url = $li.find('a')[0].pathname, + lastupdate = $li.data('lastupdate'); + return { 'url': url, 'lastupdate': lastupdate }; + }).get(); + return reports; + } + + function updateCachedReports() { + var toCache = []; + var toRemove = []; + var shouldBeCached = {}; + + localStorage.setItem('/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.getCachedUrls().forEach(function(url) { + if ( !shouldBeCached[url] ) { + toRemove.push(url); + } + }); + + if (toRemove[0]) { + removeReports(toRemove); + } + if (toCache[0]) { + fixmystreet.cachet.cacheReports(toCache); + } + } + + // Remove a list of reports from the offline cache + function removeReports(urls) { + var pathsRemoved = []; + urls.forEach(function(url) { + var html = localStorage.getItem(url); + var $reportPage = $(html); + localStorage.removeItem(url + '/map'); + $reportPage.find('img').each(function(i, img) { + if (img.src.indexOf('/photo/') === -1) { + return; + } + localStorage.removeItem(img.src); + localStorage.removeItem(img.src.replace('.jpeg', '.fp.jpeg')); + }); + localStorage.removeItem(url); + }); + fixmystreet.offlineData.remove(urls); + } + + function showReportFromCache(url) { + var html = localStorage.getItem(url); + if (!html) { + return false; + } + var map = localStorage.getItem(url + '/map'); + var found = html.match(/<body[^>]*>[\s\S]*<\/body>/); + document.body.outerHTML = found[0]; + $('#map_box').html('<img src="' + map + '">').css({ textAlign: 'center', height: 'auto' }); + replaceImages('img'); + + $('.moderate-display.segmented-control, .shadow-wrap, #update_form, #report-cta, .mysoc-footer, .nav-wrapper').hide(); + + $('.js-back-to-report-list').attr('href', '/my/planned'); + + return true; + } + + function replaceImages(selector) { + $(selector).each(function(i, img) { + if (img.src.indexOf('/photo/') > -1) { + var dataImg = localStorage.getItem(img.src); + if (dataImg) { + img.src = dataImg; + } + } + }); + } + + return { + replaceImages: replaceImages, + showReportFromCache: showReportFromCache, + removeReports: removeReports, + updateCachedReports: updateCachedReports + }; + +})(); + +if ($('#offline_list').length) { + // We are OFFLINE + var success = false; + if (location.pathname.indexOf('/report') === 0) { + success = fixmystreet.offline.showReportFromCache(location.pathname); + } + if (!success) { + var html = localStorage.getItem('/my/planned'); + if (html) { + $('#offline_list').before('<h2>Your offline reports</h2>'); + $('#offline_list').html(html); + fixmystreet.offline.replaceImages('#offline_list img'); + } + } + fixmystreet.offlineBanner.make(true); +} else { + // Put the appcache manifest in a page in an iframe so that HTML pages + // aren't cached (thanks to Jake Archibald for documenting this!) if (window.applicationCache && window.localStorage) { $(document.body).prepend('<iframe src="/offline/appcache" style="position:absolute;top:-999em;visibility:hidden"></iframe>'); } + + fixmystreet.offlineBanner.make(false); + + // On /my/planned, when online, cache all shortlisted + if (location.pathname === '/my/planned') { + fixmystreet.offline.updateCachedReports(); + } + + // Catch additions and removals from the shortlist + $(document).on('shortlist-add', function(e, id) { + var lastupdate = $('.problem-header').data('lastupdate'); + fixmystreet.cachet.cacheReports([{ 'url': '/report/' + id, 'lastupdate': lastupdate }]); + }); + $(document).on('shortlist-remove', function(e, id) { + fixmystreet.offline.removeReports(['/report/' + id]); + }); } diff --git a/web/cobrands/oxfordshire/base.scss b/web/cobrands/oxfordshire/base.scss index 955c341bf..34b7dc809 100644 --- a/web/cobrands/oxfordshire/base.scss +++ b/web/cobrands/oxfordshire/base.scss @@ -3,6 +3,7 @@ @import "../sass/mixins"; @import "../sass/base"; +@import "../sass/top-banner"; #site-header { background: none; diff --git a/web/cobrands/sass/_top-banner.scss b/web/cobrands/sass/_top-banner.scss new file mode 100644 index 000000000..8677343c2 --- /dev/null +++ b/web/cobrands/sass/_top-banner.scss @@ -0,0 +1,49 @@ +.top_banner { + color: $primary_text; + background: $primary; + p { + margin: auto; + padding: 0.5em 2em; + max-width: 50em; + text-align: center; + } + a { + color: $primary_text; + text-decoration: underline; + } +} + +.top_banner--donate { + background: #bef; +} + +// The banner interferes with the map moving/placement on mobile, and the top +// bar navigation on desktop (which both assume that .wrapper is at the top of +// the page) so hide there for now +.mappage .top_banner--donate { + display: none; +} + +// This banner is only shown via JavaScript AJAX call +.top_banner--country { + display: none; +} + +.top_banner--offline { + position: fixed; left: 0; right: 0; top: 0; z-index: 100; + opacity: 0.9; + background: #c33; + color: #fff; +} + +.top_banner--offline a { + color: #fff; +} + +.top_banner--offline a:hover { + color: #000; +} + +.top_banner__close { + float: $right; +} |