Skip to content

Commit 78eb9eb

Browse files
committed
changes in response to copilot review findings
1 parent bbf954f commit 78eb9eb

6 files changed

Lines changed: 51 additions & 33 deletions

File tree

components/classroom/auth-button.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
import { CleanupRegistry } from '../../utilities/CleanupRegistry.js'
2+
13
const CENTRAL = "https://three.t-pen.org"
24

5+
/**
6+
* AuthButton - Authentication button for login/logout functionality.
7+
* @element auth-button
8+
*/
39
class AuthButton extends HTMLElement {
10+
/** @type {CleanupRegistry} Registry for cleanup handlers */
11+
cleanup = new CleanupRegistry()
12+
413
constructor() {
514
super();
615
this.attachShadow({ mode: 'open' });
@@ -9,6 +18,11 @@ class AuthButton extends HTMLElement {
918
connectedCallback() {
1019
// When the component is added to the DOM, call the render function
1120
this.render();
21+
this.addEventListeners();
22+
}
23+
24+
disconnectedCallback() {
25+
this.cleanup.run();
1226
}
1327

1428
render() {
@@ -32,10 +46,13 @@ class AuthButton extends HTMLElement {
3246
</style>
3347
<button id="auth-btn">${token ? "Logout" : "Login"}</button>
3448
`;
49+
}
3550

36-
// If the token exists (logged in), logout on click; otherwise, login
51+
addEventListeners() {
52+
const token = this.getTokenFromURL() || localStorage.getItem('userToken');
3753
const button = this.shadowRoot.querySelector('#auth-btn');
38-
button.addEventListener('click', () => {
54+
// If the token exists (logged in), logout on click; otherwise, login
55+
this.cleanup.onElement(button, 'click', () => {
3956
if (token) {
4057
this.logout();
4158
} else {

components/project-options/index.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { stringFromDate, escapeHtml } from '/js/utils.js'
66
import { renderPermissionError } from '../../utilities/renderPermissionError.js'
77
import CheckPermissions from '../check-permissions/checkPermissions.js'
88
import { onProjectReady } from '../../utilities/projectReady.js'
9+
import { CleanupRegistry } from '../../utilities/CleanupRegistry.js'
910
import vault from '../../js/vault.js'
1011

1112
/**
@@ -157,8 +158,8 @@ customElements.define('tpen-project-options', ProjectOptions)
157158
* @element line-annotation-link
158159
*/
159160
class LineAnnotationLink extends HTMLElement {
160-
/** @type {Function|null} Handler for mouseenter event */
161-
_mouseEnterHandler = null
161+
/** @type {CleanupRegistry} Registry for cleanup handlers */
162+
cleanup = new CleanupRegistry()
162163

163164
constructor() {
164165
super()
@@ -170,17 +171,20 @@ class LineAnnotationLink extends HTMLElement {
170171

171172
connectedCallback() {
172173
this.render()
173-
this._mouseEnterHandler = () => this.fetchCount()
174-
this.shadowRoot.querySelector('a')?.addEventListener('mouseenter', this._mouseEnterHandler)
174+
this.addEventListeners()
175175
}
176176

177-
disconnectedCallback() {
178-
const anchor = this.shadowRoot?.querySelector('a')
179-
if (anchor && this._mouseEnterHandler) {
180-
anchor.removeEventListener('mouseenter', this._mouseEnterHandler)
177+
addEventListeners() {
178+
const anchor = this.shadowRoot.querySelector('a')
179+
if (anchor) {
180+
this.cleanup.onElement(anchor, 'mouseenter', () => this.fetchCount())
181181
}
182182
}
183183

184+
disconnectedCallback() {
185+
this.cleanup.run()
186+
}
187+
184188
async fetchCount() {
185189
if (this._linesCount) return
186190
const page = { id: this._pageId, type: 'page' }

components/projects/project-header.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "../layer-selector/index.js"
44
import "../column-selector/index.js"
55
import CheckPermissions from "../check-permissions/checkPermissions.js"
66
import { CleanupRegistry } from '../../utilities/CleanupRegistry.js'
7+
import { onProjectReady } from '../../utilities/projectReady.js'
78

89
/**
910
* ProjectHeader - Navigation header for transcription interface with canvas selection.
@@ -15,6 +16,8 @@ export default class ProjectHeader extends HTMLElement {
1516

1617
/** @type {CleanupRegistry} Registry for cleanup handlers */
1718
cleanup = new CleanupRegistry()
19+
/** @type {Function|null} Unsubscribe function for project ready listener */
20+
_unsubProject = null
1821

1922
constructor() {
2023
super()
@@ -60,14 +63,11 @@ export default class ProjectHeader extends HTMLElement {
6063
this.loadFailed = true
6164
this.render()
6265
})
63-
this.cleanup.onEvent(eventDispatcher, 'tpen-project-loaded', this.authgate.bind(this))
64-
65-
if(TPEN.activeProject?._createdAt){
66-
this.authgate()
67-
}
66+
this._unsubProject = onProjectReady(this, this.authgate)
6867
}
6968

7069
disconnectedCallback() {
70+
try { this._unsubProject?.() } catch {}
7171
this.cleanup.run()
7272
}
7373

components/quicktype/quicktype.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import TPEN from "../../api/TPEN.js"
22
import { CleanupRegistry } from '../../utilities/CleanupRegistry.js'
3+
import { onProjectReady } from '../../utilities/projectReady.js'
34

45
const eventDispatcher = TPEN.eventDispatcher
56

@@ -10,6 +11,8 @@ const eventDispatcher = TPEN.eventDispatcher
1011
class TpenQuickType extends HTMLElement {
1112
/** @type {CleanupRegistry} Registry for cleanup handlers */
1213
cleanup = new CleanupRegistry()
14+
/** @type {Function|null} Unsubscribe function for project ready listener */
15+
_unsubProject = null
1316

1417
constructor() {
1518
super()
@@ -67,15 +70,13 @@ class TpenQuickType extends HTMLElement {
6770

6871
connectedCallback() {
6972
TPEN.attachAuthentication(this)
70-
this.cleanup.onEvent(eventDispatcher, "tpen-project-loaded", () => this.loadQuickType())
73+
this._unsubProject = onProjectReady(this, () => this.loadQuickType())
7174
this.render()
7275
this.addEventListeners()
73-
if (TPEN.activeProject) {
74-
this.loadQuickType()
75-
}
7676
}
7777

7878
disconnectedCallback() {
79+
try { this._unsubProject?.() } catch {}
7980
this.cleanup.run()
8081
}
8182

components/simple-transcription/index.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -530,12 +530,8 @@ export default class SimpleTranscriptionInterface extends HTMLElement {
530530
const imgBottom = this.shadowRoot.querySelector('#imgBottom img')
531531

532532
if (imgTop && imgBottom) {
533-
const onLoad = () => {
534-
// Update lines once image is loaded
535-
this.updateLines()
536-
}
537-
538-
imgTop.addEventListener('load', onLoad, { once: true })
533+
// Use cleanup registry for consistency, even for one-time listeners
534+
this.cleanup.onElement(imgTop, 'load', () => this.updateLines(), { once: true })
539535
imgTop.src = imageResource
540536
imgBottom.src = imageResource
541537
}

components/transcription-block/index.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,23 +108,23 @@ export default class TranscriptionBlock extends HTMLElement {
108108
const nextPageButton = this.shadowRoot.querySelector('.next-page-button')
109109
const inputField = this.shadowRoot.querySelector('.transcription-input')
110110

111-
// Shadow DOM element listeners (cleaned up when shadow DOM is replaced)
111+
// Shadow DOM element listeners
112112
if (prevButton) {
113-
prevButton.addEventListener('click', this.moveToPreviousLine.bind(this))
113+
this.cleanup.onElement(prevButton, 'click', this.moveToPreviousLine.bind(this))
114114
}
115115
if (prevPageButton) {
116-
prevPageButton.addEventListener('click', () => this.navigateToPage('prev'))
116+
this.cleanup.onElement(prevPageButton, 'click', () => this.navigateToPage('prev'))
117117
}
118118
if (nextButton) {
119-
nextButton.addEventListener('click', this.moveToNextLine.bind(this))
119+
this.cleanup.onElement(nextButton, 'click', this.moveToNextLine.bind(this))
120120
}
121121
if (nextPageButton) {
122-
nextPageButton.addEventListener('click', () => this.navigateToPage('next'))
122+
this.cleanup.onElement(nextPageButton, 'click', () => this.navigateToPage('next'))
123123
}
124124
if (inputField) {
125-
inputField.addEventListener('blur', () => this.checkDirtyLines())
126-
inputField.addEventListener('keydown', (e) => this.handleKeydown(e))
127-
inputField.addEventListener('input', () => {
125+
this.cleanup.onElement(inputField, 'blur', () => this.checkDirtyLines())
126+
this.cleanup.onElement(inputField, 'keydown', (e) => this.handleKeydown(e))
127+
this.cleanup.onElement(inputField, 'input', () => {
128128
this.#transcriptions[TPEN.activeLineIndex] = inputField.value ?? ''
129129
this.markLineDirty(TPEN.activeLineIndex)
130130
this.persistDraft(TPEN.activeLineIndex)

0 commit comments

Comments
 (0)