diff --git a/capabilities/testdrive-jsui/js/controls/contents-control.js b/capabilities/testdrive-jsui/js/controls/contents-control.js index b4351052..db5afe89 100644 --- a/capabilities/testdrive-jsui/js/controls/contents-control.js +++ b/capabilities/testdrive-jsui/js/controls/contents-control.js @@ -256,33 +256,41 @@ class ContentsControl extends ControlBase { * Build the control content * Override of base class method to provide contents-specific functionality */ - buildContent() { + + /** + * Generate contents control content (called by base class buildContent) + */ + generateContent() { + // Extract headings first + this.extractHeadings(); + return this.safeOperation(() => { - // Extract headings on first build - this.extractHeadings(); + return this.generateContentsHTML(); + }, 'Error generating contents', 'generateContent'); + } - // Generate and set content - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.generateContentsHTML(); + /** + * Override buildContent to add control reference and auto-refresh + */ + buildContent() { + super.buildContent(); - // Store reference to this control for onclick handlers - this.element.contentsControl = this; + // Store reference to this control for onclick handlers + if (this.element) { + this.element.contentsControl = this; + } + + // Set up auto-refresh for dynamic content + if (this.updateInterval) { + clearInterval(this.updateInterval); + } + + this.updateInterval = setInterval(() => { + const currentHeadingCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length; + if (currentHeadingCount !== this.headings.length) { + this.refreshContents(); } - - // Set up auto-refresh for dynamic content - if (this.updateInterval) { - clearInterval(this.updateInterval); - } - - this.updateInterval = setInterval(() => { - const currentHeadingCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length; - if (currentHeadingCount !== this.headings.length) { - this.refreshContents(); - } - }, 5000); // Check every 5 seconds - - }, null, 'buildContent'); + }, 5000); // Check every 5 seconds } /** diff --git a/capabilities/testdrive-jsui/js/controls/control-base.js b/capabilities/testdrive-jsui/js/controls/control-base.js index 7b42d94a..f6b62d50 100644 --- a/capabilities/testdrive-jsui/js/controls/control-base.js +++ b/capabilities/testdrive-jsui/js/controls/control-base.js @@ -260,6 +260,9 @@ class ControlBase { // Style expanded panel panel.style.cssText = ` + position: relative; + display: flex; + flex-direction: column; background: rgba(248, 249, 250, 0.95); border: 1px solid #dee2e6; border-radius: 8px; @@ -267,6 +270,10 @@ class ControlBase { backdrop-filter: blur(8px); min-width: 300px; min-height: 200px; + max-height: calc(100vh - 40px); + width: auto; + height: auto; + overflow: hidden; `; // Style header @@ -281,6 +288,22 @@ class ControlBase { border-bottom: 1px solid #dee2e6; cursor: move; user-select: none; + flex-shrink: 0; + min-height: 40px; + border-radius: 7px 7px 0 0; + margin: -1px -1px 0 -1px; + `; + } + + // Style content area container + const contentArea = this.element.querySelector('.control-content'); + if (contentArea) { + contentArea.style.cssText = ` + flex: 1; + overflow: hidden; + display: flex; + flex-direction: column; + min-height: 0; `; } @@ -512,15 +535,16 @@ class ControlBase { resizeHandle.style.cssText = ` position: absolute; bottom: 4px; - right: 4px; - width: 8px; - height: 8px; + right: 20px; + width: 12px; + height: 12px; cursor: se-resize; - font-size: 8px; + font-size: 10px; line-height: 1; user-select: none; color: #999; background: transparent; + z-index: 10; `; // Add to the expanded panel @@ -636,14 +660,55 @@ class ControlBase { /** * Build the control content (to be overridden by subclasses) */ + /** + * Build content with consistent styling - calls subclass generateContent() + */ buildContent() { - // Default implementation - subclasses should override this const content = this.element?.querySelector('.control-content'); if (content) { - content.innerHTML = this.config.defaultContent; + // Get content from subclass + const innerContent = this.generateContent ? this.generateContent() : this.config.defaultContent; + + // Apply consistent container styling + content.innerHTML = ` +
Panel content goes here...
`; + } + /** * Show the control */ diff --git a/capabilities/testdrive-jsui/js/controls/debug-control.js b/capabilities/testdrive-jsui/js/controls/debug-control.js index dfc63209..c0fb71a4 100644 --- a/capabilities/testdrive-jsui/js/controls/debug-control.js +++ b/capabilities/testdrive-jsui/js/controls/debug-control.js @@ -423,35 +423,36 @@ class DebugControl extends ControlBase { } /** - * Build the control content - * Override of base class method to provide debug-specific functionality + * Generate debug control content (called by base class buildContent) + */ + generateContent() { + return this.safeOperation(() => { + return ` + ${this.generateSystemInfoHTML()} + ${this.generatePerformanceHTML()} + ${this.generateFilterControlsHTML()} + ${this.generateMessagesHTML()} + ${this.generateControlButtonsHTML()} + +Error generating edit tools
', 'generateEditToolsHTML'); @@ -539,16 +535,25 @@ class EditControl extends ControlBase { * Build the control content * Override of base class method to provide edit-specific functionality */ - buildContent() { + /** + * Generate edit control content (called by base class buildContent) + */ + generateContent() { return this.safeOperation(() => { - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.generateEditToolsHTML(); + return this.generateEditToolsHTML(); + }, 'Error generating edit content', 'generateContent'); + } - // Store reference to this control for onclick handlers - this.element.editControl = this; - } - }, null, 'buildContent'); + /** + * Override buildContent to add control reference + */ + buildContent() { + super.buildContent(); + + // Store reference to this control for onclick handlers + if (this.element) { + this.element.editControl = this; + } } /** diff --git a/capabilities/testdrive-jsui/js/controls/status-control.js b/capabilities/testdrive-jsui/js/controls/status-control.js index 934a0efd..4f1ae60c 100644 --- a/capabilities/testdrive-jsui/js/controls/status-control.js +++ b/capabilities/testdrive-jsui/js/controls/status-control.js @@ -131,10 +131,7 @@ class StatusControl extends ControlBase { const formatNumber = (num) => num.toLocaleString(); return ` -Error displaying statistics
', 'formatStatistics'); @@ -322,30 +318,37 @@ class StatusControl extends ControlBase { * Build the control content * Override of base class method to provide status-specific functionality */ - buildContent() { + /** + * Generate status control content (called by base class buildContent) + */ + generateContent() { + // Analyze document first + this.analyzeDocument(); + return this.safeOperation(() => { - // Analyze document first - this.analyzeDocument(); + return this.formatStatistics(); + }, 'Error generating status content', 'generateContent'); + } - // Generate and set content - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.formatStatistics(); + /** + * Override buildContent to add control reference and auto-refresh + */ + buildContent() { + super.buildContent(); - // Store reference to this control for onclick handlers - this.element.statusControl = this; - } + // Store reference to this control for onclick handlers + if (this.element) { + this.element.statusControl = this; + } - // Set up auto-refresh for dynamic content - if (this.updateInterval) { - clearInterval(this.updateInterval); - } + // Set up auto-refresh for dynamic content + if (this.updateInterval) { + clearInterval(this.updateInterval); + } - this.updateInterval = setInterval(() => { - this.refreshStats(); - }, 10000); // Update every 10 seconds - - }, null, 'buildContent'); + this.updateInterval = setInterval(() => { + this.refreshStats(); + }, 10000); // Update every 10 seconds } /** diff --git a/testdrive-jsui/static/js/controls/contents-control.js b/testdrive-jsui/static/js/controls/contents-control.js index b4351052..db5afe89 100644 --- a/testdrive-jsui/static/js/controls/contents-control.js +++ b/testdrive-jsui/static/js/controls/contents-control.js @@ -256,33 +256,41 @@ class ContentsControl extends ControlBase { * Build the control content * Override of base class method to provide contents-specific functionality */ - buildContent() { + + /** + * Generate contents control content (called by base class buildContent) + */ + generateContent() { + // Extract headings first + this.extractHeadings(); + return this.safeOperation(() => { - // Extract headings on first build - this.extractHeadings(); + return this.generateContentsHTML(); + }, 'Error generating contents', 'generateContent'); + } - // Generate and set content - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.generateContentsHTML(); + /** + * Override buildContent to add control reference and auto-refresh + */ + buildContent() { + super.buildContent(); - // Store reference to this control for onclick handlers - this.element.contentsControl = this; + // Store reference to this control for onclick handlers + if (this.element) { + this.element.contentsControl = this; + } + + // Set up auto-refresh for dynamic content + if (this.updateInterval) { + clearInterval(this.updateInterval); + } + + this.updateInterval = setInterval(() => { + const currentHeadingCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length; + if (currentHeadingCount !== this.headings.length) { + this.refreshContents(); } - - // Set up auto-refresh for dynamic content - if (this.updateInterval) { - clearInterval(this.updateInterval); - } - - this.updateInterval = setInterval(() => { - const currentHeadingCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length; - if (currentHeadingCount !== this.headings.length) { - this.refreshContents(); - } - }, 5000); // Check every 5 seconds - - }, null, 'buildContent'); + }, 5000); // Check every 5 seconds } /** diff --git a/testdrive-jsui/static/js/controls/control-base.js b/testdrive-jsui/static/js/controls/control-base.js index 7b42d94a..f6b62d50 100644 --- a/testdrive-jsui/static/js/controls/control-base.js +++ b/testdrive-jsui/static/js/controls/control-base.js @@ -260,6 +260,9 @@ class ControlBase { // Style expanded panel panel.style.cssText = ` + position: relative; + display: flex; + flex-direction: column; background: rgba(248, 249, 250, 0.95); border: 1px solid #dee2e6; border-radius: 8px; @@ -267,6 +270,10 @@ class ControlBase { backdrop-filter: blur(8px); min-width: 300px; min-height: 200px; + max-height: calc(100vh - 40px); + width: auto; + height: auto; + overflow: hidden; `; // Style header @@ -281,6 +288,22 @@ class ControlBase { border-bottom: 1px solid #dee2e6; cursor: move; user-select: none; + flex-shrink: 0; + min-height: 40px; + border-radius: 7px 7px 0 0; + margin: -1px -1px 0 -1px; + `; + } + + // Style content area container + const contentArea = this.element.querySelector('.control-content'); + if (contentArea) { + contentArea.style.cssText = ` + flex: 1; + overflow: hidden; + display: flex; + flex-direction: column; + min-height: 0; `; } @@ -512,15 +535,16 @@ class ControlBase { resizeHandle.style.cssText = ` position: absolute; bottom: 4px; - right: 4px; - width: 8px; - height: 8px; + right: 20px; + width: 12px; + height: 12px; cursor: se-resize; - font-size: 8px; + font-size: 10px; line-height: 1; user-select: none; color: #999; background: transparent; + z-index: 10; `; // Add to the expanded panel @@ -636,14 +660,55 @@ class ControlBase { /** * Build the control content (to be overridden by subclasses) */ + /** + * Build content with consistent styling - calls subclass generateContent() + */ buildContent() { - // Default implementation - subclasses should override this const content = this.element?.querySelector('.control-content'); if (content) { - content.innerHTML = this.config.defaultContent; + // Get content from subclass + const innerContent = this.generateContent ? this.generateContent() : this.config.defaultContent; + + // Apply consistent container styling + content.innerHTML = ` +Panel content goes here...
`; + } + /** * Show the control */ diff --git a/testdrive-jsui/static/js/controls/debug-control.js b/testdrive-jsui/static/js/controls/debug-control.js index dfc63209..c0fb71a4 100644 --- a/testdrive-jsui/static/js/controls/debug-control.js +++ b/testdrive-jsui/static/js/controls/debug-control.js @@ -423,35 +423,36 @@ class DebugControl extends ControlBase { } /** - * Build the control content - * Override of base class method to provide debug-specific functionality + * Generate debug control content (called by base class buildContent) + */ + generateContent() { + return this.safeOperation(() => { + return ` + ${this.generateSystemInfoHTML()} + ${this.generatePerformanceHTML()} + ${this.generateFilterControlsHTML()} + ${this.generateMessagesHTML()} + ${this.generateControlButtonsHTML()} + +Error generating edit tools
', 'generateEditToolsHTML'); @@ -539,16 +535,25 @@ class EditControl extends ControlBase { * Build the control content * Override of base class method to provide edit-specific functionality */ - buildContent() { + /** + * Generate edit control content (called by base class buildContent) + */ + generateContent() { return this.safeOperation(() => { - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.generateEditToolsHTML(); + return this.generateEditToolsHTML(); + }, 'Error generating edit content', 'generateContent'); + } - // Store reference to this control for onclick handlers - this.element.editControl = this; - } - }, null, 'buildContent'); + /** + * Override buildContent to add control reference + */ + buildContent() { + super.buildContent(); + + // Store reference to this control for onclick handlers + if (this.element) { + this.element.editControl = this; + } } /** diff --git a/testdrive-jsui/static/js/controls/status-control.js b/testdrive-jsui/static/js/controls/status-control.js index 934a0efd..4f1ae60c 100644 --- a/testdrive-jsui/static/js/controls/status-control.js +++ b/testdrive-jsui/static/js/controls/status-control.js @@ -131,10 +131,7 @@ class StatusControl extends ControlBase { const formatNumber = (num) => num.toLocaleString(); return ` -Error displaying statistics
', 'formatStatistics'); @@ -322,30 +318,37 @@ class StatusControl extends ControlBase { * Build the control content * Override of base class method to provide status-specific functionality */ - buildContent() { + /** + * Generate status control content (called by base class buildContent) + */ + generateContent() { + // Analyze document first + this.analyzeDocument(); + return this.safeOperation(() => { - // Analyze document first - this.analyzeDocument(); + return this.formatStatistics(); + }, 'Error generating status content', 'generateContent'); + } - // Generate and set content - const content = this.element?.querySelector('.control-content'); - if (content) { - content.innerHTML = this.formatStatistics(); + /** + * Override buildContent to add control reference and auto-refresh + */ + buildContent() { + super.buildContent(); - // Store reference to this control for onclick handlers - this.element.statusControl = this; - } + // Store reference to this control for onclick handlers + if (this.element) { + this.element.statusControl = this; + } - // Set up auto-refresh for dynamic content - if (this.updateInterval) { - clearInterval(this.updateInterval); - } + // Set up auto-refresh for dynamic content + if (this.updateInterval) { + clearInterval(this.updateInterval); + } - this.updateInterval = setInterval(() => { - this.refreshStats(); - }, 10000); // Update every 10 seconds - - }, null, 'buildContent'); + this.updateInterval = setInterval(() => { + this.refreshStats(); + }, 10000); // Update every 10 seconds } /**