From 2892f63843f98a667e5bd0258c78bb8a257efcc6 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 17 Feb 2026 13:43:11 -0600 Subject: [PATCH 1/6] I think this gets the sync --- .../annotorious-annotator/line-parser.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index 715bd00e..9a7f57b8 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1106,11 +1106,23 @@ class AnnotoriousAnnotator extends HTMLElement { saveButton.textContent = "ERROR" throw err }) - page.items = page.items.map(i => ({ - ...i, - ...(mod.items?.find(a => a.target === i.target) ?? {}) - })) + page.items = page.items.map(i => { + const selectorValue = i.target?.selector?.value ?? i.target + const match = mod.items?.find(a => { + const aSelector = a.target?.selector?.value ?? a.target + return aSelector === selectorValue + }) + return match ? { ...i, ...match } : i + }) this.#modifiedAnnotationPage = page + this.#resolvedAnnotationPage = JSON.parse(JSON.stringify(page)) + this.#resolvedAnnotationPage.$isDirty = false + // Sync server-assigned IDs back to Annotorious so subsequent saves use the correct IDs + let syncAnnotations = JSON.parse(JSON.stringify(page.items)) + syncAnnotations = this.formatAnnotations(syncAnnotations) + syncAnnotations = this.convertSelectors(syncAnnotations, true) + this.#annotoriousInstance.clearAnnotations() + this.#annotoriousInstance.setAnnotations(syncAnnotations, false) TPEN.eventDispatcher.dispatch("tpen-page-committed", this.#modifiedAnnotationPage) TPEN.eventDispatcher.dispatch("tpen-toast", { message: "Annotations Saved", @@ -1118,7 +1130,6 @@ class AnnotoriousAnnotator extends HTMLElement { }) saveButton.removeAttribute("disabled") saveButton.textContent = "Save Annotations" - this.#resolvedAnnotationPage.$isDirty = false return this.#modifiedAnnotationPage } From b126346a3e64cd0965f64f8cefd84ae5ed23bc60 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 17 Feb 2026 13:56:59 -0600 Subject: [PATCH 2/6] Changes while reviewing --- components/annotorious-annotator/line-parser.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index 9a7f57b8..ab18eb68 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1108,10 +1108,12 @@ class AnnotoriousAnnotator extends HTMLElement { }) page.items = page.items.map(i => { const selectorValue = i.target?.selector?.value ?? i.target - const match = mod.items?.find(a => { - const aSelector = a.target?.selector?.value ?? a.target - return aSelector === selectorValue - }) + // Prefer matching by ID for previously-saved annotations, fall back to selector for new ones + const match = mod.items?.find(a => a.id === i.id) + ?? mod.items?.find(a => { + const aSelector = a.target?.selector?.value ?? a.target + return aSelector === selectorValue + }) return match ? { ...i, ...match } : i }) this.#modifiedAnnotationPage = page From ee8f7458954ff80f86836e375d3ee7f6d9f981ab Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 17 Feb 2026 14:07:36 -0600 Subject: [PATCH 3/6] changes while reviewing --- components/annotorious-annotator/line-parser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index ab18eb68..852d02fb 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1118,13 +1118,13 @@ class AnnotoriousAnnotator extends HTMLElement { }) this.#modifiedAnnotationPage = page this.#resolvedAnnotationPage = JSON.parse(JSON.stringify(page)) - this.#resolvedAnnotationPage.$isDirty = false // Sync server-assigned IDs back to Annotorious so subsequent saves use the correct IDs - let syncAnnotations = JSON.parse(JSON.stringify(page.items)) + let syncAnnotations = page.items syncAnnotations = this.formatAnnotations(syncAnnotations) syncAnnotations = this.convertSelectors(syncAnnotations, true) this.#annotoriousInstance.clearAnnotations() this.#annotoriousInstance.setAnnotations(syncAnnotations, false) + this.#resolvedAnnotationPage.$isDirty = false TPEN.eventDispatcher.dispatch("tpen-page-committed", this.#modifiedAnnotationPage) TPEN.eventDispatcher.dispatch("tpen-toast", { message: "Annotations Saved", From 459a845bcf5991e1d543b29d743f28f852bd1ab1 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 17 Feb 2026 14:12:18 -0600 Subject: [PATCH 4/6] changes while reviewing --- .../annotorious-annotator/line-parser.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index 852d02fb..65e40a5a 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1084,7 +1084,9 @@ class AnnotoriousAnnotator extends HTMLElement { let page = JSON.parse(JSON.stringify(this.#resolvedAnnotationPage)) page.items = allAnnotations const pageID = page["@id"] ?? page.id - const mod = await fetch(`${TPEN.servicesURL}/project/${TPEN.activeProject._id}/page/${pageID.split("/").pop()}`, { + let mod + try { + const res = await fetch(`${TPEN.servicesURL}/project/${TPEN.activeProject._id}/page/${pageID.split("/").pop()}`, { method: "PUT", headers: { "Content-Type": "application/json", @@ -1092,20 +1094,18 @@ class AnnotoriousAnnotator extends HTMLElement { }, body: JSON.stringify({ "items": page.items }) }) - .then(res => { - if(!res.ok) { - TPEN.eventDispatcher.dispatch("tpen-toast", { - message: "ERROR Annotations Not Saved", - status: "error" - }) - throw new Error("Could not save annotations", { "cause": `\n${res.status} Error from TPEN Services. Check the Network response.` }) - } - return res.json() - }) - .catch(err => { - saveButton.textContent = "ERROR" - throw err - }) + if (!res.ok) { + TPEN.eventDispatcher.dispatch("tpen-toast", { + message: "ERROR Annotations Not Saved", + status: "error" + }) + throw new Error("Could not save annotations", { "cause": `\n${res.status} Error from TPEN Services. Check the Network response.` }) + } + mod = await res.json() + } catch (err) { + saveButton.textContent = "ERROR" + throw err + } page.items = page.items.map(i => { const selectorValue = i.target?.selector?.value ?? i.target // Prefer matching by ID for previously-saved annotations, fall back to selector for new ones @@ -1119,7 +1119,7 @@ class AnnotoriousAnnotator extends HTMLElement { this.#modifiedAnnotationPage = page this.#resolvedAnnotationPage = JSON.parse(JSON.stringify(page)) // Sync server-assigned IDs back to Annotorious so subsequent saves use the correct IDs - let syncAnnotations = page.items + let syncAnnotations = JSON.parse(JSON.stringify(page.items)) syncAnnotations = this.formatAnnotations(syncAnnotations) syncAnnotations = this.convertSelectors(syncAnnotations, true) this.#annotoriousInstance.clearAnnotations() From dbc3f34de8bf71a8304dba6b701d220670a2900e Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 17 Feb 2026 15:10:27 -0600 Subject: [PATCH 5/6] Stop 'delete all annotations' button mashing --- components/annotorious-annotator/line-parser.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index 65e40a5a..db32f178 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1140,17 +1140,23 @@ class AnnotoriousAnnotator extends HTMLElement { * https://annotorious.dev/api-reference/openseadragon-annotator/#clearannotations */ async deleteAllAnnotations() { + const deleteAllBtn = this.shadowRoot.getElementById("deleteAllBtn") + deleteAllBtn.setAttribute("disabled", "true") + deleteAllBtn.textContent = "deleting. please wait..." this.#annotoriousInstance.clearAnnotations() this.#resolvedAnnotationPage.$isDirty = true - await this.saveAnnotations() try { + await this.saveAnnotations() await this.clearColumnsServerSide() } catch (err) { - console.error("Could not clear columns server side.", err) + console.error("Could not delete all annotations.", err) TPEN.eventDispatcher.dispatch("tpen-toast", { - message: "Could not clear columns. Some column data may remain.", + message: "Could not delete all annotations.", status: "error" }) + } finally { + deleteAllBtn.removeAttribute("disabled") + deleteAllBtn.textContent = "Delete All Annotations" } } From 9c5d40332414018762e9b81da04979f6fffddefe Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Wed, 18 Feb 2026 08:19:12 -0600 Subject: [PATCH 6/6] revert change --- .../annotorious-annotator/line-parser.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/annotorious-annotator/line-parser.js b/components/annotorious-annotator/line-parser.js index db32f178..64223323 100644 --- a/components/annotorious-annotator/line-parser.js +++ b/components/annotorious-annotator/line-parser.js @@ -1084,9 +1084,7 @@ class AnnotoriousAnnotator extends HTMLElement { let page = JSON.parse(JSON.stringify(this.#resolvedAnnotationPage)) page.items = allAnnotations const pageID = page["@id"] ?? page.id - let mod - try { - const res = await fetch(`${TPEN.servicesURL}/project/${TPEN.activeProject._id}/page/${pageID.split("/").pop()}`, { + const mod = await fetch(`${TPEN.servicesURL}/project/${TPEN.activeProject._id}/page/${pageID.split("/").pop()}`, { method: "PUT", headers: { "Content-Type": "application/json", @@ -1094,18 +1092,20 @@ class AnnotoriousAnnotator extends HTMLElement { }, body: JSON.stringify({ "items": page.items }) }) - if (!res.ok) { - TPEN.eventDispatcher.dispatch("tpen-toast", { - message: "ERROR Annotations Not Saved", - status: "error" - }) - throw new Error("Could not save annotations", { "cause": `\n${res.status} Error from TPEN Services. Check the Network response.` }) - } - mod = await res.json() - } catch (err) { - saveButton.textContent = "ERROR" - throw err - } + .then(res => { + if(!res.ok) { + TPEN.eventDispatcher.dispatch("tpen-toast", { + message: "ERROR Annotations Not Saved", + status: "error" + }) + throw new Error("Could not save annotations", { "cause": `\n${res.status} Error from TPEN Services. Check the Network response.` }) + } + return res.json() + }) + .catch(err => { + saveButton.textContent = "ERROR" + throw err + }) page.items = page.items.map(i => { const selectorValue = i.target?.selector?.value ?? i.target // Prefer matching by ID for previously-saved annotations, fall back to selector for new ones