diff --git a/VERSION b/VERSION index 23e16210..81c8e30c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.3.3-20240912 +5.3.3-20240913 diff --git a/classes/core/obfdb.php b/classes/core/obfdb.php index e731288b..bc4c2985 100644 --- a/classes/core/obfdb.php +++ b/classes/core/obfdb.php @@ -794,6 +794,9 @@ public function update($table, $data) foreach ($data as $item => $value) { if ($value === null) { $setsql[] = $this->format_table_column($item) . '=NULL'; + } elseif (preg_match('/^POINT\(-?\d+(\.\d+)?,-?\d+(\.\d+)?\)$/', $value)) { + // special case for POINT data type (no escape if strictly matches which we know is safe) + $setsql[] = $this->format_table_column($item) . '=' . $value; } else { $setsql[] = $this->format_table_column($item) . '=' . $this->format_value($value); } diff --git a/classes/metadata/coordinates.php b/classes/metadata/coordinates.php new file mode 100644 index 00000000..d7ea28ab --- /dev/null +++ b/classes/metadata/coordinates.php @@ -0,0 +1,34 @@ +name]; + if ($coordinates) { + // unpack binary if needed. note this check is very specific to this application and not a general solution + // the expected binary data is 25 bytes long, and the expected non-binary data is less than that + // note there is a very unlikely edge case if someone sets the default value to be a string of 25 characters (which is not possible via the UI, but could be done via the API) + // TODO this should be fixed with better metadata abstraction + if (strlen($coordinates) == 25) { + $data = unpack('x/x/x/x/corder/Ltype/dlat/dlon', $coordinates); + $coordinates = $data['lat'] . ',' . $data['lon']; + } + + $coordinates = explode(',', $coordinates); + if (count($coordinates) == 2) { + $latitude = (float) $coordinates[0]; + $longitude = (float) $coordinates[1]; + $row['metadata_' . $this->name] = [$latitude, $longitude]; + + // set, early return. + return; + } + } + + // not set or not valid + $row['metadata_' . $this->name] = null; + } +} diff --git a/html/media/metadata_addedit.html b/html/media/metadata_addedit.html index acc819b0..6b0d0e18 100644 --- a/html/media/metadata_addedit.html +++ b/html/media/metadata_addedit.html @@ -1,7 +1,6 @@ -
- +
New Metadata Field @@ -31,7 +30,7 @@ Tags Media Playlist - + Coordinates
@@ -39,7 +38,7 @@ - +
@@ -66,12 +65,14 @@ + > - - + +
@@ -83,10 +84,11 @@
- +
- + \ No newline at end of file diff --git a/models/media_model.php b/models/media_model.php index 2f7df950..e3f02443 100644 --- a/models/media_model.php +++ b/models/media_model.php @@ -1446,6 +1446,7 @@ public function save($args = []) $metadata_tags = []; foreach ($metadata_fields as $metadata_field) { + // TODO proper abstraction using metadata classes if ($metadata_field['type'] == 'tags') { $tags = []; if (!empty($item['metadata_' . $metadata_field['name']])) { @@ -1458,6 +1459,8 @@ public function save($args = []) } } $metadata['metadata_' . $metadata_field['name']] = implode(',', $tags); + } elseif ($metadata_field['type'] == 'coordinates') { + $metadata['metadata_' . $metadata_field['name']] = 'POINT(' . implode(',', $item['metadata_' . $metadata_field['name']]) . ')'; } else { $metadata['metadata_' . $metadata_field['name']] = $item['metadata_' . $metadata_field['name']] ?? null; } diff --git a/ui/fields/coordinates.js b/ui/fields/coordinates.js index a6f070b6..9ea572a6 100644 --- a/ui/fields/coordinates.js +++ b/ui/fields/coordinates.js @@ -2,30 +2,53 @@ import { html, render } from "../vendor.js"; import { OBField } from "../base/field.js"; class OBFieldCoordinates extends OBField { - #init; + _value = null; + _lat = null; + _lng = null; - #value; + renderEdit() { + let lat = null; + let lng = null; - async connected() { - if (this.#init) { - return; + if (this._lat != null) { + lat = parseFloat(this._lat).toFixed(5); } - this.#init = true; - - this.#value = ""; - this.renderComponent().then(() => {}); - } + if (this._lng != null) { + lng = parseFloat(this._lng).toFixed(5); + } - renderEdit() { render( - html` `, + html` +
+
+ +
+
+ +
+
+ `, this.root, ); } renderView() { - render(html`
${this.value}
`, this.root); + if (this._lat != null && this._lng != null) { + render(html`
${this._lat}, ${this._lng}
`, this.root); + } else { + render(html`
`, this.root); + } } scss() { @@ -39,29 +62,64 @@ class OBFieldCoordinates extends OBField { border-radius: 2px; border: 0; padding: 5px; - width: 250px; + width: 75px; vertical-align: middle; } + + #input { + display: flex; + + #lat::after { + content: ','; + padding-right: 10px; + padding-left: 2px; + font-size: 1.2em; + font-weight: bold; + } + } + + } `; } - #updateValue(event) { - const value = event.target.value; - this.value = value; + _updateLat(event) { + const lat = parseFloat(event.target.value); + if (lat >= -90 && lat <= 90) { + this._lat = lat; + } + this.refresh(); + } + + _updateLng(event) { + const lng = event.target.value; + if (lng >= -180 && lng <= 180) { + this._lng = lng; + } + this.refresh(); } get value() { - return this.#value; + return [this._lat, this._lng]; } set value(value) { - this.#addressCoordinates(value).then((result) => { - this.#value = result; - this.renderComponent(); - }); + // make sure value is an array of 2 numbers + if (value == null) { + this._lat = null; + this._lng = null; + } else if (Array.isArray(value) && value.length == 2 && !isNaN(value[0]) && !isNaN(value[1])) { + this._lat = value[0]; + this._lng = value[1]; + } else { + console.warn("Invalid coordinates value: " + value); + } + + this.refresh(); } + /* + // TODO address lookup async #addressCoordinates(address) { return OB.API.postPromise("metadata", "address_coordinates", { address: address }).then((response) => { if (response.status) { @@ -70,6 +128,7 @@ class OBFieldCoordinates extends OBField { } }); } + */ } customElements.define("ob-field-coordinates", OBFieldCoordinates);