diff options
Diffstat (limited to 'web/js/map-OpenLayers.js')
| -rw-r--r-- | web/js/map-OpenLayers.js | 1014 | 
1 files changed, 473 insertions, 541 deletions
| 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' } );          }      } | 
