aboutsummaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorMatthew Somerville <matthew-github@dracos.co.uk>2016-11-29 17:44:04 +0000
committerMatthew Somerville <matthew-github@dracos.co.uk>2016-12-16 10:15:35 +0000
commit34f942d7881451e164431a3231774568421a00f5 (patch)
treeb9ff457f3286413fdd228027b2d4015ef8fd13ff /web
parentfddf7f9585e50a60acca01b84bc8f9cfc267dd0b (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.scss35
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js3
-rw-r--r--web/cobrands/fixmystreet/offline.js276
-rw-r--r--web/cobrands/oxfordshire/base.scss1
-rw-r--r--web/cobrands/sass/_top-banner.scss49
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 &ndash; <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;
+}