From b67b34928a415522253f9625e455df329aa70e8e Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 8 Mar 2022 16:41:21 +0000 Subject: [PATCH] Initial Commit for Issue/3819. World map component added and a small change to the Component draggable behaviour to accomodate it. --- .eslintrc.json | 3 + .../design/AppPreview/componentStructure.json | 3 +- packages/client/manifest.json | 76 +++++ packages/client/package.json | 2 + .../client/src/components/Component.svelte | 7 +- .../src/components/app/EmbeddedMap.svelte | 266 ++++++++++++++++++ .../src/components/app/EmbeddedMapControls.js | 192 +++++++++++++ packages/client/src/components/app/index.js | 1 + 8 files changed, 548 insertions(+), 2 deletions(-) create mode 100644 packages/client/src/components/app/EmbeddedMap.svelte create mode 100644 packages/client/src/components/app/EmbeddedMapControls.js diff --git a/.eslintrc.json b/.eslintrc.json index 4dc11c0d65..8f4f68036b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -28,5 +28,8 @@ ], "rules": { "no-self-assign": "off" + }, + "globals": { + "GeolocationPositionError": true } } diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index cacd70a89b..6873ae547d 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -82,7 +82,8 @@ "link", "icon", "embed", - "markdownviewer" + "markdownviewer", + "embeddedmap" ] } ] diff --git a/packages/client/manifest.json b/packages/client/manifest.json index d8e589588f..11c927700e 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2474,6 +2474,82 @@ } ] }, + "embeddedmap": { + "name": "Embedded Map", + "icon": "Location", + "styles": ["size"], + "editable": true, + "draggable": false, + "illegalChildren": [ + "section" + ], + "settings": [ + { + "type": "dataProvider", + "label": "Provider", + "key": "dataProvider" + }, + { + "type": "select", + "label": "Map Type", + "key": "mapType", + "options": [ + "Roadmap", + "Terrain", + "Satellite", + "Hybrid" + ], + "defaultValue": "Roadmap" + }, + { + "type": "boolean", + "label": "Enable Fullscreen", + "key": "fullScreenEnabled", + "defaultValue": true + }, + { + "type": "boolean", + "label": "Enabled Location", + "key": "locationEnabled", + "defaultValue": false + }, + { + "type": "boolean", + "label": "Enable Zoom", + "key": "zoomEnabled", + "defaultValue": true + }, + { + "type": "number", + "label": "Zoom Level (0-100)", + "key": "zoomLevel", + "defaultValue": 72, + "max" : 100, + "min" : 0 + }, + { + "type": "field", + "label": "Latitude Key", + "key": "latitudeKey" + }, + { + "type": "field", + "label": "Longitude Key", + "key": "longitudeKey" + }, + { + "type": "field", + "label": "Title Key", + "key": "titleKey" + }, + { + "type": "text", + "label": "Tile URL", + "key": "tileURL", + "defaultValue": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + } + ] + }, "attachmentfield": { "name": "Attachment", "icon": "Attach", diff --git a/packages/client/package.json b/packages/client/package.json index 8772b9135f..16a2f34c8e 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -32,8 +32,10 @@ "@spectrum-css/vars": "^3.0.1", "apexcharts": "^3.22.1", "dayjs": "^1.10.5", + "leaflet": "^1.7.1", "regexparam": "^1.3.0", "rollup-plugin-polyfill-node": "^0.8.0", + "screenfull": "^6.0.1", "shortid": "^2.2.15", "svelte": "^3.38.2", "svelte-apexcharts": "^1.0.2", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 78fff52426..e4176587ee 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -103,7 +103,12 @@ ($builderStore.previewType === "layout" || insideScreenslot) && !isBlock $: editing = editable && selected && $builderStore.editMode - $: draggable = !inDragPath && interactive && !isLayout && !isScreen + $: draggable = + !inDragPath && + interactive && + !isLayout && + !isScreen && + definition?.draggable !== false $: droppable = interactive && !isLayout && !isScreen // Empty components are those which accept children but do not have any. diff --git a/packages/client/src/components/app/EmbeddedMap.svelte b/packages/client/src/components/app/EmbeddedMap.svelte new file mode 100644 index 0000000000..63b98ba651 --- /dev/null +++ b/packages/client/src/components/app/EmbeddedMap.svelte @@ -0,0 +1,266 @@ + + +
+ {#if error} +
{error}
+ {/if} + +
+
+ + diff --git a/packages/client/src/components/app/EmbeddedMapControls.js b/packages/client/src/components/app/EmbeddedMapControls.js new file mode 100644 index 0000000000..ca1b1ed22a --- /dev/null +++ b/packages/client/src/components/app/EmbeddedMapControls.js @@ -0,0 +1,192 @@ +import L from "leaflet" +import screenfull from "screenfull" + +const createButton = function (html, title, className, container, fn) { + let link = L.DomUtil.create("a", className, container) + link.innerHTML = html + link.href = "#" + link.title = title + + link.setAttribute("role", "button") + link.setAttribute("aria-label", title) + + L.DomEvent.disableClickPropagation(link) + L.DomEvent.on(link, "click", L.DomEvent.stop) + L.DomEvent.on(link, "click", fn, this) + L.DomEvent.on(link, "click", this._refocusOnMap, this) + + return link +} + +// Full Screen Control + +const FullScreenControl = L.Control.extend({ + options: { + position: "topright", + fullScreenContent: + '' + + '' + + '', + fullScreenTitle: "Enter Fullscreen", + }, + onAdd: function () { + var fullScreenClassName = "leaflet-control-fullscreen", + container = L.DomUtil.create("div", fullScreenClassName + " leaflet-bar"), + options = this.options + + this._fullScreenButton = this._createButton( + options.fullScreenContent, + options.fullScreenTitle, + "map-fullscreen", + container, + this._fullScreen + ) + + return container + }, + _fullScreen: function () { + var map = this._map + if (screenfull.isEnabled) { + screenfull.toggle(map.getContainer()) + } + }, + _createButton: createButton, +}) + +const initFullScreenControl = () => { + L.Map.mergeOptions({ + fullScreen: false, + }) + + L.Map.addInitHook(function () { + if (this.options.fullScreen) { + this.fullScreenControl = new FullScreenControl() + this.addControl(this.fullScreenControl) + } else { + this.fullScreenControl = null + } + }) +} + +// Location Control + +const LocationControl = L.Control.extend({ + options: { + position: "topright", + locationContent: + '' + + '' + + '', + locationTitle: "Show Your Location", + }, + onAdd: function () { + var locationClassName = "leaflet-control-location", + container = L.DomUtil.create("div", locationClassName + " leaflet-bar"), + options = this.options + + this._locationButton = this._createButton( + options.locationContent, + options.locationTitle, + "map-location", + container, + this._location + ) + + this._updateDisabled() + + return container + }, + disable: function () { + this._disabled = true + this._updateDisabled() + return this + }, + enable: function () { + this._disabled = false + this._updateDisabled() + return this + }, + _location: function () { + if (this._disabled == true) { + return + } + this.disable() + + const success = pos => { + this._map.closePopup() + if (typeof this.options.onLocationSuccess === "function") { + this.options.onLocationSuccess({ + lat: pos.coords.latitude, + lng: pos.coords.longitude, + }) + } + } + + const error = err => { + if (typeof this.options.onLocationFail === "function") { + this.options.onLocationFail(err) + } + } + + this._getPosition() + .then(success) + .catch(error) + .finally(() => { + this.enable() + }) + }, + _getPosition: function () { + var options = { + enableHighAccuracy: false, + timeout: 5000, + maximumAge: 30000, + } + + return new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(resolve, reject, options) + }) + }, + + _createButton: createButton, + + _updateDisabled: function () { + let disabledClassName = "leaflet-disabled" + L.DomUtil.removeClass(this._locationButton, disabledClassName) + this._locationButton.setAttribute("aria-disabled", "false") + + if (this._disabled) { + L.DomUtil.addClass(this._locationButton, disabledClassName) + this._locationButton.setAttribute("aria-disabled", "true") + } + }, +}) + +const initLocationControl = () => { + L.Map.mergeOptions({ + location: false, + onLocationFail: null, + onLocationSuccess: null, + }) + + L.Map.addInitHook(function () { + if (this.options.location) { + this.localControl = new LocationControl() + this.addControl(this.LocationControl) + } else { + this.localControl = null + } + }) +} + +const initMapControls = () => { + initFullScreenControl() + initLocationControl() +} + +export { + initFullScreenControl, + initLocationControl, + initMapControls, + FullScreenControl, + LocationControl, +} diff --git a/packages/client/src/components/app/index.js b/packages/client/src/components/app/index.js index 5af62201e5..e23659620b 100644 --- a/packages/client/src/components/app/index.js +++ b/packages/client/src/components/app/index.js @@ -31,6 +31,7 @@ export { default as cardstat } from "./CardStat.svelte" export { default as spectrumcard } from "./SpectrumCard.svelte" export { default as tag } from "./Tag.svelte" export { default as markdownviewer } from "./MarkdownViewer.svelte" +export { default as embeddedmap } from "./EmbeddedMap.svelte" export * from "./charts" export * from "./forms" export * from "./table"