Commit 6a1ec6b5 authored by Matthias Larisch's avatar Matthias Larisch

Komoot addresspicker, update leaflet and typeahead

parent ef254727
Pipeline #44059410 passed with stages
in 14 minutes and 5 seconds
......@@ -9,6 +9,7 @@
- prepare support for separated email domain for platform mailboxes
- add security headers !633 @nicksellen
- changed tile maps to wikimedia !639 @alex.simm
- Use typeahead-address-photon for address autocomplete. Update leaflet and typeahead for recent NPM versions in the same go !640 @NerdyProjects
## Bugfixes
- Improve/correct user profile badge count !612 @pmayd
......
/*
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
(c) 2012-2013, Lennard Voogdt
http://leafletjs.com
https://github.com/lvoogdt
*//*global L*/(function(e,t,n){"use strict";L.AwesomeMarkers={};L.AwesomeMarkers.version="2.0.1";L.AwesomeMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"awesome-marker",prefix:"glyphicon",spinClass:"fa-spin",icon:"home",markerColor:"blue",iconColor:"white"},initialize:function(e){e=L.Util.setOptions(this,e)},createIcon:function(){var e=t.createElement("div"),n=this.options;n.icon&&(e.innerHTML=this._createInner());n.bgPos&&(e.style.backgroundPosition=-n.bgPos.x+"px "+ -n.bgPos.y+"px");this._setIconStyles(e,"icon-"+n.markerColor);return e},_createInner:function(){var e,t="",n="",r="",i=this.options;i.icon.slice(0,i.prefix.length+1)===i.prefix+"-"?e=i.icon:e=i.prefix+"-"+i.icon;i.spin&&typeof i.spinClass=="string"&&(t=i.spinClass);i.iconColor&&(i.iconColor==="white"||i.iconColor==="black"?n="icon-"+i.iconColor:r="style='color: "+i.iconColor+"' ");return"<i "+r+"class='"+i.prefix+" "+e+" "+t+" "+n+"'></i>"},_setIconStyles:function(e,t){var n=this.options,r=L.point(n[t==="shadow"?"shadowSize":"iconSize"]),i;t==="shadow"?i=L.point(n.shadowAnchor||n.iconAnchor):i=L.point(n.iconAnchor);!i&&r&&(i=r.divideBy(2,!0));e.className="awesome-marker-"+t+" "+n.className;if(i){e.style.marginLeft=-i.x+"px";e.style.marginTop=-i.y+"px"}if(r){e.style.width=r.x+"px";e.style.height=r.y+"px"}},createShadow:function(){var e=t.createElement("div");this._setIconStyles(e,"shadow");return e}});L.AwesomeMarkers.icon=function(e){return new L.AwesomeMarkers.Icon(e)}})(this,document);
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
(function($) {
this.AddressPickerResult = (function() {
function AddressPickerResult(placeResult, fromReverseGeocoding) {
this.placeResult = placeResult;
this.fromReverseGeocoding = fromReverseGeocoding != null ? fromReverseGeocoding : false;
this.latitude = this.placeResult.geometry.location.lat();
this.longitude = this.placeResult.geometry.location.lng();
}
AddressPickerResult.prototype.addressTypes = function() {
var component, type, types, _i, _j, _len, _len1, _ref, _ref1;
types = [];
_ref = this.addressComponents();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
component = _ref[_i];
_ref1 = component.types;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
type = _ref1[_j];
if (types.indexOf(type) === -1) {
types.push(type);
}
}
}
return types;
};
AddressPickerResult.prototype.addressComponents = function() {
return this.placeResult.address_components || [];
};
AddressPickerResult.prototype.address = function() {
return this.placeResult.formatted_address;
};
AddressPickerResult.prototype.nameForType = function(type, shortName) {
var component, _i, _len, _ref;
if (shortName == null) {
shortName = false;
}
_ref = this.addressComponents();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
component = _ref[_i];
if (component.types.indexOf(type) !== -1) {
return (shortName ? component.short_name : component.long_name);
}
}
return null;
};
AddressPickerResult.prototype.lat = function() {
return this.latitude;
};
AddressPickerResult.prototype.lng = function() {
return this.longitude;
};
AddressPickerResult.prototype.setLatLng = function(latitude, longitude) {
this.latitude = latitude;
this.longitude = longitude;
};
AddressPickerResult.prototype.isAccurate = function() {
return !this.placeResult.geometry.viewport;
};
AddressPickerResult.prototype.isReverseGeocoding = function() {
return this.fromReverseGeocoding;
};
return AddressPickerResult;
})();
return this.AddressPicker = (function(_super) {
__extends(AddressPicker, _super);
function AddressPicker(options) {
if (options == null) {
options = {};
}
this.sessionToken = new google.maps.places.AutocompleteSessionToken();
this.markerDragged = __bind(this.markerDragged, this);
this.updateBoundsForPlace = __bind(this.updateBoundsForPlace, this);
this.updateMap = __bind(this.updateMap, this);
this.options = $.extend({
local: [],
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d.num);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
autocompleteService: {
types: ["geocode"]
},
zoomForLocation: 16,
reverseGeocoding: false,
placeDetails: true
}, options);
AddressPicker.__super__.constructor.call(this, this.options);
if (this.options.map) {
this.initMap();
}
this.placeService = new google.maps.places.PlacesService(document.createElement('div'));
}
AddressPicker.prototype.bindDefaultTypeaheadEvent = function(typeahead) {
typeahead.bind("typeahead:selected", this.updateMap);
return typeahead.bind("typeahead:cursorchanged", this.updateMap);
};
AddressPicker.prototype.initMap = function() {
var _ref, _ref1;
this.mapOptions = $.extend({
zoom: 3,
center: L.latLng(0, 0),
boundsForLocation: this.updateBoundsForPlace,
}, this.options.map);
if(this.mapOptions.map) {
this.map = this.mapOptions.map
}
else {
this.map = L.map(this.mapOptions.id, this.mapOptions);
L.tileLayer("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png", {
attribution: "Geocoding by <a href=\"https://google.com\">Google</a>, Tiles by <a href=\"https://foundation.wikimedia.org/w/index.php?title=Maps_Terms_of_Use\">Wikimedia</a>"
}).addTo(this.map);
}
this.lastResult = null;
var fsIcon = L.AwesomeMarkers.icon({
icon: "smile",
markerColor: "orange",
prefix: "img"
});
this.marker = L.marker(this.mapOptions.center, {icon: fsIcon}).addTo(this.map);
};
AddressPicker.prototype.get = function(query, cb) {
var service;
service = new google.maps.places.AutocompleteService();
this.options.autocompleteService.input = query;
this.options.autocompleteService.sessionToken = this.sessionToken;
return service.getPlacePredictions(this.options.autocompleteService, (function(_this) {
return function(predictions) {
$(_this).trigger('addresspicker:predictions', [predictions]);
return cb(predictions);
};
})(this));
};
AddressPicker.prototype.updateMap = function(event, place) {
if (this.options.placeDetails) {
place.sessionToken = this.sessionToken
return this.placeService.getDetails(place, (function(_this) {
return function(response) {
var _ref;
_this.lastResult = new AddressPickerResult(response);
if (_this.marker) {
_this.marker.setLatLng(L.latLng(response.geometry.location.lat(), response.geometry.location.lng()));
}
if (_this.map) {
if ((_ref = _this.mapOptions) != null) {
_ref.boundsForLocation(response);
}
}
_this.sessionToken = new google.maps.places.AutocompleteSessionToken();
return $(_this).trigger('addresspicker:selected', _this.lastResult);
};
})(this));
} else {
return $(this).trigger('addresspicker:selected', place);
}
};
AddressPicker.prototype.updateBoundsForPlace = function(response) {
if (response.geometry.viewport) {
return this.map.fitBounds(L.latLngBounds(L.latLng(response.geometry.viewport.getNorthEast().lat(), response.geometry.viewport.getNorthEast().lng()),
L.latLng(response.geometry.viewport.getSouthWest().lat(), response.geometry.viewport.getSouthWest().lng())));
} else {
this.map.setCenter(L.latLng(response.geometry.location.lat(), response.geometry.location.lng()));
return this.map.setZoom(this.options.zoomForLocation);
}
};
AddressPicker.prototype.markerDragged = function() {
if (this.options.reverseGeocoding) {
return this.reverseGeocode(this.marker.getPosition());
} else {
if (this.lastResult) {
this.lastResult.setLatLng(this.marker.getPosition().lat(), this.marker.getPosition().lng());
} else {
this.lastResult = new AddressPickerResult({
geometry: {
location: this.marker.getPosition()
}
});
}
return $(this).trigger('addresspicker:selected', this.lastResult);
}
};
AddressPicker.prototype.reverseGeocode = function(position) {
if (this.geocoder == null) {
this.geocoder = new google.maps.Geocoder();
}
return this.geocoder.geocode({
location: position
}, (function(_this) {
return function(results) {
if (results && results.length > 0) {
_this.lastResult = new AddressPickerResult(results[0], true);
return $(_this).trigger('addresspicker:selected', _this.lastResult);
}
};
})(this));
};
AddressPicker.prototype.getGMap = function() {
return this.map;
};
AddressPicker.prototype.getGMarker = function() {
return this.marker;
};
return AddressPicker;
})(Bloodhound);
})(jQuery);
}).call(this);
/*!
* typeahead.js 0.10.4
* https://github.com/twitter/typeahead.js
* Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
*/
(function($) {
var _ = function() {
"use strict";
return {
isMsie: function() {
return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
},
isBlankString: function(str) {
return !str || /^\s*$/.test(str);
},
escapeRegExChars: function(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
},
isString: function(obj) {
return typeof obj === "string";
},
isNumber: function(obj) {
return typeof obj === "number";
},
isArray: $.isArray,
isFunction: $.isFunction,
isObject: $.isPlainObject,
isUndefined: function(obj) {
return typeof obj === "undefined";
},
toStr: function toStr(s) {
return _.isUndefined(s) || s === null ? "" : s + "";
},
bind: $.proxy,
each: function(collection, cb) {
$.each(collection, reverseArgs);
function reverseArgs(index, value) {
return cb(value, index);
}
},
map: $.map,
filter: $.grep,
every: function(obj, test) {
var result = true;
if (!obj) {
return result;
}
$.each(obj, function(key, val) {
if (!(result = test.call(null, val, key, obj))) {
return false;
}
});
return !!result;
},
some: function(obj, test) {
var result = false;
if (!obj) {
return result;
}
$.each(obj, function(key, val) {
if (result = test.call(null, val, key, obj)) {
return false;
}
});
return !!result;
},
mixin: $.extend,
getUniqueId: function() {
var counter = 0;
return function() {
return counter++;
};
}(),
templatify: function templatify(obj) {
return $.isFunction(obj) ? obj : template;
function template() {
return String(obj);
}
},
defer: function(fn) {
setTimeout(fn, 0);
},
debounce: function(func, wait, immediate) {
var timeout, result;
return function() {
var context = this, args = arguments, later, callNow;
later = function() {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
}
};
callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
}
return result;
};
},
throttle: function(func, wait) {
var context, args, timeout, result, previous, later;
previous = 0;
later = function() {
previous = new Date();
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date(), remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
}
return result;
};
},
noop: function() {}
};
}();
var VERSION = "0.10.4";
var tokenizers = function() {
"use strict";
return {
nonword: nonword,
whitespace: whitespace,
obj: {
nonword: getObjTokenizer(nonword),
whitespace: getObjTokenizer(whitespace)
}
};
function whitespace(str) {
str = _.toStr(str);
return str ? str.split(/\s+/) : [];
}
function nonword(str) {
str = _.toStr(str);
return str ? str.split(/\W+/) : [];
}
function getObjTokenizer(tokenizer) {
return function setKey() {
var args = [].slice.call(arguments, 0);
return function tokenize(o) {
var tokens = [];
_.each(args, function(k) {
tokens = tokens.concat(tokenizer(_.toStr(o[k])));
});
return tokens;
};
};
}
}();
var LruCache = function() {
"use strict";
function LruCache(maxSize) {
this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
this.reset();
if (this.maxSize <= 0) {
this.set = this.get = $.noop;
}
}
_.mixin(LruCache.prototype, {
set: function set(key, val) {
var tailItem = this.list.tail, node;
if (this.size >= this.maxSize) {
this.list.remove(tailItem);
delete this.hash[tailItem.key];
}
if (node = this.hash[key]) {
node.val = val;
this.list.moveToFront(node);
} else {
node = new Node(key, val);
this.list.add(node);
this.hash[key] = node;
this.size++;
}
},
get: function get(key) {
var node = this.hash[key];
if (node) {
this.list.moveToFront(node);
return node.val;
}
},
reset: function reset() {
this.size = 0;
this.hash = {};
this.list = new List();
}
});
function List() {
this.head = this.tail = null;
}
_.mixin(List.prototype, {
add: function add(node) {
if (this.head) {
node.next = this.head;
this.head.prev = node;
}
this.head = node;
this.tail = this.tail || node;
},
remove: function remove(node) {
node.prev ? node.prev.next = node.next : this.head = node.next;
node.next ? node.next.prev = node.prev : this.tail = node.prev;
},
moveToFront: function(node) {
this.remove(node);
this.add(node);
}
});
function Node(key, val) {
this.key = key;
this.val = val;
this.prev = this.next = null;
}
return LruCache;
}();
var PersistentStorage = function() {
"use strict";
var ls, methods;
try {
ls = window.localStorage;
ls.setItem("~~~", "!");
ls.removeItem("~~~");
} catch (err) {
ls = null;
}
function PersistentStorage(namespace) {
this.prefix = [ "__", namespace, "__" ].join("");
this.ttlKey = "__ttl__";
this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
}
if (ls && window.JSON) {
methods = {
_prefix: function(key) {
return this.prefix + key;
},
_ttlKey: function(key) {
return this._prefix(key) + this.ttlKey;
},
get: function(key) {
if (this.isExpired(key)) {
this.remove(key);
}
return decode(ls.getItem(this._prefix(key)));
},
set: function(key, val, ttl) {
if (_.isNumber(ttl)) {
ls.setItem(this._ttlKey(key), encode(now() + ttl));
} else {
ls.removeItem(this._ttlKey(key));
}
return ls.setItem(this._prefix(key), encode(val));
},
remove: function(key) {
ls.removeItem(this._ttlKey(key));
ls.removeItem(this._prefix(key));
return this;
},
clear: function() {
var i, key, keys = [], len = ls.length;
for (i = 0; i < len; i++) {
if ((key = ls.key(i)).match(this.keyMatcher)) {
keys.push(key.replace(this.keyMatcher, ""));
}
}
for (i = keys.length; i--; ) {
this.remove(keys[i]);
}
return this;
},
isExpired: function(key) {
var ttl = decode(ls.getItem(this._ttlKey(key)));
return _.isNumber(ttl) && now() > ttl ? true : false;
}
};
} else {
methods = {
get: _.noop,
set: _.noop,
remove: _.noop,
clear: _.noop,
isExpired: _.noop
};
}
_.mixin(PersistentStorage.prototype, methods);
return PersistentStorage;
function now() {
return new Date().getTime();
}
function encode(val) {
return JSON.stringify(_.isUndefined(val) ? null : val);
}
function decode(val) {
return JSON.parse(val);
}
}();
var Transport = function() {
"use strict";
var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
function Transport(o) {
o = o || {};
this.cancelled = false;
this.lastUrl = null;
this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
this._cache = o.cache === false ? new LruCache(0) : sharedCache;
}
Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
maxPendingRequests = num;
};
Transport.resetCache = function resetCache() {
sharedCache.reset();
};
_.mixin(Transport.prototype, {
_get: function(url, o, cb) {
var that = this, jqXhr;
if (this.cancelled || url !== this.lastUrl) {
return;
}
if (jqXhr = pendingRequests[url]) {
jqXhr.done(done).fail(fail);
} else if (pendingRequestsCount < maxPendingRequests) {
pendingRequestsCount++;
pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
} else {
this.onDeckRequestArgs = [].slice.call(arguments, 0);
}
function done(resp) {
cb && cb(null, resp);
that._cache.set(url, resp);
}
function fail() {
cb && cb(true);
}
function always() {
pendingRequestsCount--;
delete pendingRequests[url];
if (that.onDeckRequestArgs) {
that._get.apply(that, that.onDeckRequestArgs);
that.onDeckRequestArgs = null;
}
}
},
get: function(url, o, cb) {
var resp;
if (_.isFunction(o)) {
cb = o;
o = {};
}
this.cancelled = false;
this.lastUrl = url;
if (resp = this._cache.get(url)) {
_.defer(function() {
cb && cb(null, resp);
});
} else {
this._get(url, o, cb);
}
return !!resp;
},
cancel: function() {
this.cancelled = true;
}
});
return Transport;
function callbackToDeferred(fn) {
return function customSendWrapper(url, o) {
var deferred = $.Deferred();
fn(url, o, onSuccess, onError);
return deferred;
function onSuccess(resp) {
_.defer(function() {
deferred.resolve(resp);
});
}
function onError(err) {
_.defer(function() {
deferred.reject(err);
});
}
};
}
}();
var SearchIndex = function() {
"use strict";
function SearchIndex(o) {
o = o || {};
if (!o.datumTokenizer || !o.queryTokenizer) {
$.error("datumTokenizer and queryTokenizer are both required");
}
this.datumTokenizer = o.datumTokenizer;
this.queryTokenizer = o.queryTokenizer;
this.reset();
}
_.mixin(SearchIndex.prototype, {
bootstrap: function bootstrap(o) {
this.datums = o.datums;
this.trie = o.trie;
},
add: function(data) {
var that = this;
data = _.isArray(data) ? data : [ data ];
_.each(data, function(datum) {
var id, tokens;
id = that.datums.push(datum) - 1;
tokens = normalizeTokens(that.datumTokenizer(datum));
_.each(tokens, function(token) {