diff --git a/lib/layer/decorate.mjs b/lib/layer/decorate.mjs
index 5896f90ce..a2530a8ab 100644
--- a/lib/layer/decorate.mjs
+++ b/lib/layer/decorate.mjs
@@ -33,6 +33,7 @@ export default async layer => {
const location = {
layer,
+ table: layer.tableCurrent(),
new: true
}
@@ -44,7 +45,7 @@ export default async layer => {
mapp.utils.paramString({
locale: layer.mapview.locale.key,
layer: layer.key,
- table: layer.tableCurrent()
+ table: location.table
}),
body: JSON.stringify(Object.assign({
[layer.geom]: feature.geometry
@@ -55,7 +56,7 @@ export default async layer => {
layer.draw?.defaults || {}))
})
- layer.reload()
+ //layer.reload()
// Get the newly created location.
mapp.location.get(location)
diff --git a/lib/location/decorate.mjs b/lib/location/decorate.mjs
index 4ae3f96cc..ce0bb7da9 100644
--- a/lib/location/decorate.mjs
+++ b/lib/location/decorate.mjs
@@ -7,6 +7,7 @@ export default location => {
removeCallbacks: [],
trash,
update,
+ mvt_cache,
updateCallbacks: [],
})
@@ -47,6 +48,8 @@ async function update() {
if (!Object.keys(newValues).length) return;
+ await this.mvt_cache()
+
await mapp.utils.xhr({
method: 'POST',
url:
@@ -59,6 +62,8 @@ async function update() {
}),
body: JSON.stringify(newValues),
});
+
+ await this.mvt_cache()
let dependents = this.infoj
.filter(entry => typeof entry.newValue !== 'undefined')
@@ -119,10 +124,30 @@ function flyTo (maxZoom) {
});
}
+async function mvt_cache() {
+
+ if (!this.layer?.mvt_cache) return;
+
+ await mapp.utils.xhr(`${this.layer.mapview.host}/api/query?` +
+ mapp.utils.paramString({
+ template: 'mvt_cache_delete_intersects',
+ locale: this.layer.mapview.locale.key,
+ layer: this.layer.key,
+ mvt_cache: this.layer.mvt_cache,
+ table: this.table,
+ qID: this.layer.qID,
+ id: this.id,
+ geom: this.layer.geom
+ }))
+}
+
async function trash() {
if(!confirm(mapp.dictionary.confirm_delete)) return;
+ // Must clear cache before removing location from source.
+ await this.mvt_cache()
+
await mapp.utils.xhr(`${this.layer.mapview.host}/api/location/delete?` +
mapp.utils.paramString({
locale: this.layer.mapview.locale.key,
diff --git a/lib/location/get.mjs b/lib/location/get.mjs
index c043d490a..48570ff7e 100644
--- a/lib/location/get.mjs
+++ b/lib/location/get.mjs
@@ -65,6 +65,8 @@ export default async function (location, list = location.layer.mapview.locations
mapp.location.decorate(Object.assign(location, { infoj }))
+ location.new && await location.mvt_cache()
+
// Assign location to mapview.
list[location.hook] = location
diff --git a/lib/mapview/geoJSON.mjs b/lib/mapview/geoJSON.mjs
index 71a930d7b..b4fb4781f 100644
--- a/lib/mapview/geoJSON.mjs
+++ b/lib/mapview/geoJSON.mjs
@@ -22,24 +22,6 @@ export default function (params){
if (!feature) return;
- if (feature.getGeometry().getType() !== 'Point') {
-
- const styles = [params.Style].flat().map(style => style.getStroke())
-
- // All other geometry types must have a Stroke style.
- if (!styles.some(style => !!style)) {
-
- params.Style = new ol.style.Style({
- stroke: new ol.style.Stroke({
- color: '#3399CC'
- })
- })
-
- console.warn('Missing Stroke style for geojson vector geometry')
- }
-
- }
-
const layerVector = new ol.layer.Vector({
source: new ol.source.Vector({
features: [feature]
diff --git a/lib/ui/elements/drawing.mjs b/lib/ui/elements/drawing.mjs
index 95459989f..eff941a50 100644
--- a/lib/ui/elements/drawing.mjs
+++ b/lib/ui/elements/drawing.mjs
@@ -460,8 +460,7 @@ function circle(layer) {
layer.mapview.interactions.draw(layer.draw.circle)
- }}>
- ${label}`
+ }}>${label}`
// Return the config element in a drawer with the interaction toggle button as sibling.
return mapp.utils.html.node`
@@ -469,8 +468,7 @@ function circle(layer) {
header: mapp.utils.html`
${mapp.dictionary.circle_config}
`,
- content: layer.draw.circle.panel
- })}
+ content: layer.draw.circle.panel})}
${layer.draw.circle.btn}`
}
@@ -490,6 +488,7 @@ function locator(layer) {
const location = {
layer: layer,
+ table: layer.tableCurrent(),
new: true
}
@@ -499,28 +498,24 @@ function locator(layer) {
location.id = await mapp.utils.xhr({
method: 'POST',
- url: `${location.layer.mapview.host}/api/location/new?` +
+ url: `${layer.mapview.host}/api/location/new?` +
mapp.utils.paramString({
- locale: location.layer.mapview.locale.key,
- layer: location.layer.key,
- table: location.layer.tableCurrent()
+ locale: layer.mapview.locale.key,
+ layer: layer.key,
+ table: location.table
}),
body: JSON.stringify({
- [location.layer.geom]: {
+ [layer.geom]: {
type: 'Point',
coordinates: coords
}
})
})
-
- location.layer.reload()
-
+
mapp.location.get(location)
})
-
- }}>
- ${mapp.dictionary.draw_position}`
+ }}>${mapp.dictionary.draw_position}`
return layer.draw.locator.btn
}
\ No newline at end of file
diff --git a/lib/ui/locations/entries/geometry.mjs b/lib/ui/locations/entries/geometry.mjs
index 2eed9c105..ac9e91744 100644
--- a/lib/ui/locations/entries/geometry.mjs
+++ b/lib/ui/locations/entries/geometry.mjs
@@ -12,15 +12,11 @@ export default entry => {
// Assigning the mapview to the entry makes the entry behave like a layer object for draw and modify interactions.
entry.mapview = entry.location.layer.mapview
- // Assign Style if not already assigned.
- entry.Style = entry.Style
+ // Assign entry.style to location.style
+ entry.style = {...entry.location?.style, ...entry.style}
- // Create OL style object from style object.
- || typeof entry.style === 'object' && mapp.utils
- .style(Object.assign({}, entry.location?.style || {}, entry.style))
-
- // Assign style from location.
- || entry.location.Style
+ // Create ol style from entry.style if not yet defined.
+ entry.Style ??= mapp.utils.style(entry.style)
// Assign method to show geometry in mapview.
entry.show = show
@@ -56,10 +52,11 @@ export default entry => {
draw(entry, list);
// Push modify button into list.
- if (entry.edit?.geometry) {
+ if (entry.edit) {
// Only if the entry has a value, should the modify button be shown (as you can't modify a null geometry)
if (entry.value) {
+
// If label is provided for the Modify Button, use it. Otherwise use default.
let modifyBtnLabel = entry.edit?.modifyBtnOnly?.label || 'Modify Geometry';
@@ -95,22 +92,14 @@ export default entry => {
// Allow for geometries to be shown before confirming the deletion.
setTimeout(remove, 500)
- function remove() {
+ async function remove() {
// Return if user does not confirm deletion.
if (!confirm('Delete Geometry?')) return;
- // Set newValue to null in order update location field in database.
- entry.newValue = null
+ entry.value = null
- // Must be removed prior to database update / re-render.
- if (entry.L) {
- entry.location.layer.mapview.Map.removeLayer(entry.L)
- delete entry.L
- }
-
- // Re-renders location view after database update.
- entry.location.update()
+ postUpdate(entry)
}
}}>Delete Geometry`)
@@ -125,7 +114,7 @@ export default entry => {
// Return drawer with list elements to entry node.
return mapp.ui.elements.drawer({
data_id: `draw-drawer`,
- class: `group ${entry.draw?.groupClassList && 'expanded' || ''}`,
+ class: entry.draw?.classList,
header: mapp.utils.html`
${chkbox}
@@ -213,8 +202,10 @@ function modify(e, entry) {
if (feature) {
// Assign feature geometry as new value.
- entry.newValue = feature.geometry
- entry.location.update()
+ entry.value = feature.geometry
+
+ postUpdate(entry)
+
return;
}
@@ -226,25 +217,73 @@ function modify(e, entry) {
// Method for button element to call draw interaction.
function draw(entry, list) {
- if (typeof entry.draw === 'object') {
- entry.draw.callback = feature => {
- if (!feature) return;
+ // Drawing is only available within an edit context.
+ if (entry.edit?.draw) {
+
+ entry.draw = entry.edit.draw
+ }
+
+ // Editing with drawing is toggled off.
+ if (entry._edit?.draw) delete entry.draw
+
+ // Short circuit without an entry.draw config.
+ if (!entry.draw) return;
+
+ entry.draw.callback = feature => {
+
+ if (!feature) return;
+
+ // Assign feature geometry as new value.
+ entry.value = feature.geometry
+
+ postUpdate(entry)
+ }
- // Remove existing entry geometry layer.
- entry.location.layer.mapview.Map.removeLayer(entry.L)
+ Object.keys(entry.draw).forEach(key => {
- // Assign feature geometry as new value.
- entry.newValue = feature.geometry
- entry.location.update()
+ if (mapp.ui.elements.drawing[key]) {
+ list.push(mapp.ui.elements.drawing[key](entry))
}
+ })
- Object.keys(entry.draw).forEach(key => {
+}
- if (mapp.ui.elements.drawing[key]) {
- list.push(mapp.ui.elements.drawing[key](entry))
- }
- })
+async function postUpdate(entry) {
+
+ if (entry.L) {
+
+ // Remove existing entry geometry layer.
+ entry.location.layer.mapview.Map.removeLayer(entry.L)
+
+ delete entry.L
+ }
+
+ entry.location.view?.classList.add('disabled')
+
+ // Update the geometry field value.
+ await mapp.utils.xhr({
+ method: 'POST',
+ url:
+ `${entry.location.layer.mapview.host}/api/location/update?` +
+ mapp.utils.paramString({
+ locale: entry.location.layer.mapview.locale.key,
+ layer: entry.location.layer.key,
+ table: entry.location.table,
+ id: entry.location.id,
+ }),
+ body: JSON.stringify({ [entry.field]: entry.value }),
+ })
+
+ if (entry.location.layer.geom === entry.field) {
+ // Reload the layer if the layers geom field has been updated.
+ entry.location.layer.reload()
}
+
+ // Render geometry entry with updated entry.value
+ mapp.utils.render(entry.node, mapp.ui.locations.entries.geometry(entry))
+
+ entry.location.view?.classList.remove('disabled')
+
}
\ No newline at end of file
diff --git a/lib/utils/queryParams.mjs b/lib/utils/queryParams.mjs
index 1f2a609c7..a4b4c06e1 100644
--- a/lib/utils/queryParams.mjs
+++ b/lib/utils/queryParams.mjs
@@ -1,5 +1,5 @@
export default _this => {
-
+
// Assign empty object if not defined.
_this.queryparams = _this.queryparams || {}
@@ -7,9 +7,7 @@ export default _this => {
_this.queryparams.layer = _this.queryparams.layer || _this.viewport
// Assign table name from layer.
- if (_this.queryparams.table === true) {
- _this.queryparams.table = _this.layer?.tableCurrent()
- }
+ _this.queryparams.table &&= _this.location?.layer?.tableCurrent()
// Assign fieldValues from the location to queryparams.
if (Array.isArray(_this.queryparams.fieldValues) && _this.location) {
diff --git a/lib/utils/style.mjs b/lib/utils/style.mjs
index 9c9ecd766..6f2def83a 100644
--- a/lib/utils/style.mjs
+++ b/lib/utils/style.mjs
@@ -12,7 +12,7 @@ export default (style, feature) => {
style.forEach(style => {
// Only process icon for features if they are point geometries.
- if (style.icon && (!feature || feature?.geometryType === 'Point')) {
+ if (style.icon) {
// icon styles must always be processed as an array.
style.icon = Array.isArray(style.icon) ? style.icon : [style.icon]
@@ -44,7 +44,9 @@ export default (style, feature) => {
}))
})
- } else {
+ }
+
+ if (style.fillColor || style.strokeColor) {
// Create OL fill.
let fill = style.fillColor && new ol.style.Fill({
diff --git a/mod/location/delete.js b/mod/location/delete.js
index cfe11186a..7734680be 100644
--- a/mod/location/delete.js
+++ b/mod/location/delete.js
@@ -7,18 +7,10 @@ module.exports = async (req, res) => {
// Validate dynamic method call.
if (typeof dbs[layer.dbs || req.params.workspace.dbs] !== 'function') return;
- if (layer.mvt_cache) await dbs[layer.dbs || req.params.workspace.dbs](`
- DELETE FROM ${layer.mvt_cache}
- WHERE ST_Intersects(tile, (
- SELECT ${layer.geom}
- FROM ${req.params.table}
- WHERE ${layer.qID} = $1));`, [req.params.id])
-
var rows = await dbs[layer.dbs || req.params.workspace.dbs](`
DELETE FROM ${req.params.table} WHERE ${layer.qID} = $1;`, [req.params.id])
if (rows instanceof Error) return res.status(500).send('PostgreSQL query error - please check backend logs.')
res.send('Location delete successful')
-
}
\ No newline at end of file
diff --git a/mod/location/new.js b/mod/location/new.js
index 4e3ba0ea4..ef78fc866 100644
--- a/mod/location/new.js
+++ b/mod/location/new.js
@@ -45,17 +45,6 @@ module.exports = async (req, res) => {
if (rows instanceof Error) return res.status(500).send('Failed to query PostGIS table.')
- // Cached tiles which intersect the geometry must be retired.
- if (layer.mvt_cache) await dbs[layer.dbs || req.params.workspace.dbs](`
- DELETE
- FROM ${layer.mvt_cache}
- WHERE ST_Intersects(tile, (
- SELECT ${layer.geom}
- FROM ${req.params.table}
- WHERE ${layer.qID} = $1
- ));`, [rows[0].id])
-
// Return id of newly created location.
res.send(Array.isArray(rows) && rows[0].id?.toString() || null)
-
}
\ No newline at end of file
diff --git a/mod/location/update.js b/mod/location/update.js
index f6790a9a3..5c6c83a08 100644
--- a/mod/location/update.js
+++ b/mod/location/update.js
@@ -47,28 +47,11 @@ module.exports = async (req, res) => {
// Validate dynamic method call.
if (!Object.hasOwn(dbs, layer.dbs || req.params.workspace.dbs) || typeof dbs[layer.dbs || req.params.workspace.dbs] !== 'function') return;
- // Remove tiles from mvt_cache.
- if (layer.mvt_cache) await dbs[layer.dbs || req.params.workspace.dbs](`
- DELETE FROM ${layer.mvt_cache}
- WHERE ST_Intersects(tile, (
- SELECT ${layer.geom}
- FROM ${req.params.table}
- WHERE ${layer.qID} = $1));`, [req.params.id])
-
var q = `UPDATE ${req.params.table} SET ${fields.join()} WHERE ${layer.qID} = $1;`
var rows = await dbs[layer.dbs || req.params.workspace.dbs](q, [req.params.id])
if (rows instanceof Error) return res.status(500).send('PostgreSQL query error - please check backend logs.')
- // Remove tiles from mvt_cache.
- if (layer.mvt_cache) await dbs[layer.dbs || req.params.workspace.dbs](`
- DELETE FROM ${layer.mvt_cache}
- WHERE ST_Intersects(tile, (
- SELECT ${layer.geom}
- FROM ${req.params.table}
- WHERE ${layer.qID} = $1));`, [req.params.id])
-
res.send('This is fine.')
-
}
\ No newline at end of file
diff --git a/mod/query.js b/mod/query.js
index 22c3a41b1..f2cc7f671 100644
--- a/mod/query.js
+++ b/mod/query.js
@@ -94,6 +94,11 @@ module.exports = async (req, res) => {
try {
template.template = template.render && template.render(req.params) || template.template
+ if (!template.template) {
+
+ return res.status(400).send('Unable to parse template string.')
+ }
+
query = template.template
// Replace parameter for identifiers, e.g. table, schema, columns
diff --git a/mod/workspace/assignTemplates.js b/mod/workspace/assignTemplates.js
index 6a9efd78c..49a5c9542 100644
--- a/mod/workspace/assignTemplates.js
+++ b/mod/workspace/assignTemplates.js
@@ -64,6 +64,9 @@ module.exports = async (workspace) => {
admin: true,
render: require('./templates/mvt_cache'),
},
+ mvt_cache_delete_intersects: {
+ template: require('./templates/mvt_cache_delete_intersects'),
+ },
// Default templates can be overridden by assigning a template with the same name.
},
diff --git a/mod/workspace/templates/mvt_cache.js b/mod/workspace/templates/mvt_cache.js
index 08ae8f96a..24a07a1ed 100644
--- a/mod/workspace/templates/mvt_cache.js
+++ b/mod/workspace/templates/mvt_cache.js
@@ -1,6 +1,8 @@
module.exports = _ => {
const layer = _.workspace.locales[_.locale].layers[_.layer]
+
+ if (!layer.mvt_cache) return;
return `
diff --git a/mod/workspace/templates/mvt_cache_delete_intersects.js b/mod/workspace/templates/mvt_cache_delete_intersects.js
new file mode 100644
index 000000000..ab4386154
--- /dev/null
+++ b/mod/workspace/templates/mvt_cache_delete_intersects.js
@@ -0,0 +1,7 @@
+module.exports = `
+DELETE
+ FROM \${mvt_cache}
+ WHERE ST_Intersects(tile, (
+ SELECT \${geom}
+ FROM \${table}
+ WHERE \${qID} = %{id}));`
\ No newline at end of file