// 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.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) {
$('
').insertAfter($('#side-form'));
}
$('#side-form-error').html('' + translation_strings.reporting_a_problem + '
' + data.error + '
').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 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 = $("#categories").val();
if (category !== undefined && $("#form_category option[value="+category+"]").length) {
$("#form_category").val(category);
}
});
if (!$('#side-form-error').is(':visible')) {
$('#side-form, #site-logo').show();
}
}
function fixmystreet_activate_drag() {
fixmystreet.drag = new OpenLayers.Control.DragFeature( fixmystreet.markers, {
onComplete: function(feature, e) {
fixmystreet_update_pin( feature.geometry.clone() );
}
} );
fixmystreet.map.addControl( fixmystreet.drag );
fixmystreet.drag.activate();
}
// Need to try and fake the 'centre' being 75% from the left
function fixmystreet_midpoint() {
var $content = $('.content'), mb = $('#map_box'),
q = ( $content.offset().left - mb.offset().left + $content.width() ) / 2,
mid_point = q < 0 ? 0 : q;
return mid_point;
}
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);
if (fixmystreet.state_map && fixmystreet.state_map == 'full') {
fixmystreet.map.pan(-fixmystreet_midpoint(), -25, { animate: false });
}
}
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= 15) {
return 'normal';
} else if (zoom >= 13) {
return 'small';
} else {
return 'mini';
}
}
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();
}
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" + translation_strings.more_details + "",
{ size: new OpenLayers.Size(0, 0), offset: new OpenLayers.Pixel(0, popupYOffset) },
true, onPopupClose);
feature.popup = popup;
fixmystreet.map.addPopup(popup);
});
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#categories").length) {
$("body").on("change", "#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);
}
} else if (fixmystreet.page == 'new') {
fixmystreet_activate_drag();
}
fixmystreet.map.addLayer(fixmystreet.markers);
if ( fixmystreet.zoomToBounds ) {
fixmystreet_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' + translation_strings.home + ' ' + 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();
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();
}
});
/* Overridding the buttonDown function of PanZoom so that it does
zoomTo(0) rather than zoomToMaxExtent()
*/
OpenLayers.Control.PanZoomFMS = OpenLayers.Class(OpenLayers.Control.PanZoom, {
onButtonClick: function (evt) {
var btn = evt.buttonElement;
switch (btn.action) {
case "panup":
this.map.pan(0, -this.getSlideFactor("h"));
break;
case "pandown":
this.map.pan(0, this.getSlideFactor("h"));
break;
case "panleft":
this.map.pan(-this.getSlideFactor("w"), 0);
break;
case "panright":
this.map.pan(this.getSlideFactor("w"), 0);
break;
case "zoomin":
case "zoomout":
case "zoomworld":
var mid_point = 0;
if (fixmystreet.state_map && fixmystreet.state_map == 'full') {
mid_point = fixmystreet_midpoint();
}
var size = this.map.getSize(),
xy = { x: size.w / 2 + mid_point, y: size.h / 2 };
switch (btn.action) {
case "zoomin":
this.map.zoomTo(this.map.getZoom() + 1, xy);
break;
case "zoomout":
this.map.zoomTo(this.map.getZoom() - 1, xy);
break;
case "zoomworld":
this.map.zoomTo(0, xy);
break;
}
}
}
});
/* Overriding Permalink so that it can pass the correct zoom to OSM */
OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink, {
_updateLink: function(alter_zoom) {
var separator = this.anchor ? '#' : '?';
var href = this.base;
if (href.indexOf(separator) != -1) {
href = href.substring( 0, href.indexOf(separator) );
}
var center = this.map.getCenter();
if ( center && fixmystreet.state_map && fixmystreet.state_map == 'full' ) {
// Translate the permalink co-ords so that 'centre' is accurate
var mid_point = fixmystreet_midpoint();
var p = this.map.getViewPortPxFromLonLat(center);
p.x += mid_point;
p.y += 25;
center = this.map.getLonLatFromViewPortPx(p);
}
var zoom = this.map.getZoom();
if ( alter_zoom ) {
zoom += fixmystreet.zoomOffset;
}
href += separator + OpenLayers.Util.getParameterString(this.createParams(center, zoom));
// Could use mlat/mlon here as well if we are on a page with a marker
if (this.anchor && !this.element) {
window.location.href = href;
}
else {
this.element.href = href;
}
},
updateLink: function() {
this._updateLink(0);
}
});
OpenLayers.Control.PermalinkFMSz = OpenLayers.Class(OpenLayers.Control.PermalinkFMS, {
updateLink: function() {
this._updateLink(1);
}
});
/* Pan data request handler */
// This class is used to get a JSON object from /ajax that contains
// pins for the map and HTML for the sidebar. It does a fetch whenever the map
// is dragged (modulo a buffer extending outside the viewport).
// This subclass is required so we can pass the 'category' and 'status' query
// params to /ajax if the user has filtered the map.
OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
read: function(options) {
// Pass the values of the category and status fields as query params
var category = $("#categories").val();
if (category !== undefined) {
options.params = options.params || {};
options.params.category = category;
}
var status = $("#statuses").val();
if (status !== undefined) {
options.params = options.params || {};
options.params.status = status;
}
return OpenLayers.Protocol.HTTP.prototype.read.apply(this, [options]);
},
CLASS_NAME: "OpenLayers.Protocol.FixMyStreet"
});
/* Pan data handler */
OpenLayers.Format.FixMyStreet = OpenLayers.Class(OpenLayers.Format.JSON, {
read: function(json, filter) {
if (typeof json == 'string') {
obj = OpenLayers.Format.JSON.prototype.read.apply(this, [json, filter]);
} else {
obj = json;
}
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;
}
return fms_markers_list( obj.pins, false );
},
CLASS_NAME: "OpenLayers.Format.FixMyStreet"
});
/* Click handler */
OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
defaultHandlerOptions: {
'single': true,
'double': false,
'pixelTolerance': 0,
'stopSingle': false,
'stopDouble': false
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
{}, this.defaultHandlerOptions);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Click(
this, {
'click': this.trigger
}, this.handlerOptions);
},
trigger: function(e) {
var cobrand = $('meta[name="cobrand"]').attr('content');
if (typeof fixmystreet.nav_control != 'undefined') {
fixmystreet.nav_control.disableZoomWheel();
}
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();
}
// 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);
// Already did this first time map was clicked, so no need to do it again.
if (fixmystreet.page == 'new') {
return;
}
fixmystreet.map.updateSize(); // might have done, and otherwise Firefox gets confused.
/* 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() */
if ( navigator.userAgent.match(/like Mac OS X/i)) {
document.getElementById('side-form').style.display = 'block';
}
$('#side').hide();
// Although it's now hidden, the category filter for the map is still
// posted to the server when the report is sent. The name clashes with
// the category select element in the report form, which can cause
// issues with the wrong/no category being used for the report.
// Work around this by renaming the field when it's not shown.
$("select#categories").attr("name", "category_filter");
if (typeof heightFix !== 'undefined') {
heightFix('#report-a-problem-sidebar', '.content', 26);
}
// If we clicked the map somewhere inconvenient
var sidebar = $('#report-a-problem-sidebar');
if (sidebar.css('position') == 'absolute') {
var w = sidebar.width(), h = sidebar.height(),
o = sidebar.offset(),
$map_boxx = $('#map_box'), bo = $map_boxx.offset();
// e.xy is relative to top left of map, which might not be top left of page
e.xy.x += bo.left;
e.xy.y += bo.top;
// 24 and 64 is the width and height of the marker pin
if (e.xy.y <= o.top || (e.xy.x >= o.left && e.xy.x <= o.left + w + 24 && e.xy.y >= o.top && e.xy.y <= o.top + h + 64)) {
// top of the page, pin hidden by header;
// or underneath where the new sidebar will appear
lonlat.transform(
new OpenLayers.Projection("EPSG:4326"),
fixmystreet.map.getProjectionObject()
);
var p = fixmystreet.map.getViewPortPxFromLonLat(lonlat);
p.x -= ( o.left - bo.left + w ) / 2;
lonlat = fixmystreet.map.getLonLatFromViewPortPx(p);
fixmystreet.map.panTo(lonlat);
}
}
$('#sub_map_links').hide();
if ($('html').hasClass('mobile')) {
var $map_box = $('#map_box'),
width = $map_box.width(),
height = $map_box.height();
$map_box.append( '' + '' + translation_strings.try_again + '' + '' + translation_strings.ok + '' + '
' ).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('' + translation_strings.home + ' ' + 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';
location.hash = 'report';
if ( typeof ga !== 'undefined' && cobrand == 'fixmystreet' ) {
ga('send', 'pageview', { 'page': '/map_click' } );
}
}
});