UNPKG

npmap.js

Version:

A JavaScript web mapping library, built as a Leaflet plugin, for the National Park Service.

841 lines (700 loc) 21.6 kB
/* global L */ 'use strict'; var handlebars = require('handlebars'), reqwest = require('reqwest'); handlebars.registerHelper('toLowerCase', function(str) { return str.toLowerCase(); }); // Shim for Array.indexOf if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(searchElement, fromIndex) { if (this === undefined || this === null) { throw new TypeError('"this" is null or not defined'); } var length = this.length >>> 0; fromIndex = +fromIndex || 0; if (Math.abs(fromIndex) === Infinity) { fromIndex = 0; } if (fromIndex < 0) { fromIndex += length; if (fromIndex < 0) { fromIndex = 0; } } for (; fromIndex < length; fromIndex++) { if (this[fromIndex] === searchElement) { return fromIndex; } } return -1; }; } // Shim for Array.map because Internet Explorer 8 doesn't support it. if (!Array.prototype.map) { Array.prototype.map = function (callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(" this is null or not defined"); } var O = Object(this); var len = O.length >>> 0; if (typeof callback !== "function") { throw new TypeError(callback + " is not a function"); } if (arguments.length > 1) { T = thisArg; } A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); A[k] = mappedValue; } k++; } return A; }; } // Shim for window.atob/window.btoa. (function() { var decodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1), encodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; function base64decode(str) { var c1, c2, c3, c4, i, len, out; len = str.length; i = 0; out = ''; while (i < len) { do { c1 = decodeChars[str.charCodeAt(i++) & 0xff]; } while(i < len && c1 === -1); if (c1 === -1) { break; } do { c2 = decodeChars[str.charCodeAt(i++) & 0xff]; } while(i < len && c2 === -1); if (c2 === -1) { break; } out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); do { c3 = str.charCodeAt(i++) & 0xff; if (c3 === 61) { return out; } c3 = decodeChars[c3]; } while (i < len && c3 === -1); if (c3 === -1) { break; } out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); do { c4 = str.charCodeAt(i++) & 0xff; if (c4 === 61) { return out; } c4 = decodeChars[c4]; } while (i < len && c4 === -1); if (c4 === -1) { break; } out += String.fromCharCode(((c3 & 0x03) << 6) | c4); } return out; } function base64encode(str) { var c1, c2, c3, i, len, out; len = str.length; i = 0; out = ''; while (i < len) { c1 = str.charCodeAt(i++) & 0xff; if (i === len) { out += encodeChars.charAt(c1 >> 2); out += encodeChars.charAt((c1 & 0x3) << 4); out += '=='; break; } c2 = str.charCodeAt(i++); if (i === len) { out += encodeChars.charAt(c1 >> 2); out += encodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); out += encodeChars.charAt((c2 & 0xF) << 2); out += '='; break; } c3 = str.charCodeAt(i++); out += encodeChars.charAt(c1 >> 2); out += encodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); out += encodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)); out += encodeChars.charAt(c3 & 0x3F); } return out; } if (!window.btoa) { window.btoa = base64encode; } if (!window.atob) { window.atob = base64decode; } })(); module.exports = { _checkDisplay: function(node, changed) { if (node.style && node.style.display === 'none') { changed.push(node); node.style.display = 'block'; } }, _getAutoPanPaddingTopLeft: function(el) { var containers = this.getChildElementsByClassName(el, 'leaflet-top'); return [this.getOuterDimensions(containers[0]).width + 20, this.getOuterDimensions(containers[1]).height + 20]; }, _getAvailableVerticalSpace: function(map) { var container = map.getContainer(), bottomLeft = this.getChildElementsByClassName(container, 'leaflet-bottom')[0], bottomRight = this.getChildElementsByClassName(container, 'leaflet-bottom')[1], bottomHeight = this.getOuterDimensions(bottomLeft).height, available; if (this.getOuterDimensions(bottomRight).height > bottomHeight) { bottomHeight = this.getOuterDimensions(bottomRight).height; } available = this.getOuterDimensions(container).height - bottomHeight - this.getOuterDimensions(this.getChildElementsByClassName(container, 'leaflet-top')[1]).height; if (available > 149) { return available; } else { return 150; } }, _lazyLoader: require('./lazyloader.js'), _parseLocalUrl: function(url) { return url.replace(location.origin, ''); }, appendCssFile: function(urls, callback) { if (typeof urls === 'string') { urls = [ urls ]; } this._lazyLoader(urls, callback); }, appendJsFile: function(urls, callback) { if (typeof urls === 'string') { urls = [ urls ]; } this._lazyLoader(urls, callback); }, buildUrl: function(base, params) { var returnArray = []; if (params) { returnArray.push(base + '?'); } else { return base; } for (var param in params) { returnArray.push(encodeURIComponent(param)); returnArray.push('='); returnArray.push(encodeURIComponent(params[param])); returnArray.push('&'); } returnArray.pop(); return returnArray.join(''); }, cancelEvent: function(e) { e = e || window.event; if (e.preventDefault) { e.preventDefault(); } e.returnValue = false; }, dataToList: function(data, fields) { var dl = document.createElement('dl'); for (var prop in data) { var add = true; if (fields && L.Util.isArray(fields)) { if (fields.indexOf(prop) === -1) { add = false; } } if (add) { var dd = document.createElement('dd'), dt = document.createElement('dt'); dt.innerHTML = prop; dd.innerHTML = data[prop]; dl.appendChild(dt); dl.appendChild(dd); } } return dl; }, // TODO: Needs a lot of cleanup, and also need to document fields option. dataToTable: function(data, fields) { var table = document.createElement('table'), tableBody = document.createElement('tbody'), field, fieldTitles; table.appendChild(tableBody); if (L.Util.isArray(fields)) { fieldTitles = {}; for (var i = 0; i < fields.length; i++) { field = fields[i]; if (typeof(field) === 'string') { fieldTitles[field] = { 'title': field }; } else { fieldTitles[field.field] = field; } } } for (var prop in data) { var add = false; if (fieldTitles) { for (field in fieldTitles) { if (field === prop) { add = true; break; } } } else { add = true; } if (add) { var tdProperty = document.createElement('td'), tdValue = document.createElement('td'), tr = document.createElement('tr'); if (fieldTitles) { tdProperty.innerHTML = fieldTitles[prop].title; } else { tdProperty.innerHTML = prop; } if (fieldTitles && fieldTitles[prop] && fieldTitles[prop].separator) { tdValue.innerHTML = data[prop].replace(fieldTitles[prop].separator, '<br/>'); } else { tdValue.innerHTML = data[prop]; } if (fieldTitles && fieldTitles[prop] && fieldTitles[prop].process) { tdValue.innerHTML = fieldTitles[prop].process(tdValue.innerHTML); } tr.appendChild(tdProperty); tr.appendChild(tdValue); tableBody.appendChild(tr); } } return table; }, escapeHtml: function(unsafe) { return unsafe .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;') .replace(/'/g, '&#039;'); }, getChildElementsByClassName: function(parentNode, className) { var children = parentNode.childNodes, matches = []; function recurse(el) { var grandChildren = el.children; if (typeof el.className === 'string' && el.className.indexOf(className) !== -1) { var classNames = el.className.split(' '); for (var k = 0; k < classNames.length; k++) { if (classNames[k] === className) { matches.push(el); break; } } } if (grandChildren && grandChildren.length) { for (var j = 0; j < grandChildren.length; j++) { recurse(grandChildren[j]); } } } for (var i = 0; i < children.length; i++) { recurse(children[i]); } return matches; }, getChildElementsByNodeName: function(parentNode, nodeName) { var children = parentNode.childNodes, matches = []; nodeName = nodeName.toLowerCase(); function recurse(el) { var grandChildren = el.children; if (typeof el.nodeName === 'string' && el.nodeName.toLowerCase() === nodeName) { matches.push(el); } if (grandChildren && grandChildren.length) { for (var j = 0; j < grandChildren.length; j++) { recurse(grandChildren[j]); } } } for (var i = 0; i < children.length; i++) { recurse(children[i]); } return matches; }, getElementsByClassName: function(className) { var matches = [], regex = new RegExp('(^|\\s)' + className + '(\\s|$)'), tmp = document.getElementsByTagName('*'); for (var i = 0; i < tmp.length; i++) { if (regex.test(tmp[i].className)) { matches.push(tmp[i]); } } return matches; }, getEventObject: function(e) { if (!e) { e = window.event; } return e; }, getEventObjectTarget: function(e) { var target; if (e.target) { target = e.target; } else { target = e.srcElement; } if (target.nodeType === 3) { target = target.parentNode; } return target; }, getNextSibling: function(el) { do { el = el.nextSibling; } while (el && el.nodeType !== 1); return el; }, getOffset: function(el) { for (var lx = 0, ly = 0; el !== null; lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent); return { left: lx, top: ly }; }, getOuterDimensions: function(el) { var height = 0, width = 0; if (el) { var changed = [], parentNode = el.parentNode; this._checkDisplay(el, changed); if (el.id !== 'npmap' && parentNode) { this._checkDisplay(parentNode, changed); while (parentNode.id && parentNode.id !== 'npmap' && parentNode.id !== 'npmap-map') { parentNode = parentNode.parentNode; if (parentNode) { this._checkDisplay(parentNode, changed); } } } height = el.offsetHeight; width = el.offsetWidth; changed.reverse(); for (var i = 0; i < changed.length; i++) { changed[i].style.display = 'none'; } } return { height: height, width: width }; }, getOuterHtml: function(el) { if (!el || !el.tagName) { return ''; } var div = document.createElement('div'), ax, txt; div.appendChild(el.cloneNode(false)); txt = div.innerHTML; ax = txt.indexOf('>') + 1; txt = txt.substring(0, ax) + el.innerHTML + txt.substring(ax); div = null; return txt; }, getPosition: function(el) { var obj = { left: 0, top: 0 }, offset = this.getOffset(el), offsetParent = this.getOffset(el.parentNode); obj.left = offset.left - offsetParent.left; obj.top = offset.top - offsetParent.top; return obj; }, getPreviousSibling: function(el) { do { el = el.previousSibling; } while (el && el.nodeType !== 1); return el; }, getPropertyCount: function(obj) { if (!Object.keys) { var keys = [], k; for (k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) { keys.push(k); } } return keys.length; } else { return Object.keys(obj).length; } }, handlebars: function(template, data) { template = handlebars.compile(template); return template(data); }, isLocalUrl: function(url) { if (url.indexOf(location.origin) === 0) { return true; } else { return !(/^(?:[a-z]+:)?\/\//i.test(url)); } }, isNumeric: function(val) { return !isNaN(parseFloat(val)) && isFinite(val); }, linkify: function(text, shorten, target) { var regexRoot = '\\b(https?:\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[A-Z0-9+&@#/%=~_|])', regexLink = new RegExp(regexRoot, 'gi'), regexShorten = new RegExp('>' + regexRoot +'</a>', 'gi'), textLinked = text.replace(regexLink, '<a href="$1"' + (target ? ' target="' + target + '"' : '') + '>$1</a>'); if (shorten) { var matchArray = textLinked.match(regexShorten); if (matchArray) { for (var i = 0; i < matchArray.length; i++) { var newBase = matchArray[i].substr(1, matchArray[i].length - 5).replace(/https?:\/\//gi, ''), newName = newBase.substr(0, shorten) + (newBase.length > shorten ? '&hellip;' : ''); if (newBase.length-1 === shorten) { newName = newName.substr(0, shorten) + newBase.substr(shorten, 1); } textLinked = textLinked.replace(matchArray[i], '>' + newName + '</a>'); } } } return textLinked; }, loadFile: function(url, type, callback) { if (this.isLocalUrl(url)) { if (type === 'xml') { var request = new XMLHttpRequest(); request.onload = function() { var text = this.responseText; if (text) { callback(text); } else { callback(false); } }; request.open('get', this._parseLocalUrl(url), true); request.send(); } else { reqwest({ error: function() { callback(false); }, success: function(response) { if (response) { if (type === 'text') { callback(response.responseText); } else { callback(response); } } else { callback(false); } }, type: type, url: this._parseLocalUrl(url) }); } } else { var supportsCors = (window.location.protocol.indexOf('https:') === 0 ? true : (this.supportsCors() === 'yes')); reqwest({ crossOrigin: supportsCors, error: function() { callback(false); }, success: function(response) { if (response && response.success) { callback(response.data); } else { callback(false); } }, type: 'json' + (supportsCors ? '' : 'p'), url: 'https://npmap-proxy.herokuapp.com/?type=' + type + '&url=' + encodeURIComponent(url) }); } }, mediaToList: function(data, media) { var imageDiv = [], imageLi = [], imageList = document.createElement('ul'), imageTypes = { focus: function(guids) { var imgs = [], regex = new RegExp('[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(}){0,1}', 'g'), attrs, guidArray, i; guidArray = guids.match(regex); for (i = 0; i < guidArray.length; i++) { attrs = { src: 'http://focus.nps.gov/GetAsset/' + guidArray[i] + '/proxy/lores', href: 'http://focus.nps.gov/AssetDetail?assetID=' + guidArray[i] }; imgs.push(attrs); } return imgs; } }, mediaNavDiv = document.createElement('div'), btnDiv, imageAttrs, mediaIndex, next, prev; function changeImage(direction) { var lis = imageList.childNodes, maxImg = lis.length, next = btnDiv.childNodes[1], previous = btnDiv.childNodes[0], curImg, i, li; for (i = 0; i < lis.length; i++) { li = lis[i]; if (li.style.display !== 'none') { curImg = i; break; } } if ((curImg + direction) < maxImg && (curImg + direction) > -1) { for (i = 0; i < lis.length; i++) { li = lis[i]; if (i === (curImg + direction)) { li.style.display = 'inherit'; } else { li.style.display = 'none'; } } } if ((curImg + direction) <= 0) { L.DomUtil.addClass(previous, 'disabled'); } else { L.DomUtil.removeClass(previous, 'disabled'); } if ((curImg + direction + 1) >= maxImg) { L.DomUtil.addClass(next, 'disabled'); } else { L.DomUtil.removeClass(next, 'disabled'); } } for (mediaIndex = 0; mediaIndex < media.length; mediaIndex++) { var newAnchor = [], newImage = []; if (imageTypes[media[mediaIndex].type]) { imageAttrs = imageTypes[media[mediaIndex].type](data[media[mediaIndex].id]); for (var k = 0; k < imageAttrs.length; k++) { imageLi.push(document.createElement('li')); imageLi[k].style.float = 'left'; imageLi[k].style.display = k > 0 ? 'none' : 'inherit'; imageDiv.push(document.createElement('div')); imageDiv[k].style.width = '250px'; imageDiv[k].style.height = (250 * 0.75) + 'px'; imageDiv[k].style.marginLeft = 'auto'; imageDiv[k].style.marginRight = 'auto'; newAnchor.push(document.createElement('a')); newAnchor[k].href = imageAttrs[k].href; newImage.push(document.createElement('img')); newImage[k].src = imageAttrs[k].src; newAnchor[k].appendChild(newImage[k]); imageDiv[k].appendChild(newAnchor[k]); imageLi[k].appendChild(imageDiv[k]); imageList.appendChild(imageLi[k]); } } } imageList.className = 'clearfix'; mediaNavDiv.appendChild(imageList); btnDiv = document.createElement('div'); btnDiv.style.float = 'right'; prev = document.createElement('button'); prev.setAttribute('class', 'btn btn-circle disabled prev'); prev.innerHTML = '&lt;'; next = document.createElement('button'); next.setAttribute('class', 'btn btn-circle next'); next.innerHTML = '&gt;'; L.DomEvent.addListener(prev, 'click', function() { changeImage(-1); }); L.DomEvent.addListener(next, 'click', function() { changeImage(1); }); btnDiv.appendChild(prev); btnDiv.appendChild(next); if (imageAttrs.length > 1) { mediaNavDiv.appendChild(btnDiv); } return mediaNavDiv; }, parseDomainFromUrl: function(url) { var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i); return matches && matches[1]; }, putCursorAtEndOfInput: function(input) { if (input.setSelectionRange) { var length = input.value.length * 2; input.setSelectionRange(length, length); } else { input.value = input.value; } }, reqwest: reqwest, strict: function(_, type) { if (typeof _ !== type) { throw new Error('Invalid argument: ' + type + ' expected'); } }, strictInstance: function(_, klass, name) { if (!(_ instanceof klass)) { throw new Error('Invalid argument: ' + name + ' expected'); } }, strictOneOf: function(_, values) { if (values.indexOf(_) === -1) { throw new Error('Invalid argument: ' + _ + ' given, valid values are ' + values.join(', ')); } }, stripHtml: function(html) { var tmp = document.createElement('div'); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ''; }, // http://stackoverflow.com/a/7616755/27540 supportsCors: function() { if ('withCredentials' in new XMLHttpRequest()) { return 'yes'; } else if (typeof XDomainRequest !== 'undefined') { return 'partial'; } else { return 'no'; } }, unescapeHtml: function(unsafe) { return unsafe .replace(/&amp;/g, '&') .replace(/&lt;/g, '<') .replace(/&gt;/g, '>') .replace(/&quot;/g, '\"') .replace(/&#039;/g, '\''); } };