TPEN3 Web Component Lifecycle Audit Report
Discovering the scope of #388, #398, #400, & #401.
Overview
This report audits all web components in the TPEN3 Interfaces codebase against the expected lifecycle pattern:
auth() -> connectedCallback() -> tpen-project-loaded -> CheckPermissions -> render() -> register event listeners -> disconnectedCallback()
Expected Lifecycle Elements:
- auth(): Authentication attachment via
TPEN.attachAuthentication()
- connectedCallback(): Standard web component lifecycle hook
- tpen-project-loaded: Event listener for project data availability
- CheckPermissions: Permission validation before rendering
- render(): UI rendering method
- Event listener registration: Setting up event listeners (various naming conventions)
- disconnectedCallback(): Cleanup of event listeners and resources
Component Inventory
Components Directory (Excluding Classroom)
| Component |
File Path |
| CheckPermissions |
components/check-permissions/checkPermissions.js |
| PermissionMatchElement |
components/check-permissions/permission-match-element.js |
| PermissionMatch |
components/check-permissions/permission-match.js |
| DeclineProject |
components/decline-project/index.js |
| DefaultTranscribe |
components/default-transcribe/index.js |
| FeedbackButton |
components/feedback-button/index.js |
| Feedback |
components/feedback/index.js |
| Alert |
components/gui/alert/Alert.js |
| AlertContainer |
components/gui/alert/AlertContainer.js |
| Confirm |
components/gui/confirm/Confirm.js |
| ConfirmContainer |
components/gui/confirm/ConfirmContainer.js |
| Header |
components/gui/site/Header.js |
| NoAuthHeader |
components/gui/site/NoAuthHeader.js |
| Page |
components/gui/site/Page.js |
| Footer |
components/gui/site/Footer.js |
| Toast |
components/gui/toast/Toast.js |
| ToastContainer |
components/gui/toast/ToastContainer.js |
| Card |
components/gui/card/Card.js |
| ProjectList |
components/projects/index.js |
| ProjectListView |
components/projects/project-list-view.js |
| ProjectListWrite |
components/projects/project-list-write.js |
| ProjectHeader |
components/projects/project-header.js |
| ListNavigation |
components/projects/list-navigation.js |
| PublicLogin |
components/public-login/index.js |
| PublicUserProfile |
components/public-user-profile/index.js |
| UserProfile |
components/user-profile/index.js |
| ContributionActivity |
components/user-profile/contributionActivity.js |
| Report |
components/user-profile/report.js |
| UserStats |
components/user-profile/userStats.js |
| ProjectCollaborators |
components/project-collaborators/index.js |
| MemberInvitation |
components/member-invitation/index.js |
| LineText |
components/line-text/index.js |
| LineImage |
components/line-image/index.js |
| LineHistory |
components/line-history/index.js |
| QuickGuide |
components/quick-guide/index.js |
| SplitScreen |
components/split-screen/index.js |
| RolesHandler |
components/roles-handler/index.js |
| ManageRole |
components/manage-role/index.js |
| LeaveProject |
components/leave-project/index.js |
| NavigationManager |
components/navigation-manager/index.js |
| ContinueWorking |
components/continue-working/index.js |
| CreateColumn |
components/create-column/index.js |
| ProjectMetadata |
components/project-metadata/index.js |
| ProjectPermissions |
components/project-permissions/index.js |
| ProjectLayers |
components/project-layers/index.js |
| ProjectDetails |
components/project-details/index.js |
| ProjectOptions |
components/project-options/index.js |
| ProjectExport |
components/project-export/index.js |
| ProjectTools |
components/project-tools/index.js |
| CopyExistingProject |
components/copy-existing-project/index.js |
| CopyProjectWithCustomization |
components/copy-project-with-customization/index.js |
| CopyProjectWithGroupMember |
components/copy-project-with-group-member/index.js |
| CopyProjectWithoutAnnotations |
components/copy-project-without-annotations/index.js |
| ImportImage |
components/import-image/index.js |
| ImportProject |
components/import-project/index.js |
| ManageLayers |
components/manage-layers/index.js |
| ManagePages |
components/manage-pages/index.js |
| LayerSelector |
components/layer-selector/index.js |
| ColumnSelector |
components/column-selector/index.js |
| PageTool |
components/page-tool/index.js |
| MagnifierTool |
components/magnifier-tool/index.js |
| QuicktypeManager |
components/quicktype-manager/index.js |
| QuicktypeTool |
components/quicktype-tool/index.js |
| QuicktypeEditorDialog |
components/quicktype-tool/quicktype-editor-dialog.js |
| WorkspaceTools |
components/workspace-tools/index.js |
| SplitscreenTool |
components/splitscreen-tool/index.js |
| TranscriptionBlock |
components/transcription-block/index.js |
| SimpleTranscription |
components/simple-transcription/index.js |
| ReadOnlyViewTranscribe |
components/read-only-transcribe/index.js |
| UpdateMetadata |
components/update-metadata/index.js |
| FixedExplanatoryGuide |
components/explanatory-guide/fixedGuideComponent.js |
| RelativeExplanatoryGuide |
components/explanatory-guide/relativeGuideComponent.js |
| AnnotoriousAnnotator (plain) |
components/annotorious-annotator/plain.js |
| AnnotoriousAnnotator (line-parser) |
components/annotorious-annotator/line-parser.js |
| LegacyAnnotator |
components/legacy-annotator/plain.js |
| TpenQuickType |
components/quicktype/quicktype.js |
| NewAction |
components/new-action.js |
Interfaces Directory
| Interface |
File Path |
| TranscriptionInterface |
interfaces/transcription/index.js |
| ManageColumnsInterface |
interfaces/manage-columns/index.js |
| ManageProjectInterface |
interfaces/manage-project/index.js |
| TpenCustomProperty |
interfaces/custom/index.js |
| ImportTpen28Interface |
interfaces/import-tpen28/index.js |
| NavigationInterface |
interfaces/navigation/index.js |
| QuicktypeInterface |
interfaces/quicktype/index.js |
Detailed Component Analysis
Legend
- ✅ Implements correctly
- ⚠️ Partial implementation / Inconsistent naming
- ❌ Missing
- 🔶 Memory leak risk
- N/A Not applicable for this component type
Category 1: Project-Dependent Components (Require Full Lifecycle)
These components depend on project data and should follow the complete lifecycle pattern.
1. DefaultTranscribe (components/default-transcribe/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
eventDispatcher.on('tpen-project-loaded', (ev) => {...}) |
| CheckPermissions |
⚠️ |
Uses CheckPermissions.checkAllAccess('LINE', 'TEXT') but with incorrect permissions check pattern |
| render() |
✅ |
Present (inline in connectedCallback after project loads) |
| Event listeners |
⚠️ |
Uses attachEventListeners() - inconsistent naming |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK - registers global event listeners |
Memory Leak Issues:
- Registers
tpen-project-loaded listener without cleanup
- Multiple resize observers without cleanup
- Event listeners on elements without removal
2. ProjectCollaborators (components/project-collaborators/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on('tpen-project-loaded', () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('GROUP') and checkEditAccess('PROJECT', 'MEMBERS') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
No dedicated setup method - inline event registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Memory Leak Issues:
- Global event listener for
tpen-project-loaded not cleaned up
3. MemberInvitation (components/member-invitation/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess("PROJECT", "MEMBERS") |
| render() |
✅ |
Present with proper permission gating |
| Event listeners |
⚠️ |
Inline event registration, no dedicated method |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
4. LineText (components/line-text/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in constructor |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
eventDispatcher.on("tpen-project-loaded", () => this.lineIndex && this.render()) |
| CheckPermissions |
⚠️ |
No permission checks before rendering |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses attachEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Memory Leak Issues:
- Global event listeners (
tpen-project-loaded, tpen-line-loaded)
- MutationObserver on textarea without cleanup
5. LineImage (components/line-image/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
6. LineHistory (components/line-history/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
7. ManageRole (components/manage-role/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses registerEventListeners() - inconsistent naming |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
8. LeaveProject (components/leave-project/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() - inconsistent naming |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
9. NavigationManager (components/navigation-manager/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() - inconsistent naming |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
10. ContinueWorking (components/continue-working/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
No listener - renders immediately |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
11. CreateColumn (components/create-column/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", (ev) => this.render()) |
| CheckPermissions |
⚠️ |
Uses CheckPermissions.checkAllAccess but not in standard pattern |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
12. ProjectMetadata (components/project-metadata/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT', 'METADATA') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
13. ProjectPermissions (components/project-permissions/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT') for edit operations |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
14. ProjectLayers (components/project-layers/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT', 'LAYERS') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
15. ProjectDetails (components/project-details/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
16. ProjectOptions (components/project-options/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
17. ProjectExport (components/project-export/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
18. ProjectTools (components/project-tools/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT', 'TOOLS') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
19-22. Copy Project Variants (copy-existing-project, copy-project-with-customization, copy-project-with-group-member, copy-project-without-annotations)
All share similar patterns:
| Element |
Status |
Notes |
| auth() |
✅ |
Present |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
Missing |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
23. ImportImage (components/import-image/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not needed - standalone form |
| CheckPermissions |
❌ |
Not needed - creates new project |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
24. ImportProject (components/import-project/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not needed - standalone form |
| CheckPermissions |
❌ |
Not needed - creates new project |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
25. ManageLayers (components/manage-layers/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT', 'LAYERS') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
26. ManagePages (components/manage-pages/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT', 'PAGES') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
27. LayerSelector (components/layer-selector/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
28. ColumnSelector (components/column-selector/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
29. PageTool (components/page-tool/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
30. MagnifierTool (components/magnifier-tool/index.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
31. QuicktypeManager (components/quicktype-manager/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT', 'OPTIONS') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
32. QuicktypeTool (components/quicktype-tool/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
33. QuicktypeEditorDialog (components/quicktype-tool/quicktype-editor-dialog.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
✅ |
Present - just calls render() |
| tpen-project-loaded |
❌ |
Not used - dialog component |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() - called on open() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK - lots of event listeners |
34. WorkspaceTools (components/workspace-tools/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
35. SplitscreenTool (components/splitscreen-tool/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
36. TranscriptionBlock (components/transcription-block/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
37. SimpleTranscription (components/simple-transcription/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on("tpen-project-loaded", () => this.render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('LINE', 'TEXT') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
38. UpdateMetadata (components/update-metadata/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
eventDispatcher.on("tpen-project-loaded", () => this.openModal()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess('PROJECT', 'METADATA') and checkEditAccess |
| render() |
⚠️ |
No explicit render() - uses openModal() |
| Event listeners |
✅ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
39. RolesHandler (components/roles-handler/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
eventDispatcher.on('tpen-project-loaded', () => this.render()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses registerEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
40. QuickGuide (components/quick-guide/index.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment (may be intentional - public component) |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
❌ |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
41. SplitScreen (components/split-screen/index.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
❌ |
Not needed - UI layout component |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration with resize events |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK - has window resize listener |
42-43. Annotorious Components (plain.js, line-parser.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in constructor |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Uses in line-parser.js |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkAllAccess("LINE", "SELECTOR") in line-parser |
| render() |
✅ |
Present (calls loadAnnotorious) |
| Event listeners |
⚠️ |
Uses listenTo() method |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK - has window beforeunload listener |
44. LegacyAnnotator (components/legacy-annotator/plain.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in constructor |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
❌ |
No permission checks |
| render() |
⚠️ |
No explicit render() - uses processAnnotationPage |
| Event listeners |
⚠️ |
Uses listen() method |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
45. TpenQuickType (components/quicktype/quicktype.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in constructor |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
In constructor: eventDispatcher.on("tpen-project-loaded", () => this.loadQuickType()) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
✅ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
46. NewAction (components/new-action.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
❌ |
Not present - uses constructor only |
| tpen-project-loaded |
❌ |
Not needed |
| CheckPermissions |
❌ |
Not needed - navigation component |
| render() |
⚠️ |
Inline in constructor |
| Event listeners |
⚠️ |
Inline in constructor |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Category 2: GUI Components (Utility/Display)
These are UI utility components that may not need the full lifecycle pattern.
47. Alert (components/gui/alert/Alert.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed - UI component |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING |
48. AlertContainer (components/gui/alert/AlertContainer.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
⚠️ |
Inline in connectedCallback |
| Event listeners |
⚠️ |
Uses TPEN.eventDispatcher.on() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
49. Confirm (components/gui/confirm/Confirm.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING |
50. ConfirmContainer (components/gui/confirm/ConfirmContainer.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
⚠️ |
Inline in connectedCallback |
| Event listeners |
⚠️ |
Uses TPEN.eventDispatcher.on() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
51. Toast (components/gui/toast/Toast.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING |
52. ToastContainer (components/gui/toast/ToastContainer.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
⚠️ |
Inline in connectedCallback |
| Event listeners |
⚠️ |
Uses TPEN.eventDispatcher.on() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
53. Header (components/gui/site/Header.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
54. NoAuthHeader (components/gui/site/NoAuthHeader.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed - no auth header |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
❌ |
Missing |
55. Page (components/gui/site/Page.js)
| Element |
Status |
Notes |
| auth() |
✅ |
Uses authgate() function |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListener() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
56. Footer (components/gui/site/Footer.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
N/A |
None needed |
| disconnectedCallback() |
✅ |
Not needed - no listeners |
57. Card (components/gui/card/Card.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
⚠️ |
Inline in connectedCallback |
| Event listeners |
N/A |
None |
| disconnectedCallback() |
✅ |
Not needed - no listeners |
58-59. FixedExplanatoryGuide, RelativeExplanatoryGuide
| Element |
Status |
Notes |
| auth() |
N/A |
Not needed |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Category 3: Project List Components
60. ProjectList (components/projects/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used - different event pattern |
| CheckPermissions |
N/A |
Lists user's projects |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
61. ProjectListView (components/projects/project-list-view.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
N/A |
View component |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
62. ProjectListWrite (components/projects/project-list-write.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
N/A |
View component |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
63. ProjectHeader (components/projects/project-header.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
N/A |
View component |
| render() |
✅ |
Present |
| Event listeners |
N/A |
None |
| disconnectedCallback() |
✅ |
Not needed |
64. ListNavigation (components/projects/list-navigation.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth attachment |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
❌ |
Not used |
| CheckPermissions |
N/A |
Navigation component |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses addEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Category 4: User/Auth Components
65. PublicLogin (components/public-login/index.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Login component |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Not needed |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
66. PublicUserProfile (components/public-user-profile/index.js)
| Element |
Status |
Notes |
| auth() |
❌ |
No auth - public profile |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
Public component |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
67. UserProfile (components/user-profile/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
User's own profile |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Uses setupEventListeners() |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
68-70. User Profile Sub-components (ContributionActivity, Report, UserStats)
| Element |
Status |
Notes |
| auth() |
✅ |
Via parent or direct |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
N/A |
Not needed |
| CheckPermissions |
N/A |
User's own data |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
Category 5: Interface Entry Points
71. TranscriptionInterface (interfaces/transcription/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(document.body) |
| connectedCallback() |
N/A |
Not a web component - entry script |
| tpen-project-loaded |
✅ |
Uses event listener |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkViewAccess and checkEditAccess |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Multiple event listeners |
| disconnectedCallback() |
N/A |
Not a web component |
72. ManageColumnsInterface (interfaces/manage-columns/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
Present |
| connectedCallback() |
N/A |
Entry script |
| tpen-project-loaded |
✅ |
Present |
| CheckPermissions |
✅ |
Uses CheckPermissions |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Multiple |
| disconnectedCallback() |
N/A |
Entry script |
73. ManageProjectInterface (interfaces/manage-project/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(container) |
| connectedCallback() |
N/A |
Entry script |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on('tpen-project-loaded', () => render()) |
| CheckPermissions |
✅ |
Uses CheckPermissions.checkEditAccess('PROJECT') |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Multiple |
| disconnectedCallback() |
N/A |
Entry script |
74. TpenCustomProperty (interfaces/custom/index.js)
| Element |
Status |
Notes |
| auth() |
✅ |
TPEN.attachAuthentication(this) in connectedCallback |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
TPEN.eventDispatcher.on('tpen-project-loaded', () => this.render(), this) |
| CheckPermissions |
❌ |
No permission checks |
| render() |
✅ |
Present |
| Event listeners |
⚠️ |
Inline registration |
| disconnectedCallback() |
🔶❌ |
MISSING - MEMORY LEAK RISK |
75. ImportTpen28Interface (interfaces/import-tpen28/index.js)
Not a web component - entry script with event listeners attached to DOM elements.
76. NavigationInterface (interfaces/navigation/index.js)
Just imports NavigationManager component.
77. QuicktypeInterface (interfaces/quicktype/index.js)
Just imports QuicktypeManager component.
Category 6: Check Permissions Components
78. CheckPermissions (components/check-permissions/checkPermissions.js)
Static utility class - not a web component.
79. PermissionMatchElement (components/check-permissions/permission-match-element.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Uses parent permissions |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Listens for project changes |
| CheckPermissions |
✅ |
Uses CheckPermissions internally |
| render() |
✅ |
updateVisibility() acts as render |
| Event listeners |
✅ |
Global event listener setup |
| disconnectedCallback() |
✅ |
PROPERLY IMPLEMENTED - removes event listener |
80. PermissionMatch (components/check-permissions/permission-match.js)
| Element |
Status |
Notes |
| auth() |
N/A |
Uses parent permissions |
| connectedCallback() |
✅ |
Present |
| tpen-project-loaded |
✅ |
Listens for project changes |
| CheckPermissions |
✅ |
Uses CheckPermissions internally |
| render() |
✅ |
checkAndApply() acts as render |
| Event listeners |
✅ |
Global event listener setup |
| disconnectedCallback() |
✅ |
PROPERLY IMPLEMENTED - removes event listener |
Category 7: Utility/Non-Component Files
The following files are NOT web components:
components/iiif-tools/index.js - Utility functions
components/annotorious-annotator/detect-lines.js - Utility functions
components/quicktype/validation.js - Validation functions
Summary Statistics
Components with disconnectedCallback() Implemented
Only 3 components properly implement disconnectedCallback():
PermissionMatchElement - removes event listener
PermissionMatch - removes event listener
Footer (not needed - no listeners)
Card (not needed - no listeners)
ProjectHeader (not needed - no listeners)
Components Missing disconnectedCallback() (Memory Leak Risk)
~65+ components are missing disconnectedCallback() and register event listeners that are never cleaned up.
Event Listener Method Naming Inconsistencies
| Method Name |
Count |
Components Using |
setupEventListeners() |
~15 |
NavigationManager, ManagePages, PageTool, QuicktypeTool, etc. |
addEventListeners() |
~10 |
LeaveProject, ManageLayers, TranscriptionBlock, Header, etc. |
attachEventListeners() |
~5 |
DefaultTranscribe, LineText, etc. |
registerEventListeners() |
~3 |
ManageRole, RolesHandler |
listen() |
~2 |
LegacyAnnotator |
listenTo() |
~2 |
AnnotoriousAnnotator variants |
| Inline registration |
~40+ |
Most components |
CheckPermissions Usage
| Status |
Count |
Notes |
| ✅ Uses CheckPermissions |
~20 |
Properly gating render |
| ❌ Missing CheckPermissions |
~45+ |
Should be audited for need |
Auth Pattern Usage
| Pattern |
Count |
Notes |
TPEN.attachAuthentication(this) in connectedCallback |
~40 |
Most common |
TPEN.attachAuthentication(this) in constructor |
~5 |
Annotorious variants |
authgate() function |
~2 |
Page component |
| No auth |
~20 |
May be intentional for public components |
Recommendations
1. Standardize Event Listener Method Names
Choose one name and use it consistently:
// Recommended: setupEventListeners()
setupEventListeners() {
// All event listener registration here
}
2. Implement disconnectedCallback() for All Components
Every component that registers event listeners should clean them up:
disconnectedCallback() {
// Remove all event listeners
TPEN.eventDispatcher.off('tpen-project-loaded', this._boundRender)
// Remove DOM event listeners
this.someElement?.removeEventListener('click', this._boundHandler)
}
3. Store Bound Event Handlers
To properly remove event listeners, store bound handlers:
connectedCallback() {
this._boundRender = this.render.bind(this)
TPEN.eventDispatcher.on('tpen-project-loaded', this._boundRender)
}
disconnectedCallback() {
TPEN.eventDispatcher.off('tpen-project-loaded', this._boundRender)
}
4. Standardize Auth Pattern
Implement authgate() consistently:
async authgate() {
TPEN.attachAuthentication(this)
if (!TPEN.getAuthorization()) {
// Handle unauthenticated state
}
}
5. Implement Permission Checks Consistently
All project-dependent components should check permissions before rendering:
render() {
if (!CheckPermissions.checkViewAccess('RESOURCE_TYPE')) {
this.shadowRoot.innerHTML = '<p>Access denied</p>'
return
}
// Normal render logic
}
6. Create a Base Component Class
Consider creating a base class that implements the standard lifecycle:
class TpenComponent extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
this._eventListeners = []
}
connectedCallback() {
TPEN.attachAuthentication(this)
this._boundProjectLoaded = this.onProjectLoaded.bind(this)
TPEN.eventDispatcher.on('tpen-project-loaded', this._boundProjectLoaded)
}
disconnectedCallback() {
TPEN.eventDispatcher.off('tpen-project-loaded', this._boundProjectLoaded)
this._eventListeners.forEach(({ element, event, handler }) => {
element.removeEventListener(event, handler)
})
}
onProjectLoaded() {
this.checkPermissions() && this.render()
}
checkPermissions() {
return true // Override in subclass
}
render() {
// Override in subclass
}
addListener(element, event, handler) {
element.addEventListener(event, handler)
this._eventListeners.push({ element, event, handler })
}
}
TPEN3 Web Component Lifecycle Audit Report
Discovering the scope of #388, #398, #400, & #401.
Overview
This report audits all web components in the TPEN3 Interfaces codebase against the expected lifecycle pattern:
Expected Lifecycle Elements:
TPEN.attachAuthentication()Component Inventory
Components Directory (Excluding Classroom)
components/check-permissions/checkPermissions.jscomponents/check-permissions/permission-match-element.jscomponents/check-permissions/permission-match.jscomponents/decline-project/index.jscomponents/default-transcribe/index.jscomponents/feedback-button/index.jscomponents/feedback/index.jscomponents/gui/alert/Alert.jscomponents/gui/alert/AlertContainer.jscomponents/gui/confirm/Confirm.jscomponents/gui/confirm/ConfirmContainer.jscomponents/gui/site/Header.jscomponents/gui/site/NoAuthHeader.jscomponents/gui/site/Page.jscomponents/gui/site/Footer.jscomponents/gui/toast/Toast.jscomponents/gui/toast/ToastContainer.jscomponents/gui/card/Card.jscomponents/projects/index.jscomponents/projects/project-list-view.jscomponents/projects/project-list-write.jscomponents/projects/project-header.jscomponents/projects/list-navigation.jscomponents/public-login/index.jscomponents/public-user-profile/index.jscomponents/user-profile/index.jscomponents/user-profile/contributionActivity.jscomponents/user-profile/report.jscomponents/user-profile/userStats.jscomponents/project-collaborators/index.jscomponents/member-invitation/index.jscomponents/line-text/index.jscomponents/line-image/index.jscomponents/line-history/index.jscomponents/quick-guide/index.jscomponents/split-screen/index.jscomponents/roles-handler/index.jscomponents/manage-role/index.jscomponents/leave-project/index.jscomponents/navigation-manager/index.jscomponents/continue-working/index.jscomponents/create-column/index.jscomponents/project-metadata/index.jscomponents/project-permissions/index.jscomponents/project-layers/index.jscomponents/project-details/index.jscomponents/project-options/index.jscomponents/project-export/index.jscomponents/project-tools/index.jscomponents/copy-existing-project/index.jscomponents/copy-project-with-customization/index.jscomponents/copy-project-with-group-member/index.jscomponents/copy-project-without-annotations/index.jscomponents/import-image/index.jscomponents/import-project/index.jscomponents/manage-layers/index.jscomponents/manage-pages/index.jscomponents/layer-selector/index.jscomponents/column-selector/index.jscomponents/page-tool/index.jscomponents/magnifier-tool/index.jscomponents/quicktype-manager/index.jscomponents/quicktype-tool/index.jscomponents/quicktype-tool/quicktype-editor-dialog.jscomponents/workspace-tools/index.jscomponents/splitscreen-tool/index.jscomponents/transcription-block/index.jscomponents/simple-transcription/index.jscomponents/read-only-transcribe/index.jscomponents/update-metadata/index.jscomponents/explanatory-guide/fixedGuideComponent.jscomponents/explanatory-guide/relativeGuideComponent.jscomponents/annotorious-annotator/plain.jscomponents/annotorious-annotator/line-parser.jscomponents/legacy-annotator/plain.jscomponents/quicktype/quicktype.jscomponents/new-action.jsInterfaces Directory
interfaces/transcription/index.jsinterfaces/manage-columns/index.jsinterfaces/manage-project/index.jsinterfaces/custom/index.jsinterfaces/import-tpen28/index.jsinterfaces/navigation/index.jsinterfaces/quicktype/index.jsDetailed Component Analysis
Legend
Category 1: Project-Dependent Components (Require Full Lifecycle)
These components depend on project data and should follow the complete lifecycle pattern.
1. DefaultTranscribe (
components/default-transcribe/index.js)TPEN.attachAuthentication(this)in connectedCallbackeventDispatcher.on('tpen-project-loaded', (ev) => {...})CheckPermissions.checkAllAccess('LINE', 'TEXT')but with incorrect permissions check patternattachEventListeners()- inconsistent namingMemory Leak Issues:
tpen-project-loadedlistener without cleanup2. ProjectCollaborators (
components/project-collaborators/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on('tpen-project-loaded', () => this.render())CheckPermissions.checkViewAccess('GROUP')andcheckEditAccess('PROJECT', 'MEMBERS')Memory Leak Issues:
tpen-project-loadednot cleaned up3. MemberInvitation (
components/member-invitation/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess("PROJECT", "MEMBERS")4. LineText (
components/line-text/index.js)TPEN.attachAuthentication(this)in constructoreventDispatcher.on("tpen-project-loaded", () => this.lineIndex && this.render())attachEventListeners()Memory Leak Issues:
tpen-project-loaded,tpen-line-loaded)5. LineImage (
components/line-image/index.js)TPEN.attachAuthentication(this)in connectedCallback6. LineHistory (
components/line-history/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())7. ManageRole (
components/manage-role/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())registerEventListeners()- inconsistent naming8. LeaveProject (
components/leave-project/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())addEventListeners()- inconsistent naming9. NavigationManager (
components/navigation-manager/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())setupEventListeners()- inconsistent naming10. ContinueWorking (
components/continue-working/index.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()11. CreateColumn (
components/create-column/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", (ev) => this.render())CheckPermissions.checkAllAccessbut not in standard patternsetupEventListeners()12. ProjectMetadata (
components/project-metadata/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('PROJECT', 'METADATA')13. ProjectPermissions (
components/project-permissions/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess('PROJECT')for edit operations14. ProjectLayers (
components/project-layers/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('PROJECT', 'LAYERS')15. ProjectDetails (
components/project-details/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('PROJECT')setupEventListeners()16. ProjectOptions (
components/project-options/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess('PROJECT')addEventListeners()17. ProjectExport (
components/project-export/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('PROJECT')18. ProjectTools (
components/project-tools/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('PROJECT', 'TOOLS')19-22. Copy Project Variants (
copy-existing-project,copy-project-with-customization,copy-project-with-group-member,copy-project-without-annotations)All share similar patterns:
23. ImportImage (
components/import-image/index.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()24. ImportProject (
components/import-project/index.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()25. ManageLayers (
components/manage-layers/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess('PROJECT', 'LAYERS')addEventListeners()26. ManagePages (
components/manage-pages/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess('PROJECT', 'PAGES')setupEventListeners()27. LayerSelector (
components/layer-selector/index.js)TPEN.attachAuthentication(this)in connectedCallback28. ColumnSelector (
components/column-selector/index.js)TPEN.attachAuthentication(this)in connectedCallback29. PageTool (
components/page-tool/index.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()30. MagnifierTool (
components/magnifier-tool/index.js)31. QuicktypeManager (
components/quicktype-manager/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkEditAccess('PROJECT', 'OPTIONS')setupEventListeners()32. QuicktypeTool (
components/quicktype-tool/index.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()33. QuicktypeEditorDialog (
components/quicktype-tool/quicktype-editor-dialog.js)setupEventListeners()- called on open()34. WorkspaceTools (
components/workspace-tools/index.js)TPEN.attachAuthentication(this)in connectedCallback35. SplitscreenTool (
components/splitscreen-tool/index.js)TPEN.attachAuthentication(this)in connectedCallback36. TranscriptionBlock (
components/transcription-block/index.js)TPEN.attachAuthentication(this)in connectedCallbackaddEventListeners()37. SimpleTranscription (
components/simple-transcription/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on("tpen-project-loaded", () => this.render())CheckPermissions.checkViewAccess('LINE', 'TEXT')setupEventListeners()38. UpdateMetadata (
components/update-metadata/index.js)TPEN.attachAuthentication(this)in connectedCallbackeventDispatcher.on("tpen-project-loaded", () => this.openModal())CheckPermissions.checkViewAccess('PROJECT', 'METADATA')andcheckEditAccesssetupEventListeners()39. RolesHandler (
components/roles-handler/index.js)TPEN.attachAuthentication(this)in connectedCallbackeventDispatcher.on('tpen-project-loaded', () => this.render())registerEventListeners()40. QuickGuide (
components/quick-guide/index.js)41. SplitScreen (
components/split-screen/index.js)42-43. Annotorious Components (plain.js, line-parser.js)
TPEN.attachAuthentication(this)in constructorCheckPermissions.checkAllAccess("LINE", "SELECTOR")in line-parserlistenTo()method44. LegacyAnnotator (
components/legacy-annotator/plain.js)TPEN.attachAuthentication(this)in constructorlisten()method45. TpenQuickType (
components/quicktype/quicktype.js)TPEN.attachAuthentication(this)in constructoreventDispatcher.on("tpen-project-loaded", () => this.loadQuickType())setupEventListeners()46. NewAction (
components/new-action.js)Category 2: GUI Components (Utility/Display)
These are UI utility components that may not need the full lifecycle pattern.
47. Alert (
components/gui/alert/Alert.js)48. AlertContainer (
components/gui/alert/AlertContainer.js)TPEN.eventDispatcher.on()49. Confirm (
components/gui/confirm/Confirm.js)50. ConfirmContainer (
components/gui/confirm/ConfirmContainer.js)TPEN.eventDispatcher.on()51. Toast (
components/gui/toast/Toast.js)52. ToastContainer (
components/gui/toast/ToastContainer.js)TPEN.eventDispatcher.on()53. Header (
components/gui/site/Header.js)TPEN.attachAuthentication(this)addEventListeners()54. NoAuthHeader (
components/gui/site/NoAuthHeader.js)55. Page (
components/gui/site/Page.js)authgate()functionaddEventListener()56. Footer (
components/gui/site/Footer.js)57. Card (
components/gui/card/Card.js)58-59. FixedExplanatoryGuide, RelativeExplanatoryGuide
Category 3: Project List Components
60. ProjectList (
components/projects/index.js)TPEN.attachAuthentication(this)in connectedCallbackaddEventListeners()61. ProjectListView (
components/projects/project-list-view.js)TPEN.attachAuthentication(this)in connectedCallback62. ProjectListWrite (
components/projects/project-list-write.js)TPEN.attachAuthentication(this)in connectedCallbacksetupEventListeners()63. ProjectHeader (
components/projects/project-header.js)64. ListNavigation (
components/projects/list-navigation.js)addEventListeners()Category 4: User/Auth Components
65. PublicLogin (
components/public-login/index.js)66. PublicUserProfile (
components/public-user-profile/index.js)67. UserProfile (
components/user-profile/index.js)TPEN.attachAuthentication(this)setupEventListeners()68-70. User Profile Sub-components (ContributionActivity, Report, UserStats)
Category 5: Interface Entry Points
71. TranscriptionInterface (
interfaces/transcription/index.js)TPEN.attachAuthentication(document.body)CheckPermissions.checkViewAccessandcheckEditAccess72. ManageColumnsInterface (
interfaces/manage-columns/index.js)73. ManageProjectInterface (
interfaces/manage-project/index.js)TPEN.attachAuthentication(container)TPEN.eventDispatcher.on('tpen-project-loaded', () => render())CheckPermissions.checkEditAccess('PROJECT')74. TpenCustomProperty (
interfaces/custom/index.js)TPEN.attachAuthentication(this)in connectedCallbackTPEN.eventDispatcher.on('tpen-project-loaded', () => this.render(), this)75. ImportTpen28Interface (
interfaces/import-tpen28/index.js)Not a web component - entry script with event listeners attached to DOM elements.
76. NavigationInterface (
interfaces/navigation/index.js)Just imports NavigationManager component.
77. QuicktypeInterface (
interfaces/quicktype/index.js)Just imports QuicktypeManager component.
Category 6: Check Permissions Components
78. CheckPermissions (
components/check-permissions/checkPermissions.js)Static utility class - not a web component.
79. PermissionMatchElement (
components/check-permissions/permission-match-element.js)updateVisibility()acts as render80. PermissionMatch (
components/check-permissions/permission-match.js)checkAndApply()acts as renderCategory 7: Utility/Non-Component Files
The following files are NOT web components:
components/iiif-tools/index.js- Utility functionscomponents/annotorious-annotator/detect-lines.js- Utility functionscomponents/quicktype/validation.js- Validation functionsSummary Statistics
Components with
disconnectedCallback()ImplementedOnly 3 components properly implement disconnectedCallback():
PermissionMatchElement- removes event listenerPermissionMatch- removes event listenerFooter(not needed - no listeners)Card(not needed - no listeners)ProjectHeader(not needed - no listeners)Components Missing
disconnectedCallback()(Memory Leak Risk)~65+ components are missing disconnectedCallback() and register event listeners that are never cleaned up.
Event Listener Method Naming Inconsistencies
setupEventListeners()addEventListeners()attachEventListeners()registerEventListeners()listen()listenTo()CheckPermissions Usage
Auth Pattern Usage
TPEN.attachAuthentication(this)in connectedCallbackTPEN.attachAuthentication(this)in constructorauthgate()functionRecommendations
1. Standardize Event Listener Method Names
Choose one name and use it consistently:
2. Implement disconnectedCallback() for All Components
Every component that registers event listeners should clean them up:
3. Store Bound Event Handlers
To properly remove event listeners, store bound handlers:
4. Standardize Auth Pattern
Implement
authgate()consistently:5. Implement Permission Checks Consistently
All project-dependent components should check permissions before rendering:
6. Create a Base Component Class
Consider creating a base class that implements the standard lifecycle: