RP_Rave1_theme/assets/vendor/gmap3/dist/gmap3.js

1131 lines
30 KiB
JavaScript
Raw Normal View History

2024-11-06 10:10:48 +00:00
/*!
* GMAP3 Plugin for jQuery
* Version : 7.1
* Date : 2016/04/17
* Author : DEMONTE Jean-Baptiste
* Contact : jbdemonte@gmail.com
* Web site : http://gmap3.net
* Licence : GPL-3.0+
*/
(function ($, window, document) {
"use strict";
var gm, services = {}, loadOptions,
// Proxify functions to get shorter minimized code
when = $.when,
extend = $.extend,
isArray = $.isArray,
isFunction = $.isFunction,
deferred = $.Deferred;
/**
* Duplicate option to never modify original object
* @param {Object} options
* @returns {Object}
*/
function dupOpts(options) {
return extend(true, {}, options || {});
}
/**
* Slice an array like
* @params {Array|Object}
* @params {Number} [start]
* @params {Number} [end]
* @returns {Array}
*/
function slice() {
var fn = Array.prototype.slice,
args = fn.call(arguments, 1);
return fn.apply(arguments[0], args);
}
/**
* Return true if value is undefined
* @param {*} value
* @returns {Boolean}
*/
function isUndefined(value) {
return typeof value === 'undefined';
}
/**
* Equivalent to Promise.all
* @param {Deferred[]} deferreds
* @returns {Deferred}
*/
function all(deferreds) {
return when.apply($, deferreds);
}
/**
* Equivalent to Promise.resolve
* @param {*} value
* @returns {Deferred}
*/
function resolved(value) {
return when().then(function () {
return value;
});
}
/**
* return the distance between 2 latLng in meters
* @param {LatLng} origin
* @param {LatLng} destination
* @returns {Number}
**/
function distanceInMeter(origin, destination) {
var m = Math,
pi = m.PI,
e = pi * origin.lat() / 180,
f = pi * origin.lng() / 180,
g = pi * destination.lat() / 180,
h = pi * destination.lng() / 180,
cos = m.cos,
sin = m.sin;
return 1000 * 6371 * m.acos(m.min(cos(e) * cos(g) * cos(f) * cos(h) + cos(e) * sin(f) * cos(g) * sin(h) + sin(e) * sin(g), 1));
}
function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
function serialize(obj) {
return objectKeys(obj).map(function (key) {
return encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]);
}).join("&");
}
// Auto-load google maps library if needed
(function () {
var dfd = deferred(),
cbName = '__gmap3',
script;
$.holdReady(true);
ready(function () {
if (window.google && window.google.maps || loadOptions === false) {
dfd.resolve();
} else {
// callback function - resolving promise after maps successfully loaded
window[cbName] = function () {
delete window[cbName];
dfd.resolve();
};
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?callback=' + cbName + (loadOptions ? '&' + (typeof loadOptions === 'string' ? loadOptions : serialize(loadOptions)) : '');
$("head").append(script);
}
});
return dfd.promise();
})().then(function () {
$.holdReady(false);
});
/**
* Instantiate only once a google service
* @param {String} name
* @returns {Object}
*/
function service(name) {
if (!services[name]) {
services[name] = gmElement(name);
}
return services[name];
}
/**
* Return GoogleMap Class (or overwritten by user) instance
* @param {String} name
* @returns {Object}
*/
function gmElement(name) {
var cls = gm[name];
function F(args) {
return cls.apply(this, args);
}
F.prototype = cls.prototype;
return new F(slice(arguments, 1));
}
/**
* Resolve a GeocodeRequest
* https://developers.google.com/maps/documentation/javascript/geocoding
* @param {String|Object} request
* @returns {Deferred}
*/
function geocode(request) {
var dfd = deferred();
if (typeof request === 'string') {
request = {
address: request
};
}
service('Geocoder').geocode(request, function(results, status) {
if (status === gm.GeocoderStatus.OK) {
dfd.resolve(results[0].geometry.location);
} else {
dfd.reject();
}
});
return dfd;
}
/**
* Callable function taking a parameter as string
* @callback StringCallback
* @param {String}
*/
/**
* Split a string and execute a function on each item
* @param {String} str - Space separated list of items
* @param {StringCallback} fn - Callback function
*/
function foreachStr(str, fn) {
str.split(' ').forEach(fn);
}
/**
* Execute a function on each items if items is an array and on items as a single element if it is not an array
* @param {Array|*} items - Items to execute foreach callback on
* @param {Function} fn - Callback function
*/
function foreach(items, fn) {
(isArray(items) ? items : [items]).forEach(fn);
}
/**
* Return Object keys
* @param {Object} obj
* @returns {String[]}
*/
function objectKeys(obj) {
return Object.keys(obj);
}
/**
* Return Object values
* @param {Object} obj
* @returns {*[]}
*/
function objectValues(obj) {
return objectKeys(obj).map(function (key) {
return obj[key];
});
}
/**
* Resolution function
* @callback OptionCallback
* @param {Object} options
* @returns {Deferred|*}
*/
/**
* Convert bounds from array [ n, e, s, w ] to google.maps.LatLngBounds
* @param {Object} options - Container of options.bounds
* @param {OptionCallback} fn
* @returns {Deferred}
*/
function resolveLatLngBounds(options, fn) {
options = dupOpts(options);
if (options.bounds) {
options.bounds = toLatLngBound(options.bounds);
}
return resolved(fn(options));
}
/**
* Resolve an address location / convert a LatLng array to google.maps.LatLng object
* @param {Object} options
* @param {String} key - LatLng key name in options object
* @param {OptionCallback} fn
* @returns {Deferred}
*/
function resolveLatLng(options, key, fn) {
var dfd = deferred();
options = dupOpts(options);
when()
.then(function () {
var address = options.address;
if (address) {
delete options.address;
return geocode(address).then(function (latLng) {
options[key] = latLng;
});
}
options[key] = toLatLng(options[key]);
})
.then(function () {
dfd.resolve(fn(options));
});
return dfd;
}
/**
* Convert an array of mixed LatLng to google.maps.LatLng object
* No address resolution here
* @param {Object} options
* @param {String} key - Array key name in options object
* @param {OptionCallback} fn
* @returns {Deferred}
*/
function resolveArrayOfLatLng(options, key, fn) {
options = dupOpts(options);
options[key] = (options[key] || []).map(function (item) {
return toLatLng(item);
});
return resolved(fn(options));
}
/**
* Convert a LatLng array to google.maps.LatLng
* @param {Array|*} mixed
* @param {Boolean} [convertLiteral]
* @returns {LatLng}
*/
function toLatLng(mixed, convertLiteral) {
return isArray(mixed) ? new gm.LatLng(mixed[0], mixed[1]) : (convertLiteral && mixed && !(mixed instanceof gm.LatLng) ? new gm.LatLng(mixed.lat, mixed.lng) : mixed);
}
/**
* Convert a LatLngBound array to google.maps.LatLngBound
* @param {Array|*} mixed
* @param {Boolean} [convertLiteral]
* @returns {LatLngBounds}
*/
function toLatLngBound(mixed, convertLiteral) {
if (isArray(mixed)) {
return new gm.LatLngBounds({lat: mixed[2], lng: mixed[3]}, {lat: mixed[0], lng: mixed[1]});
} else if (convertLiteral && !mixed.getCenter){
return new gm.LatLngBounds({lat: mixed.south, lng: mixed.west}, {lat: mixed.north, lng: mixed.east});
}
return mixed;
}
/**
* Create a custom overlay view
* @param {Map} map
* @param {Object} options
* @returns {OverlayView}
*/
function createOverlayView(map, options) {
var GMOverlayView = gm.OverlayView;
var $div = $(document.createElement("div"))
.css({
border: "none",
borderWidth: 0,
position: "absolute"
})
.append(options.content);
options = extend({x: 0, y: 0}, options);
if (options.position) {
options.position = toLatLng(options.position, true);
} else if (options.bounds) {
options.bounds = toLatLngBound(options.bounds, true);
}
/**
* Class OverlayView
* @constructor
*/
function OverlayView() {
var self = this,
listeners = [];
GMOverlayView.call(self);
self.setMap(map);
function fromLatLngToDivPixel(latlng) {
return self.getProjection().fromLatLngToDivPixel(latlng);
}
self.onAdd = function () {
var panes = self.getPanes();
panes.overlayMouseTarget.appendChild($div[0]);
};
if (options.position) {
self.getPosition = function () {
return options.position;
};
self.setPosition = function (latlng) {
options.position = latlng;
self.draw();
};
self.draw = function () {
var ps = fromLatLngToDivPixel(options.position);
$div.css({
left: (ps.x + options.x) + 'px',
top: (ps.y + options.y) + 'px'
});
};
} else {
self.getBounds = function () {
return options.bounds;
};
self.setBounds = function (bounds) {
options.bounds = bounds;
self.draw();
};
self.draw = function() {
var sw = fromLatLngToDivPixel(options.bounds.getSouthWest());
var ne = fromLatLngToDivPixel(options.bounds.getNorthEast());
$div.css({
left: (sw.x + options.x) + 'px',
top: (ne.y + options.y) + 'px',
width: (ne.x - sw.x + options.x) + 'px',
height: (sw.y - ne.y + options.y) + 'px'
});
};
}
self.onRemove = function () {
listeners.map(function (handler) {
gm.event.removeListener(handler);
});
$div.remove();
self.$ = $div = null; // mem leaks
};
self.$ = $div;
}
OverlayView.prototype = new GMOverlayView();
return new OverlayView();
}
/**
* Return a map projection
* @param {Map} map
* @returns {*}
*/
function getProjection(map) {
function Overlay() {
var self = this;
self.onAdd = self.onRemove = self.draw = function () {};
return gm.OverlayView.call(self);
}
Overlay.prototype = new gm.OverlayView();
var overlay = new Overlay();
overlay.setMap(map);
return overlay.getProjection();
}
/**
* Class used as event first parameter on clustering overlays
* @param {Cluster} cluster
* @param {Marker[]} markers
* @param {OverlayView} overlay
* @param {LatLngBounds} bounds
* @constructor
*/
function ClusterOverlay(cluster, markers, overlay, bounds) {
var self = this;
self.cluster = cluster;
self.markers = markers;
self.$ = overlay.$;
self.overlay = overlay;
overlay.getBounds = function () {
return gmElement('LatLngBounds', bounds.getSouthWest(), bounds.getNorthEast());
};
}
/**
* Cluster Group definition.
* @typedef {Object} ClusterGroupDef
* @property {String|jQuery} content
* @property {Number} [x] Offset
* @property {Number} [y] Offset
*/
/**
* Cluster evaluation function
* @callback clusterCallback
* @param {Marker[]} markers
* @return {ClusterGroupDef|undefined}
*/
/**
* Class used to handle clustering
* @param {Map} map
* @param {Object} options
* @param {Integer} [options.size]
* @param {Object[]} [options.markers] markers definition
* @param {clusterCallback} [options.cb] callback used to evaluate clustering elements
* @constructor
*/
function Cluster(map, options) {
var timer, igniter, previousViewHash, projection, filter,
self = this,
markers = [],
radius = (options.size || 200) >> 1,
enabled = true,
overlays = {},
handlers = [];
options = options || {};
options.markers = options.markers || [];
/**
* Cluster evaluation function
* @callback bindCallback
* @param {ClusterOverlay[]} instances
*/
/**
* Bind a function to each current or future overlays
* @param {bindCallback} fn
*/
self._b = function (fn) {
fn(objectValues(overlays));
handlers.push(fn);
};
/**
* Get the marker list
* @returns {Marker[]}
*/
self.markers = function () {
return slice(markers);
};
/**
* Get the current groups
* @returns {ClusterOverlay[]}
*/
self.groups = function () {
return objectValues(overlays);
};
/**
* Enable the clustering feature
*/
self.enable = function () {
if (!enabled) {
enabled = true;
previousViewHash = '';
delayRedraw();
}
};
/**
* Disable the clustering feature
*/
self.disable = function () {
if (enabled) {
enabled = false;
previousViewHash = '';
delayRedraw();
}
};
/**
* Add a marker
* @param {Marker} marker
*/
self.add = function (marker) {
markers.push(marker);
previousViewHash = '';
delayRedraw();
};
/**
* Remove a marker
* @param {Marker} marker
*/
self.remove = function (marker) {
markers = markers.filter(function (item) {
return item !== marker;
});
previousViewHash = '';
delayRedraw();
};
/**
* Filtering function, Cluster only handle those who return true
* @callback filterCallback
* @param {Marker} marker
* @returns {Boolean}
*/
/**
* Set a filter function
* @param {filterCallback} fn
*/
self.filter = function (fn) {
if (filter !== fn) {
filter = fn;
previousViewHash = '';
delayRedraw();
}
};
/**
* Generate extended visible bounds
* @returns {LatLngBounds}
*/
function extendsMapBounds() {
var circle = gmElement('Circle', {
center: map.getCenter(),
radius: 1.15 * distanceInMeter(map.getCenter(), map.getBounds().getNorthEast()) // + 15%
});
return circle.getBounds();
}
/**
* Generate bounds extended by radius
* @param {LatLng} latLng
* @returns {LatLngBounds}
*/
function extendsBounds(latLng) {
var p = projection.fromLatLngToDivPixel(latLng);
return gmElement('LatLngBounds',
projection.fromDivPixelToLatLng(gmElement('Point', p.x - radius, p.y + radius)),
projection.fromDivPixelToLatLng(gmElement('Point', p.x + radius, p.y - radius))
);
}
options.markers.map(function (opts) {
opts.position = toLatLng(opts.position);
markers.push(gmElement('Marker', opts));
});
/**
* Redraw clusters
*/
function redraw() {
var keys, bounds, overlayOptions, hash, currentMarkers, viewHash,
zoom = map.getZoom(),
currentHashes = {},
newOverlays = [],
ignore = {};
viewHash = '' + zoom;
if (zoom > 3) {
bounds = extendsMapBounds();
foreach(markers, function (marker, index) {
if (!bounds.contains(marker.getPosition())) {
viewHash += '-' + index;
ignore[index] = true;
if (marker.getMap()) {
marker.setMap(null);
}
}
});
}
if (filter) {
foreach(markers, function (marker, index) {
if (!ignore[index] && !filter(marker)) {
viewHash += '-' + index;
ignore[index] = true;
if (marker.getMap()) {
marker.setMap(null);
}
}
});
}
if (viewHash === previousViewHash) {
return;
}
previousViewHash = viewHash;
foreach(markers, function (marker, index) {
if (ignore[index]) {
return;
}
keys = [index];
bounds = extendsBounds(marker.getPosition());
if (enabled) {
foreach(slice(markers, index + 1), function (marker, idx) {
idx += index + 1;
if (!ignore[idx] && bounds.contains(marker.getPosition())) {
keys.push(idx);
ignore[idx] = true;
}
});
}
hash = keys.join('-');
currentHashes[hash] = true;
if (overlays[hash]) { // hash is already set
return;
}
currentMarkers = keys.map(function (key) {
return markers[key];
});
// ask the user callback on this subset (may be composed by only one marker)
overlayOptions = options.cb(slice(currentMarkers));
// create an overlay if cb returns its properties
if (overlayOptions) {
bounds = gmElement('LatLngBounds');
foreach(currentMarkers, function (marker) {
bounds.extend(marker.getPosition());
if (marker.getMap()) {
marker.setMap(null);
}
});
overlayOptions = dupOpts(overlayOptions);
overlayOptions.position = bounds.getCenter();
overlays[hash] = new ClusterOverlay(self, slice(currentMarkers), createOverlayView(map, overlayOptions), bounds);
newOverlays.push(overlays[hash]);
} else {
foreach(currentMarkers, function (marker) {
if (!marker.getMap()) { // to avoid marker blinking
marker.setMap(map);
}
});
}
});
// remove previous overlays
foreach(objectKeys(overlays), function (key) {
if (!currentHashes[key]) {
overlays[key].overlay.setMap(null);
delete overlays[key];
}
});
if (newOverlays.length) {
foreach(handlers, function (fn) {
fn(newOverlays);
});
}
}
/**
* Restart redraw timer
*/
function delayRedraw() {
clearTimeout(timer);
timer = setTimeout(redraw, 100);
}
/**
* Init clustering
*/
function init() {
gm.event.addListener(map, "zoom_changed", delayRedraw);
gm.event.addListener(map, "bounds_changed", delayRedraw);
redraw();
}
igniter = setInterval(function () {
projection = getProjection(map);
if (projection) {
clearInterval(igniter);
init();
}
}, 10);
}
/**
* Configure google maps loading library
* @param {string|object} options
*/
$.gmap3 = function (options) {
loadOptions = options;
};
/**
* jQuery Plugin
*/
$.fn.gmap3 = function (options) {
var items = [];
gm = window.google.maps; // once gmap3 is loaded, google.maps library should be loaded
this.each(function () {
var $this = $(this), gmap3 = $this.data("gmap3");
if (!gmap3) {
gmap3 = new Gmap3($this, options);
$this.data("gmap3", gmap3);
}
items.push(gmap3);
});
return new Handler(this, items);
};
/**
* Class Handler
* Chainable objet which handle all Gmap3 items associated to all jQuery elements in the current command set
* @param {jQuery} chain - "this" to return to maintain the jQuery chain
* @param {Gmap3[]} items
* @constructor
*/
function Handler(chain, items) {
var self = this;
// Map all functions from Gmap3 class
objectKeys(items[0]).forEach(function (name) {
self[name] = function () {
var results = [],
args = slice(arguments);
items.forEach(function (item) {
results.push(item[name].apply(item, args));
});
return name === 'get' ? (results.length > 1 ? results : results[0]) : self;
};
});
self.$ = chain;
}
/**
* Class Gmap3
* Handle a Google.maps.Map instance
* @param {jQuery} $container - Element to display the map in
* @param {Object} options - MapOptions
* @constructor
*/
function Gmap3($container, options) {
var map,
previousResults = [],
promise = when(),
self = this;
function context() {
return {
$: $container,
get: self.get
};
}
/**
* Attach events to instances
* @param {Object } events
* @param {Array|Object} instances
* @param {array} [args] arguments to add
* @param {Boolean} once
*/
function attachEvents(events, instances, args, once) {
var hasArgs = arguments.length > 3;
if (!hasArgs) {
once = args;
}
$.each(events, function (eventName, handlers) {
foreach(instances, function (instance) {
var isClusterOverlay = instance instanceof ClusterOverlay;
var isDom = isClusterOverlay || (instance instanceof gm.OverlayView);
var eventListener = isDom ? instance.$.get(0) : instance;
gm.event['add' + (isDom ? 'Dom' : '') + 'Listener' + (once ? 'Once' : '')](eventListener, eventName, function (event) {
foreach(handlers, function (handler) {
if (isFunction(handler)) {
if (isClusterOverlay) {
handler.call(context(), undefined /* marker */, instance, instance.cluster, event);
} else if (hasArgs) {
var buffer = slice(args);
buffer.unshift(instance);
buffer.push(event);
handler.apply(context(), buffer);
} else {
handler.call(context(), instance, event);
}
}
});
});
});
});
}
/**
* Decorator to handle multiple call based on array of options
* @param {Function} fn
* @returns {Deferred}
*/
function multiple(fn) {
return function (options) {
if (isArray(options)) {
var instances = [];
var promises = options.map(function (opts) {
return fn.call(self, opts).then(function (instance) {
instances.push(instance);
});
});
return all(promises).then(function () {
previousResults.push(instances);
return instances;
});
} else {
return fn.apply(self, arguments).then(function (instance) {
previousResults.push(instance);
return instance;
});
}
};
}
/**
* Decorator to chain promise result onto the main promise chain
* @param {Function} fn
* @returns {Deferred}
*/
function chainToPromise(fn) {
return function () {
var args = slice(arguments);
promise = promise.then(function (instance) {
if (isFunction(args[0])) {
// handle return as a deferred / promise to support both sync & async result
return when(args[0].call(context(), instance)).then(function (value) {
args[0] = value;
return fn.apply(self, args);
});
}
return when(fn.apply(self, args));
});
return promise;
};
}
self.map = chainToPromise(function (options) {
return map || resolveLatLng(options, 'center', function (opts) {
map = gmElement('Map', $container.get(0), opts);
previousResults.push(map);
return map;
});
});
// Space separated string of : separated element
// (google.maps class name) : (latLng property name) : (add map - 0|1 - default = 1)
foreachStr('Marker:position Circle:center InfoWindow:position:0 Polyline:path Polygon:paths', function (item) {
item = item.split(':');
var property = item[1] || '';
self[item[0].toLowerCase()] = chainToPromise(multiple(function (options) {
return (property.match(/^path/) ? resolveArrayOfLatLng : resolveLatLng)(options, property, function (opts) {
if (item[2] !== '0') {
opts.map = map;
}
return gmElement(item[0], opts);
});
}));
});
foreachStr('TrafficLayer TransitLayer BicyclingLayer', function (item) {
self[item.toLowerCase()] = chainToPromise(function () {
var instance = gmElement(item);
previousResults.push(instance);
instance.setMap(map);
return instance;
});
});
self.kmllayer = chainToPromise(multiple(function (options) {
options = dupOpts(options);
options.map = map;
return when(gmElement('KmlLayer', options));
}));
self.rectangle = chainToPromise(multiple(function (options) {
return resolveLatLngBounds(options, function (opts) {
opts.map = map;
return gmElement('Rectangle', opts);
});
}));
self.overlay = chainToPromise(multiple(function (options) {
function fn(opts) {
return createOverlayView(map, opts);
}
options = dupOpts(options);
return options.bounds ? resolveLatLngBounds(options, fn) : resolveLatLng(options, 'position', fn);
}));
self.groundoverlay = chainToPromise(function (url, bounds, options) {
return resolveLatLngBounds({bounds: bounds}, function (opts) {
options = dupOpts(options);
options.map = map;
var instance = gmElement('GroundOverlay', url, opts.bounds, options);
previousResults.push(instance);
return instance;
});
});
self.styledmaptype = chainToPromise(function (styleId, styles, options) {
var instance = gmElement('StyledMapType', styles, options);
previousResults.push(instance);
map.mapTypes.set(styleId, instance);
return instance;
});
self.streetviewpanorama = chainToPromise(function (container, options) {
return resolveLatLng(options, 'position', function (opts) {
var instance = gmElement('StreetViewPanorama', $(container).get(0), opts);
map.setStreetView(instance);
previousResults.push(instance);
return instance;
});
});
self.route = chainToPromise(function (options) {
var dfd = deferred();
options = dupOpts(options);
options.origin = toLatLng(options.origin);
options.destination = toLatLng(options.destination);
service('DirectionsService').route(options, function (results, status) {
previousResults.push(results);
dfd.resolve(status === gm.DirectionsStatus.OK ? results : false);
});
return dfd;
});
self.cluster = chainToPromise(function (options) {
var cluster = new Cluster(map, dupOpts(options));
previousResults.push(cluster);
return resolved(cluster);
});
self.directionsrenderer = chainToPromise(function (options) {
var instance;
if (options) {
options = dupOpts(options);
options.map = map;
if (options.panel) {
options.panel = $(options.panel).get(0);
}
instance = gmElement('DirectionsRenderer', options);
}
previousResults.push(instance);
return instance;
});
self.latlng = chainToPromise(multiple(function (options) {
return resolveLatLng(options, 'latlng', function (opts) {
previousResults.push(opts.latlng);
return opts.latlng;
});
}));
self.fit = chainToPromise(function () {
var bounds = gmElement('LatLngBounds');
foreach(previousResults, function (instances) {
if (instances !== map) {
foreach(instances, function (instance) {
if (instance) {
if (instance.getPosition && instance.getPosition()) {
bounds.extend(instance.getPosition());
} else if (instance.getBounds && instance.getBounds()) {
bounds.extend(instance.getBounds().getNorthEast());
bounds.extend(instance.getBounds().getSouthWest());
} else if (instance.getPaths && instance.getPaths()) {
foreach(instance.getPaths().getArray(), function (path) {
foreach(path.getArray(), function (latLng) {
bounds.extend(latLng);
});
});
} else if (instance.getPath && instance.getPath()) {
foreach(instance.getPath().getArray(), function (latLng) {
bounds.extend(latLng);
});
} else if (instance.getCenter && instance.getCenter()) {
bounds.extend(instance.getCenter());
}
}
});
}
});
if (!bounds.isEmpty()) {
map.fitBounds(bounds);
}
return true;
});
self.wait = function (duration) {
promise = promise.then(function (instance) {
var dfd = deferred();
setTimeout(function () {
dfd.resolve(instance);
}, duration);
return dfd;
});
};
self.then = function (fn) {
if (isFunction(fn)) {
promise = promise.then(function (instance) {
return when(fn.call(context(), instance)).then(function (newInstance) {
return isUndefined(newInstance) ? instance : newInstance;
});
});
}
};
foreachStr('on once', function (name, once) {
self[name] = function () {
var events = arguments[0];
if (events) {
if (typeof events === 'string') { // cast call on('click', handler) to on({click: handler})
events = {};
events[arguments[0]] = slice(arguments, 1);
}
promise.then(function (instances) {
if (instances) {
if (instances instanceof Cluster) {
instances._b(function (items) {
if (items && items.length) {
attachEvents(events, items, once);
}
});
return attachEvents(events, instances.markers(), [undefined, instances], once);
}
attachEvents(events, instances, once);
}
});
}
};
});
self.get = function (index) {
if (isUndefined(index)) {
return previousResults.map(function (instance) {
return isArray(instance) ? instance.slice() : instance;
});
} else {
if (index < 0) {
index = previousResults.length + index;
}
return isArray(previousResults[index]) ? previousResults[index].slice() : previousResults[index];
}
};
if (options) {
self.map(options);
}
}
})(jQuery, window, document);