UNPKG

@binary-constructions/semantic-map

Version:

A markup wrapper for the Leaflet map API

147 lines (123 loc) 5.16 kB
const GEOJSON_GEOMETRY_TYPES = [ "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection", ]; function mapNumber(value, context) { const parsed = Number(value); if (parsed === NaN) { throw "doesn't parse as a number"; } return parsed; } function mapSelected(value, context, selection) { if (!selection.some(s => s === value)) { throw "not one of the allowed values"; } return value; } function escapeHtml(text) { var map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } const attribute_transforms_ordered = [ [ "disable-doubleclick-default", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], [ "enable-clustering", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], [ "features", (value, context) => { const parsed = JSON.parse(value); let features = undefined; if (Array.isArray(parsed)) { features = parsed; } else if (typeof parsed === 'object') { if (parsed.type === "FeatureCollection") { if (Array.isArray(parsed.features)) { features = parsed.features; } else { throw "FeatureCollection does not define features"; } } else if (parsed.type === "Feature") { features = [ parsed ]; } else if (GEOJSON_GEOMETRY_TYPES.includes(parsed.type)) { features = [ { type: "Feature", geometry: parsed, } ]; } else { throw "invalid or missing value of member 'type'"; } } else { throw "neither an object nor an array"; } if (features.some(f => (typeof f !== 'object' || f.type !== "Feature"))) { // TODO: fully validate GeoJSON objects? throw "invalid feature definitions found"; } return features; } ], [ "fit-features", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], [ "geometry-coordinates", (value, context) => { const parsed = JSON.parse(value); // TODO: properly validate dependent on GeoJSON type? if (!Array.isArray(parsed)) { throw "not a (nested) array of coordinates"; } return parsed; } ], [ "geometries", (value, context) => { const parsed = JSON.parse(value); // TODO: properly validate as GeoJSON geometry? if (!Array.isArray(parsed) || parsed.some(g => (typeof g !== 'object' || !g.type || !GEOJSON_GEOMETRY_TYPES.includes(g.type)))) { throw "not an array of objects with a valid GeoJSON 'type' property"; } return parsed; } ], [ "geometry-type", (value, context) => mapSelected(value, context, GEOJSON_GEOMETRY_TYPES) ], //[ "icon-name", (value, context) => value], [ "hide-zoom-control", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], [ "icon-size", (value, context) => mapNumber(value, context) ], //[ "id", (value, context) => value], [ "initial-center", (value, context) => { const parsed = JSON.parse(value); if (!Array.isArray(parsed) || parsed.length !== 2 || parsed.some(n => typeof n !== "number")) { throw "doesn't parse as an array of two numbers"; } return parsed; } ], [ "initial-zoom", (value, context) => mapNumber(value, context) ], [ "max-zoom", (value, context) => mapNumber(value, context) ], [ "max-native-zoom", (value, context) => mapNumber(value, context) ], [ "min-zoom", (value, context) => mapNumber(value, context) ], [ "properties", (value, context) => { const parsed = JSON.parse(value); if (typeof parsed !== 'object' || !Object.keys(parsed).length) { throw "doesn't parse as an object with at least one property"; } return parsed; } ], //[ "property-key", (value, context) => value], [ "property-parse", (value, context) => mapSelected(value, context, [ "literal", "escaped", "json" ]) ], [ "property-value", (value, context) => context["property-parse"] === "escaped" ? escapeHtml(value) : context["property-parse"] === "json" ? JSON.parse(value) : value ], //[ "ref", (value, context) => value ], [ "show-user-location", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], [ "show-user-location-accuracy", (value, context) => mapSelected(value, context, [ "true", "false" ]) === "true" ], //[ "tile-url-template", (value, context) => value ], ]; export const attribute_transforms = attribute_transforms_ordered.reduce((a, t) => { a[t[0]] = t[1]; return a; }, {}); export const attribute_transforms_order = attribute_transforms_ordered.map(t => t[0]);