diff --git a/docs/pages/Tools/Draw/Draw.md b/docs/pages/Tools/Draw/Draw.md index a4c8e238..8921623d 100644 --- a/docs/pages/Tools/Draw/Draw.md +++ b/docs/pages/Tools/Draw/Draw.md @@ -86,8 +86,13 @@ There are five files that are group editable with the correct permission. The gr "default": "No" }, { - "type": "date", + "type": "incrementer", "field": "g", + "default": "ID-#" + }, + { + "type": "date", + "field": "h", "format": "YYYY-MM-DDTHH:mm:ss", "default": "2000-01-01T00:00:00" // Can be "NOW", "STARTTIME" or "ENDTIME" too for dynamic defaults } @@ -95,7 +100,7 @@ There are five files that are group editable with the correct permission. The gr "example_2": [ { "type": "checkbox", - "field": "h", + "field": "i", "default": false } ] diff --git a/src/essence/Ancillary/Coordinates.js b/src/essence/Ancillary/Coordinates.js index e6b3d586..1f79af53 100644 --- a/src/essence/Ancillary/Coordinates.js +++ b/src/essence/Ancillary/Coordinates.js @@ -775,9 +775,10 @@ function urlClick(e) { } function toggleTimeUI() { - const active = $(this).hasClass('active') - $(this).toggleClass('active') + const active = $('#toggleTimeUI').hasClass('active') + $('#toggleTimeUI').toggleClass('active') $('#timeUI').toggleClass('active') + const newBottom = active ? 0 : 40 const timeBottom = active ? -40 : 0 diff --git a/src/essence/Tools/Draw/DrawTool.js b/src/essence/Tools/Draw/DrawTool.js index ccdc1f2a..25e6fa12 100644 --- a/src/essence/Tools/Draw/DrawTool.js +++ b/src/essence/Tools/Draw/DrawTool.js @@ -5,6 +5,7 @@ import DrawTool_History from './DrawTool_History' import DrawTool_Publish from './DrawTool_Publish' import DrawTool_Shapes from './DrawTool_Shapes' import DrawTool_FileModal from './DrawTool_FileModal' +import DrawTool_Templater from './DrawTool_Templater' import $ from 'jquery' import * as d3 from 'd3' @@ -1077,6 +1078,19 @@ var DrawTool = { ) }, addDrawing: function (body, callback, failure) { + // Add template property defaults + const file = DrawTool.getFileObjectWithId(body.file_id) + if (file?.template?.template && body?.properties) { + let newProps = JSON.parse(body.properties) + const templateDefaults = DrawTool_Templater.getTemplateDefaults( + file?.template?.template, + L_.layers.layer[`DrawTool_${body.file_id}`] + ) + + newProps = { ...newProps, ...templateDefaults } + body.properties = JSON.stringify(newProps) + } + if (body.file_id == null) { CursorInfo.update( 'No file chosen. Please select or make a file for drawings.', diff --git a/src/essence/Tools/Draw/DrawTool_Editing.js b/src/essence/Tools/Draw/DrawTool_Editing.js index bcacc877..bcd1b4ea 100644 --- a/src/essence/Tools/Draw/DrawTool_Editing.js +++ b/src/essence/Tools/Draw/DrawTool_Editing.js @@ -2350,7 +2350,10 @@ var Editing = { if (DrawTool.plugins?.Geologic?.custom?.resetGeologic) DrawTool.plugins.Geologic.custom.resetGeologic() - const templaterProperties = templater.getValues() + const templaterProperties = templater.getValues( + L_.layers.layer[DrawTool.lastContextLayerIndexFileId.layer], + properties + ) if (templaterProperties === false) return if (!grouping) { diff --git a/src/essence/Tools/Draw/DrawTool_Templater.css b/src/essence/Tools/Draw/DrawTool_Templater.css index 619573dc..7b983b2c 100644 --- a/src/essence/Tools/Draw/DrawTool_Templater.css +++ b/src/essence/Tools/Draw/DrawTool_Templater.css @@ -276,3 +276,6 @@ .drawToolTemplaterLiBody_dropdown_default input[type='number'] { width: 90px !important; } +.drawToolTemplaterLiBody_incrementer_default { + width: 100%; +} diff --git a/src/essence/Tools/Draw/DrawTool_Templater.js b/src/essence/Tools/Draw/DrawTool_Templater.js index a7e5e66e..e98db8d2 100644 --- a/src/essence/Tools/Draw/DrawTool_Templater.js +++ b/src/essence/Tools/Draw/DrawTool_Templater.js @@ -23,6 +23,7 @@ const DrawTool_Templater = { template.map((t, idx) => { if( properties[t.field] != null) { + t._default = t.default t.default = properties[t.field] } // prettier-ignore @@ -92,6 +93,15 @@ const DrawTool_Templater = { ``, `` ].join('\n') + case 'incrementer': + return [ + `
  • `, + `
    ${t.field}:
    `, + ``, + `
  • ` + ].join('\n') default: return null } @@ -211,9 +221,10 @@ const DrawTool_Templater = { }) return { - getValues: () => { + getValues: (layer, existingProperties) => { const values = {} const invalids = {} + template.forEach((t, idx) => { switch (t.type) { case 'checkbox': @@ -341,6 +352,24 @@ const DrawTool_Templater = { if (values[t.field] === 'Invalid Date') values[t.field] = null break + case 'incrementer': + values[t.field] = $( + `#${containerId} #drawToolTemplater_${idx} input` + ).val() + + const nextIncrement = + DrawTool_Templater._getNextIncrement( + values[t.field], + t, + layer, + existingProperties + ) + + if (nextIncrement.error != null) + invalids[t.field] = nextIncrement.error + else values[t.field] = nextIncrement.newValue + + break default: break } @@ -413,12 +442,85 @@ const DrawTool_Templater = { ) return removedOffset }, + + /** + * + * @param {*} value + * @param {*} t + * @param {*} layer + * @returns {newValue: Number, error: String} + */ + _getNextIncrement(value, t, layer, existingProperties) { + const response = { + newValue: value, + error: null, + } + + let usedValues = [] + const split = (t._default || t.default).split('#') + const start = split[0] + const end = split[1] + for (var i = 0; i < layer.length; i++) { + if (layer[i] == null) continue + let geojson = + layer[i].feature || + layer[i]._layers[Object.keys(layer[i]._layers)[0]].feature + if (geojson?.properties?.[t.field] != null) { + let featuresVal = geojson?.properties?.[t.field] + + featuresVal = featuresVal.replace(start, '').replace(end, '') + + if (featuresVal !== '#') { + featuresVal = parseInt(featuresVal) + usedValues.push(featuresVal) + } + } + } + if ((response.newValue || '').indexOf('#') !== -1) { + // Actually increment the incrementer for the first time + let bestVal = 0 + usedValues.sort(function (a, b) { + return a - b + }) + usedValues = [...new Set(usedValues)] // makes it unique + usedValues.forEach((v) => { + if (bestVal === v) bestVal++ + }) + response.newValue = response.newValue.replace('#', bestVal) + } else if (existingProperties) { + let numVal = response.newValue.replace(start, '').replace(end, '') + if (numVal != '#') { + numVal = parseInt(numVal) + if (existingProperties[t.field] === response.newValue) { + // In case of a resave, make sure the id exists only once + let count = 0 + usedValues.forEach((v) => { + if (numVal === v) count++ + }) + if (count > 1) + response.error = `Incrementing field: '${t.field}' is not unique` + } else { + // In case a manual change, make sure the id is unique + if (usedValues.indexOf(numVal) !== -1) + response.error = `Incrementing field: '${t.field}' is not unique` + } + } + } + + // Check that the field still matches the surrounding string + const incRegex = new RegExp(`^${start}\\d+${end}$`) + if (incRegex.test(response.newValue) == false) { + response.error = `Incrementing field: '${t.field}' must follow syntax: '${start}{#}${end}'` + } + return response + }, _templateInDesignIdx: 0, _templateInDesign: {}, _TEMPLATE_TYPES: [ 'checkbox', 'date', 'dropdown', + 'incrementer', 'number', 'slider', 'text', @@ -697,6 +799,17 @@ const DrawTool_Templater = { "" ] break + case 'incrementer': + // prettier-ignore + typeMarkup = [ + `
    `, + `
    `, + `
    Value with a single '#' to place an incrementing number:
    `, + ``, + "
    ", + "
    " + ] + break default: break } @@ -788,6 +901,7 @@ const DrawTool_Templater = { ).val() const items = [] + const invalids = {} $(`#${containerId} #drawToolTemplaterDesignContent > li`).each( function () { const item = {} @@ -919,6 +1033,21 @@ const DrawTool_Templater = { ) .prop('checked') break + case 'incrementer': + item.default = $(this) + .find( + '.drawToolTemplaterLiBody_incrementer_default input' + ) + .val() + + if ( + ((item.default || '').match(/#/g) || []).length != 1 + ) { + invalids[ + item.field + ] = `'${item.field}' must contain exactly one '#' symbol` + } + break default: break } @@ -963,6 +1092,7 @@ const DrawTool_Templater = { return false } } + for (let i = 0; i < template.template.length; i++) { const t = template.template[i] if (t.field == null || t.field == '') { @@ -993,7 +1123,7 @@ const DrawTool_Templater = { } catch (error) { // no good CursorInfo.update( - `Template cannot contain invalid reges: ${t.regex}`, + `Template cannot contain invalid regex: ${t.regex}`, 6000, true, { x: 305, y: 6 }, @@ -1003,6 +1133,17 @@ const DrawTool_Templater = { return false } } + if (invalids[t.field] != null) { + CursorInfo.update( + `Template field: ${invalids[t.field]}`, + 6000, + true, + { x: 305, y: 6 }, + '#e9ff26', + 'black' + ) + return false + } } return template }, @@ -1072,6 +1213,45 @@ const DrawTool_Templater = { } return true }, + getTemplateDefaults: function (template, layer) { + const defaultProps = {} + + template.forEach((t, idx) => { + if (t.field != null && t.default != null && t.default != '') { + let f = t.field + let v = t.default + switch (t.type) { + case 'incrementer': + const nextIncrement = + DrawTool_Templater._getNextIncrement( + t.default, + t, + layer + ) + v = nextIncrement.newValue + break + case 'date': + if (v === 'NOW') + v = moment + .utc(new Date().getTime()) + .format(t.format || 'YYYY-MM-DDTHH:mm:ss') + else if (v === 'STARTTIME') + v = moment + .utc(TimeControl.getStartTime()) + .format(t.format || 'YYYY-MM-DDTHH:mm:ss') + else if (v === 'ENDTIME') + v = moment + .utc(TimeControl.getEndTime()) + .format(t.format || 'YYYY-MM-DDTHH:mm:ss') + break + default: + } + defaultProps[f] = v + } + }) + + return defaultProps + }, } export default DrawTool_Templater diff --git a/src/essence/Tools/Draw/config.json b/src/essence/Tools/Draw/config.json index 1bfe5fa2..293c34cf 100644 --- a/src/essence/Tools/Draw/config.json +++ b/src/essence/Tools/Draw/config.json @@ -61,8 +61,13 @@ "default": "No" }, { - "type": "date", + "type": "incrementer", "field": "g", + "default": "ID-#" + }, + { + "type": "date", + "field": "h", "format": "HH:mm:ss", "default": "now" }