diff options
| -rwxr-xr-x | templates/web/base/around/display_location.html | 1 | ||||
| -rw-r--r-- | templates/web/base/report/_main.html | 3 | ||||
| -rw-r--r-- | templates/web/base/report/display.html | 2 | ||||
| -rw-r--r-- | templates/web/base/report/new/fill_in_details.html | 2 | ||||
| -rw-r--r-- | templates/web/base/report/photo-js.html | 12 | ||||
| -rw-r--r-- | templates/web/zurich/report/photo-js.html | 6 | ||||
| -rw-r--r-- | web/cobrands/fixmystreet/fixmystreet.js | 229 | ||||
| -rw-r--r-- | web/cobrands/sass/_base.scss | 25 | ||||
| -rw-r--r-- | web/js/map-OpenLayers.js | 51 | ||||
| -rw-r--r-- | web/js/map-google.js | 2 | 
10 files changed, 282 insertions, 51 deletions
diff --git a/templates/web/base/around/display_location.html b/templates/web/base/around/display_location.html index 0ae1aadf5..d7608f7aa 100755 --- a/templates/web/base/around/display_location.html +++ b/templates/web/base/around/display_location.html @@ -27,6 +27,7 @@          }      ); +    PROCESS "report/photo-js.html";      PROCESS "maps/${map.type}.html" around_page = 1;      sidebar_html = PROCESS 'report/new/sidebar.html' js = 1 report.used_map = 1; diff --git a/templates/web/base/report/_main.html b/templates/web/base/report/_main.html index 4821b3fa0..a07aab214 100644 --- a/templates/web/base/report/_main.html +++ b/templates/web/base/report/_main.html @@ -1,5 +1,8 @@  [% moderating = c.user && c.user.has_permission_to('moderate', problem.bodies_str) %] +<a href="[% c.uri_for( '/around', { lat => latitude, lon => longitude } ) %]" +    class="problem-back js-back-to-report-list">[% loc('Back to all reports') %]</a> +  <div class="problem-header clearfix" problem-id="[% problem.id %]">    [% IF moderating %] diff --git a/templates/web/base/report/display.html b/templates/web/base/report/display.html index e9f0b2914..50c649f9a 100644 --- a/templates/web/base/report/display.html +++ b/templates/web/base/report/display.html @@ -14,6 +14,7 @@  </div>  <div id="map_sidebar"> +  <div id="side-report">  [% IF login_success %]      <p class='form-success'>[% loc('You have successfully signed in; please check and confirm your details are accurate:') %]</p> @@ -43,6 +44,7 @@      [% INCLUDE 'report/update-form.html' %]  [% END %] +  </div>  </div>  [% INCLUDE 'footer.html' %] diff --git a/templates/web/base/report/new/fill_in_details.html b/templates/web/base/report/new/fill_in_details.html index e980c6065..debc2af2d 100644 --- a/templates/web/base/report/new/fill_in_details.html +++ b/templates/web/base/report/new/fill_in_details.html @@ -31,7 +31,7 @@      [% map_html %]      </div>      <div id="map_sidebar"> -        <div id="side"> +        <div id="side-form">    [% ELSE %]      <div id="map_sidebar">          <div id="skipped-map"> diff --git a/templates/web/base/report/photo-js.html b/templates/web/base/report/photo-js.html index 9075ce005..05588d085 100644 --- a/templates/web/base/report/photo-js.html +++ b/templates/web/base/report/photo-js.html @@ -1,8 +1,6 @@ -[% IF c.cobrand.allow_photo_display(problem) %] -    [% extra_css = BLOCK %] -	    <link rel="stylesheet" href="[% version('/js/fancybox/jquery.fancybox-1.3.4.css') %]"> -    [% END %] -    [% extra_js = BLOCK %] -        <script src="[% version('/js/fancybox/jquery.fancybox-1.3.4.pack.js') %]" charset="utf-8"></script> -    [% END %] +[% extra_css = BLOCK %] +    <link rel="stylesheet" href="[% version('/js/fancybox/jquery.fancybox-1.3.4.css') %]"> +[% END %] +[% extra_js = BLOCK %] +    <script src="[% version('/js/fancybox/jquery.fancybox-1.3.4.pack.js') %]" charset="utf-8"></script>  [% END %] diff --git a/templates/web/zurich/report/photo-js.html b/templates/web/zurich/report/photo-js.html deleted file mode 100644 index 05588d085..000000000 --- a/templates/web/zurich/report/photo-js.html +++ /dev/null @@ -1,6 +0,0 @@ -[% extra_css = BLOCK %] -    <link rel="stylesheet" href="[% version('/js/fancybox/jquery.fancybox-1.3.4.css') %]"> -[% END %] -[% extra_js = BLOCK %] -    <script src="[% version('/js/fancybox/jquery.fancybox-1.3.4.pack.js') %]" charset="utf-8"></script> -[% END %] diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index a7a6977bd..b971b423d 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -208,13 +208,23 @@ $.extend(fixmystreet.set_up, {      }).resize();    }, -  dropzone: function() { +  dropzone: function($context) { + +    // Pass a jQuery element, eg $('.foobar'), into this function +    // to limit all the selectors to that element. Handy if you want +    // to only bind/detect Dropzones in a particular part of the page, +    // or if your selectors (eg: "#form_photo") aren't unique across +    // the whole page. +    if (typeof $context === undefined) { +        $context = $(document); +    } +      if ('Dropzone' in window) {        Dropzone.autoDiscover = false;      } -    if ('Dropzone' in window && $('#form_photo').length) { -      var $originalLabel = $('[for="form_photo"]'); -      var $originalInput = $('#form_photos'); +    if ('Dropzone' in window && $('#form_photo', $context).length) { +      var $originalLabel = $('[for="form_photo"]', $context); +      var $originalInput = $('#form_photos', $context);        var $dropzone = $('<div>').addClass('dropzone');        $originalLabel.removeAttr('for'); @@ -241,24 +251,24 @@ $.extend(fixmystreet.set_up, {          },          init: function() {            this.on("addedfile", function(file) { -            $('input[type=submit]').prop("disabled", true).removeClass('green-btn'); +            $('input[type=submit]', $context).prop("disabled", true).removeClass('green-btn');            });            this.on("queuecomplete", function() { -            $('input[type=submit]').removeAttr('disabled').addClass('green-btn'); +            $('input[type=submit]', $context).removeAttr('disabled').addClass('green-btn');            });            this.on("success", function(file, xhrResponse) { -            var ids = $('input[name=upload_fileid]').val().split(','), +            var ids = $('input[name=upload_fileid]', $context).val().split(','),                  id = (file.server_id = xhrResponse.id),                  l = ids.push(id),                  newstr = ids.join(','); -            $('input[name=upload_fileid]').val(newstr); +            $('input[name=upload_fileid]', $context).val(newstr);            });            this.on("error", function(file, errorMessage, xhrResponse) {            });            this.on("removedfile", function(file) { -            var ids = $('input[name=upload_fileid]').val().split(','), +            var ids = $('input[name=upload_fileid]', $context).val().split(','),                  newstr = $.grep(ids, function(n) { return (n!=file.server_id); }).join(','); -            $('input[name=upload_fileid]').val(newstr); +            $('input[name=upload_fileid]', $context).val(newstr);            });            this.on("maxfilesexceeded", function(file) {              this.removeFile(file); @@ -274,7 +284,7 @@ $.extend(fixmystreet.set_up, {          }        }); -      $.each($('input[name=upload_fileid]').val().split(','), function(i, f) { +      $.each($('input[name=upload_fileid]', $context).val().split(','), function(i, f) {          if (!f) {              return;          } @@ -314,7 +324,9 @@ $.extend(fixmystreet.set_up, {          if ($('#sub_map_links').length === 0) {              $('<p id="sub_map_links" />').insertAfter($('#map'));          } -        $('#sub_map_links').append('<a href="#" id="map_permalink">' + translation_strings.permalink + '</a>'); +        if ($('#map_permalink').length === 0) { +            $('#sub_map_links').append('<a href="#" id="map_permalink">' + translation_strings.permalink + '</a>'); +        }      }      if ($('.mobile').length) { @@ -324,22 +336,25 @@ $.extend(fixmystreet.set_up, {          $('#report-updates-data').insertAfter($('#map_box'));      } -    //add open/close toggle button on desk -    $('#sub_map_links').prepend('<span id="map_links_toggle"> </span>'); - -    //set up map_links_toggle click event -    $('#map_links_toggle').on('click', function() { -        var sub_map_links_css = {}, -            left_right = isR2L() ? 'left' : 'right'; -        if ($(this).hasClass('closed')) { -            $(this).removeClass('closed'); -            sub_map_links_css[left_right] = '0'; -        } else { -            $(this).addClass('closed'); -            sub_map_links_css[left_right] = -$('#sub_map_links').width(); -        } -        $('#sub_map_links').animate(sub_map_links_css, 1200); -    }); +    //add open/close toggle button (if its not there) +    if ($('#map_links_toggle').length === 0) { +        $('<span>') +            .html(' ') +            .attr('id', 'map_links_toggle') +            .on('click', function() { +                var sub_map_links_css = {}, +                    left_right = isR2L() ? 'left' : 'right'; +                if ($(this).hasClass('closed')) { +                    $(this).removeClass('closed'); +                    sub_map_links_css[left_right] = '0'; +                } else { +                    $(this).addClass('closed'); +                    sub_map_links_css[left_right] = -$('#sub_map_links').width(); +                } +                $('#sub_map_links').animate(sub_map_links_css, 1200); +            }) +            .prependTo('#sub_map_links'); +    }    },    map_sidebar_key_tools: function() { @@ -439,6 +454,65 @@ $.extend(fixmystreet.set_up, {              queue:false          }).fadeOut(500);      }); +  }, + +  ajax_history: function() { +    $('#map_sidebar').on('click', '.item-list--reports a', function(e) { +        e.preventDefault(); +        var reportPageUrl = $(this).attr('href'); +        var reportId = parseInt(reportPageUrl.replace(/^.*\/([0-9]+)$/, '$1'), 10); + +        // If we've already selected this report +        if (reportId == window.selected_problem_id) { +            return; +        } + +        fixmystreet.display.report(reportPageUrl, reportId, function() { +            // Since this navigation was the result of a user action, +            // we want to record the navigation as a state, so the user +            // can return to it later using their Back button. +            if ('pushState' in history) { +                history.pushState({ +                    reportId: reportId, +                    reportPageUrl: reportPageUrl +                }, null, reportPageUrl); +            } +        }); +    }); + +    $('#map_sidebar').on('click', '.js-back-to-report-list', function(e) { +        e.preventDefault(); +        var reportListUrl = $(this).attr('href'); +        fixmystreet.display.around(reportListUrl, function() { +            // Since this navigation was the result of a user action, +            // we want to record the navigation as a state, so the user +            // can return to it later using their Back button. +            if ('pushState' in history) { +                history.pushState(null, null, reportListUrl); +            } +        }); +    }); + +    window.addEventListener('popstate', function(e) { +        // The user has pressed the Back button, and there is a +        // stored History state for them to return to. + +        // Note: no pushState callbacks in these display_* calls, +        // because we're already inside a popstate: We want to roll +        // back to a previous state, not create a new one! + +        if (e.state === null) { +            // User has navigated Back from a pushStated state, presumably to +            // see the list of all reports (which was shown on pageload). By +            // this point, the browser has *already* updated the URL bar so +            // location.href is something like foo.com/around?pc=abc-123, +            // which we pass into fixmystreet.display.around() as a fallback +            // incase the list isn't already in the DOM. +            fixmystreet.display.around(window.location.href); +        } else if ('reportId' in e.state) { +            fixmystreet.display.report(e.state.reportPageUrl, e.state.reportId); +        } +    });    }  }); @@ -493,7 +567,8 @@ fixmystreet.update_pin = function(lonlat) {  }; -fixmystreet.begin_report = function(lonlat) { +fixmystreet.display = { +  begin_report: function(lonlat) {      fixmystreet.maps.begin_report(lonlat);      // Store pin location in form fields, and check coverage of point @@ -582,10 +657,106 @@ fixmystreet.begin_report = function(lonlat) {      fixmystreet.page = 'new';      location.hash = 'report'; +  }, + +  report: function(reportPageUrl, reportId, callback) { +    $.ajax(reportPageUrl).done(function(html, textStatus, jqXHR) { +        var $reportPage = $(html); +        var $sideReport = $reportPage.find('#side-report'); + +        if ($sideReport.length) { +            $('#side').hide(); // Hide the list of reports +            $('#side-report').remove(); // Remove any existing report page content from sidebar +            $sideReport.appendTo('#map_sidebar'); // Insert this report's content + +            var found = html.match(/<title>([\s\S]*?)<\/title>/); +            var page_title = found[1]; +            document.title = page_title; +            fixmystreet.page = 'report'; + +            fixmystreet.mobile_reporting.remove_ui(); +            if ($('html').hasClass('mobile') && fixmystreet.map.updateSize) { +                fixmystreet.map.updateSize(); +            } + +            // If this is the first individual report we've loaded, remove the +            // "all reports" sub_map_links but store them in a global variable +            // so we can reinsert them when the user returns to the all reports +            // view. With #sub_map_links detached from the DOM, we set up the +            // individual report's sub_map_links using map_controls(). +            if (!('originalSubMapLinks' in window)) { +                window.originalSubMapLinks = $('#sub_map_links').detach(); +            } +            fixmystreet.set_up.map_controls(); + +            $sideReport.find('#key-tool-problems-nearby').addClass('js-back-to-report-list'); +            fixmystreet.set_up.map_sidebar_key_tools(); + +            fixmystreet.set_up.fancybox_images(); +            fixmystreet.set_up.dropzone($sideReport); +            fixmystreet.set_up.form_focus_triggers(); + +            window.selected_problem_id = reportId; +            var marker = fixmystreet.maps.get_marker_by_id(reportId); +            if (fixmystreet.map.panTo && ($('html').hasClass('mobile') || !marker.onScreen())) { +                fixmystreet.map.panTo( +                    marker.geometry.getBounds().getCenterLonLat() +                ); +            } +            if (fixmystreet.maps.markers_resize) { +                fixmystreet.maps.markers_resize(); // force a redraw so the selected marker gets bigger +            } + +            if (typeof callback === 'function') { +                callback(); +            } + +        } else { +            window.location.href = reportPageUrl; +        } + +    }).fail(function(jqXHR, textStatus, errorThrown) { +        window.location.href = reportPageUrl; + +    }); +  }, + +  around: function(reportListUrl, callback) { +    // If the report list is already in the DOM, +    // just reveal it, rather than loading new page. +    if ($('#side').length) { +        $('#side').show(); +        $('#side-report').remove(); + +        document.title = fixmystreet.original_title; +        fixmystreet.page = 'around'; +        if ($('html').hasClass('mobile')) { +            fixmystreet.mobile_reporting.apply_ui(); +            fixmystreet.map.updateSize(); +        } + +        if ('originalSubMapLinks' in window) { +            $('#sub_map_links').replaceWith(window.originalSubMapLinks); +            delete window.originalSubMapLinks; +        } +        fixmystreet.set_up.map_controls(); + +        window.selected_problem_id = undefined; +        fixmystreet.markers.refresh({force: true}); // force a redraw to return (de)selected marker to normal size + +        if (typeof callback === 'function') { +            callback(); +        } +    } else { +        window.location.href = reportListUrl; +    } +  }  }; +  $(function() {      window.cobrand = $('meta[name="cobrand"]').attr('content'); +    fixmystreet.original_title = document.title;      if (typeof variation !== 'undefined' && variation === 1) {          $('input[name=variant]').val(1); diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss index 6fd2c6a7b..c5f9db467 100644 --- a/web/cobrands/sass/_base.scss +++ b/web/cobrands/sass/_base.scss @@ -995,6 +995,22 @@ input.final-submit {    }  } +.problem-back { +  display: block; +  font-size: 1em; +  line-height: 1.2em; +  margin-bottom: 1em; +  padding-bottom: 0.8em; +  padding-#{$left}: 22px; +  background: transparent url(/cobrands/fixmystreet/images/chevron-grey-#{$left}.svg) #{$left} 0 no-repeat; +  background-size: 13px 16px; +  border-bottom: 1px solid #eee; + +  &:link, &:visited, &:hover { +    color: #666; +  } +} +  .problem-header {    margin-bottom: 1em;  } @@ -1731,6 +1747,15 @@ table.nicetable {      float: left; // float fallback for browsers that don't support flexbox      flex: 1 0 auto; +    @media(max-width: 400px){ +      // Shameful hack to stop the control expanding wider than the window +      // on narrow devices (eg: 320px iPhone), which would cause horizontal +      // scrolling, and clipped text on the new report page, for example. +      // Flexbox will add the spacing back in anyway. Ideally we'd only apply +      // this style if flexbox is supported, but there's no easy way to do that. +      padding: 0.75em 0; +    } +      &:hover, &:focus {        background: #f3f3f3 linear-gradient(to bottom, #f9f9f9 0%, #e9e9e9 100%) 0 0 no-repeat;      } diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 345ebeced..872956716 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -38,7 +38,12 @@ var fixmystreet = fixmystreet || {};        markers_list: function(pins, transform) {          var markers = []; -        var size = fixmystreet.maps.marker_size_for_zoom(fixmystreet.map.getZoom() + fixmystreet.zoomOffset); +        var size = fixmystreet.maps.marker_size_for_zoom( +            fixmystreet.map.getZoom() + fixmystreet.zoomOffset +        ); +        var selected_size = fixmystreet.maps.selected_marker_size_for_zoom( +            fixmystreet.map.getZoom() + fixmystreet.zoomOffset +        );          for (var i=0; i<pins.length; i++) {              var pin = pins[i];              var loc = new OpenLayers.Geometry.Point(pin[1], pin[0]); @@ -49,9 +54,10 @@ var fixmystreet = fixmystreet || {};                      fixmystreet.map.getProjectionObject()                  );              } +            var marker_size = (pin[3] === window.selected_problem_id) ? selected_size : size;              var marker = new OpenLayers.Feature.Vector(loc, {                  colour: pin[2], -                size: pin[5] || size, +                size: pin[5] || marker_size,                  faded: 0,                  id: pin[3],                  title: pin[4] || '' @@ -62,21 +68,44 @@ var fixmystreet = fixmystreet || {};        },        markers_resize: function() { -        var size = fixmystreet.maps.marker_size_for_zoom(fixmystreet.map.getZoom() + fixmystreet.zoomOffset); +        var size = fixmystreet.maps.marker_size_for_zoom( +            fixmystreet.map.getZoom() + fixmystreet.zoomOffset +        ); +        var selected_size = fixmystreet.maps.selected_marker_size_for_zoom( +            fixmystreet.map.getZoom() + fixmystreet.zoomOffset +        );          for (var i = 0; i < fixmystreet.markers.features.length; i++) { -            fixmystreet.markers.features[i].attributes.size = size; +            if (fixmystreet.markers.features[i].attributes.id == window.selected_problem_id) { +                fixmystreet.markers.features[i].attributes.size = selected_size; +            } else { +                fixmystreet.markers.features[i].attributes.size = size; +            }          }          fixmystreet.markers.redraw();        }, +      get_marker_by_id: function(problem_id) { +        return fixmystreet.markers.getFeaturesByAttribute('id', problem_id)[0]; +      }, +        marker_size_for_zoom: function(zoom) {          if (zoom >= 15) { -            return 'normal'; +            return window.selected_problem_id ? 'small' : 'normal';          } else if (zoom >= 13) { -            return 'small'; +            return window.selected_problem_id ? 'mini' : 'small';          } else {              return 'mini';          } +      }, + +      selected_marker_size_for_zoom: function(zoom) { +        if (zoom >= 15) { +            return 'big'; +        } else if (zoom >= 13) { +            return 'normal'; +        } else { +            return 'small'; +        }        }      }; @@ -671,8 +700,16 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {      },      trigger: function(e) { +        // If we are looking at an individual report, and the report was +        // ajaxed into the DOM from the all reports page, then clicking +        // the map background should take us back to the all reports list. +        if ($('.js-back-to-report-list').length) { +            $('.js-back-to-report-list').trigger('click'); +            return true; +        } +          var lonlat = fixmystreet.map.getLonLatFromViewPortPx(e.xy); -        fixmystreet.begin_report(lonlat); +        fixmystreet.display.begin_report(lonlat);          if ( typeof ga !== 'undefined' && window.cobrand == 'fixmystreet' ) {              ga('send', 'pageview', { 'page': '/map_click' } ); diff --git a/web/js/map-google.js b/web/js/map-google.js index a00d52ba1..fa2b6d90e 100644 --- a/web/js/map-google.js +++ b/web/js/map-google.js @@ -82,7 +82,7 @@ fixmystreet.maps = {};      function map_clicked(e) {          var lonlat = e.latLng; -        fixmystreet.begin_report(lonlat); +        fixmystreet.display.begin_report(lonlat);      }      /* Pan data handler */  | 
