From e5497b1a9254b4b732b5d6ccf00f4ca9059cd775 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:39:27 +0000 Subject: [PATCH 1/6] Initial plan From 182d6ce84811396dfb0b7975b7bdcdd3e632447e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:43:32 +0000 Subject: [PATCH 2/6] Fix blank page when loading pages with no lines Handle pages without lines in updateTranscriptionImages by still loading and displaying the canvas even when there are no line annotations. Shows the full page image instead of returning early. Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- interfaces/transcription/index.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/interfaces/transcription/index.js b/interfaces/transcription/index.js index 19b9296d..2a560010 100644 --- a/interfaces/transcription/index.js +++ b/interfaces/transcription/index.js @@ -518,7 +518,21 @@ export default class TranscriptionInterface extends HTMLElement { const { orderedItems, columnsInPage } = orderPageItemsByColumns(projectPage, this.#page) this.#page.items = orderedItems let thisLine = this.#page.items?.[0] - if (!thisLine) return + + // Handle pages with no lines - still load the canvas + if (!thisLine) { + // Get canvas from page target even when there are no lines + const { canvasID } = this.setCanvasAndSelector(null, this.#page) + if (!canvasID) return + const canvas = this.#canvas = await vault.get(canvasID, 'canvas') + // Show full page when there are no lines + const regionValue = `0,0,${canvas?.width ?? 'full'},${(canvas?.height && canvas?.height / 10) ?? 120}` + topImage.canvas = canvasID + bottomImage.canvas = canvas + topImage.setAttribute('region', regionValue) + return + } + if (!(thisLine?.body)) thisLine = await vault.get(thisLine, 'annotation', true) const { canvasID, region } = this.setCanvasAndSelector(thisLine, this.#page) const canvas = this.#canvas = await vault.get(canvasID, 'canvas') From ab582e5ad55f781e1d01db4883d6f1e7c93801bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:57:00 +0000 Subject: [PATCH 3/6] Add dismissible modal for pages without lines Shows an alert when a page has no line annotations with a link to the annotation interface where users can manually define lines. The alert is dismissible by clicking the "Got it" button. Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- interfaces/transcription/index.js | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/interfaces/transcription/index.js b/interfaces/transcription/index.js index 2a560010..0b23ec25 100644 --- a/interfaces/transcription/index.js +++ b/interfaces/transcription/index.js @@ -7,6 +7,7 @@ import '../../components/line-image/index.js' import CheckPermissions from "../../components/check-permissions/checkPermissions.js" import { orderPageItemsByColumns } from "../../utilities/columnOrdering.js" import { renderPermissionError } from "../../utilities/renderPermissionError.js" +import '../../components/gui/alert/AlertContainer.js' export default class TranscriptionInterface extends HTMLElement { #page #canvas @@ -419,6 +420,38 @@ export default class TranscriptionInterface extends HTMLElement { }) } + showNoLinesAlert() { + const alertContainer = document.querySelector('tpen-alert-container') + if (!alertContainer) return + + const alertElem = document.createElement('tpen-alert') + const message = document.createElement('div') + message.innerHTML = ` +

This page has no line annotations defined.

+

To add lines, visit the annotation interface.

+ ` + + const okButton = document.createElement('button') + const buttonContainer = document.createElement('div') + buttonContainer.classList.add("button-container") + okButton.textContent = 'Got it' + + const handleOk = () => { + alertElem.dismiss() + } + okButton.addEventListener('click', handleOk) + + alertElem.appendChild(message) + buttonContainer.appendChild(okButton) + alertElem.appendChild(buttonContainer) + + const screenLockingSection = alertContainer.shadowRoot.querySelector('.alert-area') + if (screenLockingSection) { + screenLockingSection.appendChild(alertElem) + alertElem.show() + } + } + updateLines() { if (TPEN.activeLineIndex < 0 || !this.#page) return const topImage = this.shadowRoot.querySelector('#topImage') @@ -530,6 +563,8 @@ export default class TranscriptionInterface extends HTMLElement { topImage.canvas = canvasID bottomImage.canvas = canvas topImage.setAttribute('region', regionValue) + // Show alert to inform user about missing lines + this.showNoLinesAlert() return } From 65fa6e267d0a177f20b1c3bebd1682fdb9d72317 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:58:49 +0000 Subject: [PATCH 4/6] Improve alert security and encapsulation - Encode URL parameters to prevent injection vulnerabilities - Replace innerHTML with DOM element creation for better security - Add CSS via style element instead of inline styles - Add fallback for potential future public API on AlertContainer Co-authored-by: cubap <1119165+cubap@users.noreply.github.com> --- interfaces/transcription/index.js | 57 ++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/interfaces/transcription/index.js b/interfaces/transcription/index.js index 0b23ec25..88921e4a 100644 --- a/interfaces/transcription/index.js +++ b/interfaces/transcription/index.js @@ -424,12 +424,46 @@ export default class TranscriptionInterface extends HTMLElement { const alertContainer = document.querySelector('tpen-alert-container') if (!alertContainer) return + // Build URL with proper encoding + const projectId = encodeURIComponent(TPEN.screen?.projectInQuery ?? '') + const pageId = encodeURIComponent(TPEN.screen?.pageInQuery ?? '') + const annotatorUrl = `/interfaces/annotator?projectId=${projectId}&pageId=${pageId}` + const alertElem = document.createElement('tpen-alert') - const message = document.createElement('div') - message.innerHTML = ` -

This page has no line annotations defined.

-

To add lines, visit the annotation interface.

+ + // Add styles for the alert content + const style = document.createElement('style') + style.textContent = ` + .no-lines-message p:first-child { + margin-bottom: 1em; + } + .alert-link { + color: #4fc3f7; + text-decoration: underline; + } ` + alertElem.shadowRoot.appendChild(style) + + // Create message with proper DOM elements + const messageContainer = document.createElement('div') + messageContainer.classList.add('no-lines-message') + + const paragraph1 = document.createElement('p') + paragraph1.textContent = 'This page has no line annotations defined.' + + const paragraph2 = document.createElement('p') + paragraph2.textContent = 'To add lines, visit the ' + + const link = document.createElement('a') + link.href = annotatorUrl + link.textContent = 'annotation interface' + link.classList.add('alert-link') + + paragraph2.appendChild(link) + paragraph2.appendChild(document.createTextNode('.')) + + messageContainer.appendChild(paragraph1) + messageContainer.appendChild(paragraph2) const okButton = document.createElement('button') const buttonContainer = document.createElement('div') @@ -441,14 +475,19 @@ export default class TranscriptionInterface extends HTMLElement { } okButton.addEventListener('click', handleOk) - alertElem.appendChild(message) + alertElem.appendChild(messageContainer) buttonContainer.appendChild(okButton) alertElem.appendChild(buttonContainer) - const screenLockingSection = alertContainer.shadowRoot.querySelector('.alert-area') - if (screenLockingSection) { - screenLockingSection.appendChild(alertElem) - alertElem.show() + // Use the container's method if available, otherwise access shadow DOM + if (typeof alertContainer.addCustomAlert === 'function') { + alertContainer.addCustomAlert(alertElem) + } else { + const screenLockingSection = alertContainer.shadowRoot.querySelector('.alert-area') + if (screenLockingSection) { + screenLockingSection.appendChild(alertElem) + alertElem.show() + } } } From 4a66caa2d17d1f77f2e85ce7caa1f3a10242f0f9 Mon Sep 17 00:00:00 2001 From: cubap Date: Wed, 17 Dec 2025 12:44:12 -0600 Subject: [PATCH 5/6] fix links and build alert cleanly --- components/gui/alert/AlertContainer.js | 4 ++ interfaces/transcription/index.js | 68 ++++++++------------------ 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/components/gui/alert/AlertContainer.js b/components/gui/alert/AlertContainer.js index a2e7ebb2..992e2536 100644 --- a/components/gui/alert/AlertContainer.js +++ b/components/gui/alert/AlertContainer.js @@ -86,6 +86,10 @@ class AlertContainer extends HTMLElement { transition: all 0.3s ease-in-out; font-size: 14pt; } + tpen-alert a { + color: var(--primary-color); + text-decoration: underline; + } .alert-area tpen-alert { top: 0px; right: 0px; diff --git a/interfaces/transcription/index.js b/interfaces/transcription/index.js index 88921e4a..3b9ad0e0 100644 --- a/interfaces/transcription/index.js +++ b/interfaces/transcription/index.js @@ -424,62 +424,34 @@ export default class TranscriptionInterface extends HTMLElement { const alertContainer = document.querySelector('tpen-alert-container') if (!alertContainer) return - // Build URL with proper encoding const projectId = encodeURIComponent(TPEN.screen?.projectInQuery ?? '') const pageId = encodeURIComponent(TPEN.screen?.pageInQuery ?? '') - const annotatorUrl = `/interfaces/annotator?projectId=${projectId}&pageId=${pageId}` + const annotatorUrl = `/interfaces/annotator?projectID=${projectId}&pageID=${pageId}` const alertElem = document.createElement('tpen-alert') - - // Add styles for the alert content - const style = document.createElement('style') - style.textContent = ` - .no-lines-message p:first-child { - margin-bottom: 1em; - } - .alert-link { - color: #4fc3f7; - text-decoration: underline; - } + alertElem.innerHTML = ` + +
+

This page has no line annotations defined.

+

To add lines, visit the annotation interface.

+
+
+ +
` - alertElem.shadowRoot.appendChild(style) - - // Create message with proper DOM elements - const messageContainer = document.createElement('div') - messageContainer.classList.add('no-lines-message') - const paragraph1 = document.createElement('p') - paragraph1.textContent = 'This page has no line annotations defined.' - - const paragraph2 = document.createElement('p') - paragraph2.textContent = 'To add lines, visit the ' - - const link = document.createElement('a') - link.href = annotatorUrl - link.textContent = 'annotation interface' - link.classList.add('alert-link') - - paragraph2.appendChild(link) - paragraph2.appendChild(document.createTextNode('.')) - - messageContainer.appendChild(paragraph1) - messageContainer.appendChild(paragraph2) - - const okButton = document.createElement('button') - const buttonContainer = document.createElement('div') - buttonContainer.classList.add("button-container") - okButton.textContent = 'Got it' - - const handleOk = () => { + alertElem.querySelector('#no-lines-ok').addEventListener('click', () => { alertElem.dismiss() - } - okButton.addEventListener('click', handleOk) - - alertElem.appendChild(messageContainer) - buttonContainer.appendChild(okButton) - alertElem.appendChild(buttonContainer) + }) - // Use the container's method if available, otherwise access shadow DOM if (typeof alertContainer.addCustomAlert === 'function') { alertContainer.addCustomAlert(alertElem) } else { From 88563b7e4901433012123b7419b0f2369e8cc80a Mon Sep 17 00:00:00 2001 From: cubap Date: Wed, 17 Dec 2025 12:49:58 -0600 Subject: [PATCH 6/6] Update index.js --- interfaces/transcription/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/transcription/index.js b/interfaces/transcription/index.js index 3b9ad0e0..bca7728f 100644 --- a/interfaces/transcription/index.js +++ b/interfaces/transcription/index.js @@ -441,7 +441,7 @@ export default class TranscriptionInterface extends HTMLElement {

This page has no line annotations defined.

-

To add lines, visit the annotation interface.

+

To add lines, visit the column and line interface.