diff options
44 files changed, 1804 insertions, 1537 deletions
diff --git a/templates/web/angus/maps/fms.html b/templates/web/angus/maps/fms.html index 53e2d8195..a47a5a6e3 100644 --- a/templates/web/angus/maps/fms.html +++ b/templates/web/angus/maps/fms.html @@ -4,7 +4,6 @@ <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-bing-ol.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-fms.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> <script src="[% version('/cobrands/angus/position_map.js') %]" charset="utf-8"></script> [% END %] diff --git a/templates/web/base/around/display_location.html b/templates/web/base/around/display_location.html index 737a44c34..ed4ce209c 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/common_header_tags.html b/templates/web/base/common_header_tags.html index 184e2c297..cef93770f 100644 --- a/templates/web/base/common_header_tags.html +++ b/templates/web/base/common_header_tags.html @@ -8,12 +8,14 @@ <script type="text/javascript" src="[% start %]/js/translation_strings.[% lang_code %].js?[% Math.int( date.now / 3600 ) %]"></script> <script type="text/javascript" src="[% version('/jslib/jquery-1.7.2.min.js') %]"></script> +<!--[if lte IE 9]> + <script type="text/javascript" src="[% version('/js/history.polyfill.min.js') %]"></script> +<![endif]--> <script type="text/javascript" src="[% version('/js/validation_rules.js') %]"></script> <script src="[% version('/js/jquery.validate.min.js') %]" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" src="[% version('/js/dropzone.min.js') %]"></script> <script type="text/javascript" src="[% version('/js/geo.min.js') %]"></script> -<script type="text/javascript" src="[% version('/js/fixmystreet.js') %]"></script> <script type="text/javascript" src="[% version('/cobrands/fixmystreet/fixmystreet.js') %]"></script> [% IF admin %] diff --git a/templates/web/base/front/javascript.html b/templates/web/base/front/javascript.html index 869e5f676..b24c7493f 100644 --- a/templates/web/base/front/javascript.html +++ b/templates/web/base/front/javascript.html @@ -9,7 +9,6 @@ Modernizr.load({ "preload![% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]", "preload![% version('/js/map-OpenLayers.js') %]", "preload![% version('/js/map-OpenStreetMap.js') %]", - "preload![% version('/js/jquery.ba-hashchange.min.js') %]" ] }); </script> diff --git a/templates/web/base/maps/bing.html b/templates/web/base/maps/bing.html index 95ec233e8..6af4c3562 100644 --- a/templates/web/base/maps/bing.html +++ b/templates/web/base/maps/bing.html @@ -3,7 +3,6 @@ <script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-bing-ol.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = INCLUDE maps/openlayers.html %] diff --git a/templates/web/base/maps/fms.html b/templates/web/base/maps/fms.html index aeb8343d0..03eb843da 100644 --- a/templates/web/base/maps/fms.html +++ b/templates/web/base/maps/fms.html @@ -4,7 +4,6 @@ <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-bing-ol.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-fms.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = INCLUDE maps/openlayers.html include_key = 1 %] diff --git a/templates/web/base/maps/google-ol.html b/templates/web/base/maps/google-ol.html index ec3383d5e..cccea5b24 100644 --- a/templates/web/base/maps/google-ol.html +++ b/templates/web/base/maps/google-ol.html @@ -3,7 +3,6 @@ <script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.google.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-google-ol.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_sub_links = BLOCK %] diff --git a/templates/web/base/maps/google.html b/templates/web/base/maps/google.html index 741edec40..86ca51fab 100644 --- a/templates/web/base/maps/google.html +++ b/templates/web/base/maps/google.html @@ -9,12 +9,12 @@ </style> <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script> <script type="text/javascript" src="[% version('/js/map-google.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] <script type="text/javascript"> -var fixmystreet = { +var fixmystreet = fixmystreet || {}; +$.extend(fixmystreet, { 'page': '[% page %]', 'area': [ [% map.area.join(',') %] ], 'all_pins': '[% all_pins %]', @@ -27,7 +27,7 @@ var fixmystreet = { 'zoom': [% map.zoom %], [%- END %] 'pins': [% INCLUDE maps/pins_js.html %] -} +}); </script> <div id="map_box"> [% pre_map %] diff --git a/templates/web/base/maps/mapquest-attribution.html b/templates/web/base/maps/mapquest-attribution.html index 698fa186d..ab4424cdd 100644 --- a/templates/web/base/maps/mapquest-attribution.html +++ b/templates/web/base/maps/mapquest-attribution.html @@ -2,7 +2,6 @@ <script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenStreetMap.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] diff --git a/templates/web/base/maps/openlayers.html b/templates/web/base/maps/openlayers.html index 698ae2dab..37059910e 100644 --- a/templates/web/base/maps/openlayers.html +++ b/templates/web/base/maps/openlayers.html @@ -6,7 +6,8 @@ <input type="hidden" name="zoom" value="[% map.zoom %]"> <script type="text/javascript"> -var fixmystreet = { +var fixmystreet = fixmystreet || {}; +$.extend(fixmystreet, { 'page': '[% page %]', 'area': [ [% map.area.join(',') %] ], 'all_pins': '[% all_pins %]', @@ -26,7 +27,7 @@ var fixmystreet = { 'key': '[% c.config.BING_MAPS_API_KEY %]', [%- END %] 'pins': [% INCLUDE maps/pins_js.html %] -} +}); </script> <div id="map_box" aria-hidden="true"> [% pre_map %] diff --git a/templates/web/base/maps/osm-streetview.html b/templates/web/base/maps/osm-streetview.html index e7811ba40..2ff3b4723 100644 --- a/templates/web/base/maps/osm-streetview.html +++ b/templates/web/base/maps/osm-streetview.html @@ -2,7 +2,6 @@ <script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-streetview.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] diff --git a/templates/web/base/maps/osm-toner-lite.html b/templates/web/base/maps/osm-toner-lite.html index 27397141d..5e48f7569 100644 --- a/templates/web/base/maps/osm-toner-lite.html +++ b/templates/web/base/maps/osm-toner-lite.html @@ -3,7 +3,6 @@ <script type="text/javascript" src="https://stamen-maps.a.ssl.fastly.net/js/tile.stamen.js?v1.3.0"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-toner-lite.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] diff --git a/templates/web/base/maps/osm.html b/templates/web/base/maps/osm.html index 698fa186d..ab4424cdd 100644 --- a/templates/web/base/maps/osm.html +++ b/templates/web/base/maps/osm.html @@ -2,7 +2,6 @@ <script type="text/javascript" src="[% version('/js/OpenLayers/OpenLayers.fixmystreet.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-OpenStreetMap.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] diff --git a/templates/web/base/report/_main.html b/templates/web/base/report/_main.html index 1eb6f809e..1d958c30b 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/display_tools.html b/templates/web/base/report/display_tools.html index 435bfcbc1..590f81593 100644 --- a/templates/web/base/report/display_tools.html +++ b/templates/web/base/report/display_tools.html @@ -23,19 +23,14 @@ [% IF c.cobrand.moniker == 'fixmystreet' %] <div id="report-share" class="hidden-js" align="center"> - <div id="fb-root"></div> - <a href="https://twitter.com/share" class="twitter-share-button" data-text="I just reported ‘[% problem.title_safe | html %]’" data-via="fixmystreet" data-related="mysociety" data-count="none" data-dnt="true">Tweet</a> - <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script> - - <script>(function(d, s, id) { - var js, fjs = d.getElementsByTagName(s)[0]; - if (d.getElementById(id)) return; - js = d.createElement(s); js.id = id; - js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.6"; - fjs.parentNode.insertBefore(js, fjs); - }(document, 'script', 'facebook-jssdk'));</script> - <div style="line-height:1" class="fb-share-button" data-layout="button" data-mobile-iframe="true"><a class="fb-xfbml-parse-ignore" target="_blank" href="https://www.facebook.com/sharer/sharer.php?src=sdkpreparse">Share</a></div> - + <a class="btn btn--social btn--twitter" href="https://twitter.com/intent/tweet?text=I%20just%20viewed%20this%20report:%20‘[% problem.title_safe | uri %]’&via=fixmystreet&related=mySociety"> + <img alt="" src="/i/twitter-icon-32.png" width="17" height="32"> + Tweet + </a> + <a class="btn btn--social btn--facebook" href="https://www.facebook.com/sharer/sharer.php?u=[% c.cobrand.base_url %][% c.req.uri.path %]"> + <img alt="" src="/i/facebook-icon-32.png" width="17" height="32"> + Share + </a> </div> [% END %] 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/bristol/maps/bristol.html b/templates/web/bristol/maps/bristol.html index c6e74022b..42cb86bf2 100644 --- a/templates/web/bristol/maps/bristol.html +++ b/templates/web/bristol/maps/bristol.html @@ -4,10 +4,9 @@ <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-base.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-bristol.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_html = BLOCK %] [% INCLUDE maps/openlayers.html %] [% INCLUDE maps/wmts_config.html %] -[% END %]
\ No newline at end of file +[% END %] diff --git a/templates/web/fixmystreet.com/front/javascript.html b/templates/web/fixmystreet.com/front/javascript.html index bd59e1c6d..389b7ad93 100644 --- a/templates/web/fixmystreet.com/front/javascript.html +++ b/templates/web/fixmystreet.com/front/javascript.html @@ -9,7 +9,6 @@ Modernizr.load({ "preload![% version('/js/map-OpenLayers.js') %]", "preload![% version('/js/map-bing-ol.js') %]", "preload![% version('/js/map-fms.js') %]", - "preload![% version('/js/jquery.ba-hashchange.min.js') %]" ] }); </script> diff --git a/templates/web/seesomething/index.html b/templates/web/seesomething/index.html index cccd15709..dfd982e85 100644 --- a/templates/web/seesomething/index.html +++ b/templates/web/seesomething/index.html @@ -5,7 +5,8 @@ <form action="[% c.uri_for('/around') %]" method="get" name="mapForm" id="mapForm"> <script type="text/javascript"> -var fixmystreet = { +var fixmystreet = fixmystreet || {}; +$.extend(fixmystreet, { 'page': '', 'latitude': 52.505241, 'longitude': -1.815285, @@ -13,8 +14,7 @@ var fixmystreet = { 'numZoomLevels': 5, 'zoomOffset': 13, 'map_type': "" - -} +}); </script> <div id="map_box"> <div id="map"></div> diff --git a/templates/web/zurich/maps/zurich.html b/templates/web/zurich/maps/zurich.html index e0a3979ed..2f21c91a6 100644 --- a/templates/web/zurich/maps/zurich.html +++ b/templates/web/zurich/maps/zurich.html @@ -4,7 +4,6 @@ <script type="text/javascript" src="[% version('/js/map-OpenLayers.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-base.js') %]"></script> <script type="text/javascript" src="[% version('/js/map-wmts-zurich.js') %]"></script> -<script type="text/javascript" src="[% version('/js/jquery.ba-hashchange.min.js') %]"></script> [% END %] [% map_sub_links = BLOCK %] 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/angus/position_map.js b/web/cobrands/angus/position_map.js index 31ca1c09a..d5d3c942f 100644 --- a/web/cobrands/angus/position_map.js +++ b/web/cobrands/angus/position_map.js @@ -52,14 +52,7 @@ var add_streetlights = (function() { fixmystreet.markers.features[0].move(lonlat); // Need to ensure the correct coords are used for the report - // We can't call fixmystreet_update_pin because that refreshes the category list, - // clobbering the value we stored in the #form_column_id field. - lonlat.transform( - fixmystreet.map.getProjectionObject(), - new OpenLayers.Projection("EPSG:4326") - ); - document.getElementById('fixmystreet.latitude').value = lonlat.lat || lonlat.y; - document.getElementById('fixmystreet.longitude').value = lonlat.lon || lonlat.x; + fixmystreet.maps.update_pin(lonlat); // Make sure the marker that was clicked is drawn on top of its neighbours var layer = e.feature.layer; @@ -318,18 +311,19 @@ var add_streetlights = (function() { streetlight_fault_layer.setVisibility(false); } }); - - // Make sure the streetlights get hidden if the back button is pressed - $(window).on('hashchange', function() { - if (location.hash === '') { - streetlight_layer.setVisibility(false); - streetlight_fault_layer.setVisibility(false); - fixmystreet.markers.setVisibility(true); - fixmystreet.bbox_strategy.activate(); - fixmystreet.markers.refresh( { force: true } ); - } - }); } + + // Make sure the streetlights get hidden if the back button is pressed + fixmystreet.maps.display_around = (function(original) { + function hide_streetlights() { + streetlight_layer.setVisibility(false); + streetlight_fault_layer.setVisibility(false); + fixmystreet.markers.setVisibility(true); + original.apply(fixmystreet.maps); + } + return hide_streetlights; + })(fixmystreet.maps.display_around); + return add_streetlights; })(); diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index 38bbf4ea0..f9ce02f32 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -3,6 +3,8 @@ * FixMyStreet JavaScript */ +var fixmystreet = fixmystreet || {}; + /* * Find directionality of content */ @@ -10,146 +12,420 @@ function isR2L() { return !!$('html[dir=rtl]').length; } -/* - * very simple tab function - * - * elem: trigger element, must have an href attribute (so probably needs to be an <a>) - */ -function tabs(elem, indirect) { - var href = elem.attr('href'); - //stupid IE sometimes adds the full uri into the href attr, so trim - var start = href.indexOf('#'), - target = href.slice(start, href.length); - - if (indirect) { - elem = $(target + '_tab'); - } +// Some small jQuery extensions +(function($) { + var opened; - if(!$(target).hasClass('open')) - { - //toggle class on nav - $('.tab-nav .active').removeClass('active'); - elem.addClass('active'); + $.fn.extend({ + // A sliding drawer from the bottom of the page, small version + // that doesn't change the main content at all. + small_drawer: function(id) { + var $this = $(this), d = $('#' + id); + this.toggle(function() { + if (opened) { + opened.click(); + } + if (!$this.addClass('hover').data('setup')) { + d.hide().removeClass('hidden-js').css({ + padding: '1em', + background: '#fff' + }); + $this.data('setup', true); + } + d.slideDown(); + opened = $this; + }, function(e) { + $this.removeClass('hover'); + d.slideUp(); + opened = null; + }); + }, + + // A sliding drawer from the bottom of the page, large version + drawer: function(id, ajax) { + + // The link/button that triggered the drawer + var $this = $(this); + + // A bunch of elements that will come in handy when opening/closing + // the drawer. Because $sw changes its position in the DOM, we capture + // all these elements just once, the first time .drawer() is called. + var $sidebar = $('#map_sidebar'); + var $sw = $this.parents('.shadow-wrap'); + var $swparent = $sw.parent(); + var $drawer = $('#' + id); + + this.toggle(function() { + // Find the specified drawer, or create it if it doesn't exist + if ($drawer.length === 0) { + $drawer = $('<div id="' + id + '">'); + $drawer.appendTo($swparent); + } + + if (!$this.addClass('hover').data('setup')) { + // Optionally fill $drawer with HTML from an AJAX data source + if (ajax) { + var href = $this.attr('href') + ';ajax=1'; + var margin = isR2L() ? 'margin-left' : 'margin-right'; + var $ajax_result = $('<div>').appendTo($drawer); + $ajax_result.html('<p style="text-align:center">Loading</p>'); + $ajax_result.load(href); + } + + // Style up the $drawer + var drawer_top = $(window).height() - $sw.height(); + var drawer_css = { + position: 'fixed', + zIndex: 10, + top: drawer_top, + bottom: 0, + width: $sidebar.css('width'), + paddingLeft: $sidebar.css('padding-left'), + paddingRight: $sidebar.css('padding-right'), + overflow: 'auto', + background: '#fff' + }; + drawer_css[isR2L() ? 'right' : 'left'] = 0; + $drawer.css(drawer_css).removeClass('hidden-js').find('h2').css({ marginTop: 0 }); + $this.data('setup', true); + } + + // Insert the .shadow-wrap controls into the top of the drawer. + $sw.addClass('static').prependTo($drawer); + + // Animate the drawer into place, enitrely covering the sidebar. + var sidebar_top_px = $sidebar.position().top; + $drawer.show().animate({ top: sidebar_top_px }, 1000); + + }, function(e) { + // Slide the drawer down, move the .shadow-wrap back to its + // original parent, and hide the drawer for potential re-use later. + $this.removeClass('hover'); + var drawer_top = $(window).height() - $sw.height(); - //hide / show the correct tab - $('.tab.open').hide().removeClass('open'); - $(target).show().addClass('open'); + $drawer.animate({ top: drawer_top }, 1000, function() { + $sw.removeClass('static').appendTo($swparent); + $drawer.hide(); + }); + }); } -} + }); +})(jQuery); + +fixmystreet.mobile_reporting = { + apply_ui: function() { + // Creates the "app-like" mobile reporting UI with full screen map + // and special "OK/Cancel" buttons etc. + $('html').addClass('mobile-reporting-map'); + + var banner_text = '<a href="/">' + translation_strings.home + '</a> ' + translation_strings.place_pin_on_map; + $('.big-green-banner') + .addClass('mobile-map-banner') + .appendTo('#map_box') + .html(banner_text); + }, -$(function(){ - var $html = $('html'); + remove_ui: function() { + // Removes the "app-like" mobile reporting UI, reverting all the + // changes made by fixmystreet.mobile_reporting.apply_ui(). - var cobrand = $('meta[name="cobrand"]').attr('content'); + $('html').removeClass('mobile-reporting-map'); + var banner_text = translation_strings.report_problem_heading; if (typeof variation !== 'undefined' && variation === 1) { - $('input[name=variant]').val(1); + banner_text = 'Click map to request a fix'; } + $('.big-green-banner') + .removeClass('mobile-map-banner') + .prependTo('#side') + .html(banner_text); + $('#map_box').css({ width: "", height: "", position: "" }); + $('#mob_sub_map_links').remove(); + } +}; - // Deal with switching between mobile and desktop versions on resize - var last_type; - $(window).resize(function(){ - var type = Modernizr.mq('(min-width: 48em)') || $('html.iel8').length ? 'desktop' : 'mobile'; - if (last_type == type) { return; } - if (type == 'mobile') { - $html.addClass('mobile'); - $('#map_box').css({ height: '10em' }); - if (typeof fixmystreet !== 'undefined') { - fixmystreet.state_map = ''; // XXX +fixmystreet.resize_to = { + mobile_page: function() { + $('html').addClass('mobile'); + if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') { + fixmystreet.mobile_reporting.apply_ui(); + } + + // Hide sidebar notes ("rap-notes") on the /report/new page on mobile, + // and provide a button that reveals/hides them again. + var $rapSidebar = $('#report-a-problem-sidebar'); + if ($rapSidebar.length) { + $rapSidebar.hide(); + $('<a>') + .addClass('rap-notes-trigger button-fwd') + .html(translation_strings.how_to_send) + .insertBefore($rapSidebar) + .on('click', function(){ + $rapSidebar.slideToggle(100); + $(this).toggleClass('clicked'); + }); + } + + // On the front page, make it so that the "report a problem" menu item + // scrolls to the top of the page, and has a hover effect, rather than + // just being an innert span. + $('span.report-a-problem-btn').on('click.reportBtn', function() { + $('html, body').animate({scrollTop:0}, 500); + }).css({ cursor:'pointer' }).on('hover.reportBtn', function() { + $(this).toggleClass('hover'); + }); + }, + + desktop_page: function() { + $('html').removeClass('mobile'); + fixmystreet.mobile_reporting.remove_ui(); + + // Undo the special "rap-notes" tweaks that might have + // been put into place by previous mobile UI. + $('#report-a-problem-sidebar').show(); + $('.rap-notes-trigger').remove(); + + // On a desktop, so reset the "Report a problem" nav item to act + // like an innert span again. + $('span.report-a-problem-btn').css({ cursor:'' }).off('.reportBtn'); + } +}; + +fixmystreet.set_up = fixmystreet.set_up || {}; +$.extend(fixmystreet.set_up, { + basics: function() { + // Add a class to the whole page saying JavaScript is enabled (for CSS and so on) + $('html').removeClass('no-js').addClass('js'); + + // Preload the new report pin + if ( typeof fixmystreet !== 'undefined' && typeof fixmystreet.pin_prefix !== 'undefined' ) { + document.createElement('img').src = fixmystreet.pin_prefix + 'pin-green.png'; + } else { + document.createElement('img').src = '/i/pin-green.png'; + } + + // Focus on postcode box on front page + $('#pc').focus(); + + // In case we've come here by clicking back to a form that disabled a submit button + $('input[type=submit]').removeAttr('disabled'); + }, + + questionnaire: function() { + // Questionnaire hide/showings + if (!$('#been_fixed_no').prop('checked') && !$('#been_fixed_unknown').prop('checked')) { + $('.js-another-questionnaire').hide(); + } + $('#been_fixed_no').on('click', function() { + $('.js-another-questionnaire').show('fast'); + }); + $('#been_fixed_unknown').on('click', function() { + $('.js-another-questionnaire').show('fast'); + }); + $('#been_fixed_yes').on('click', function() { + $('.js-another-questionnaire').hide('fast'); + }); + }, + + form_validation: function() { + // FIXME - needs to use translated string + jQuery.validator.addMethod('validCategory', function(value, element) { + return this.optional(element) || value != '-- Pick a category --'; }, translation_strings.category ); + + var form_submitted = 0; + var submitted = false; + + $("form.validate").each(function(){ + $(this).validate({ + rules: validation_rules, + messages: translation_strings, + onkeyup: false, + onfocusout: false, + errorElement: 'div', + errorClass: 'form-error', + // we do this to stop things jumping around on blur + success: function (err) { if ( form_submitted ) { err.addClass('label-valid').removeClass('label-valid-hidden').html( ' ' ); } else { err.addClass('label-valid-hidden'); } }, + errorPlacement: function( error, element ) { + // Different for old/new style design + if ($('.form-field').length) { + element.parent('div.form-field').before( error ); + } else { + element.before( error ); } - if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') { - // Immediately go full screen map if on around page - $('#site-header').hide(); - $('#map_box').prependTo('.wrapper').css({ - position: 'absolute', - top: 0, left: 0, right: 0, bottom: 0, - height: 'auto', - margin: 0 - }); - $('#fms_pan_zoom').css({ top: '2.75em' }); - $('.big-green-banner') - .addClass('mobile-map-banner') - .appendTo('#map_box') - .html('<a href="/">' + translation_strings.home + '</a> ' + translation_strings.place_pin_on_map); + }, + submitHandler: function(form) { + if (form.submit_problem) { + $('input[type=submit]', form).prop("disabled", true); } - $('span.report-a-problem-btn').on('click.reportBtn', function(){ - $('html, body').animate({scrollTop:0}, 500); - }).css({ cursor:'pointer' }).on('hover.reportBtn', function(){ - $(this).toggleClass('hover'); - }); - } else { - // Make map full screen on non-mobile sizes. - $html.removeClass('mobile'); - $('#map_box').css({ height: '' }); - if (typeof fixmystreet !== 'undefined') { - fixmystreet.state_map = 'full'; + + form.submit(); + }, + // make sure we can see the error message when we focus on invalid elements + showErrors: function( errorMap, errorList ) { + if ( submitted && errorList.length ) { + $(window).scrollTop( $(errorList[0].element).offset().top - 120 ); } - if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') { - // Remove full-screen-ness - var banner_text = translation_strings.report_problem_heading; - if (cobrand !== 'oxfordshire') { - $('#site-header').show(); + this.defaultShowErrors(); + submitted = false; + }, + invalidHandler: function(form, validator) { submitted = true; } + }); + }); + + $('input[type=submit]').click( function(e) { form_submitted = 1; } ); + + /* set correct required status depending on what we submit + * NB: need to add things to form_category as the JS updating + * of this we do after a map click removes them */ + $('#submit_sign_in').click( function(e) { + $('#form_category').addClass('required validCategory').removeClass('valid'); + $('#form_name').removeClass(); + $('#form_first_name').removeClass(); + $('#form_last_name').removeClass(); + $('#form_fms_extra_title').removeClass(); + } ); + + $('#submit_register').click( function(e) { + $('#form_category').addClass('required validCategory').removeClass('valid'); + $('#form_name').addClass('required'); + if ( $('#mapForm').length ) { + $('#form_name').addClass('validName'); + } + $('#form_first_name').addClass('required'); + $('#form_last_name').addClass('required'); + $('#form_fms_extra_title').addClass('required'); + } ); + + $('#problem_submit > input[type="submit"]').click( function(e) { + $('#form_category').addClass('required validCategory').removeClass('valid'); + $('#form_name').addClass('required'); + if ( $('#mapForm').length ) { + $('#form_name').addClass('validName'); + } + $('#form_first_name').addClass('required'); + $('#form_last_name').addClass('required'); + $('#form_fms_extra_title').addClass('required'); + } ); + + $('#update_post').click( function(e) { + $('#form_name').addClass('required').removeClass('valid'); + } ); + + $('#facebook_sign_in, #twitter_sign_in').click(function(e){ + $('#form_email').removeClass(); + $('#form_rznvy').removeClass(); + $('#email').removeClass(); + }); + }, + + geolocation: function() { + if (geo_position_js.init()) { + var link = '<a href="LINK" id="geolocate_link">… ' + translation_strings.geolocate + '</a>'; + $('form[action="/alert/list"]').append(link.replace('LINK','/alert/list')); + if ($('body.frontpage').length) { + $('#postcodeForm').after(link.replace('LINK','/around')); + } else{ + $('#postcodeForm').append(link.replace('LINK','/around')); + } + $('#geolocate_link').click(function(e) { + var $link = $(this); + e.preventDefault(); + // Spinny thing! + if($('.mobile').length){ + $link.append(' <img src="/cobrands/fixmystreet/images/spinner-black.gif" alt="" align="bottom">'); + }else{ + var spincolor = $('<span>').css("color","white").css("color") === $('#front-main').css("background-color")? 'white' : 'yellow'; + $link.append(' <img src="/cobrands/fixmystreet/images/spinner-' + spincolor + '.gif" alt="" align="bottom">'); + } + geo_position_js.getCurrentPosition(function(pos) { + $link.find('img').remove(); + var latitude = pos.coords.latitude; + var longitude = pos.coords.longitude; + var page = $link.attr('href'); + location.href = page + '?latitude=' + latitude + ';longitude=' + longitude; + }, function(err) { + $link.find('img').remove(); + if (err.code == 1) { // User said no + $link.html(translation_strings.geolocation_declined); + } else if (err.code == 2) { // No position + $link.html(translation_strings.geolocation_no_position); + } else if (err.code == 3) { // Too long + $link.html(translation_strings.geolocation_no_result); + } else { // Unknown + $link.html(translation_strings.geolocation_unknown); } - $('#map_box').prependTo('.content').css({ - position: '', - top: '', left: '', right: '', bottom: '', - height: '', - margin: '' - }); - if (typeof variation !== 'undefined' && variation === 1) { - banner_text = 'Click map to request a fix'; + }, { + enableHighAccuracy: true, + timeout: 10000 + }); + }); + } + }, + + category_change: function() { + // Deal with changes to category by asking for details from the server. + // Delegation is necessary because #form_category may be replaced during the lifetime of the page + $("#problem_form").on("change.category", "select#form_category", function(){ + var args = { + category: $(this).val() + }; + + args.latitude = $('input[name="latitude"]').val(); + args.longitude = $('input[name="longitude"]').val(); + + $.getJSON('/report/new/category_extras', args, function(data) { + var $category_meta = $('#category_meta'); + if ( data.category_extra ) { + if ( $category_meta.length ) { + $category_meta.html( data.category_extra ); + } else { + $('#form_category_row').after( data.category_extra ); } - $('.big-green-banner') - .removeClass('mobile-map-banner') - .prependTo('#side') - .html(banner_text); + } else { + $category_meta.empty(); } - $('#fms_pan_zoom').css({ top: '' }); - $('span.report-a-problem-btn').css({ cursor:'' }).off('.reportBtn'); + }); + }); + }, + + add_validation: function() { + // Map form doesn't work in some browsers with HTML5 validation and hidden form, so + // we disable validation by default, and add it in the JS case. + $('#mapForm').removeAttr('novalidate'); + }, + + on_resize: function() { + var last_type; + $(window).on('resize', function() { + var type = Modernizr.mq('(min-width: 48em)') || $('html.iel8').length ? 'desktop' : 'mobile'; + if (last_type == type) { return; } + if (type == 'mobile') { + fixmystreet.resize_to.mobile_page(); + } else { + fixmystreet.resize_to.desktop_page(); } last_type = type; }).resize(); + }, - /* - * Report a problem page - */ - //show/hide notes on mobile - $('.mobile #report-a-problem-sidebar').after('<a href="#" class="rap-notes-trigger button-fwd">' + translation_strings.how_to_send + '</a>').hide(); - $('.rap-notes-trigger').click(function(e){ - e.preventDefault(); - //check if we've already moved the notes - if($('.rap-notes').length > 0){ - //if we have, show and hide .content - $('.content').hide(); - $('.rap-notes').show(); - }else{ - //if not, move them and show, hiding .content - $('.content').after('<div class="content rap-notes"></div>').hide(); - $('#report-a-problem-sidebar').appendTo('.rap-notes').show().after('<a href="#" class="rap-notes-close button-back">' + translation_strings.back + '</a>'); - } - $('html, body').scrollTop($('#report-a-problem-sidebar').offset().top); - location.hash = 'rap-notes'; - }); - $('.mobile').on('click', '.rap-notes-close', function(e){ - e.preventDefault(); - //hide notes, show .content - $('.content').show(); - $('.rap-notes').hide(); - $('html, body').scrollTop($('#mob_ok').offset().top); - location.hash = 'report'; - }); + dropzone: function($context) { - //move 'skip this step' link on mobile - $('.mobile #skip-this-step').addClass('chevron').wrap('<li>').parent().appendTo('#key-tools'); + // 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); + } - // Set up the Dropzone image uploader - if('Dropzone' in window){ + 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'); @@ -169,39 +445,39 @@ $(function(){ dictInvalidFileType: translation_strings.upload_invalid_file_type, dictMaxFilesExceeded: translation_strings.upload_max_files_exceeded, - fallback: function(){ + fallback: function() { $dropzone.remove(); $originalLabel.attr('for', 'form_photo'); $originalInput.show(); }, - init: function(){ - this.on("addedfile", function(file){ - $('input[type=submit]').prop("disabled", true).removeClass('green-btn'); + init: function() { + this.on("addedfile", function(file) { + $('input[type=submit]', $context).prop("disabled", true).removeClass('green-btn'); }); - this.on("queuecomplete", function(){ - $('input[type=submit]').removeAttr('disabled').addClass('green-btn'); + this.on("queuecomplete", function() { + $('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("error", function(file, errorMessage, xhrResponse) { }); - this.on("removedfile", function(file){ - var ids = $('input[name=upload_fileid]').val().split(','), - newstr = $.grep(ids, function(n){ return (n!=file.server_id); }).join(','); - $('input[name=upload_fileid]').val(newstr); + this.on("removedfile", function(file) { + var ids = $('input[name=upload_fileid]', $context).val().split(','), + newstr = $.grep(ids, function(n) { return (n!=file.server_id); }).join(','); + $('input[name=upload_fileid]', $context).val(newstr); }); - this.on("maxfilesexceeded", function(file){ + this.on("maxfilesexceeded", function(file) { this.removeFile(file); var $message = $('<div class="dz-message dz-error-message">'); $message.text(translation_strings.upload_max_files_exceeded); $message.prependTo(this.element); - setTimeout(function(){ - $message.slideUp(250, function(){ + setTimeout(function() { + $message.slideUp(250, function() { $message.remove(); }); }, 2000); @@ -209,7 +485,7 @@ $(function(){ } }); - $.each($('input[name=upload_fileid]').val().split(','), function(i, f) { + $.each($('input[name=upload_fileid]', $context).val().split(','), function(i, f) { if (!f) { return; } @@ -220,56 +496,102 @@ $(function(){ photodrop.options.maxFiles -= 1; }); } + }, - /* - * Tabs - */ - //make initial tab active - $('.tab-nav a').first().addClass('active'); - $('.tab').first().addClass('open'); - - //hide other tabs - $('.tab').not('.open').hide(); + mobile_ui_tweaks: function() { + //move 'skip this step' link on mobile + $('.mobile #skip-this-step').addClass('chevron').wrap('<li>').parent().appendTo('#key-tools'); - //set up click event - $(".tab-nav").on('click', 'a', function(e){ - e.preventDefault(); - tabs($(this)); - }); - $('.tab_link').click(function(e) { - e.preventDefault(); - tabs($(this), 1); + // nicetable - on mobile shift 'name' col to be a row + $('.mobile .nicetable th.title').remove(); + $('.mobile .nicetable td.title').each(function(i) { + $(this).attr('colspan', 5).insertBefore($(this).parent('tr')).wrap('<tr class="heading" />'); }); + }, - /* - * Skip to nav on mobile - */ - $('.mobile').on('click', '#nav-link', function(e){ + on_mobile_nav_click: function() { + $('.mobile').on('click', '#nav-link', function(e) { e.preventDefault(); var offset = $('#main-nav').offset().top; $('html, body').animate({scrollTop:offset}, 1000); - window.location.hash = 'main-nav'; + + // Registering a pushState here means that mobile users can + // press their browser's Back button to return out of the + // mobile menu (easier than scrolling all the way back up + // the page). However, to show the map page popstate listener + // that this was a special state, we set hashchange to true in + // the event state, so we can detect it, and ignore it, later. + if ('pushState' in history) { + history.pushState({ + hashchange: true + }, null); + } }); + }, + map_controls: function() { + //add permalink on desktop, force hide on mobile + //add links container (if its not there) + if (window.cobrand != 'zurich' && !$('.mobile').length) { + if ($('#sub_map_links').length === 0) { + $('<p id="sub_map_links" />').insertAfter($('#map')); + } + if ($('#map_permalink').length === 0) { + $('#sub_map_links').append('<a href="#" id="map_permalink">' + translation_strings.permalink + '</a>'); + } + } - /* - * Show stuff on input focus - */ - var form_focus_data = $('.form-focus-trigger').map(function() { - return $(this).val(); - }).get().join(''); - if (!form_focus_data) { - $('.form-focus-hidden').hide(); - $('.form-focus-trigger').on('focus', function(){ - $('.form-focus-hidden').fadeIn(500); + if ($('.mobile').length) { + $('#map_permalink').hide(); + $('#key-tools a.feed').appendTo('#sub_map_links'); + $('#key-tools li:empty').remove(); + $('#report-updates-data').insertAfter($('#map_box')); + } + + //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() { + if ($('html.mobile').length) { + $('#council_wards').hide().removeClass('hidden-js').find('h2').hide(); + $('#key-tool-wards').click(function(e) { + e.preventDefault(); + $('#council_wards').slideToggle('800', function() { + $('#key-tool-wards').toggleClass('hover'); + }); }); + } else { + $('#key-tool-wards').drawer('council_wards', false); + $('#key-tool-around-updates').drawer('updates_ajax', true); } + $('#key-tool-report-updates').small_drawer('report-updates-data'); + $('#key-tool-report-share').small_drawer('report-share'); + }, - /* Log in with email button */ + email_login_form: function() { + // Log in with email button var email_form = $('#js-social-email-hide'), button = $('<button class="btn btn--social btn--social-email">Log in with email</button>'), form_box = $('<div class="form-box"></div>'); - button.click(function(e){ + button.click(function(e) { e.preventDefault(); email_form.fadeIn(500); form_box.hide(); @@ -278,158 +600,42 @@ $(function(){ if ($('.form-error').length) { button.click(); } + }, - /* - * Show on click - pretty generic - */ - $('.hideshow-trigger').on('click', function(e){ - e.preventDefault(); - var href = $(this).attr('href'), - //stupid IE sometimes adds the full uri into the href attr, so trim - start = href.indexOf('#'), - target = href.slice(start, href.length); - - $(target).removeClass('hidden-js'); - - $(this).hide(); - }); - - /* - * nicetable - on mobile shift 'name' col to be a row - */ - $('.mobile .nicetable th.title').remove(); - $('.mobile .nicetable td.title').each(function(i){ - $(this).attr('colspan', 5).insertBefore($(this).parent('tr')).wrap('<tr class="heading" />'); - }); - // $('.mobile .nicetable tr.heading > td.title').css({'min-width':'300px'}); - // $('.mobile .nicetable tr > td.data').css({'max-width':'12%'}); - - /* - * Map controls prettiness - */ - -// A sliding drawer from the bottom of the page, small version -// that doesn't change the main content at all. -(function($){ - - var opened; - - $.fn.small_drawer = function(id) { - var $this = $(this), d = $('#' + id); - this.toggle(function(){ - if (opened) { - opened.click(); - } - if (!$this.addClass('hover').data('setup')) { - d.hide().removeClass('hidden-js').css({ - padding: '1em', - background: '#fff' - }); - $this.data('setup', true); - } - d.slideDown(); - opened = $this; - }, function(e){ - $this.removeClass('hover'); - d.slideUp(); - opened = null; - }); - }; - -})(jQuery); - -// A sliding drawer from the bottom of the page, large version -$.fn.drawer = function(id, ajax) { - - // The link/button that triggered the drawer - var $this = $(this); - - // A bunch of elements that will come in handy when opening/closing - // the drawer. Because $sw changes its position in the DOM, we capture - // all these elements just once, the first time .drawer() is called. - var $sidebar = $('#map_sidebar'); - var $sw = $this.parents('.shadow-wrap'); - var $swparent = $sw.parent(); - var $drawer = $('#' + id); - - this.toggle(function(){ - // Find the specified drawer, or create it if it doesn't exist - if ($drawer.length === 0) { - $drawer = $('<div id="' + id + '">'); - $drawer.appendTo($swparent); - } - - if (!$this.addClass('hover').data('setup')) { - // Optionally fill $drawer with HTML from an AJAX data source - if (ajax) { - var href = $this.attr('href') + ';ajax=1'; - var margin = isR2L() ? 'margin-left' : 'margin-right'; - var $ajax_result = $('<div>').appendTo($drawer); - $ajax_result.html('<p style="text-align:center">Loading</p>'); - $ajax_result.load(href); - } - - // Style up the $drawer - var drawer_top = $(window).height() - $sw.height(); - var drawer_css = { - position: 'fixed', - zIndex: 10, - top: drawer_top, - bottom: 0, - width: $sidebar.css('width'), - paddingLeft: $sidebar.css('padding-left'), - paddingRight: $sidebar.css('padding-right'), - overflow: 'auto', - background: '#fff' - }; - drawer_css[isR2L() ? 'right' : 'left'] = 0; - $drawer.css(drawer_css).removeClass('hidden-js').find('h2').css({ marginTop: 0 }); - $this.data('setup', true); - } - - // Insert the .shadow-wrap controls into the top of the drawer. - $sw.addClass('static').prependTo($drawer); - - // Animate the drawer into place, enitrely covering the sidebar. - var sidebar_top_px = $sidebar.position().top; - $drawer.show().animate({ top: sidebar_top_px }, 1000); - - }, function(e){ - // Slide the drawer down, move the .shadow-wrap back to its - // original parent, and hide the drawer for potential re-use later. - $this.removeClass('hover'); - var drawer_top = $(window).height() - $sw.height(); - - $drawer.animate({ top: drawer_top }, 1000, function(){ - $sw.removeClass('static').appendTo($swparent); - $drawer.hide(); + fancybox_images: function() { + // Fancybox fullscreen images + if (typeof $.fancybox == 'function') { + $('a[rel=fancy]').fancybox({ + 'overlayColor': '#000000' }); - }); -}; + } + }, - if ($('html.mobile').length) { - $('#council_wards').hide().removeClass('hidden-js').find('h2').hide(); - $('#key-tool-wards').click(function(e){ - e.preventDefault(); - $('#council_wards').slideToggle('800', function(){ - $('#key-tool-wards').toggleClass('hover'); - }); + form_focus_triggers: function() { + // If all of the form-focus-triggers are empty, hide form-focus-hidden. + // (If the triggers aren't empty, then chances are we're being re-shown + // the form after a validation error, so don't hide form-focus-hidden.) + // Unhide form-focus-hidden when any of the triggers are focussed. + var form_focus_data = $('.form-focus-trigger').map(function() { + return $(this).val(); + }).get().join(''); + if (!form_focus_data) { + $('.form-focus-hidden').hide(); + $('.form-focus-trigger').on('focus', function() { + $('.form-focus-hidden').fadeIn(500); }); - } else { - $('#key-tool-wards').drawer('council_wards', false); - $('#key-tool-around-updates').drawer('updates_ajax', true); } - $('#key-tool-report-updates').small_drawer('report-updates-data'); - $('#key-tool-report-share').small_drawer('report-share'); + }, + alert_page_buttons: function() { // Go directly to RSS feed if RSS button clicked on alert page // (due to not wanting around form to submit, though good thing anyway) - $('body').on('click', '#alert_rss_button', function(e){ + $('body').on('click', '#alert_rss_button', function(e) { e.preventDefault(); var feed = $('input[name=feed][type=radio]:checked').nextAll('a').attr('href'); window.location.href = feed; }); - $('body').on('click', '#alert_email_button', function(e){ + $('body').on('click', '#alert_email_button', function(e) { e.preventDefault(); var form = $('<form/>').attr({ method:'post', action:"/alert/subscribe" }); form.append($('<input name="alert" value="Subscribe me to an email alert" type="hidden" />')); @@ -440,48 +646,15 @@ $.fn.drawer = function(id, ajax) { $('body').append(form); form.submit(); }); + }, - //add permalink on desktop, force hide on mobile - //add links container (if its not there) - if (cobrand != 'zurich' && !$('.mobile').length) { - 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 ($('.mobile').length) { - $('#map_permalink').hide(); - $('#key-tools a.feed').appendTo('#sub_map_links'); - $('#key-tools li:empty').remove(); - $('#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 close buttons for .promo's - */ - if($('.promo').length){ + promo_elements: function() { + // Add close buttons for .promo's + if ($('.promo').length) { $('.promo').append('<a href="#" class="close-promo">x</a>'); } //only close its own parent - $('.promo').on('click', '.close-promo', function(e){ + $('.promo').on('click', '.close-promo', function(e) { e.preventDefault(); $(this).parent('.promo').animate({ 'height':0, @@ -493,14 +666,340 @@ $.fn.drawer = function(id, ajax) { queue:false }).fadeOut(500); }); + }, - /* - * Fancybox fullscreen images - */ - if (typeof $.fancybox == 'function') { - $('a[rel=fancy]').fancybox({ - 'overlayColor': '#000000' + 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! + + var location = window.history.location || window.location; + + 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(location.href); + } else if ('reportId' in e.state) { + fixmystreet.display.report(e.state.reportPageUrl, e.state.reportId); + } else if ('newReportAtLonlat' in e.state) { + fixmystreet.display.begin_report(e.state.newReportAtLonlat, false); + } else if ('hashchange' in e.state) { + // This popstate was just here because the hash changed. + // (eg: mobile nav click.) We want to ignore it. + } + }); + } +}); + +// The new location will be saved to a history state unless +// savePushState is set to false. +fixmystreet.update_pin = function(lonlat, savePushState) { + var lonlats = fixmystreet.maps.update_pin(lonlat); + + if (savePushState !== false) { + if ('pushState' in history) { + var newReportUrl = '/report/new?longitude=' + lonlats.url.lon + '&latitude=' + lonlats.url.lat; + history.pushState({ + newReportAtLonlat: lonlats.state + }, null, newReportUrl); + } + } + + $.getJSON('/report/new/ajax', { + latitude: $('#fixmystreet\\.latitude').val(), + longitude: $('#fixmystreet\\.longitude').val() + }, function(data) { + if (data.error) { + if (!$('#side-form-error').length) { + $('<div id="side-form-error"/>').insertAfter($('#side-form')); + } + $('#side-form-error').html('<h1>' + translation_strings.reporting_a_problem + '</h1><p>' + data.error + '</p>').show(); + $('#side-form').hide(); + $('body').removeClass('with-notes'); + return; + } + $('#side-form, #site-logo').show(); + var old_category = $("select#form_category").val(); + $('#councils_text').html(data.councils_text); + $('#form_category_row').html(data.category); + if ($("select#form_category option[value=\""+old_category+"\"]").length) { + $("select#form_category").val(old_category); + } + if ( data.extra_name_info && !$('#form_fms_extra_title').length ) { + // there might be a first name field on some cobrands + var lb = $('#form_first_name').prev(); + if ( lb.length === 0 ) { lb = $('#form_name').prev(); } + lb.before(data.extra_name_info); + } + + // If the category filter appears on the map and the user has selected + // something from it, then pre-fill the category field in the report, + // if it's a value already present in the drop-down. + var category = $("#filter_categories").val(); + if (category !== undefined && $("#form_category option[value="+category+"]").length) { + $("#form_category").val(category); + } + + var category_select = $("select#form_category"); + if (category_select.val() != '-- Pick a category --') { + category_select.change(); + } + }); + + if (!$('#side-form-error').is(':visible')) { + $('#side-form, #site-logo').show(); + $('#map_sidebar').scrollTop(0); + } + +}; + +fixmystreet.display = { + begin_report: function(lonlat, saveHistoryState) { + lonlat = fixmystreet.maps.begin_report(lonlat); + + // Store pin location in form fields, and check coverage of point + fixmystreet.update_pin(lonlat, saveHistoryState); + + // It's possible to invoke this multiple times in a row + // (eg: by clicking on the map multiple times, to + // reposition your report). But there is some stuff we + // only want to happen the first time you switch from + // the "around" view to the "new" report view. So, here + // we check whether we've already transitioned into the + // "new" report view, and if so, we return from the + // callback early, skipping the remainder of the setup + // stuff. + if (fixmystreet.page == 'new') { + if (fixmystreet.map.panTo) { + fixmystreet.map.panDuration = 100; + fixmystreet.map.panTo(lonlat); + fixmystreet.map.panDuration = 50; + } + return; + } + + // If there are notes to be displayed, add the .with-notes class + // to make the sidebar wider. + if ($('#report-a-problem-sidebar').length) { + $('body').addClass('with-notes'); + } + + /* For some reason on IOS5 if you use the jQuery show method it + * doesn't display the JS validation error messages unless you do this + * or you cause a screen redraw by changing the phone orientation. + * NB: This has to happen after the call to show() in fixmystreet.update_pin */ + if ( navigator.userAgent.match(/like Mac OS X/i)) { + document.getElementById('side-form').style.display = 'block'; + } + $('#side').hide(); + + if (fixmystreet.map.updateSize) { + fixmystreet.map.updateSize(); // required after changing the size of the map element + } + if (fixmystreet.map.panTo) { + fixmystreet.map.panDuration = 100; + fixmystreet.map.panTo(lonlat); + fixmystreet.map.panDuration = 50; + } + + $('#sub_map_links').hide(); + if ($('html').hasClass('mobile')) { + var $map_box = $('#map_box'), + width = $map_box.width(), + height = $map_box.height(); + $map_box.append( + '<p id="mob_sub_map_links">' + + '<a href="#" id="try_again">' + + translation_strings.try_again + + '</a>' + + '<a href="#ok" id="mob_ok">' + + translation_strings.ok + + '</a>' + + '</p>') + .css({ + position: 'relative', // Stop map being absolute, so reporting form doesn't get hidden + width: width, + height: height + }); + + $('.mobile-map-banner').html('<a href="/">' + translation_strings.home + '</a> ' + translation_strings.right_place); + + // mobile user clicks 'ok' on map + $('#mob_ok').toggle(function(){ + //scroll the height of the map box instead of the offset + //of the #side-form or whatever as we will probably want + //to do this on other pages where #side-form might not be + $('html, body').animate({ scrollTop: height-60 }, 1000, function(){ + $('#mob_sub_map_links').addClass('map_complete'); + $('#mob_ok').text(translation_strings.map); + }); + }, function(){ + $('html, body').animate({ scrollTop: 0 }, 1000, function(){ + $('#mob_sub_map_links').removeClass('map_complete'); + $('#mob_ok').text(translation_strings.ok); + }); }); } + fixmystreet.page = 'new'; + }, + + 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 + $('#map_sidebar').scrollTop(0); + + 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-form').hide(); + $('#side-report').remove(); + + $('body').removeClass('with-notes'); + + document.title = fixmystreet.original_title; + fixmystreet.page = 'around'; + if ($('html').hasClass('mobile')) { + $('#mob_sub_map_links').remove(); + fixmystreet.mobile_reporting.apply_ui(); + } + + if ('originalSubMapLinks' in window) { + $('#sub_map_links').replaceWith(window.originalSubMapLinks); + delete window.originalSubMapLinks; + } + $('#sub_map_links').show(); + fixmystreet.set_up.map_controls(); + + window.selected_problem_id = undefined; + + // Perform vendor-specific map setup steps, + // to get map back into "around" mode. + fixmystreet.maps.display_around(); + + 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); + } + + $.each(fixmystreet.set_up, function(setup_name, setup_func) { + setup_func(); + }); }); diff --git a/web/cobrands/fixmystreet/images/cross-grey.png b/web/cobrands/fixmystreet/images/cross-grey.png Binary files differnew file mode 100644 index 000000000..255a4d0e9 --- /dev/null +++ b/web/cobrands/fixmystreet/images/cross-grey.png diff --git a/web/cobrands/fixmystreet/images/cross-grey.svg b/web/cobrands/fixmystreet/images/cross-grey.svg new file mode 100644 index 000000000..2155900f2 --- /dev/null +++ b/web/cobrands/fixmystreet/images/cross-grey.svg @@ -0,0 +1 @@ +<svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><title>Artboard 1</title><path d="M12.993 7.336L5.657 0 0 5.657l7.336 7.336L0 20.33l5.657 5.656 7.336-7.336 7.336 7.336 5.656-5.657-7.336-7.337 7.336-7.336L20.33 0l-7.337 7.336" fill="#D1D1D1" fill-rule="evenodd"/></svg>
\ No newline at end of file diff --git a/web/cobrands/fixmystreet/images/cross-white.png b/web/cobrands/fixmystreet/images/cross-white.png Binary files differnew file mode 100644 index 000000000..eb21ae816 --- /dev/null +++ b/web/cobrands/fixmystreet/images/cross-white.png diff --git a/web/cobrands/fixmystreet/images/cross-white.svg b/web/cobrands/fixmystreet/images/cross-white.svg new file mode 100644 index 000000000..8b57e699a --- /dev/null +++ b/web/cobrands/fixmystreet/images/cross-white.svg @@ -0,0 +1 @@ +<svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><title>Artboard 1 Copy</title><path d="M12.993 7.336L5.657 0 0 5.657l7.336 7.336L0 20.33l5.657 5.656 7.336-7.336 7.336 7.336 5.656-5.657-7.336-7.337 7.336-7.336L20.33 0l-7.337 7.336" fill="#FFF" fill-rule="evenodd"/></svg>
\ No newline at end of file diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss index 52075889b..20c745a6b 100644 --- a/web/cobrands/sass/_base.scss +++ b/web/cobrands/sass/_base.scss @@ -651,8 +651,16 @@ body.mappage .wrapper { float: $right; } -#report-share iframe { - vertical-align: top; +#report-share { + .btn { + padding-left: 1.5em; + padding-right: 1.5em; + display: inline-block; + } + + .btn + .btn { + margin-left: 1em; + } } //footer blocks @@ -749,10 +757,13 @@ input.final-submit { } } +.btn--block { + display: block; + width: auto; +} + // Under the button to override its text transform and width .btn--social { - display: block; - width: 100%; text-transform: none; text-align: center; } @@ -801,6 +812,17 @@ input.final-submit { } } +.rap-notes-trigger { + &.clicked { + background-image: inline-image("../fixmystreet/images/cross-grey.svg"); + + .iel8 & { + background-image: url("../fixmystreet/images/cross-grey.png"); + } + } +} + + .big-green-banner { position: relative; top: -1.75em; @@ -984,6 +1006,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; } @@ -1257,16 +1295,53 @@ html.js #map .noscript { } } -// only on mobile, this is a sidebar on desk (#report-a-problem-sidebar) +// only on mobile a.rap-notes-trigger, a:hover.rap-notes-trigger { - display:block; - width:90%; - padding-#{$left}: 5%; - padding-#{$right}: 5%; + display: block; + margin-bottom: 1em; } -.rap-notes { - margin:1em 0; + +#report-a-problem-sidebar { + margin-bottom: 2em; + padding: 1em; + background-color: #E9F2FF; +} + +.mobile #map_box { + height: 10em; // eg: at the top of individual report pages +} + +// When you're in the reporting flow on mobile, we hide the site-header +// and make the map full screen to reduce distractions. JavaScript also +// tweaks the text content of some of the map-related elements, to make +// it more "app-like". +.mobile-reporting-map { + #site-header { + display: none; + } + + #map_box { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + height: auto; // override `.mobile #map_box` height:10em + margin: 0; + } + + #fms_pan_zoom { + top: 2.75em; // make space for the semi-transparent "Place pin on map" bar + } + + .container { + padding: 0; // map_box needs to be full width, so remove page gutter + } + + #map_sidebar { + padding: 1em; // reinstate page gutter, but on sidebar, so map_box is unaffected + } } @@ -1683,6 +1758,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/cobrands/sass/_layout.scss b/web/cobrands/sass/_layout.scss index 3622ca0f0..52c6c075d 100644 --- a/web/cobrands/sass/_layout.scss +++ b/web/cobrands/sass/_layout.scss @@ -841,7 +841,7 @@ textarea.form-error { // Notes presented alongside the reporting form .sidebar, #report-a-problem-sidebar { - margin-bottom: 2em; + padding: 0; // If the parent is .with-notes we know we have space to // float the sidebar content to the side of the form. diff --git a/web/js/fixmystreet.js b/web/js/fixmystreet.js deleted file mode 100644 index 0a15982f5..000000000 --- a/web/js/fixmystreet.js +++ /dev/null @@ -1,210 +0,0 @@ -/* - * fixmystreet.js - * FixMyStreet JavaScript used by all cobrands. - * With the JavaScript written more proper like. - */ - -(function($){ - -/* - Deal with changes to category by asking for details from the server. - */ -$(function(){ - - var $html = $('html'); - - // Add a class to the whole page saying JavaScript is enabled (for CSS and so on) - $html.removeClass('no-js').addClass('js'); - - // Preload the new report pin - if ( typeof fixmystreet !== 'undefined' && typeof fixmystreet.pin_prefix !== 'undefined' ) { - document.createElement('img').src = fixmystreet.pin_prefix + 'pin-green.png'; - } else { - document.createElement('img').src = '/i/pin-green.png'; - } - - // Focus on postcode box on front page - $('#pc').focus(); - - // In case we've come here by clicking back to a form that disabled a submit button - $('input[type=submit]').removeAttr('disabled'); - - // Questionnaire hide/showings - if (!$('#been_fixed_no').prop('checked') && !$('#been_fixed_unknown').prop('checked')) { - $('.js-another-questionnaire').hide(); - } - $('#been_fixed_no').on('click', function() { - $('.js-another-questionnaire').show('fast'); - }); - $('#been_fixed_unknown').on('click', function() { - $('.js-another-questionnaire').show('fast'); - }); - $('#been_fixed_yes').on('click', function() { - $('.js-another-questionnaire').hide('fast'); - }); - - // Form validation - - // FIXME - needs to use translated string - jQuery.validator.addMethod('validCategory', function(value, element) { - return this.optional(element) || value != '-- Pick a category --'; }, translation_strings.category ); - - var form_submitted = 0; - var submitted = false; - - $("form.validate").each(function(){ - $(this).validate({ - rules: validation_rules, - messages: translation_strings, - onkeyup: false, - onfocusout: false, - errorElement: 'div', - errorClass: 'form-error', - // we do this to stop things jumping around on blur - success: function (err) { if ( form_submitted ) { err.addClass('label-valid').removeClass('label-valid-hidden').html( ' ' ); } else { err.addClass('label-valid-hidden'); } }, - errorPlacement: function( error, element ) { - // Different for old/new style design - if ($('.form-field').length) { - element.parent('div.form-field').before( error ); - } else { - element.before( error ); - } - }, - submitHandler: function(form) { - if (form.submit_problem) { - $('input[type=submit]', form).prop("disabled", true); - } - - form.submit(); - }, - // make sure we can see the error message when we focus on invalid elements - showErrors: function( errorMap, errorList ) { - if ( submitted && errorList.length ) { - $(window).scrollTop( $(errorList[0].element).offset().top - 120 ); - } - this.defaultShowErrors(); - submitted = false; - }, - invalidHandler: function(form, validator) { submitted = true; } - }); - }); - - $('input[type=submit]').click( function(e) { form_submitted = 1; } ); - - /* set correct required status depending on what we submit - * NB: need to add things to form_category as the JS updating - * of this we do after a map click removes them */ - $('#submit_sign_in').click( function(e) { - $('#form_category').addClass('required validCategory').removeClass('valid'); - $('#form_name').removeClass(); - $('#form_first_name').removeClass(); - $('#form_last_name').removeClass(); - $('#form_fms_extra_title').removeClass(); - } ); - - $('#submit_register').click( function(e) { - $('#form_category').addClass('required validCategory').removeClass('valid'); - $('#form_name').addClass('required'); - if ( $('#mapForm').length ) { - $('#form_name').addClass('validName'); - } - $('#form_first_name').addClass('required'); - $('#form_last_name').addClass('required'); - $('#form_fms_extra_title').addClass('required'); - } ); - - $('#problem_submit > input[type="submit"]').click( function(e) { - $('#form_category').addClass('required validCategory').removeClass('valid'); - $('#form_name').addClass('required'); - if ( $('#mapForm').length ) { - $('#form_name').addClass('validName'); - } - $('#form_first_name').addClass('required'); - $('#form_last_name').addClass('required'); - $('#form_fms_extra_title').addClass('required'); - } ); - - $('#update_post').click( function(e) { - $('#form_name').addClass('required').removeClass('valid'); - } ); - - $('#facebook_sign_in, #twitter_sign_in').click(function(e){ - $('#form_email').removeClass(); - $('#form_rznvy').removeClass(); - $('#email').removeClass(); - }); - - // Geolocation - if (geo_position_js.init()) { - var link = '<a href="LINK" id="geolocate_link">… ' + translation_strings.geolocate + '</a>'; - $('form[action="/alert/list"]').append(link.replace('LINK','/alert/list')); - if ($('body.frontpage').length) { - $('#postcodeForm').after(link.replace('LINK','/around')); - } else{ - $('#postcodeForm').append(link.replace('LINK','/around')); - } - $('#geolocate_link').click(function(e) { - var $link = $(this); - e.preventDefault(); - // Spinny thing! - if($('.mobile').length){ - $link.append(' <img src="/cobrands/fixmystreet/images/spinner-black.gif" alt="" align="bottom">'); - }else{ - var spincolor = $('<span>').css("color","white").css("color") === $('#front-main').css("background-color")? 'white' : 'yellow'; - $link.append(' <img src="/cobrands/fixmystreet/images/spinner-' + spincolor + '.gif" alt="" align="bottom">'); - } - geo_position_js.getCurrentPosition(function(pos) { - $link.find('img').remove(); - var latitude = pos.coords.latitude; - var longitude = pos.coords.longitude; - var page = $link.attr('href'); - location.href = page + '?latitude=' + latitude + ';longitude=' + longitude; - }, function(err) { - $link.find('img').remove(); - if (err.code == 1) { // User said no - $link.html(translation_strings.geolocation_declined); - } else if (err.code == 2) { // No position - $link.html(translation_strings.geolocation_no_position); - } else if (err.code == 3) { // Too long - $link.html(translation_strings.geolocation_no_result); - } else { // Unknown - $link.html(translation_strings.geolocation_unknown); - } - }, { - enableHighAccuracy: true, - timeout: 10000 - }); - }); - } - - // Delegation is necessary because #form_category may be replaced during the lifetime of the page - $("#problem_form").on("change.category", "select#form_category", function(){ - var args = { - category: $(this).val() - }; - - args.latitude = $('input[name="latitude"]').val(); - args.longitude = $('input[name="longitude"]').val(); - - $.getJSON('/report/new/category_extras', args, function(data) { - var $category_meta = $('#category_meta'); - if ( data.category_extra ) { - if ( $category_meta.length ) { - $category_meta.html( data.category_extra ); - } else { - $('#form_category_row').after( data.category_extra ); - } - } else { - $category_meta.empty(); - } - }); - }); - - // Map form doesn't work in some browsers with HTML5 validation and hidden form, so - // we disable validation by default, and add it in the JS case. - // For some reason, the removeAttr doesn't work if we place it at beginning. - $('#mapForm').removeAttr('novalidate'); -}); - -})(jQuery); - diff --git a/web/js/history.polyfill.min.js b/web/js/history.polyfill.min.js new file mode 100644 index 000000000..f773e6bef --- /dev/null +++ b/web/js/history.polyfill.min.js @@ -0,0 +1,35 @@ +/*! + * History API JavaScript Library v4.2.7 + * + * Support: IE6+, FF3+, Opera 9+, Safari, Chrome and other + * + * Copyright 2011-2015, Dmitrii Pakhtinov ( spb.piksel@gmail.com ) + * + * http://spb-piksel.ru/ + * + * MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Update: 2016-03-08 16:57 + */ +(function(q){if("function"===typeof define&&define.amd){if("undefined"!==typeof requirejs){var w="[history"+(new Date).getTime()+"]",l=requirejs.onError;q.toString=function(){return w};requirejs.onError=function(q){-1===q.message.indexOf(w)&&l.call(requirejs,q)}}define([],q)}if("object"===typeof exports&&"undefined"!==typeof module)module.exports=q();else return q()})(function(){var i=!0,k=null,p=!1;function q(a,b){var c=e.history!==r;c&&(e.history=r);a.apply(r,b);c&&(e.history=m)}function w(){}function l(a,b,c){if(a!=k&&""!==a&&!b){var b=l(),g=f.getElementsByTagName("base")[0]; +!c&&(g&&g.getAttribute("href"))&&(g.href=g.href,b=l(g.href,k,i));c=b.e;g=b.h;a=""+a;a=/^(?:\w+\:)?\/\//.test(a)?0===a.indexOf("/")?g+a:a:g+"//"+b.g+(0===a.indexOf("/")?a:0===a.indexOf("?")?c+a:0===a.indexOf("#")?c+b.f+a:c.replace(/[^\/]+$/g,"")+a)}else if(a=b?a:d.href,!j||c)a=a.replace(/^[^#]*/,"")||"#",a=d.protocol.replace(/:.*$|$/,":")+"//"+d.host+h.basepath+a.replace(RegExp("^#[/]?(?:"+h.type+")?"),"");R.href=a;var a=/(?:([a-zA-Z0-9\-]+\:))?(?:\/\/(?:[^@]*@)?([^\/:\?#]+)(?::([0-9]+))?)?([^\?#]*)(?:(\?[^#]+)|\?)?(?:(#.*))?/.exec(R.href), +b=a[2]+(a[3]?":"+a[3]:""),c=a[4]||"/",g=a[5]||"",e="#"===a[6]?"":a[6]||"",S=c+g+e,x=c.replace(RegExp("^"+h.basepath,"i"),h.type)+g;return{a:a[1]+"//"+b+S,h:a[1],g:b,i:a[2],k:a[3]||"",e:c,f:g,b:e,c:S,j:x,d:x+e}}function ba(){var a;try{a=e.sessionStorage,a.setItem(F+"t","1"),a.removeItem(F+"t")}catch(b){a={getItem:function(a){a=f.cookie.split(a+"=");return 1<a.length&&a.pop().split(";").shift()||"null"},setItem:function(a){var b={};if(b[d.href]=m.state)f.cookie=a+"="+s.stringify(b)}}}try{n=s.parse(a.getItem(F))|| +{}}catch(c){n={}}v(y+"unload",function(){a.setItem(F,s.stringify(n))},p)}function z(a,b,c,g){var d=0;c||(c={set:w},d=1);var f=!c.set,x=!c.get,K={configurable:i,set:function(){f=1},get:function(){x=1}};try{D(a,b,K),a[b]=a[b],D(a,b,c)}catch(ka){}if(!f||!x)if(a.__defineGetter__&&(a.__defineGetter__(b,K.get),a.__defineSetter__(b,K.set),a[b]=a[b],c.get&&a.__defineGetter__(b,c.get),c.set&&a.__defineSetter__(b,c.set)),!f||!x){if(d)return p;if(a===e){try{var ca=a[b];a[b]=k}catch(l){}if("execScript"in e)e.execScript("Public "+ +b,"VBScript"),e.execScript("var "+b+";","JavaScript");else try{D(a,b,{value:w})}catch(m){"onpopstate"===b&&(v("popstate",c=function(){L("popstate",c,p);var b=a.onpopstate;a.onpopstate=k;setTimeout(function(){a.onpopstate=b},1)},p),T=0)}a[b]=ca}else try{try{var h=G.create(a);D(G.getPrototypeOf(h)===a?h:a,b,c);for(var j in a)"function"===typeof a[j]&&(h[j]=a[j].bind(a));try{g.call(h,h,a)}catch(n){}a=h}catch(o){D(a.constructor.prototype,b,c)}}catch(q){return p}}return a}function da(a,b,c){c=c||{};a= +a===M?d:a;c.set=c.set||function(c){a[b]=c};c.get=c.get||function(){return a[b]};return c}function ea(a,b,c){a in A?A[a].push(b):3<arguments.length?v(a,b,c,arguments[3]):v(a,b,c)}function fa(a,b,c){var e=A[a];if(e)for(a=e.length;a--;){if(e[a]===b){e.splice(a,1);break}}else L(a,b,c)}function H(a,b){var c=(""+("string"===typeof a?a:a.type)).replace(/^on/,""),g=A[c];if(g){b="string"===typeof a?b:a;if(b.target==k)for(var d=["target","currentTarget","srcElement","type"];a=d.pop();)b=z(b,a,{get:"type"=== +a?function(){return c}:function(){return e}});T&&(("popstate"===c?e.onpopstate:e.onhashchange)||w).call(e,b);for(var d=0,f=g.length;d<f;d++)g[d].call(e,b);return i}return ga(a,b)}function U(){var a=f.createEvent?f.createEvent("Event"):f.createEventObject();a.initEvent?a.initEvent("popstate",p,p):a.type="popstate";a.state=m.state;H(a)}function u(a,b,c,e){j?B=d.href:(0===o&&(o=2),b=l(b,2===o&&-1!==(""+b).indexOf("#")),b.c!==l().c&&(B=e,c?d.replace("#"+b.d):d.hash=b.d));!I&&a&&(n[d.href]=a);E=p}function N(a){var b= +B;B=d.href;if(b){V!==d.href&&U();var a=a||e.event,b=l(b,i),c=l();a.oldURL||(a.oldURL=b.a,a.newURL=c.a);b.b!==c.b&&H(a)}}function W(a){setTimeout(function(){v("popstate",function(a){V=d.href;I||(a=z(a,"state",{get:function(){return m.state}}));H(a)},p)},0);!j&&(a!==i&&"location"in m)&&(X(t.hash),E&&(E=p,U()))}function ha(a){var a=a||e.event,b;a:{for(b=a.target||a.srcElement;b;){if("A"===b.nodeName)break a;b=b.parentNode}b=void 0}var c="defaultPrevented"in a?a.defaultPrevented:a.returnValue===p;b&& +("A"===b.nodeName&&!c)&&(c=l(),b=l(b.getAttribute("href",2)),c.a.split("#").shift()===b.a.split("#").shift()&&b.b&&(c.b!==b.b&&(t.hash=b.b),X(b.b),a.preventDefault?a.preventDefault():a.returnValue=p))}function X(a){var b=f.getElementById(a=(a||"").replace(/^#/,""));b&&(b.id===a&&"A"===b.nodeName)&&(a=b.getBoundingClientRect(),e.scrollTo(J.scrollLeft||0,a.top+(J.scrollTop||0)-(J.clientTop||0)))}function ia(){function a(a){var b=[],d="VBHistoryClass"+(new Date).getTime()+c++,g=["Class "+d],f;for(f in a)if(a.hasOwnProperty(f)){var h= +a[f];h&&(h.get||h.set)?(h.get&&g.push("Public "+("_"===f?"Default ":"")+"Property Get ["+f+"]","Call VBCVal([(accessors)].["+f+"].get.call(me),["+f+"])","End Property"),h.set&&g.push("Public Property Let ["+f+"](val)",h="Call [(accessors)].["+f+"].set.call(me,val)\nEnd Property","Public Property Set ["+f+"](val)",h)):(b.push(f),g.push("Public ["+f+"]"))}g.push("Private [(accessors)]","Private Sub Class_Initialize()","Set [(accessors)]="+d+"FactoryJS()","End Sub","End Class","Function "+d+"Factory()", +"Set "+d+"Factory=New "+d,"End Function");e.execScript(g.join("\n"),"VBScript");e[d+"FactoryJS"]=function(){return a};d=e[d+"Factory"]();for(g=0;g<b.length;g++)d[b[g]]=a[b[g]];return d}function b(a){var b=/[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,c={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return b.test(a)?'"'+a.replace(b,function(a){return a in c?c[a]:"\\u"+("0000"+ +a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}var c=e.execScript&&(e.execScript("var documentMsie/*@cc_on =1@*/;","JavaScript"),e.documentMsie);if(c&&!(f.documentMode&&7<f.documentMode)){var g=z,h=l().a,j=f.createElement("iframe");j.src="javascript:true;";j=J.firstChild.appendChild(j).contentWindow;e.execScript("Public history\nFunction VBCVal(o,r) If IsObject(o) Then Set r=o Else r=o End If End Function","VBScript");t={_:{get:M.toString}};m={back:r.back,forward:r.forward,go:r.go,emulate:k, +_:{get:function(){return"[object History]"}}};s={parse:function(a){try{return(new Function("","return "+a))()}catch(b){return k}},stringify:function(a){var c=(typeof a).charCodeAt(2);if(114===c)a=b(a);else if(109===c)a=isFinite(a)?""+a:"null";else if(111===c||108===c)a=""+a;else if(106===c)if(a){var e=(c="[object Array]"===G.prototype.toString.call(a))?"[":"{";if(c)for(var d=0;d<a.length;d++)e+=(0==d?"":",")+s.stringify(a[d]);else for(d in a)a.hasOwnProperty(d)&&(e+=(1==e.length?"":",")+b(d)+":"+ +s.stringify(a[d]));a=e+(c?"]":"}")}else a="null";else a="void 0";return a}};u=function(a,b,c,e,g){var f=j.document;0===o&&(o=2);b=l(b,2===o&&-1!==(""+b).indexOf("#"));E=p;if(b.c===l().c&&!g)a&&(n[d.href]=a);else{B=e;if(c)j.lfirst?(history.back(),u(a,b.a,0,e,1)):d.replace("#"+b.d);else if(b.a!=h||g)j.lfirst?g&&(g=0,a=n[d.href]):(j.lfirst=1,u(a,h,0,e,1)),f.open(),f.write('<script>lfirst=1;parent.location.hash="'+b.d.replace(/"/g,'\\"')+'";<\/script>'),f.close();!g&&a&&(n[d.href]=a)}};z=function(b,c, +d,f){g.apply(this,arguments)||(b===t?t[c]=d:b===m?(m[c]=d,"state"===c&&(t=a(t),e.history=m=a(m),e.execScript("var history = window.history;","JavaScript"))):b[c]=d.get&&d.get());return b};setInterval(function(){var a=l().a;if(a!=h){var b=f.createEventObject();b.oldURL=h;b.newURL=h=a;b.type="hashchange";N(b)}},100);e.JSON=s}}var e=("object"===typeof window?window:this)||{};if(!e.history||"emulate"in e.history)return e.history;var f=e.document,J=f.documentElement,G=e.Object,s=e.JSON,d=e.location,r= +e.history,m=r,O=r.pushState,Y=r.replaceState,j=function(){var a=e.navigator.userAgent;return(-1!==a.indexOf("Android 2.")||-1!==a.indexOf("Android 4.0"))&&-1!==a.indexOf("Mobile Safari")&&-1===a.indexOf("Chrome")&&-1===a.indexOf("Windows Phone")?p:!!O}(),I="state"in r,D=G.defineProperty,t=z({},"t")?{}:f.createElement("a"),y="",P=e.addEventListener?"addEventListener":(y="on")&&"attachEvent",Z=e.removeEventListener?"removeEventListener":"detachEvent",$=e.dispatchEvent?"dispatchEvent":"fireEvent",v= +e[P],L=e[Z],ga=e[$],h={basepath:"/",redirect:0,type:"/",init:0},F="__historyAPI__",R=f.createElement("a"),B=d.href,V="",T=1,E=p,o=0,n={},A={},C=f.title,Q,ja={onhashchange:k,onpopstate:k},aa={setup:function(a,b,c){h.basepath=(""+(a==k?h.basepath:a)).replace(/(?:^|\/)[^\/]*$/,"/");h.type=b==k?h.type:b;h.redirect=c==k?h.redirect:!!c},redirect:function(a,b){m.setup(b,a);b=h.basepath;if(e.top==e.self){var c=l(k,p,i).c,g=d.pathname+d.search;j?(g=g.replace(/([^\/])$/,"$1/"),c!=b&&RegExp("^"+b+"$","i").test(g)&& +d.replace(c)):g!=b&&(g=g.replace(/([^\/])\?/,"$1/?"),RegExp("^"+b,"i").test(g)&&d.replace(b+"#"+g.replace(RegExp("^"+b,"i"),h.type)+d.hash))}},pushState:function(a,b,c){var e=f.title;C!=k&&(f.title=C);O&&q(O,arguments);u(a,c);f.title=e;C=b},replaceState:function(a,b,c){var e=f.title;C!=k&&(f.title=C);delete n[d.href];Y&&q(Y,arguments);u(a,c,i);f.title=e;C=b},location:{set:function(a){0===o&&(o=1);e.location=a},get:function(){0===o&&(o=1);return t}},state:{get:function(){return"object"===typeof n[d.href]? +s.parse(s.stringify(n[d.href])):"undefined"!==typeof n[d.href]?n[d.href]:k}}},M={assign:function(a){!j&&0===(""+a).indexOf("#")?u(k,a):d.assign(a)},reload:function(a){d.reload(a)},replace:function(a){!j&&0===(""+a).indexOf("#")?u(k,a,i):d.replace(a)},toString:function(){return this.href},origin:{get:function(){return void 0!==Q?Q:!d.origin?d.protocol+"//"+d.hostname+(d.port?":"+d.port:""):d.origin},set:function(a){Q=a}},href:j?k:{get:function(){return l().a}},protocol:k,host:k,hostname:k,port:k,pathname:j? +k:{get:function(){return l().e}},search:j?k:{get:function(){return l().f}},hash:j?k:{set:function(a){u(k,(""+a).replace(/^(#|)/,"#"),p,B)},get:function(){return l().b}}};if(function(){var a=f.getElementsByTagName("script"),a=(a[a.length-1]||{}).src||"";(-1!==a.indexOf("?")?a.split("?").pop():"").replace(/(\w+)(?:=([^&]*))?/g,function(a,b,c){h[b]=(c||"").replace(/^(0|false)$/,"")});ia();v(y+"hashchange",N,p);var b=[M,t,ja,e,aa,m];I&&delete aa.state;for(var c=0;c<b.length;c+=2)for(var d in b[c])if(b[c].hasOwnProperty(d))if("object"!== +typeof b[c][d])b[c+1][d]=b[c][d];else{a=da(b[c],d,b[c][d]);if(!z(b[c+1],d,a,function(a,d){if(d===m)e.history=m=b[c+1]=a}))return L(y+"hashchange",N,p),p;b[c+1]===e&&(A[d]=A[d.substr(2)]=[])}m.setup();h.redirect&&m.redirect();h.init&&(o=1);!I&&s&&ba();if(!j)f[P](y+"click",ha,p);"complete"===f.readyState?W(i):(!j&&l().c!==h.basepath&&(E=i),v(y+"load",W,p));return i}())return m.emulate=!j,e[P]=ea,e[Z]=fa,e[$]=H,m}); diff --git a/web/js/jquery.ba-hashchange.min.js b/web/js/jquery.ba-hashchange.min.js deleted file mode 100644 index 3c607bae3..000000000 --- a/web/js/jquery.ba-hashchange.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * jQuery hashchange event - v1.3 - 7/21/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ -(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);
\ No newline at end of file diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 1379d0fa5..f6e7e8a62 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -1,504 +1,514 @@ -// This function might be passed either an OpenLayers.LonLat (so has -// lon and lat) or an OpenLayers.Geometry.Point (so has x and y) -function fixmystreet_update_pin(lonlat) { - lonlat = lonlat.clone().transform( - fixmystreet.map.getProjectionObject(), - new OpenLayers.Projection("EPSG:4326") - ); - document.getElementById('fixmystreet.latitude').value = lonlat.lat || lonlat.y; - document.getElementById('fixmystreet.longitude').value = lonlat.lon || lonlat.x; - - $.getJSON('/report/new/ajax', { - latitude: $('#fixmystreet\\.latitude').val(), - longitude: $('#fixmystreet\\.longitude').val() - }, function(data) { - if (data.error) { - if (!$('#side-form-error').length) { - $('<div id="side-form-error"/>').insertAfter($('#side-form')); - } - $('#side-form-error').html('<h1>' + translation_strings.reporting_a_problem + '</h1><p>' + data.error + '</p>').show(); - $('#side-form').hide(); - $('body').removeClass('with-notes'); - return; - } - $('#side-form, #site-logo').show(); - var old_category = $("select#form_category").val(); - $('#councils_text').html(data.councils_text); - $('#form_category_row').html(data.category); - if ($("select#form_category option[value=\""+old_category+"\"]").length) { - $("select#form_category").val(old_category); +var fixmystreet = fixmystreet || {}; + +(function() { + + fixmystreet.maps = { + // This function might be passed either an OpenLayers.LonLat (so has + // lon and lat), or an OpenLayers.Geometry.Point (so has x and y). + update_pin: function(lonlat) { + var transformedLonlat = lonlat.clone().transform( + fixmystreet.map.getProjectionObject(), + new OpenLayers.Projection("EPSG:4326") + ); + + var lat = transformedLonlat.lat || transformedLonlat.y; + var lon = transformedLonlat.lon || transformedLonlat.x; + + document.getElementById('fixmystreet.latitude').value = lat; + document.getElementById('fixmystreet.longitude').value = lon; + return { + 'url': { 'lon': lon, 'lat': lat }, + 'state': { 'lon': lonlat.lon, 'lat': lonlat.lat } + }; + }, + + display_around: function() { + // Required after changing the size of the map element + fixmystreet.map.updateSize(); + + // Dragging the map should fetch new local reports from server + fixmystreet.bbox_strategy.activate(); + + // Should not be able to drag normal pins!! + drag.deactivate(); + + // Force a redraw to return (de)selected marker to normal size + fixmystreet.markers.refresh({force: true}); + }, + + begin_report: function(lonlat) { + if (typeof lonlat.clone !== 'function') { + lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat); } - if ( data.extra_name_info && !$('#form_fms_extra_title').length ) { - // there might be a first name field on some cobrands - var lb = $('#form_first_name').prev(); - if ( lb.length === 0 ) { lb = $('#form_name').prev(); } - lb.before(data.extra_name_info); + + if (fixmystreet.page == 'new') { + /* Already have a pin */ + fixmystreet.markers.features[0].move(lonlat); + } else { + var markers = fixmystreet.maps.markers_list( [ [ lonlat.lat, lonlat.lon, 'green' ] ], false ); + fixmystreet.bbox_strategy.deactivate(); + fixmystreet.markers.removeAllFeatures(); + fixmystreet.markers.addFeatures( markers ); + drag.activate(); } - // If the category filter appears on the map and the user has selected - // something from it, then pre-fill the category field in the report, - // if it's a value already present in the drop-down. - var category = $("#filter_categories").val(); - if (category !== undefined && $("#form_category option[value="+category+"]").length) { - $("#form_category").val(category); + // check to see if markers are visible. We click the + // link so that it updates the text in case they go + // back + if ( ! fixmystreet.markers.getVisibility() ) { + $('#hide_pins_link').click(); } + return lonlat; + }, - var category_select = $("select#form_category"); - if (category_select.val() != '-- Pick a category --') { - category_select.change(); + markers_list: function(pins, transform) { + var markers = []; + 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]); + if (transform) { + // The Strategy does this for us, so don't do it in that case. + loc.transform( + new OpenLayers.Projection("EPSG:4326"), + 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] || marker_size, + faded: 0, + id: pin[3], + title: pin[4] || '' + }); + markers.push( marker ); } - }); + return markers; + }, - if (!$('#side-form-error').is(':visible')) { - $('#side-form, #site-logo').show(); - window.scrollTo(0, 0); - } -} - -function fixmystreet_activate_drag() { - fixmystreet.drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { - onComplete: function(feature, e) { - fixmystreet_update_pin( feature.geometry ); - } - } ); - fixmystreet.map.addControl( fixmystreet.drag ); - fixmystreet.drag.activate(); -} - -function fixmystreet_zoomToBounds(bounds) { - if (!bounds) { return; } - var center = bounds.getCenterLonLat(); - var z = fixmystreet.map.getZoomForExtent(bounds); - if ( z < 13 && $('html').hasClass('mobile') ) { - z = 13; - } - fixmystreet.map.setCenter(center, z); -} - -function fms_markers_list(pins, transform) { - var markers = []; - var size = fms_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]); - if (transform) { - // The Strategy does this for us, so don't do it in that case. - loc.transform( - new OpenLayers.Projection("EPSG:4326"), - fixmystreet.map.getProjectionObject() - ); + markers_resize: function() { + 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++) { + 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; + } } - var marker = new OpenLayers.Feature.Vector(loc, { - colour: pin[2], - size: pin[5] || size, - faded: 0, - id: pin[3], - title: pin[4] || '' - }); - markers.push( marker ); - } - return markers; -} - -function fms_marker_size_for_zoom(zoom) { - if (zoom >= 15) { - return 'normal'; - } else if (zoom >= 13) { - return 'small'; - } else { - return 'mini'; - } -} + fixmystreet.markers.redraw(); + }, -function fms_markers_resize() { - var size = fms_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; - } - fixmystreet.markers.redraw(); -} - -// `markers.redraw()` in fms_markers_highlight will trigger an -// `overFeature` event if the mouse cursor is still over the same -// marker on the map, which would then run fms_markers_highlight -// again, causing an infinite flicker while the cursor remains over -// the same marker. We really only want to redraw the markers when -// the cursor moves from one marker to another (ie: when there is an -// overFeature followed by an outFeature followed by an overFeature). -// Therefore, we keep track of the previous event in -// fixmystreet.latest_map_hover_event and only call fms_markers_highlight -// if we know the previous event was different to the current one. -// (See the `overFeature` and `outFeature` callbacks inside of -// fixmystreet.select_feature). - -function fms_markers_highlight(problem_id) { - for (var i = 0; i < fixmystreet.markers.features.length; i++) { - if (typeof problem_id == 'undefined') { - // There is no highlighted marker, so unfade this marker - fixmystreet.markers.features[i].attributes.faded = 0; - } else if (problem_id == fixmystreet.markers.features[i].attributes.id) { - // This is the highlighted marker, unfade it - fixmystreet.markers.features[i].attributes.faded = 0; + 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 window.selected_problem_id ? 'small' : 'normal'; + } else if (zoom >= 13) { + return window.selected_problem_id ? 'mini' : 'small'; } else { - // This is not the hightlighted marker, fade it - fixmystreet.markers.features[i].attributes.faded = 1; + return 'mini'; } - } - fixmystreet.markers.redraw(); -} - -function fms_sidebar_highlight(problem_id) { - if (typeof problem_id !== 'undefined') { - var $a = $('.item-list--reports a[href$="' + problem_id + '"]'); - $a.parent().addClass('hovered'); - } else { - $('.item-list--reports .hovered').removeClass('hovered'); - } -} - -function fms_marker_click(problem_id) { - var $a = $('.item-list--reports a[href$="' + problem_id + '"]'); - $a[0] && $a[0].click(); -} - -function fms_categories_or_status_changed() { - // If the category or status has changed we need to re-fetch map markers - fixmystreet.markers.refresh({force: true}); -} - -function fixmystreet_onload() { - if ( fixmystreet.area.length ) { - for (var i=0; i<fixmystreet.area.length; i++) { - var area = new OpenLayers.Layer.Vector("KML", { - strategies: [ new OpenLayers.Strategy.Fixed() ], - protocol: new OpenLayers.Protocol.HTTP({ - url: "/mapit/area/" + fixmystreet.area[i] + ".kml?simplify_tolerance=0.0001", - format: new OpenLayers.Format.KML() - }) - }); - fixmystreet.map.addLayer(area); - if ( fixmystreet.area.length == 1 ) { - area.events.register('loadend', null, function(a,b,c) { - if ( fixmystreet.area_format ) { - area.styleMap.styles['default'].defaultStyle = fixmystreet.area_format; - } - fixmystreet_zoomToBounds( area.getDataExtent() ); - }); - } - } - } + }, - var pin_layer_style_map = new OpenLayers.StyleMap({ - 'default': new OpenLayers.Style({ - graphicTitle: "${title}", - graphicOpacity: 1, - graphicZIndex: 11, - backgroundGraphicZIndex: 10 - }) - }); - pin_layer_style_map.addUniqueValueRules('default', 'size', { - 'normal': { - externalGraphic: fixmystreet.pin_prefix + "pin-${colour}.png", - graphicWidth: 48, - graphicHeight: 64, - graphicXOffset: -24, - graphicYOffset: -64, - backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow.png", - backgroundWidth: 60, - backgroundHeight: 30, - backgroundXOffset: -7, - backgroundYOffset: -30, - popupYOffset: -40 - }, - 'big': { - externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-big.png", - graphicWidth: 78, - graphicHeight: 105, - graphicXOffset: -39, - graphicYOffset: -105, - backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow-big.png", - backgroundWidth: 88, - backgroundHeight: 40, - backgroundXOffset: -10, - backgroundYOffset: -35 - }, - 'small': { - externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-small.png", - graphicWidth: 24, - graphicHeight: 32, - graphicXOffset: -12, - graphicYOffset: -32, - backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow-small.png", - backgroundWidth: 30, - backgroundHeight: 15, - backgroundXOffset: -4, - backgroundYOffset: -15, - popupYOffset: -20 - }, - 'mini': { - externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-mini.png", - graphicWidth: 16, - graphicHeight: 20, - graphicXOffset: -8, - graphicYOffset: -20, - popupYOffset: -10 + selected_marker_size_for_zoom: function(zoom) { + if (zoom >= 15) { + return 'big'; + } else if (zoom >= 13) { + return 'normal'; + } else { + return 'small'; } - }); - pin_layer_style_map.addUniqueValueRules('default', 'faded', { - 0: { - graphicOpacity: 1 + } + }; + + var drag = { + activate: function() { + this._drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { + onComplete: function(feature, e) { + fixmystreet.update_pin( feature.geometry ); + } + } ); + fixmystreet.map.addControl( this._drag ); + this._drag.activate(); }, - 1: { - graphicOpacity: 0.15 + deactivate: function() { + this._drag && this._drag.deactivate(); } - }); - var pin_layer_options = { - rendererOptions: { - yOrdering: true - }, - styleMap: pin_layer_style_map }; - if (fixmystreet.page == 'around') { - fixmystreet.bbox_strategy = fixmystreet.bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); - pin_layer_options.strategies = [ fixmystreet.bbox_strategy ]; - pin_layer_options.protocol = new OpenLayers.Protocol.FixMyStreet({ - url: '/ajax', - params: fixmystreet.all_pins ? { all_pins: 1 } : { }, - format: new OpenLayers.Format.FixMyStreet() - }); - } - fixmystreet.markers = new OpenLayers.Layer.Vector("Pins", pin_layer_options); - fixmystreet.markers.events.register( 'loadend', fixmystreet.markers, function(evt) { - if (fixmystreet.map.popups.length) { - fixmystreet.map.removePopup(fixmystreet.map.popups[0]); + + function zoomToBounds(bounds) { + if (!bounds) { return; } + var center = bounds.getCenterLonLat(); + var z = fixmystreet.map.getZoomForExtent(bounds); + if ( z < 13 && $('html').hasClass('mobile') ) { + z = 13; } - }); + fixmystreet.map.setCenter(center, z); + } - var markers = fms_markers_list( fixmystreet.pins, true ); - fixmystreet.markers.addFeatures( markers ); - - if (fixmystreet.page == 'around' || fixmystreet.page == 'reports' || fixmystreet.page == 'my') { - fixmystreet.select_feature = new OpenLayers.Control.SelectFeature( - fixmystreet.markers, - { - hover: true, - // Override clickFeature so that we can use it even though - // hover is true. http://gis.stackexchange.com/a/155675 - clickFeature: function (feature) { - fms_marker_click(feature.attributes.id); - }, - overFeature: function (feature) { - if (fixmystreet.latest_map_hover_event != 'overFeature') { - document.getElementById('map').style.cursor = 'pointer'; - fms_markers_highlight(feature.attributes.id); - fms_sidebar_highlight(feature.attributes.id); - fixmystreet.latest_map_hover_event = 'overFeature'; - } - }, - outFeature: function (feature) { - if (fixmystreet.latest_map_hover_event != 'outFeature') { - document.getElementById('map').style.cursor = ''; - fms_markers_highlight(); - fms_sidebar_highlight(); - fixmystreet.latest_map_hover_event = 'outFeature'; - } - } + // `markers.redraw()` in markers_highlight will trigger an + // `overFeature` event if the mouse cursor is still over the same + // marker on the map, which would then run markers_highlight + // again, causing an infinite flicker while the cursor remains over + // the same marker. We really only want to redraw the markers when + // the cursor moves from one marker to another (ie: when there is an + // overFeature followed by an outFeature followed by an overFeature). + // Therefore, we keep track of the previous event in + // fixmystreet.latest_map_hover_event and only call markers_highlight + // if we know the previous event was different to the current one. + // (See the `overFeature` and `outFeature` callbacks inside of + // fixmystreet.select_feature). + + function markers_highlight(problem_id) { + for (var i = 0; i < fixmystreet.markers.features.length; i++) { + if (typeof problem_id == 'undefined') { + // There is no highlighted marker, so unfade this marker + fixmystreet.markers.features[i].attributes.faded = 0; + } else if (problem_id == fixmystreet.markers.features[i].attributes.id) { + // This is the highlighted marker, unfade it + fixmystreet.markers.features[i].attributes.faded = 0; + } else { + // This is not the hightlighted marker, fade it + fixmystreet.markers.features[i].attributes.faded = 1; } - ); - fixmystreet.map.addControl( fixmystreet.select_feature ); - fixmystreet.select_feature.activate(); - fixmystreet.map.events.register( 'zoomend', null, fms_markers_resize ); - - // If the category filter dropdown exists on the page set up the - // event handlers to populate it and react to it changing - if ($("select#filter_categories").length) { - $("body").on("change", "#filter_categories", fms_categories_or_status_changed); } - // Do the same for the status dropdown - if ($("select#statuses").length) { - $("body").on("change", "#statuses", fms_categories_or_status_changed); + fixmystreet.markers.redraw(); + } + + function sidebar_highlight(problem_id) { + if (typeof problem_id !== 'undefined') { + var $a = $('.item-list--reports a[href$="/' + problem_id + '"]'); + $a.parent().addClass('hovered'); + } else { + $('.item-list--reports .hovered').removeClass('hovered'); } - } else if (fixmystreet.page == 'new') { - fixmystreet_activate_drag(); } - fixmystreet.map.addLayer(fixmystreet.markers); - if ( fixmystreet.zoomToBounds ) { - fixmystreet_zoomToBounds( fixmystreet.markers.getDataExtent() ); + function marker_click(problem_id) { + var $a = $('.item-list--reports a[href$="/' + problem_id + '"]'); + $a[0] && $a[0].click(); } - $('#hide_pins_link').click(function(e) { - e.preventDefault(); - var showhide = [ - 'Show pins', 'Hide pins', - 'Dangos pinnau', 'Cuddio pinnau', - "Vis nåler", "Skjul nåler", - "Zeige Stecknadeln", "Stecknadeln ausblenden" - ]; - for (var i=0; i<showhide.length; i+=2) { - if (this.innerHTML == showhide[i]) { - fixmystreet.markers.setVisibility(true); - fixmystreet.select_feature.activate(); - this.innerHTML = showhide[i+1]; - } else if (this.innerHTML == showhide[i+1]) { - fixmystreet.markers.setVisibility(false); - fixmystreet.select_feature.deactivate(); - this.innerHTML = showhide[i]; + function categories_or_status_changed() { + // If the category or status has changed we need to re-fetch map markers + fixmystreet.markers.refresh({force: true}); + } + + function onload() { + if ( fixmystreet.area.length ) { + for (var i=0; i<fixmystreet.area.length; i++) { + var area = new OpenLayers.Layer.Vector("KML", { + strategies: [ new OpenLayers.Strategy.Fixed() ], + protocol: new OpenLayers.Protocol.HTTP({ + url: "/mapit/area/" + fixmystreet.area[i] + ".kml?simplify_tolerance=0.0001", + format: new OpenLayers.Format.KML() + }) + }); + fixmystreet.map.addLayer(area); + if ( fixmystreet.area.length == 1 ) { + area.events.register('loadend', null, function(a,b,c) { + if ( fixmystreet.area_format ) { + area.styleMap.styles['default'].defaultStyle = fixmystreet.area_format; + } + zoomToBounds( area.getDataExtent() ); + }); + } } } - }); - $('#all_pins_link').click(function(e) { - e.preventDefault(); - fixmystreet.markers.setVisibility(true); - var texts = [ - 'en', 'Show old', 'Hide old', - 'nb', 'Vis gamle', 'Skjul gamle', - 'cy', 'Cynnwys hen adroddiadau', 'Cuddio hen adroddiadau' - ]; - for (var i=0; i<texts.length; i+=3) { - if (this.innerHTML == texts[i+1]) { - this.innerHTML = texts[i+2]; - fixmystreet.markers.protocol.options.params = { all_pins: 1 }; - fixmystreet.markers.refresh( { force: true } ); - lang = texts[i]; - } else if (this.innerHTML == texts[i+2]) { - this.innerHTML = texts[i+1]; - fixmystreet.markers.protocol.options.params = { }; - fixmystreet.markers.refresh( { force: true } ); - lang = texts[i]; + var pin_layer_style_map = new OpenLayers.StyleMap({ + 'default': new OpenLayers.Style({ + graphicTitle: "${title}", + graphicOpacity: 1, + graphicZIndex: 11, + backgroundGraphicZIndex: 10 + }) + }); + pin_layer_style_map.addUniqueValueRules('default', 'size', { + 'normal': { + externalGraphic: fixmystreet.pin_prefix + "pin-${colour}.png", + graphicWidth: 48, + graphicHeight: 64, + graphicXOffset: -24, + graphicYOffset: -64, + backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow.png", + backgroundWidth: 60, + backgroundHeight: 30, + backgroundXOffset: -7, + backgroundYOffset: -30, + popupYOffset: -40 + }, + 'big': { + externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-big.png", + graphicWidth: 78, + graphicHeight: 105, + graphicXOffset: -39, + graphicYOffset: -105, + backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow-big.png", + backgroundWidth: 88, + backgroundHeight: 40, + backgroundXOffset: -10, + backgroundYOffset: -35 + }, + 'small': { + externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-small.png", + graphicWidth: 24, + graphicHeight: 32, + graphicXOffset: -12, + graphicYOffset: -32, + backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow-small.png", + backgroundWidth: 30, + backgroundHeight: 15, + backgroundXOffset: -4, + backgroundYOffset: -15, + popupYOffset: -20 + }, + 'mini': { + externalGraphic: fixmystreet.pin_prefix + "pin-${colour}-mini.png", + graphicWidth: 16, + graphicHeight: 20, + graphicXOffset: -8, + graphicYOffset: -20, + popupYOffset: -10 } + }); + pin_layer_style_map.addUniqueValueRules('default', 'faded', { + 0: { + graphicOpacity: 1 + }, + 1: { + graphicOpacity: 0.4 + } + }); + var pin_layer_options = { + rendererOptions: { + yOrdering: true + }, + styleMap: pin_layer_style_map + }; + if (fixmystreet.page == 'around') { + fixmystreet.bbox_strategy = fixmystreet.bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); + pin_layer_options.strategies = [ fixmystreet.bbox_strategy ]; + pin_layer_options.protocol = new OpenLayers.Protocol.FixMyStreet({ + url: '/ajax', + params: fixmystreet.all_pins ? { all_pins: 1 } : { }, + format: new OpenLayers.Format.FixMyStreet() + }); } - if (lang == 'cy') { - document.getElementById('hide_pins_link').innerHTML = 'Cuddio pinnau'; - } else if (lang == 'nb') { - document.getElementById('hide_pins_link').innerHTML = 'Skjul nåler'; - } else { - document.getElementById('hide_pins_link').innerHTML = 'Hide pins'; - } - }); - -} - -$(function(){ + fixmystreet.markers = new OpenLayers.Layer.Vector("Pins", pin_layer_options); + fixmystreet.markers.events.register( 'loadend', fixmystreet.markers, function(evt) { + if (fixmystreet.map.popups.length) { + fixmystreet.map.removePopup(fixmystreet.map.popups[0]); + } + }); - // Set specific map config - some other JS included in the - // template should define this - set_map_config(); + var markers = fixmystreet.maps.markers_list( fixmystreet.pins, true ); + fixmystreet.markers.addFeatures( markers ); + + if (fixmystreet.page == 'around' || fixmystreet.page == 'reports' || fixmystreet.page == 'my') { + fixmystreet.select_feature = new OpenLayers.Control.SelectFeature( + fixmystreet.markers, + { + hover: true, + // Override clickFeature so that we can use it even though + // hover is true. http://gis.stackexchange.com/a/155675 + clickFeature: function (feature) { + marker_click(feature.attributes.id); + }, + overFeature: function (feature) { + if (fixmystreet.latest_map_hover_event != 'overFeature') { + document.getElementById('map').style.cursor = 'pointer'; + markers_highlight(feature.attributes.id); + sidebar_highlight(feature.attributes.id); + fixmystreet.latest_map_hover_event = 'overFeature'; + } + }, + outFeature: function (feature) { + if (fixmystreet.latest_map_hover_event != 'outFeature') { + document.getElementById('map').style.cursor = ''; + markers_highlight(); + sidebar_highlight(); + fixmystreet.latest_map_hover_event = 'outFeature'; + } + } + } + ); + fixmystreet.map.addControl( fixmystreet.select_feature ); + fixmystreet.select_feature.activate(); + fixmystreet.map.events.register( 'zoomend', null, fixmystreet.maps.markers_resize ); + + // If the category filter dropdown exists on the page set up the + // event handlers to populate it and react to it changing + if ($("select#filter_categories").length) { + $("body").on("change", "#filter_categories", categories_or_status_changed); + } + // Do the same for the status dropdown + if ($("select#statuses").length) { + $("body").on("change", "#statuses", categories_or_status_changed); + } + } else if (fixmystreet.page == 'new') { + drag.activate(); + } + fixmystreet.map.addLayer(fixmystreet.markers); + + if ( fixmystreet.zoomToBounds ) { + zoomToBounds( fixmystreet.markers.getDataExtent() ); + } + + $('#hide_pins_link').click(function(e) { + e.preventDefault(); + var showhide = [ + 'Show pins', 'Hide pins', + 'Dangos pinnau', 'Cuddio pinnau', + "Vis nåler", "Skjul nåler", + "Zeige Stecknadeln", "Stecknadeln ausblenden" + ]; + for (var i=0; i<showhide.length; i+=2) { + if (this.innerHTML == showhide[i]) { + fixmystreet.markers.setVisibility(true); + fixmystreet.select_feature.activate(); + this.innerHTML = showhide[i+1]; + } else if (this.innerHTML == showhide[i+1]) { + fixmystreet.markers.setVisibility(false); + fixmystreet.select_feature.deactivate(); + this.innerHTML = showhide[i]; + } + } + }); - // Create the basics of the map - fixmystreet.map = new OpenLayers.Map( - "map", OpenLayers.Util.extend({ - controls: fixmystreet.controls, - displayProjection: new OpenLayers.Projection("EPSG:4326") - }, fixmystreet.map_options) - ); + $('#all_pins_link').click(function(e) { + e.preventDefault(); + fixmystreet.markers.setVisibility(true); + var texts = [ + 'en', 'Show old', 'Hide old', + 'nb', 'Vis gamle', 'Skjul gamle', + 'cy', 'Cynnwys hen adroddiadau', 'Cuddio hen adroddiadau' + ]; + for (var i=0; i<texts.length; i+=3) { + if (this.innerHTML == texts[i+1]) { + this.innerHTML = texts[i+2]; + fixmystreet.markers.protocol.options.params = { all_pins: 1 }; + fixmystreet.markers.refresh( { force: true } ); + lang = texts[i]; + } else if (this.innerHTML == texts[i+2]) { + this.innerHTML = texts[i+1]; + fixmystreet.markers.protocol.options.params = { }; + fixmystreet.markers.refresh( { force: true } ); + lang = texts[i]; + } + } + if (lang == 'cy') { + document.getElementById('hide_pins_link').innerHTML = 'Cuddio pinnau'; + } else if (lang == 'nb') { + document.getElementById('hide_pins_link').innerHTML = 'Skjul nåler'; + } else { + document.getElementById('hide_pins_link').innerHTML = 'Hide pins'; + } + }); - // Need to do this here, after the map is created (might not have been when - // resize() called) - if ($('html').hasClass('mobile') && fixmystreet.page == 'around') { - $('#fms_pan_zoom').css({ top: '2.75em' }); } - // Set it up our way + $(function(){ - var layer; - if (!fixmystreet.layer_options) { - fixmystreet.layer_options = [ {} ]; - } - if (!fixmystreet.layer_name) { - fixmystreet.layer_name = ""; - } - for (var i=0; i<fixmystreet.layer_options.length; i++) { - fixmystreet.layer_options[i] = OpenLayers.Util.extend({ - // This option is used by XYZ-based layers - zoomOffset: fixmystreet.zoomOffset, - // This option is used by FixedZoomLevels-based layers - minZoomLevel: fixmystreet.zoomOffset, - // This option is thankfully used by them both - numZoomLevels: fixmystreet.numZoomLevels - }, fixmystreet.layer_options[i]); - if (fixmystreet.layer_options[i].matrixIds) { - layer = new fixmystreet.map_type(fixmystreet.layer_options[i]); - } else { - layer = new fixmystreet.map_type(fixmystreet.layer_name, fixmystreet.layer_options[i]); - } - fixmystreet.map.addLayer(layer); - } + // Set specific map config - some other JS included in the + // template should define this + fixmystreet.maps.config(); - if (!fixmystreet.map.getCenter()) { - var centre = new OpenLayers.LonLat( fixmystreet.longitude, fixmystreet.latitude ); - centre.transform( - new OpenLayers.Projection("EPSG:4326"), - fixmystreet.map.getProjectionObject() + // Create the basics of the map + fixmystreet.map = new OpenLayers.Map( + "map", OpenLayers.Util.extend({ + controls: fixmystreet.controls, + displayProjection: new OpenLayers.Projection("EPSG:4326") + }, fixmystreet.map_options) ); - fixmystreet.map.setCenter(centre, fixmystreet.zoom || 3); - } - if (document.getElementById('mapForm')) { - var click = new OpenLayers.Control.Click(); - fixmystreet.map.addControl(click); - click.activate(); - } - - $(window).hashchange(function(){ - if (location.hash == '#report' && $('.rap-notes').is(':visible')) { - $('.rap-notes-close').click(); - return; + // Set it up our way + + var layer; + if (!fixmystreet.layer_options) { + fixmystreet.layer_options = [ {} ]; + } + if (!fixmystreet.layer_name) { + fixmystreet.layer_name = ""; + } + for (var i=0; i<fixmystreet.layer_options.length; i++) { + fixmystreet.layer_options[i] = OpenLayers.Util.extend({ + // This option is used by XYZ-based layers + zoomOffset: fixmystreet.zoomOffset, + // This option is used by FixedZoomLevels-based layers + minZoomLevel: fixmystreet.zoomOffset, + // This option is thankfully used by them both + numZoomLevels: fixmystreet.numZoomLevels + }, fixmystreet.layer_options[i]); + if (fixmystreet.layer_options[i].matrixIds) { + layer = new fixmystreet.map_type(fixmystreet.layer_options[i]); + } else { + layer = new fixmystreet.map_type(fixmystreet.layer_name, fixmystreet.layer_options[i]); + } + fixmystreet.map.addLayer(layer); } - if (location.hash && location.hash != '#') { - return; + if (!fixmystreet.map.getCenter()) { + var centre = new OpenLayers.LonLat( fixmystreet.longitude, fixmystreet.latitude ); + centre.transform( + new OpenLayers.Projection("EPSG:4326"), + fixmystreet.map.getProjectionObject() + ); + fixmystreet.map.setCenter(centre, fixmystreet.zoom || 3); } - // Okay, back to around view. - fixmystreet.bbox_strategy.activate(); - fixmystreet.markers.refresh( { force: true } ); - if ( fixmystreet.state_pins_were_hidden ) { - // If we had pins hidden when we clicked map (which had to show the pin layer as I'm doing it in one layer), hide them again. - $('#hide_pins_link').click(); + if (document.getElementById('mapForm')) { + var click = new OpenLayers.Control.Click(); + fixmystreet.map.addControl(click); + click.activate(); } - fixmystreet.drag.deactivate(); - $('#side-form').hide(); - $('#side').show(); - $('body').removeClass('with-notes'); - fixmystreet.map.updateSize(); // required after changing the size of the map element - $('#sub_map_links').show(); - //only on mobile - $('#mob_sub_map_links').remove(); - $('.mobile-map-banner').html('<a href="/">' + translation_strings.home + '</a> ' + translation_strings.place_pin_on_map); - fixmystreet.page = 'around'; - }); - // Hide the pin filter submit button. Not needed because we'll use JS - // to refresh the map when the filter inputs are changed. - $(".report-list-filters [type=submit]").hide(); + // Hide the pin filter submit button. Not needed because we'll use JS + // to refresh the map when the filter inputs are changed. + $(".report-list-filters [type=submit]").hide(); - if (fixmystreet.page == "my" || fixmystreet.page == "reports") { - $(".report-list-filters select").change(function() { - $(this).closest("form").submit(); - }); - } + if (fixmystreet.page == "my" || fixmystreet.page == "reports") { + $(".report-list-filters select").change(function() { + $(this).closest("form").submit(); + }); + } - // Vector layers must be added onload as IE sucks - if ($.browser.msie) { - $(window).load(fixmystreet_onload); - } else { - fixmystreet_onload(); - } + // Vector layers must be added onload as IE sucks + if ($.browser.msie) { + $(window).load(onload); + } else { + onload(); + } + + (function() { + var timeout; + $('.item-list--reports').on('mouseenter', '.item-list--reports__item', function(){ + var href = $('a', this).attr('href'); + var id = parseInt(href.replace(/^.*[/]([0-9]+)$/, '$1')); + clearTimeout(timeout); + markers_highlight(id); + }).on('mouseleave', '.item-list--reports__item', function(){ + timeout = setTimeout(markers_highlight, 50); + }); + })(); + }); + +// End maps closure +})(); - (function() { - var timeout; - $('.item-list--reports').on('mouseenter', '.item-list--reports__item', function(){ - var href = $('a', this).attr('href'); - var id = parseInt(href.replace(/^.*[/]([0-9]+)$/, '$1')); - clearTimeout(timeout); - fms_markers_highlight(id); - }).on('mouseleave', '.item-list--reports__item', function(){ - timeout = setTimeout(fms_markers_highlight, 50); - }); - })(); -}); /* Overridding the buttonDown function of PanZoom so that it does zoomTo(0) rather than zoomToMaxExtent() @@ -663,7 +673,7 @@ OpenLayers.Format.FixMyStreet = OpenLayers.Class(OpenLayers.Format.JSON, { if (typeof(obj.current) != 'undefined' && (current = document.getElementById('current'))) { current.innerHTML = obj.current; } - return fms_markers_list( obj.pins, false ); + return fixmystreet.maps.markers_list( obj.pins, false ); }, CLASS_NAME: "OpenLayers.Format.FixMyStreet" }); @@ -691,96 +701,18 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { }, trigger: function(e) { - var cobrand = $('meta[name="cobrand"]').attr('content'); - var lonlat = fixmystreet.map.getLonLatFromViewPortPx(e.xy); - if (fixmystreet.page == 'new') { - /* Already have a pin */ - fixmystreet.markers.features[0].move(lonlat); - } else { - var markers = fms_markers_list( [ [ lonlat.lat, lonlat.lon, 'green' ] ], false ); - fixmystreet.bbox_strategy.deactivate(); - fixmystreet.markers.removeAllFeatures(); - fixmystreet.markers.addFeatures( markers ); - fixmystreet_activate_drag(); + // 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; } - // check to see if markers are visible. We click the - // link so that it updates the text in case they go - // back - if ( ! fixmystreet.markers.getVisibility() ) { - fixmystreet.state_pins_were_hidden = true; - $('#hide_pins_link').click(); - } - - // Store pin location in form fields, and check coverage of point - fixmystreet_update_pin(lonlat); - - // It's possible to invoke the OpenLayers.Control `trigger` callback - // multiple times in a row (eg: by clicking on the map multiple times, - // to reposition your report). - // But there is some stuff we only want to happen the first time you - // switch from the "around" view to the "new" report view. - // So, here we check whether we've already transitioned into the "new" - // report view, and if so, we return from the callback early, - // skipping the remainder of the setup stuff. - if (fixmystreet.page == 'new') { - fixmystreet.map.panDuration = 100; - fixmystreet.map.panTo(lonlat); - fixmystreet.map.panDuration = 50; - return; - } - - // If there are notes to be displayed, add the .with-notes class - // to make the sidebar wider. - if ($('#report-a-problem-sidebar').length) { - $('body').addClass('with-notes'); - } - - /* For some reason on IOS5 if you use the jQuery show method it - * doesn't display the JS validation error messages unless you do this - * or you cause a screen redraw by changing the phone orientation. - * NB: This has to happen after the call to show() in fixmystreet_update_pin */ - if ( navigator.userAgent.match(/like Mac OS X/i)) { - document.getElementById('side-form').style.display = 'block'; - } - $('#side').hide(); - - fixmystreet.map.updateSize(); // required after changing the size of the map element - - fixmystreet.map.panDuration = 100; - fixmystreet.map.panTo(lonlat); - fixmystreet.map.panDuration = 50; - - $('#sub_map_links').hide(); - if ($('html').hasClass('mobile')) { - var $map_box = $('#map_box'), - width = $map_box.width(), - height = $map_box.height(); - $map_box.append( '<p id="mob_sub_map_links">' + '<a href="#" id="try_again">' + translation_strings.try_again + '</a>' + '<a href="#ok" id="mob_ok">' + translation_strings.ok + '</a>' + '</p>' ).css({ position: 'relative', width: width, height: height, marginBottom: '1em' }); - // Making it relative here makes it much easier to do the scrolling later - - $('.mobile-map-banner').html('<a href="/">' + translation_strings.home + '</a> ' + translation_strings.right_place); - - // mobile user clicks 'ok' on map - $('#mob_ok').toggle(function(){ - //scroll the height of the map box instead of the offset - //of the #side-form or whatever as we will probably want - //to do this on other pages where #side-form might not be - $('html, body').animate({ scrollTop: height-60 }, 1000, function(){ - $('#mob_sub_map_links').addClass('map_complete'); - $('#mob_ok').text(translation_strings.map); - }); - }, function(){ - $('html, body').animate({ scrollTop: 0 }, 1000, function(){ - $('#mob_sub_map_links').removeClass('map_complete'); - $('#mob_ok').text(translation_strings.ok); - }); - }); - } + var lonlat = fixmystreet.map.getLonLatFromViewPortPx(e.xy); + fixmystreet.display.begin_report(lonlat); - fixmystreet.page = 'new'; - location.hash = 'report'; - if ( typeof ga !== 'undefined' && cobrand == 'fixmystreet' ) { + if ( typeof ga !== 'undefined' && window.cobrand == 'fixmystreet' ) { ga('send', 'pageview', { 'page': '/map_click' } ); } } diff --git a/web/js/map-OpenStreetMap.js b/web/js/map-OpenStreetMap.js index 5dcf3cab3..b2d6a4f8b 100644 --- a/web/js/map-OpenStreetMap.js +++ b/web/js/map-OpenStreetMap.js @@ -1,4 +1,4 @@ -function set_map_config(perm) { +fixmystreet.maps.config = function() { var permalink_id; if ($('#map_permalink').length) { permalink_id = 'map_permalink'; @@ -10,7 +10,7 @@ function set_map_config(perm) { new OpenLayers.Control.PermalinkFMS(permalink_id), new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' }) ]; -} +}; // http://www.openstreetmap.org/openlayers/OpenStreetMap.js (added maxResolution) diff --git a/web/js/map-bing-ol.js b/web/js/map-bing-ol.js index 5e29daea1..3ad92b27e 100644 --- a/web/js/map-bing-ol.js +++ b/web/js/map-bing-ol.js @@ -1,4 +1,4 @@ -function _set_map_config() { +fixmystreet.maps.config = function() { var permalink_id; if ($('#map_permalink').length) { permalink_id = 'map_permalink'; @@ -15,12 +15,8 @@ function _set_map_config() { if ( fixmystreet.page == 'report' ) { fixmystreet.controls.push( new OpenLayers.Control.PermalinkFMS('key-tool-problems-nearby', '/around') ); } -} - -function set_map_config(perm) { - _set_map_config(); fixmystreet.map_type = OpenLayers.Layer.Bing; -} +}; OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { attributionTemplate: '${logo}${copyrights}', diff --git a/web/js/map-fms.js b/web/js/map-fms.js index c5bf70191..65c02a503 100644 --- a/web/js/map-fms.js +++ b/web/js/map-fms.js @@ -1,13 +1,14 @@ -var fms_tile_base = [ [ '', 'a-', 'b-', 'c-' ], '//{S}tilma.mysociety.org/sv' ]; +fixmystreet.maps.tile_base = [ [ '', 'a-', 'b-', 'c-' ], '//{S}tilma.mysociety.org/sv' ]; -function set_map_config(perm) { - _set_map_config(); - - if (fixmystreet.map_type) { - fms_tile_base = fixmystreet.map_type; - } - fixmystreet.map_type = OpenLayers.Layer.BingUK; -} +fixmystreet.maps.config = (function(original) { + return function(){ + if (fixmystreet.map_type) { + this.tile_base = fixmystreet.map_type; + } + original(); + fixmystreet.map_type = OpenLayers.Layer.BingUK; + }; +})(fixmystreet.maps.config); OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, { uk_bounds: [ @@ -54,8 +55,8 @@ OpenLayers.Layer.BingUK = OpenLayers.Class(OpenLayers.Layer.Bing, { var in_uk = this.in_uk(bounds.getCenterLonLat()); if (z >= 16 && in_uk) { urls = []; - for (var i=0; i< fms_tile_base[0].length; i++) { - urls.push( fms_tile_base[1].replace('{S}', fms_tile_base[0][i]) + "/${z}/${x}/${y}.png" ); + for (var i=0; i< fixmystreet.maps.tile_base[0].length; i++) { + urls.push( fixmystreet.maps.tile_base[1].replace('{S}', fixmystreet.maps.tile_base[0][i]) + "/${z}/${x}/${y}.png" ); } } else { var type = ''; diff --git a/web/js/map-google-ol.js b/web/js/map-google-ol.js index 5a1aa3c57..96ec6fe9b 100644 --- a/web/js/map-google-ol.js +++ b/web/js/map-google-ol.js @@ -15,7 +15,7 @@ $(function(){ } }); -function set_map_config(perm) { +fixmystreet.maps.config = function() { var permalink_id; if ($('#map_permalink').length) { permalink_id = 'map_permalink'; @@ -37,5 +37,4 @@ function set_map_config(perm) { {}, { type: google.maps.MapTypeId.HYBRID } ]; -} - +}; diff --git a/web/js/map-google.js b/web/js/map-google.js index 5009bebac..4c3f6188e 100644 --- a/web/js/map-google.js +++ b/web/js/map-google.js @@ -5,313 +5,269 @@ TODO Pin size on report page */ -function PaddingControl(div) { - div.style.padding = '40px'; -} +var fixmystreet = fixmystreet || {}; +fixmystreet.maps = {}; -function fixmystreet_update_pin(lonlat) { - document.getElementById('fixmystreet.latitude').value = lonlat.lat(); - document.getElementById('fixmystreet.longitude').value = lonlat.lng(); +(function() { - $.getJSON('/report/new/ajax', { - latitude: $('#fixmystreet\\.latitude').val(), - longitude: $('#fixmystreet\\.longitude').val() - }, function(data) { - if (data.error) { - if (!$('#side-form-error').length) { - $('<div id="side-form-error"/>').insertAfter($('#side-form')); - } - $('#side-form-error').html('<h1>' + translation_strings.reporting_a_problem + '</h1><p>' + data.error + '</p>').show(); - $('#side-form').hide(); - return; - } - $('#side-form, #site-logo').show(); - $('#councils_text').html(data.councils_text); - $('#form_category_row').html(data.category); - if ( data.extra_name_info && !$('#form_fms_extra_title').length ) { - // there might be a first name field on some cobrands - var lb = $('#form_first_name').prev(); - if ( lb.length === 0 ) { lb = $('#form_name').prev(); } - lb.before(data.extra_name_info); - } - }); - - if (!$('#side-form-error').is(':visible')) { - $('#side-form, #site-logo').show(); - } -} - -var infowindow = new google.maps.InfoWindow(); -function make_infowindow(marker) { - return function() { - infowindow.setContent(marker.title + "<br><a href=/report/" + marker.id + ">" + translation_strings.more_details + "</a>"); - infowindow.open(fixmystreet.map, marker); + fixmystreet.maps.update_pin = function(lonlat) { + var lat = lonlat.lat(); + var lon = lonlat.lng(); + document.getElementById('fixmystreet.latitude').value = lat; + document.getElementById('fixmystreet.longitude').value = lon; + return { + 'url': { 'lon': lon, 'lat': lat }, + 'state': { 'lon': lon, 'lat': lat } + }; }; -} -function fms_markers_list(pins, transform) { - var markers = []; - if (fixmystreet.markers) { - for (var m=0; m<fixmystreet.markers.length; m++) { - fixmystreet.markers[m].setMap(null); - } - } - for (var i=0; i<pins.length; i++) { - var pin = pins[i]; - var pin_args = { - position: new google.maps.LatLng( pin[0], pin[1] ), - //size: pin[5] || 'normal', - id: pin[3], - title: pin[4] || '', - map: fixmystreet.map - }; - if (pin[2] == 'green') { - pin_args.icon = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|87dd00"; - } - if (pin[2] == 'yellow') { - pin_args.icon = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ffd600"; + fixmystreet.maps.begin_report = function(lonlat) { + if (typeof lonlat.lat !== 'function') { + lonlat = new google.maps.LatLng(lonlat.lat, lonlat.lon); } - var marker = new google.maps.Marker(pin_args); - if (fixmystreet.page == 'around' || fixmystreet.page == 'reports' || fixmystreet.page == 'my') { - var l = new google.maps.event.addListener(marker, 'click', make_infowindow(marker)); + + if (fixmystreet.page == 'new') { + /* Already have a pin */ + fixmystreet.report_marker.setPosition(lonlat); + } else { + var marker = new google.maps.Marker({ + position: lonlat, + draggable: true, + animation: google.maps.Animation.DROP, + map: fixmystreet.map + }); + var l = google.maps.event.addListener(marker, 'dragend', function(){ + fixmystreet.update_pin( marker.getPosition() ); + }); + fixmystreet.report_marker = marker; + google.maps.event.removeListener(fixmystreet.event_update_map); + for (m=0; m<fixmystreet.markers.length; m++) { + fixmystreet.markers[m].setMap(null); + } } - markers.push( marker ); - } - return markers; -} + return lonlat; + }; -function fms_map_clicked(e) { - var lonlat = e.latLng; - if (fixmystreet.page == 'new') { - /* Already have a pin */ - fixmystreet.report_marker.setPosition(lonlat); - } else { - var marker = new google.maps.Marker({ - position: lonlat, - draggable: true, - animation: google.maps.Animation.DROP, - map: fixmystreet.map - }); - var l = google.maps.event.addListener(marker, 'dragend', function(){ - fixmystreet_update_pin( marker.getPosition() ); - }); - fixmystreet.report_marker = marker; - google.maps.event.removeListener(fixmystreet.event_update_map); - for (m=0; m<fixmystreet.markers.length; m++) { - fixmystreet.markers[m].setMap(null); + fixmystreet.maps.display_around = function() { + if (fixmystreet.report_marker) { + fixmystreet.report_marker.setMap(null); } - } + fixmystreet.event_update_map = google.maps.event.addListener(fixmystreet.map, 'idle', update_pins); + google.maps.event.trigger(fixmystreet.map, 'idle'); + }; - // check to see if markers are visible. We click the - // link so that it updates the text in case they go - // back - if ( ! 1 ) { // XXX fixmystreet.markers.getVisibility() ) - fixmystreet.state_pins_were_hidden = true; - $('#hide_pins_link').click(); + function PaddingControl(div) { + div.style.padding = '40px'; } - // Store pin location in form fields, and check coverage of point - fixmystreet_update_pin(lonlat); - - // Already did this first time map was clicked, so no need to do it again. - if (fixmystreet.page == 'new') { - return; + var infowindow = new google.maps.InfoWindow(); + function make_infowindow(marker) { + return function() { + infowindow.setContent(marker.title + "<br><a href=/report/" + marker.id + ">" + translation_strings.more_details + "</a>"); + infowindow.open(fixmystreet.map, marker); + }; } - $('#side').hide(); - - // If we clicked the map somewhere inconvenient - // TODO - - $('#sub_map_links').hide(); - fixmystreet.page = 'new'; - location.hash = 'report'; -} - -/* Pan data handler */ -function fms_read_pin_json(obj) { - var current, current_near; - if (typeof(obj.current) != 'undefined' && (current = document.getElementById('current'))) { - current.innerHTML = obj.current; - } - if (typeof(obj.current_near) != 'undefined' && (current_near = document.getElementById('current_near'))) { - current_near.innerHTML = obj.current_near; + function markers_list(pins, transform) { + var markers = []; + if (fixmystreet.markers) { + for (var m=0; m<fixmystreet.markers.length; m++) { + fixmystreet.markers[m].setMap(null); + } + } + for (var i=0; i<pins.length; i++) { + var pin = pins[i]; + var pin_args = { + position: new google.maps.LatLng( pin[0], pin[1] ), + //size: pin[5] || 'normal', + id: pin[3], + title: pin[4] || '', + map: fixmystreet.map + }; + if (pin[2] == 'green') { + pin_args.icon = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|87dd00"; + } + if (pin[2] == 'yellow') { + pin_args.icon = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ffd600"; + } + var marker = new google.maps.Marker(pin_args); + if (fixmystreet.page == 'around' || fixmystreet.page == 'reports' || fixmystreet.page == 'my') { + var l = new google.maps.event.addListener(marker, 'click', make_infowindow(marker)); + } + markers.push( marker ); + } + return markers; } - fixmystreet.markers = fms_markers_list( obj.pins, false ); -} -function fms_update_pins() { - var b = fixmystreet.map.getBounds(), - b_sw = b.getSouthWest(), - b_ne = b.getNorthEast(), - bbox = b_sw.lng() + ',' + b_sw.lat() + ',' + b_ne.lng() + ',' + b_ne.lat(), - params = { - bbox: bbox - }; - if (fixmystreet.all_pins) { - params.all_pins = 1; + function map_clicked(e) { + if ($('.js-back-to-report-list').length) { + $('.js-back-to-report-list').trigger('click'); + return true; + } + + var lonlat = e.latLng; + fixmystreet.display.begin_report(lonlat); } - $.getJSON('/ajax', params, fms_read_pin_json); -} -function fms_map_initialize() { - var centre = new google.maps.LatLng( fixmystreet.latitude, fixmystreet.longitude ); - var map_args = { - mapTypeId: google.maps.MapTypeId.ROADMAP, - center: centre, - zoom: 13 + fixmystreet.zoom, - disableDefaultUI: true, - panControl: true, - panControlOptions: { - position: google.maps.ControlPosition.RIGHT_TOP - }, - zoomControl: true, - zoomControlOptions: { - position: google.maps.ControlPosition.RIGHT_TOP - }, - mapTypeControl: true, - mapTypeControlOptions: { - position: google.maps.ControlPosition.RIGHT_TOP, - style: google.maps.MapTypeControlStyle.DROPDOWN_MENU + /* Pan data handler */ + function read_pin_json(obj) { + var current, current_near; + if (typeof(obj.current) != 'undefined' && (current = document.getElementById('current'))) { + current.innerHTML = obj.current; } - }; - if (!fixmystreet.zoomToBounds) { - map_args.minZoom = 13; - map_args.maxZoom = 18; + if (typeof(obj.current_near) != 'undefined' && (current_near = document.getElementById('current_near'))) { + current_near.innerHTML = obj.current_near; + } + fixmystreet.markers = markers_list( obj.pins, false ); } - fixmystreet.map = new google.maps.Map(document.getElementById("map"), map_args); - - /* Space above the top right controls */ - var paddingDiv = document.createElement('div'); - var paddingControl = new PaddingControl(paddingDiv); - paddingDiv.index = 0; - fixmystreet.map.controls[google.maps.ControlPosition.RIGHT_TOP].push(paddingDiv); - if (document.getElementById('mapForm')) { - var l = google.maps.event.addListener(fixmystreet.map, 'click', fms_map_clicked); + function update_pins() { + var b = fixmystreet.map.getBounds(), + b_sw = b.getSouthWest(), + b_ne = b.getNorthEast(), + bbox = b_sw.lng() + ',' + b_sw.lat() + ',' + b_ne.lng() + ',' + b_ne.lat(), + params = { + bbox: bbox + }; + if (fixmystreet.all_pins) { + params.all_pins = 1; + } + $.getJSON('/ajax', params, read_pin_json); } - $(window).hashchange(function(){ - if (location.hash == '#report' && $('.rap-notes').is(':visible')) { - $('.rap-notes-close').click(); - return; + function map_initialize() { + var centre = new google.maps.LatLng( fixmystreet.latitude, fixmystreet.longitude ); + var map_args = { + mapTypeId: google.maps.MapTypeId.ROADMAP, + center: centre, + zoom: 13 + fixmystreet.zoom, + disableDefaultUI: true, + panControl: true, + panControlOptions: { + position: google.maps.ControlPosition.RIGHT_TOP + }, + zoomControl: true, + zoomControlOptions: { + position: google.maps.ControlPosition.RIGHT_TOP + }, + mapTypeControl: true, + mapTypeControlOptions: { + position: google.maps.ControlPosition.RIGHT_TOP, + style: google.maps.MapTypeControlStyle.DROPDOWN_MENU + } + }; + if (!fixmystreet.zoomToBounds) { + map_args.minZoom = 13; + map_args.maxZoom = 18; } + fixmystreet.map = new google.maps.Map(document.getElementById("map"), map_args); - if (location.hash && location.hash != '#') { - return; - } + /* Space above the top right controls */ + var paddingDiv = document.createElement('div'); + var paddingControl = new PaddingControl(paddingDiv); + paddingDiv.index = 0; + fixmystreet.map.controls[google.maps.ControlPosition.RIGHT_TOP].push(paddingDiv); - // Okay, back to around view. - fixmystreet.report_marker.setMap(null); - fixmystreet.event_update_map = google.maps.event.addListener(fixmystreet.map, 'idle', fms_update_pins); - google.maps.event.trigger(fixmystreet.map, 'idle'); - if ( fixmystreet.state_pins_were_hidden ) { - // If we had pins hidden when we clicked map (which had to show the pin layer as I'm doing it in one layer), hide them again. - $('#hide_pins_link').click(); + if (document.getElementById('mapForm')) { + var l = google.maps.event.addListener(fixmystreet.map, 'click', map_clicked); } - $('#side-form').hide(); - $('#side').show(); - $('#sub_map_links').show(); - //only on mobile - $('#mob_sub_map_links').remove(); - $('.mobile-map-banner').html('<a href="/">' + translation_strings.home + '</a> ' + translation_strings.place_pin_on_map); - fixmystreet.page = 'around'; - }); - if ( fixmystreet.area.length ) { - for (var i=0; i<fixmystreet.area.length; i++) { - var args = { - url: "http://mapit.mysociety.org/area/" + fixmystreet.area[i] + ".kml?simplify_tolerance=0.0001", - clickable: false, - preserveViewport: true, - map: fixmystreet.map - }; - if ( fixmystreet.area.length == 1 ) { - args.preserveViewport = false; + if ( fixmystreet.area.length ) { + for (var i=0; i<fixmystreet.area.length; i++) { + var args = { + url: "http://mapit.mysociety.org/area/" + fixmystreet.area[i] + ".kml?simplify_tolerance=0.0001", + clickable: false, + preserveViewport: true, + map: fixmystreet.map + }; + if ( fixmystreet.area.length == 1 ) { + args.preserveViewport = false; + } + var a = new google.maps.KmlLayer(args); + a.setMap(fixmystreet.map); } - var a = new google.maps.KmlLayer(args); - a.setMap(fixmystreet.map); } - } - if (fixmystreet.page == 'around') { - fixmystreet.event_update_map = google.maps.event.addListener(fixmystreet.map, 'idle', fms_update_pins); - } + if (fixmystreet.page == 'around') { + fixmystreet.event_update_map = google.maps.event.addListener(fixmystreet.map, 'idle', update_pins); + } - fixmystreet.markers = fms_markers_list( fixmystreet.pins, true ); + fixmystreet.markers = markers_list( fixmystreet.pins, true ); - /* - if ( fixmystreet.zoomToBounds ) { - var bounds = fixmystreet.markers.getDataExtent(); - if (bounds) { - var center = bounds.getCenterLonLat(); - var z = fixmystreet.map.getZoomForExtent(bounds); - if ( z < 13 && $('html').hasClass('mobile') ) { - z = 13; + /* + if ( fixmystreet.zoomToBounds ) { + var bounds = fixmystreet.markers.getDataExtent(); + if (bounds) { + var center = bounds.getCenterLonLat(); + var z = fixmystreet.map.getZoomForExtent(bounds); + if ( z < 13 && $('html').hasClass('mobile') ) { + z = 13; + } + fixmystreet.map.setCenter(center, z); } - fixmystreet.map.setCenter(center, z); } - } - */ + */ - $('#hide_pins_link').click(function(e) { - var i, m; - e.preventDefault(); - var showhide = [ - 'Show pins', 'Hide pins', - 'Dangos pinnau', 'Cuddio pinnau', - "Vis nåler", "Gjem nåler", - "Zeige Stecknadeln", "Stecknadeln ausblenden" - ]; - for (i=0; i<showhide.length; i+=2) { - if (this.innerHTML == showhide[i]) { - for (m=0; m<fixmystreet.markers.length; m++) { - fixmystreet.markers[m].setMap(fixmystreet.map); - } - this.innerHTML = showhide[i+1]; - } else if (this.innerHTML == showhide[i+1]) { - for (m=0; m<fixmystreet.markers.length; m++) { - fixmystreet.markers[m].setMap(null); + $('#hide_pins_link').click(function(e) { + var i, m; + e.preventDefault(); + var showhide = [ + 'Show pins', 'Hide pins', + 'Dangos pinnau', 'Cuddio pinnau', + "Vis nåler", "Gjem nåler", + "Zeige Stecknadeln", "Stecknadeln ausblenden" + ]; + for (i=0; i<showhide.length; i+=2) { + if (this.innerHTML == showhide[i]) { + for (m=0; m<fixmystreet.markers.length; m++) { + fixmystreet.markers[m].setMap(fixmystreet.map); + } + this.innerHTML = showhide[i+1]; + } else if (this.innerHTML == showhide[i+1]) { + for (m=0; m<fixmystreet.markers.length; m++) { + fixmystreet.markers[m].setMap(null); + } + this.innerHTML = showhide[i]; } - this.innerHTML = showhide[i]; } - } - }); + }); - $('#all_pins_link').click(function(e) { - var i; - e.preventDefault(); - for (i=0; i<fixmystreet.markers.length; i++) { - fixmystreet.markers[i].setMap(fixmystreet.map); - } - var texts = [ - 'en', 'Show old', 'Hide old', - 'nb', 'Inkluder utdaterte problemer', 'Skjul utdaterte rapporter', - 'cy', 'Cynnwys hen adroddiadau', 'Cuddio hen adroddiadau' - ]; - for (i=0; i<texts.length; i+=3) { - if (this.innerHTML == texts[i+1]) { - this.innerHTML = texts[i+2]; - fixmystreet.markers.protocol.options.params = { all_pins: 1 }; - fixmystreet.markers.refresh( { force: true } ); - lang = texts[i]; - } else if (this.innerHTML == texts[i+2]) { - this.innerHTML = texts[i+1]; - fixmystreet.markers.protocol.options.params = { }; - fixmystreet.markers.refresh( { force: true } ); - lang = texts[i]; + $('#all_pins_link').click(function(e) { + var i; + e.preventDefault(); + for (i=0; i<fixmystreet.markers.length; i++) { + fixmystreet.markers[i].setMap(fixmystreet.map); } - } - if (lang == 'cy') { - document.getElementById('hide_pins_link').innerHTML = 'Cuddio pinnau'; - } else if (lang == 'nb') { - document.getElementById('hide_pins_link').innerHTML = 'Gjem nåler'; - } else { - document.getElementById('hide_pins_link').innerHTML = 'Hide pins'; - } - }); + var texts = [ + 'en', 'Show old', 'Hide old', + 'nb', 'Inkluder utdaterte problemer', 'Skjul utdaterte rapporter', + 'cy', 'Cynnwys hen adroddiadau', 'Cuddio hen adroddiadau' + ]; + for (i=0; i<texts.length; i+=3) { + if (this.innerHTML == texts[i+1]) { + this.innerHTML = texts[i+2]; + fixmystreet.markers.protocol.options.params = { all_pins: 1 }; + fixmystreet.markers.refresh( { force: true } ); + lang = texts[i]; + } else if (this.innerHTML == texts[i+2]) { + this.innerHTML = texts[i+1]; + fixmystreet.markers.protocol.options.params = { }; + fixmystreet.markers.refresh( { force: true } ); + lang = texts[i]; + } + } + if (lang == 'cy') { + document.getElementById('hide_pins_link').innerHTML = 'Cuddio pinnau'; + } else if (lang == 'nb') { + document.getElementById('hide_pins_link').innerHTML = 'Gjem nåler'; + } else { + document.getElementById('hide_pins_link').innerHTML = 'Hide pins'; + } + }); + + } -} + google.maps.visualRefresh = true; + google.maps.event.addDomListener(window, 'load', map_initialize); -google.maps.visualRefresh = true; -google.maps.event.addDomListener(window, 'load', fms_map_initialize); +})(); diff --git a/web/js/map-streetview.js b/web/js/map-streetview.js index 58d856781..6d9195246 100644 --- a/web/js/map-streetview.js +++ b/web/js/map-streetview.js @@ -1,4 +1,4 @@ -function set_map_config(perm) { +fixmystreet.maps.config = function() { fixmystreet.controls = [ new OpenLayers.Control.ArgParser(), new OpenLayers.Control.Navigation(), @@ -6,7 +6,7 @@ function set_map_config(perm) { new OpenLayers.Control.PanZoomFMS() ]; fixmystreet.map_type = OpenLayers.Layer.StreetView; -} +}; // http://os.openstreetmap.org/openlayers/OS.js (added one line) diff --git a/web/js/map-toner-lite.js b/web/js/map-toner-lite.js index 5291d0254..eda12ff28 100644 --- a/web/js/map-toner-lite.js +++ b/web/js/map-toner-lite.js @@ -1,4 +1,4 @@ -function set_map_config(perm) { +fixmystreet.maps.config = function() { var permalink_id; if ($('#map_permalink').length) { permalink_id = 'map_permalink'; @@ -16,4 +16,4 @@ function set_map_config(perm) { // The Stamen JS returns HTTP urls, fix that stamen.tile.getProvider('toner-lite').url = 'https://stamen-tiles-{S}a.ssl.fastly.net/toner-lite/{Z}/{X}/{Y}.png'; -} +}; diff --git a/web/js/map-wmts-bristol.js b/web/js/map-wmts-bristol.js index 0fb664d76..94ed2bdb2 100644 --- a/web/js/map-wmts-bristol.js +++ b/web/js/map-wmts-bristol.js @@ -94,10 +94,10 @@ var matrix_ids = [ ]; /* - * set_map_config() is called on dom ready in map-OpenLayers.js + * maps.config() is called on dom ready in map-OpenLayers.js * to setup the way the map should operate. */ - function set_map_config(perm) { +fixmystreet.maps.config = function() { // This stuff is copied from js/map-bing-ol.js var nav_opts = { zoomWheelEnabled: false }; @@ -120,9 +120,9 @@ var matrix_ids = [ } setup_wmts_base_map(); -} +}; -function fms_marker_size_for_zoom(zoom) { +fixmystreet.maps.marker_size_for_zoom = function(zoom) { if (zoom >= 7) { return 'normal'; } else if (zoom >= 4) { @@ -130,4 +130,4 @@ function fms_marker_size_for_zoom(zoom) { } else { return 'mini'; } -} +}; diff --git a/web/js/map-wmts-zurich.js b/web/js/map-wmts-zurich.js index aa673f52d..1995cb401 100644 --- a/web/js/map-wmts-zurich.js +++ b/web/js/map-wmts-zurich.js @@ -113,58 +113,62 @@ var matrix_ids = [ } ]; -function fixmystreet_zurich_admin_drag() { - var admin_drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { - onComplete: function(feature, e) { - var lonlat = feature.geometry.clone(); - lonlat.transform( - fixmystreet.map.getProjectionObject(), - new OpenLayers.Projection("EPSG:4326") - ); - if (window.confirm( 'Richtiger Ort?' ) ) { - // Store new co-ordinates - document.getElementById('fixmystreet.latitude').value = lonlat.y; - document.getElementById('fixmystreet.longitude').value = lonlat.x; - } else { - // Put it back - var lat = document.getElementById('fixmystreet.latitude').value; - var lon = document.getElementById('fixmystreet.longitude').value; - lonlat = new OpenLayers.LonLat(lon, lat).transform( - new OpenLayers.Projection("EPSG:4326"), - fixmystreet.map.getProjectionObject() +(function() { + + function admin_drag() { + var drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, { + onComplete: function(feature, e) { + var lonlat = feature.geometry.clone(); + lonlat.transform( + fixmystreet.map.getProjectionObject(), + new OpenLayers.Projection("EPSG:4326") ); - fixmystreet.markers.features[0].move(lonlat); + if (window.confirm( 'Richtiger Ort?' ) ) { + // Store new co-ordinates + document.getElementById('fixmystreet.latitude').value = lonlat.y; + document.getElementById('fixmystreet.longitude').value = lonlat.x; + } else { + // Put it back + var lat = document.getElementById('fixmystreet.latitude').value; + var lon = document.getElementById('fixmystreet.longitude').value; + lonlat = new OpenLayers.LonLat(lon, lat).transform( + new OpenLayers.Projection("EPSG:4326"), + fixmystreet.map.getProjectionObject() + ); + fixmystreet.markers.features[0].move(lonlat); + } } - } - } ); - fixmystreet.map.addControl( admin_drag ); - admin_drag.activate(); -} + } ); + fixmystreet.map.addControl( drag ); + drag.activate(); + } -$(function(){ - $('#map_layer_toggle').toggle(function(){ - $(this).text('Luftbild'); - fixmystreet.map.setBaseLayer(fixmystreet.map.layers[1]); - }, function(){ - $(this).text('Stadtplan'); - fixmystreet.map.setBaseLayer(fixmystreet.map.layers[0]); - }); + $(function(){ + $('#map_layer_toggle').toggle(function(){ + $(this).text('Luftbild'); + fixmystreet.map.setBaseLayer(fixmystreet.map.layers[1]); + }, function(){ + $(this).text('Stadtplan'); + fixmystreet.map.setBaseLayer(fixmystreet.map.layers[0]); + }); - /* Admin dragging of pin */ - if (fixmystreet.page == 'admin') { - if ($.browser.msie) { - $(window).load(fixmystreet_zurich_admin_drag); - } else { - fixmystreet_zurich_admin_drag(); + /* Admin dragging of pin */ + if (fixmystreet.page == 'admin') { + if ($.browser.msie) { + $(window).load(admin_drag); + } else { + admin_drag(); + } } - } -}); + }); + +})(); /* - * set_map_config() is called on dom ready in map-OpenLayers.js + * maps.config() is called on dom ready in map-OpenLayers.js * to setup the way the map should operate. */ - function set_map_config(perm) { +fixmystreet.maps.config = function() { // This stuff is copied from js/map-bing-ol.js fixmystreet.controls = [ @@ -183,9 +187,9 @@ $(function(){ setup_wmts_base_map(); fixmystreet.area_format = { fillColor: 'none', strokeWidth: 4, strokeColor: 'black' }; -} +}; -function fms_marker_size_for_zoom(zoom) { +fixmystreet.maps.marker_size_for_zoom = function(zoom) { if (zoom >= 6) { return 'normal'; } else if (zoom >= 3) { @@ -193,4 +197,4 @@ function fms_marker_size_for_zoom(zoom) { } else { return 'mini'; } -} +}; |