(function () {
// holds a function queue to call once page is loaded
function Main() {
var VERSION = '{{VERSION}}';
this.VERSION = VERSION;
/**
* Call a render function, wrapped in a try/catch
* @param {() => void} fnc
*/
function callRenderFunction(fnc) {
try {
fnc();
} catch (e) {
console.log('-- version --', VERSION);
console.error(e);
}
}
var ready = false;
var callbacks = [];
/**
* this function mirrors the array appending function
* so that we can at least append functions to a global array
* before the maps are ready to be rendered
*
* All shortcodes should execute the following:
* window.WPLeafletMapPlugin = window.WPLeafletMapPlugin || [];
* window.WPLeafletMapPlugin.push(function () {
*
* Think of it as a whenReady callback
*/
this.push = function (fnc) {
if (ready) {
callRenderFunction(fnc);
} else {
callbacks.push(fnc);
}
};
/**
* Same as above, but what if someone wants to execute a function
* before other functions?
*/
this.unshift = function (fnc) {
if (ready) {
callRenderFunction(fnc);
} else {
callbacks.unshift(fnc);
}
};
/**
* execute all callbacks once page/Leaflet is loaded
*/
this.init = function () {
ready = true;
for (var i = 0, len = callbacks.length; i < len; i++) {
callRenderFunction(callbacks[i]);
}
};
/**
* Create map from a div element
* @since 2.18.0
*/
this.createMap = function (options) {
// gets maps by className in order
var elems = document.getElementsByClassName('WPLeafletMap');
var i = this.maps.length;
var container = elems[i];
var map = L.map(container, options);
// removed from PHP in 2.18.0
if (options.fitBounds) {
map._shouldFitBounds = true;
}
// removed from PHP in 2.18.0
if (options.attribution) {
addAttributionToMap(options.attribution, map);
}
this.maps.push(map);
return map;
};
/**
* Create image map from a div element
* @since 2.18.0
*/
this.createImageMap = function (options) {
var map = this.createMap(options);
// moved from PHP in 2.18.0
map.is_image_map = true;
this.images.push(map);
return map;
};
/**
* maps are created iteratively, so the last map is the current map
*/
this.getCurrentMap = function () {
return this.maps[this.maps.length - 1];
};
/**
* Get/Create L.FeatureGroup for ALL shapes; used for `fitbounds`
* @since 2.13.0
*/
this.getCurrentGroup = function () {
// marker groups are mapid -> feature group
var mapid = this.maps.length;
if (!this.markergroups[mapid]) {
this.markergroups[mapid] = this.newMarkerGroup(this.maps[mapid - 1]);
}
return this.markergroups[mapid];
};
/**
* backwards-compatible getCurrentGroup
* @deprecated 2.13.0
*/
this.getCurrentMarkerGroup = this.getCurrentGroup;
/**
* get FeatureGroup and add to map
*
* ! This is extracted so that it can be overwritten by plugins
*/
this.getGroup = function (map) {
return new L.FeatureGroup().addTo(map);
};
/**
* group is created and event is added
*/
this.newMarkerGroup = function (map) {
var mg = this.getGroup(map);
mg.timeout = null;
// custom attribute
if (map._shouldFitBounds) {
mg.on(
'layeradd',
function (event) {
if (event.layer instanceof L.FeatureGroup) {
// wait for featuregroup/ajax-geojson to be ready
event.layer.on('ready', function () {
map.fitBounds(mg.getBounds());
});
}
// needs a timeout so that it doesn't
// opt out of a bound change
window.clearTimeout(this.timeout);
this.timeout = window.setTimeout(function () {
try {
map.fitBounds(mg.getBounds());
} catch (e) {
// ajax-geojson might not have valid bounds yet
}
}, 100);
},
mg
);
}
return mg;
};
/** Adds all properties as a table-view for GeoJSON popups */
this.propsToTable = function (props) {
var prop;
var keys = [];
for (prop in props) {
if (Object.prototype.hasOwnProperty.call(props, prop)) {
keys.push(prop);
}
}
keys = keys.sort();
var output = '
';
for (var i = 0, len = keys.length; i < len; i++) {
var key = keys[i];
output += '| ' + key + ' | ';
output += '' + props[key] + ' |
';
}
output += '
';
return output;
};
function trim(a) {
return a.trim();
}
function addAttributionToMap(attribution, map) {
if (!attribution) {
return;
}
var attributions = attribution.split(';');
var attControl = L.control
.attribution({
prefix: false,
})
.addTo(map);
for (var i = 0, len = attributions.length; i < len; i++) {
var att = trim(attributions[i]);
attControl.addAttribution(att);
}
}
var unescape = (this.unescape = function (str) {
var div = document.createElement('div');
div.innerHTML = str;
return div.innerText || str;
});
var templateRe = /\{ *(.*?) *\}/g;
/**
* It interpolates variables in curly brackets (regex above)
*
* ex: "Property Value: {property_key}"
*
* @param {string} str
* @param {object} data e.g. feature.properties
*/
this.template = function (str, data) {
if (data == null) {
return str;
}
return str.replace(templateRe, function (match, key) {
var obj = liquid(key);
var value = parseKey(data, obj.key);
if (value == null) {
return obj.default || match;
}
return value;
});
};
/** used in strToPath */
var strToPathRe = /[.‘’'“”"\[\]]+/g;
/**
* Converts nested object keys to array
*
* ex: `this.that['and'].theOther[4]` ->
* ['this', 'that', 'and', 'theOther', '4']
* @param {string} key
*/
function strToPath(key) {
if (key == null) {
return [];
}
var input = key.split(strToPathRe);
var output = [];
// failsafe for all empty strings;
// mostly catches brackets at the end of a string
for (var i = 0, len = input.length; i < len; i++) {
if (input[i] !== '') {
output.push(input[i]);
}
}
return output;
}
/**
* It uses strToPath to access a possibly nested path value
*
* @param {object} obj
* @param {string} key
*/
function parseKey(obj, key) {
var arr = strToPath(unescape(key));
var value = obj;
for (var i = 0, len = arr.length; i < len; i++) {
value = value[arr[i]];
if (!value) {
return undefined;
}
}
return value;
}
/**
* parses liquid tags from a string
*
* @param {string} str
*/
function liquid(str) {
var tags = str.split(' | ');
var obj = {};
// removes initial variable from array
var key = tags.shift();
for (var i = 0, len = tags.length; i < len; i++) {
var tag = tags[i].split(': ');
var tagName = tag.shift();
var tagValue = tag.join(': ') || true;
obj[tagName] = tagValue;
}
// always preserve the original string
obj.key = key;
return obj;
}
function waitFor(prop, cb) {
if (typeof L !== 'undefined' && typeof L[prop] !== 'undefined') {
cb();
} else {
setTimeout(function () {
waitFor(prop, cb);
}, 100);
}
}
/** wait for leaflet-svg-icon (if deferred) */
this.waitForSVG = function (cb) {
waitFor('SVGIcon', cb);
};
/** wait for leaflet-ajax-geojson (if deferred) */
this.waitForAjax = function (cb) {
waitFor('AjaxGeoJSON', cb);
};
this.createScale = function (options) {
L.control.scale(options).addTo(this.getCurrentMap());
};
this.getIconOptions = function (options) {
var _options = options || {};
var iconArrays = [
'iconSize',
'iconAnchor',
'shadowSize',
'shadowAnchor',
'popupAnchor',
'tooltipAnchor',
];
var default_icon = L.Icon.Default.prototype.options;
// arrays are strings, unfortunately...
for (var i = 0, len = iconArrays.length; i < len; i++) {
var option_name = iconArrays[i];
var option = _options[option_name];
// convert "1,2" to [1, 2];
if (option) {
var arr = option.split(',');
// array.map for ie<9
for (var j = 0, lenJ = arr.length; j < lenJ; j++) {
arr[j] = Number(arr[j]);
}
_options[option_name] = arr;
}
}
// default popupAnchor
if (!_options.popupAnchor) {
// set (roughly) to size of icon
_options.popupAnchor = (function (i_size) {
// copy array
i_size = i_size.slice();
// inverse coordinates
i_size[0] = 0;
i_size[1] *= -1;
// bottom position on popup is 7px
i_size[1] -= 3;
return i_size;
})(_options.iconSize || default_icon.iconSize);
}
if (_options.iconUrl) {
_options.icon = new L.Icon(_options);
}
return _options;
};
// these accessible properties hold map objects
this.maps = [];
this.images = [];
this.markergroups = {};
this.markers = [];
this.lines = [];
this.polygons = [];
this.circles = [];
this.geojsons = [];
this.overlays = [];
}
/**
* window.WPLeafletMapPlugin can be used, by saving arguments,
* before it is officially initialized
*
* This is used to deal with the potential for deferred scripts
*/
var original = window.WPLeafletMapPlugin;
window.WPLeafletMapPlugin = new Main();
// check for functions to execute
if (!!original) {
for (var i = 0, len = original.length; i < len; i++) {
window.WPLeafletMapPlugin.push(original[i]);
}
// empty the array
original.splice(0);
// re-add any methods that may have been added to the original
for (var k in original) {
if (original.hasOwnProperty(k)) {
window.WPLeafletMapPlugin[k] = original[k];
}
}
}
// onload waits for Leaflet to load
if (window.addEventListener) {
window.addEventListener('load', window.WPLeafletMapPlugin.init, false);
} else if (window.attachEvent) {
window.attachEvent('onload', window.WPLeafletMapPlugin.init);
}
})();