/** * jQuery Validation Plugin 1.9.0 * * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ * http://docs.jquery.com/Plugins/Validation * * Copyright (c) 2006 - 2011 Jörn Zaefferer * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html */ (function($) { $.extend($.fn, { // http://docs.jquery.com/Plugins/Validation/validate validate: function( options ) { // if nothing is selected, return nothing; can't chain anyway if (!this.length) { options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" ); return; } // check if a validator for this form was already created var validator = $.data(this[0], 'validator'); if ( validator ) { return validator; } // Add novalidate tag if HTML5. this.attr('novalidate', 'novalidate'); validator = new $.validator( options, this[0] ); $.data(this[0], 'validator', validator); if ( validator.settings.onsubmit ) { var inputsAndButtons = this.find("input, button"); // allow suppresing validation by adding a cancel class to the submit button inputsAndButtons.filter(".cancel").click(function () { validator.cancelSubmit = true; }); // when a submitHandler is used, capture the submitting button if (validator.settings.submitHandler) { inputsAndButtons.filter(":submit").click(function () { validator.submitButton = this; }); } // validate the form on submit this.submit( function( event ) { if ( validator.settings.debug ) // prevent form submit to be able to see console output event.preventDefault(); function handle() { if ( validator.settings.submitHandler ) { if (validator.submitButton) { // insert a hidden input as a replacement for the missing submit button var hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); } validator.settings.submitHandler.call( validator, validator.currentForm ); if (validator.submitButton) { // and clean up afterwards; thanks to no-block-scope, hidden can be referenced hidden.remove(); } return false; } return true; } // prevent submit for invalid forms or custom submit handlers if ( validator.cancelSubmit ) { validator.cancelSubmit = false; return handle(); } if ( validator.form() ) { if ( validator.pendingRequest ) { validator.formSubmitted = true; return false; } return handle(); } else { validator.focusInvalid(); return false; } }); } return validator; }, // http://docs.jquery.com/Plugins/Validation/valid valid: function() { if ( $(this[0]).is('form')) { return this.validate().form(); } else { var valid = true; var validator = $(this[0].form).validate(); this.each(function() { valid &= validator.element(this); }); return valid; } }, // attributes: space seperated list of attributes to retrieve and remove removeAttrs: function(attributes) { var result = {}, $element = this; $.each(attributes.split(/\s/), function(index, value) { result[value] = $element.attr(value); $element.removeAttr(value); }); return result; }, // http://docs.jquery.com/Plugins/Validation/rules rules: function(command, argument) { var element = this[0]; if (command) { var settings = $.data(element.form, 'validator').settings; var staticRules = settings.rules; var existingRules = $.validator.staticRules(element); switch(command) { case "add": $.extend(existingRules, $.validator.normalizeRule(argument)); staticRules[element.name] = existingRules; if (argument.messages) settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); break; case "remove": if (!argument) { delete staticRules[element.name]; return existingRules; } var filtered = {}; $.each(argument.split(/\s/), function(index, method) { filtered[method] = existingRules[method]; delete existingRules[method]; }); return filtered; } } var data = $.validator.normalizeRules( $.extend( {}, $.validator.metadataRules(element), $.validator.classRules(element), $.validator.attributeRules(element), $.validator.staticRules(element) ), element); // make sure required is at front if (data.required) { var param = data.required; delete data.required; data = $.extend({required: param}, data); } return data; } }); // Custom selectors $.extend($.expr[":"], { // http://docs.jquery.com/Plugins/Validation/blank blank: function(a) {return !$.trim("" + a.value);}, // http://docs.jquery.com/Plugins/Validation/filled filled: function(a) {return !!$.trim("" + a.value);}, // http://docs.jquery.com/Plugins/Validation/unchecked unchecked: function(a) {return !a.checked;} }); // constructor for validator $.validator = function( options, form ) { this.settings = $.extend( true, {}, $.validator.defaults, options ); this.currentForm = form; this.init(); }; $.validator.format = function(source, params) { if ( arguments.length == 1 ) return function() { var args = $.makeArray(arguments); args.unshift(source); return $.validator.format.apply( this, args ); }; if ( arguments.length > 2 && params.constructor != Array ) { params = $.makeArray(arguments).slice(1); } if ( params.constructor != Array ) { params = [ params ]; } $.each(params, function(i, n) { source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); }); return source; }; $.extend($.validator, { defaults: { messages: {}, groups: {}, rules: {}, errorClass: "error", validClass: "valid", errorElement: "label", focusInvalid: true, errorContainer: $( [] ), errorLabelContainer: $( [] ), onsubmit: true, ignore: ":hidden", ignoreTitle: false, onfocusin: function(element, event) { this.lastActive = element; // hide error label and remove error class on focus if enabled if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); this.addWrapper(this.errorsFor(element)).hide(); } }, onfocusout: function(element, event) { if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { this.element(element); } }, onkeyup: function(element, event) { if ( element.name in this.submitted || element == this.lastElement ) { this.element(element); } }, onclick: function(element, event) { // click on selects, radiobuttons and checkboxes if ( element.name in this.submitted ) this.element(element); // or option elements, check parent select in that case else if (element.parentNode.name in this.submitted) this.element(element.parentNode); }, highlight: function(element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).addClass(errorClass).removeClass(validClass); } else { $(element).addClass(errorClass).removeClass(validClass); } }, unhighlight: function(element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).removeClass(errorClass).addClass(validClass); } else { $(element).removeClass(errorClass).addClass(validClass); } } }, // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults setDefaults: function(settings) { $.extend( $.validator.defaults, settings ); }, messages: { required: "This field is required.", remote: "Please fix this field.", email: "Please enter a valid email address.", url: "Please enter a valid URL.", date: "Please enter a valid date.", dateISO: "Please enter a valid date (ISO).", number: "Please enter a valid number.", digits: "Please enter only digits.", creditcard: "Please enter a valid credit card number.", equalTo: "Please enter the same value again.", accept: "Please enter a value with a valid extension.", maxlength: $.validator.format("Please enter no more than {0} characters."), minlength: $.validator.format("Please enter at least {0} characters."), rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), range: $.validator.format("Please enter a value between {0} and {1}."), max: $.validator.format("Please enter a value less than or equal to {0}."), min: $.validator.format("Please enter a value greater than or equal to {0}.") }, autoCreateRanges: false, prototype: { init: function() { this.labelContainer = $(this.settings.errorLabelContainer); this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); this.submitted = {}; this.valueCache = {}; this.pendingRequest = 0; this.pending = {}; this.invalid = {}; this.reset(); var groups = (this.groups = {}); $.each(this.settings.groups, function(key, value) { $.each(value.split(/\s/), function(index, name) { groups[name] = key; }); }); var rules = this.settings.rules; $.each(rules, function(key, value) { rules[key] = $.validator.normalizeRule(value); }); function delegate(event) { var validator = $.data(this[0].form, "validator"), eventType = "on" + event.type.replace(/^validate/, ""); validator.settings[eventType] && validator.settings[eventType].call(validator, this[0], event); } $(this.currentForm) .validateDelegate("[type='text'], [type='password'], [type='file'], select, textarea, " + "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + "[type='email'], [type='datetime'], [type='date'], [type='month'], " + "[type='week'], [type='time'], [type='datetime-local'], " + "[type='range'], [type='color'] ", "focusin focusout keyup", delegate) .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); if (this.settings.invalidHandler) $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); }, // http://docs.jquery.com/Plugins/Validation/Validator/form form: function() { this.checkForm(); $.extend(this.submitted, this.errorMap); this.invalid = $.extend({}, this.errorMap); if (!this.valid()) $(this.currentForm).triggerHandler("invalid-form", [this]); this.showErrors(); return this.valid(); }, checkForm: function() { this.prepareForm(); for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { this.check( elements[i] ); } return this.valid(); }, // http://docs.jquery.com/Plugins/Validation/Validator/element element: function( element ) { element = this.validationTargetFor( this.clean( element ) ); this.la
#!/usr/bin/perl
#
# FixMyStreet:Map::OSM
# OSM maps on FixMyStreet.
#
# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/

package FixMyStreet::Map::OSM;

use strict;
use Math::Trig;
use mySociety::Gaze;
use Utils;

use constant ZOOM_LEVELS    => 5;
use constant MIN_ZOOM_LEVEL => 13;

sub map_type {
    return 'OpenLayers.Layer.OSM.Mapnik';
}

sub map_template {
    return 'osm';
}

sub map_tiles {
    my ($self, $x, $y, $z) = @_;
    my $tile_url = $self->base_tile_url();
    return [
        "http://a.$tile_url/$z/" . ($x - 1) . "/" . ($y - 1) . ".png",
        "http://b.$tile_url/$z/$x/" . ($y - 1) . ".png",
        "http://c.$tile_url/$z/" . ($x - 1) . "/$y.png",
        "http://$tile_url/$z/$x/$y.png",
    ];
}

sub base_tile_url {
    return 'tile.openstreetmap.org';
}

sub copyright {
    return _('Map &copy; <a id="osm_link" href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>');
}

# display_map C PARAMS
# PARAMS include:
# latitude, longitude for the centre point of the map
# CLICKABLE is set if the map is clickable
# PINS is array of pins to show, location and colour
sub display_map {
    my ($self, $c, %params) = @_;

    my $numZoomLevels = ZOOM_LEVELS;
    my $zoomOffset = MIN_ZOOM_LEVEL;
    if ($params{any_zoom}) {
        $numZoomLevels = 18;
        $zoomOffset = 0;
    }

    # Adjust zoom level dependent upon population density
    my $dist = mySociety::Gaze::get_radius_containing_population( $params{latitude}, $params{longitude}, 200_000 );
    my $default_zoom = $numZoomLevels - 3;
    $default_zoom = $numZoomLevels - 2 if $dist < 10;

    # Map centre may be overridden in the query string
    $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0)
        if defined $c->req->params->{lat};
    $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0)
        if defined $c->req->params->{lon};

    my $zoom = defined $c->req->params->{zoom} ? $c->req->params->{zoom} + 0 : $default_zoom;
    $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels;
    $zoom = 0 if $zoom < 0;
    my $zoom_act = $zoomOffset + $zoom;
    my ($x_tile, $y_tile) = latlon_to_tile_with_adjust($params{latitude}, $params{longitude}, $zoom_act);

    foreach my $pin (@{$params{pins}}) {
        ($pin->{px}, $pin->{py}) = latlon_to_px($pin->{latitude}, $pin->{longitude}, $x_tile, $y_tile, $zoom_act);
    }

    $c->stash->{map} = {
        %params,
        type => $self->map_template(),
        map_type => $self->map_type(),
        tiles => $self->map_tiles( $x_tile, $y_tile, $zoom_act ),
        copyright => $self->copyright(),
        x_tile => $x_tile,
        y_tile => $y_tile,
        zoom => $zoom,
        zoom_act => $zoom_act,
        zoomOffset => $zoomOffset,
        numZoomLevels => $numZoomLevels,
        compass => compass( $x_tile, $y_tile, $zoom_act ),
    };
}

sub map_pins {
    my ($self, $c, $interval) = @_;

    my $bbox = $c->req->param('bbox');
    my ( $min_lon, $min_lat, $max_lon, $max_lat ) = split /,/, $bbox;

    my ( $around_map, $around_map_list, $nearby