npmap.js
Version:
A JavaScript web mapping library, built as a Leaflet plugin, for the National Park Service.
448 lines (370 loc) • 12.7 kB
JavaScript
/* global L */
/* jshint camelcase: false */
'use strict';
var util = require('./util/util');
var Popup = L.Popup.extend({
options: {
autoPanPaddingBottomRight: [20, 20],
autoPanPaddingTopLeft: [20, 20],
offset: [0, -1]
},
_data: [],
_html: null,
_results: [],
onAdd: function(map) {
var content = this._content;
if (window.addEventListener) {
content.addEventListener('DOMMouseScroll', this._handleMouseWheel, false);
}
content.onmousewheel = this._handleMouseWheel;
L.Popup.prototype.onAdd.apply(this, [
map
]);
},
_back: function() {
this.setContent(this._html).update();
this._html = null;
},
_createAction: function(config, data, div) {
var a = document.createElement('a'),
li = document.createElement('li');
li.appendChild(a);
a.innerHTML = util.handlebars(config.text, data);
if (config.menu) {
var menu = L.DomUtil.create('ul', 'menu', div);
for (var i = 0; i < config.menu.length; i++) {
(function() {
var item = config.menu[i],
itemA = document.createElement('a'),
itemLi = document.createElement('li');
itemA.innerHTML = util.handlebars(item.text, data);
L.DomEvent.addListener(itemA, 'click', function() {
var data = null;
try {
data = this.parentNode.parentNode.parentNode.parentNode.npmap_data;
} catch (exception) {}
menu.style.display = 'none';
item.handler(data);
});
itemLi.appendChild(itemA);
menu.appendChild(itemLi);
})();
}
L.DomEvent.addListener(a, 'click', function(e) {
this._toggleMenu(menu, e);
}, this);
} else if (config.handler) {
L.DomEvent.addListener(a, 'click', function() {
var data = null;
try {
data = this.parentNode.parentNode.parentNode.parentNode.npmap_data;
} catch (exception) {}
config.handler(data);
});
}
return li;
},
_handleMouseWheel: function(e) {
if (e) {
var delta = e.wheelDelta,
parentNode = this.parentNode;
if (L.DomUtil.hasClass(parentNode, 'leaflet-popup-scrolled')) {
if (parentNode.scrollTop === 0 && delta > 0) {
util.cancelEvent();
} else if ((parentNode.scrollTop === parentNode.scrollHeight - util.getOuterDimensions(parentNode).height) && delta < 0) {
util.cancelEvent();
}
}
}
},
_handleResults: function(results, mapPopupConfig) {
var div;
function getLayerConfig(layer) {
if (layer.options && layer.options.popup) {
return layer.options.popup;
} else {
return null;
}
}
if (mapPopupConfig && typeof mapPopupConfig === 'function') {
var html = mapPopupConfig(results);
div = document.createElement('div');
if (typeof html === 'string') {
div.innerHTML = html;
} else {
div = html;
}
} else {
if (results.length > 1) {
div = this._resultsToHtml(results);
} else {
var all = [],
result = results[0],
i;
if (result.results && result.results.length) {
for (i = 0; i < result.results.length; i++) {
all.push({
layerConfig: getLayerConfig(result.layer),
result: result.results[i],
resultConfig: null
});
}
} else if (result.subLayers && result.subLayers.length) {
for (i = 0; i < result.subLayers.length; i++) {
var subLayer = result.subLayers[i];
if (subLayer.results && subLayer.results.length) {
for (var j = 0; j < subLayer.results.length; j++) {
all.push({
layerConfig: getLayerConfig(result.layer),
result: subLayer.results[j],
resultConfig: subLayer.popup || null
});
}
}
}
}
if (all.length === 1) {
var first = all[0];
div = this._resultToHtml(first.result, first.layerConfig, first.resultConfig);
} else {
div = this._resultsToHtml(results);
}
}
}
return div;
},
_more: function(index) {
this._html = this.getContent();
this.setContent(this._results[index]).update();
},
_resultToHtml: function(result, layerConfig, resultConfig, addBack, mapConfig) {
var div;
if (mapConfig && typeof mapConfig === 'function') {
var html = mapConfig(result);
div = document.createElement('div');
if (typeof html === 'string') {
div.innerHTML = html;
} else {
div = html;
}
return div;
} else if (layerConfig && typeof layerConfig === 'function') {
div = L.DomUtil.create('div', 'layer');
div.innerHTML = layerConfig(result);
div.npmap_data = result;
return div;
} else {
var config = layerConfig,
actions, description, divContent, media, obj, title, ul;
div = L.DomUtil.create('div', 'layer');
div.npmap_data = result;
if (!config) {
if (resultConfig) {
config = resultConfig;
} else {
config = {
description: {
format: 'table'
}
};
}
}
if (config.title) {
obj = null;
if (typeof config.title === 'function') {
obj = config.title(result);
} else {
obj = config.title;
}
if (obj && typeof obj === 'string') {
title = L.DomUtil.create('div', 'title', div);
title.innerHTML = util.unescapeHtml(util.handlebars(obj, result));
}
}
if (config.description) {
divContent = L.DomUtil.create('div', 'content', div);
obj = null;
if (typeof config.description === 'function') {
obj = config.description(result);
} else {
obj = config.description;
}
if (obj) {
if (obj.format === 'list') {
obj = util.dataToList(result, obj.fields);
} else if (obj.format === 'table') {
obj = util.dataToTable(result, obj.fields);
}
description = L.DomUtil.create('div', 'description', divContent);
if (typeof obj === 'string') {
description.innerHTML = util.unescapeHtml(util.handlebars(obj, result));
} else if ('nodeType' in obj) {
description.appendChild(obj);
}
}
}
// TODO: Needs more work to support {string}s and possibly other config options
if (config.media) {
var mediaObj, mediaDiv;
if (!divContent) {
divContent = L.DomUtil.create('div', 'content', div);
}
media = [];
for (var i = 0; i < config.media.length; i++) {
if (result[config.media[i].id]) {
media.push(config.media[i]);
}
}
if (media.length) {
mediaObj = util.mediaToList(result, media);
if (mediaObj) {
mediaDiv = L.DomUtil.create('div', 'media clearfix', divContent);
mediaDiv.appendChild(mediaObj);
}
}
}
if (config.actions) {
obj = null;
if (typeof config.actions === 'function') {
obj = config.actions(result);
} else {
obj = config.actions;
}
if (obj) {
actions = L.DomUtil.create('div', 'actions', div);
if (L.Util.isArray(obj)) {
ul = document.createElement('ul');
actions.appendChild(ul);
for (var j = 0; j < obj.length; j++) {
ul.appendChild(this._createAction(obj[j], result, actions));
}
} else if (typeof obj === 'string') {
actions.innerHTML = util.unescapeHtml(util.handlebars(obj, result));
} else if ('nodeType' in obj) {
actions.appendChild(obj);
}
}
}
if (addBack) {
var a = document.createElement('a'),
li = document.createElement('li');
L.DomEvent.addListener(a, 'click', this._back, this);
a.innerHTML = '« Back';
li.appendChild(a);
if (actions) {
actions.childNodes[0].insertBefore(li, actions.childNodes[0].childNodes[0]);
} else {
ul = document.createElement('ul');
ul.appendChild(li);
L.DomUtil.create('div', 'actions', div).appendChild(ul);
}
}
return div;
}
},
_resultsToHtml: function(results) {
var div = document.createElement('div'),
index = 0,
me = this;
function listener() {
me._more(this.id);
}
for (var i = 0; i < results.length; i++) {
var divLayer = L.DomUtil.create('div', 'layer', div),
divLayerTitle = L.DomUtil.create('div', 'title', divLayer),
resultLayer = results[i],
a, childNode, divLayerContent, j, k, layerConfig, li, more, resultConfig, single, ul;
if (resultLayer.layer.options) {
if (resultLayer.layer.options.popup) {
layerConfig = resultLayer.layer.options.popup;
}
if (resultLayer.layer.options.name) {
divLayerTitle.innerHTML = resultLayer.layer.options.name;
} else {
divLayerTitle.innerHTML = 'Unnamed';
}
}
if (resultLayer.results && resultLayer.results.length) {
divLayerContent = L.DomUtil.create('div', 'content', divLayer);
ul = document.createElement('ul');
for (j = 0; j < resultLayer.results.length; j++) {
var result = resultLayer.results[j];
a = document.createElement('a');
li = document.createElement('li');
single = this._resultToHtml(result, layerConfig, resultConfig, true);
for (k = 0; k < single.childNodes.length; k++) {
childNode = single.childNodes[k];
if (L.DomUtil.hasClass(childNode, 'title')) {
more = util.stripHtml(childNode.innerHTML);
break;
}
}
if (!more) {
more = 'Untitled';
}
L.DomEvent.addListener(a, 'click', function() {
me._more(this.id);
});
this._results[index] = single;
a.id = index;
a.innerHTML = more;
li.appendChild(a);
ul.appendChild(li);
divLayerContent.appendChild(ul);
index++;
}
} else if (resultLayer.subLayers && resultLayer.subLayers.length) {
divLayerContent = L.DomUtil.create('div', 'content', divLayer);
for (j = 0; j < resultLayer.subLayers.length; j++) {
var divSubLayer = L.DomUtil.create('div', 'sublayer', divLayerContent),
divSubLayerTitle = L.DomUtil.create('div', 'title', divSubLayer),
divSubLayerContent = L.DomUtil.create('div', 'content', divSubLayer),
resultSubLayer = resultLayer.subLayers[j];
divSubLayerTitle.innerHTML = resultSubLayer.name;
ul = document.createElement('ul');
divSubLayerContent.appendChild(ul);
for (k = 0; k < resultSubLayer.results.length; k++) {
var resultFinal = resultSubLayer.results[k];
if (resultSubLayer.popup) {
resultConfig = resultSubLayer.popup;
}
a = document.createElement('a');
li = document.createElement('li');
single = this._resultToHtml(resultFinal, layerConfig, resultConfig, true);
for (var l = 0; l < single.childNodes.length; l++) {
childNode = single.childNodes[l];
if (L.DomUtil.hasClass(childNode, 'title')) {
more = util.stripHtml(childNode.innerHTML);
break;
}
}
if (!more) {
more = 'Untitled';
}
L.DomEvent.addListener(a, 'click', listener);
this._results[index] = single;
a.id = index;
a.innerHTML = more;
li.appendChild(a);
ul.appendChild(li);
index++;
}
}
}
}
return div;
},
_toggleMenu: function(menu, e) {
if (!menu.style.display || menu.style.display === 'none') {
var to = e.toElement;
menu.style.bottom = '0';
menu.style.display = 'block';
menu.style.left = to.offsetLeft + 'px';
} else {
menu.style.display = 'none';
}
}
});
module.exports = function(options) {
return new Popup(options);
};