generated from coulomb/repo-seed
docs: comprehensive feature documentation and HTML generation system
Added complete documentation for all TestDrive-JSUI controls and features, plus flexible HTML generation system supporting standalone and external modes. Documentation (8 files, 3,533 lines): - docs/features/README.md: Central hub with overview, config, examples - docs/features/section-editing.md: Section editing guide - docs/features/edit-control.md: Document actions and editing tools - docs/features/status-control.md: Real-time statistics and tracking - docs/features/contents-control.md: Table of contents navigation - docs/features/debug-control.md: Development and debugging tools - docs/features/keyboard-shortcuts.md: Complete shortcuts reference - docs/features/themes.md: Visual theming and customization HTML Generation System (3 files, 1,104 lines): - js/utils/html-generator.js: Dual-mode HTML generator class * Standalone mode: All CSS/JS embedded inline * External mode: References _jsui/ directory * Configurable options for title, content, controls, theme * Download and save functionality - _jsui/ directory: External resources structure * README.md: Comprehensive usage guide * css/: Symlinked CSS files (base, editor, controls, themes) * js/: Symlinked JavaScript files (core, components, controls) * Enables smaller HTML files with browser caching - examples/html-generator-demo.html: Interactive demo * Web-based configuration form * Side-by-side mode comparison * Live generation and preview * Download and copy functionality Key Features: - 4,637 total lines of documentation and code - All controls documented with examples and troubleshooting - Flexible deployment options (standalone vs external) - Developer-friendly structure with clear guides - Production-ready system 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
731
docs/features/contents-control.md
Normal file
731
docs/features/contents-control.md
Normal file
@@ -0,0 +1,731 @@
|
||||
# Contents Control
|
||||
|
||||
**Interactive table of contents navigation** 📋
|
||||
|
||||
The Contents Control provides an automatically generated, hierarchical table of contents for quick document navigation. Click any heading to jump to that section with smooth scrolling and visual highlighting. Perfect for long documents with multiple sections. Positioned in the northwest by default.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Contents Control extracts all headings from your document and displays them in a structured, clickable table of contents. Navigate long documents quickly and understand document structure at a glance.
|
||||
|
||||
### Position
|
||||
- **Default**: Northwest (nw) - top-left corner
|
||||
- **Appearance**: 📋 icon when collapsed
|
||||
- **Title**: "Contents"
|
||||
|
||||
### Key Features
|
||||
|
||||
- 📋 **Automatic extraction** - Finds all headings (h1-h6) in document
|
||||
- 🔍 **Search functionality** - Filter headings by text
|
||||
- 🎯 **Click to navigate** - Smooth scroll to any heading
|
||||
- ✨ **Visual feedback** - Temporary highlight on target heading
|
||||
- 🔄 **Auto-refresh** - Updates when document structure changes
|
||||
- 📐 **Hierarchical display** - Proper indentation for heading levels
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable/Disable
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
contentsControl: true // Enable (default: true)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
contentsControl: 'nw' // Northwest (default), or: ne, e, se, s, sw, w
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Automatic Heading Extraction
|
||||
|
||||
The Contents Control automatically scans your document for headings (h1-h6) and builds a table of contents.
|
||||
|
||||
#### How It Works
|
||||
|
||||
**Scanning**:
|
||||
- Queries document for `h1, h2, h3, h4, h5, h6` elements
|
||||
- Extracts heading text and level
|
||||
- Generates unique IDs for navigation (if not present)
|
||||
|
||||
**ID Generation**:
|
||||
- Converts heading text to URL-safe format
|
||||
- Removes special characters
|
||||
- Replaces spaces with hyphens
|
||||
- Ensures uniqueness with counter suffix if needed
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
# Getting Started
|
||||
## Installation Steps
|
||||
### Prerequisites
|
||||
```
|
||||
|
||||
Becomes:
|
||||
```javascript
|
||||
[
|
||||
{ id: 'getting-started', text: 'Getting Started', level: 1 },
|
||||
{ id: 'installation-steps', text: 'Installation Steps', level: 2 },
|
||||
{ id: 'prerequisites', text: 'Prerequisites', level: 3 }
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Hierarchical Display
|
||||
|
||||
Headings are displayed with indentation based on their level.
|
||||
|
||||
#### Indentation Rules
|
||||
|
||||
- **H1**: No indentation (0px)
|
||||
- **H2**: 15px indent
|
||||
- **H3**: 30px indent
|
||||
- **H4**: 45px indent
|
||||
- **H5**: 60px indent
|
||||
- **H6**: 75px indent
|
||||
|
||||
**Formula**: `indent = (level - 1) × 15px`
|
||||
|
||||
#### Visual Indicators
|
||||
|
||||
Each heading link shows:
|
||||
- **Level badge**: `H1`, `H2`, etc. (gray color)
|
||||
- **Heading text**: Blue, underlined on hover
|
||||
- **Hover effect**: Light gray background
|
||||
|
||||
**Example Display**:
|
||||
```
|
||||
H1 Getting Started
|
||||
H2 Installation Steps
|
||||
H3 Prerequisites
|
||||
H3 Download
|
||||
H2 Configuration
|
||||
H3 Basic Setup
|
||||
H3 Advanced Options
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Search Functionality
|
||||
|
||||
Filter headings by text to quickly find sections in large documents.
|
||||
|
||||
#### Usage
|
||||
|
||||
1. Type in the search box at the top of the Contents panel
|
||||
2. Results filter in real-time as you type
|
||||
3. Matching headings remain visible
|
||||
4. Clear search to show all headings
|
||||
|
||||
**Search behavior**:
|
||||
- Case-insensitive
|
||||
- Partial text matching
|
||||
- Searches heading text only (not IDs)
|
||||
- Updates status count: "Found X headings"
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Search: "install"
|
||||
|
||||
Results:
|
||||
H1 Getting Started
|
||||
H2 Installation Steps
|
||||
H2 Uninstall Guide
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Click to Navigate
|
||||
|
||||
Click any heading in the Contents panel to jump to that section.
|
||||
|
||||
#### Navigation Behavior
|
||||
|
||||
**Smooth scrolling**:
|
||||
- Animated scroll to target heading
|
||||
- Position: `block: 'start'` (heading at top)
|
||||
- Duration: Browser default (~500ms)
|
||||
|
||||
**Visual highlight**:
|
||||
- Target heading gets yellow background (`#fff3cd`)
|
||||
- Highlight fades after 1.5 seconds
|
||||
- Smooth transition (300ms ease)
|
||||
|
||||
**Example user flow**:
|
||||
1. User clicks "Installation Steps" in Contents
|
||||
2. Document smoothly scrolls to that heading
|
||||
3. Heading briefly highlights in yellow
|
||||
4. Highlight fades back to normal
|
||||
|
||||
---
|
||||
|
||||
### 5. Refresh Functionality
|
||||
|
||||
Update the table of contents when document structure changes.
|
||||
|
||||
#### Manual Refresh
|
||||
|
||||
**Button**: "🔄 Refresh Contents" at bottom of panel
|
||||
|
||||
**Usage**:
|
||||
- Click to re-scan document for headings
|
||||
- Shows "✅ Updated" confirmation for 1 second
|
||||
- Rebuilds entire table of contents
|
||||
|
||||
**When to use**:
|
||||
- After adding new headings via section editing
|
||||
- After programmatically modifying document
|
||||
- To ensure TOC is up-to-date
|
||||
|
||||
#### Auto-Refresh
|
||||
|
||||
**Automatic detection** every 5 seconds:
|
||||
- Counts current headings in document
|
||||
- Compares to stored count
|
||||
- Refreshes automatically if different
|
||||
|
||||
**Silent updates**:
|
||||
- No visual feedback (unlike manual refresh)
|
||||
- Preserves scroll position
|
||||
- Maintains search query
|
||||
|
||||
**Disable auto-refresh**:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
clearInterval(editor.contentsControl.updateInterval);
|
||||
editor.contentsControl.updateInterval = null;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Heading Status
|
||||
|
||||
Shows count of headings found.
|
||||
|
||||
**Display**: "Found X heading(s)" (gray text, centered)
|
||||
|
||||
**Updates**:
|
||||
- After manual refresh
|
||||
- During search filtering
|
||||
- On auto-refresh
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Found 12 headings (all headings)
|
||||
Found 3 headings (filtered by search)
|
||||
No headings found (empty document)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
markdown: '# Chapter 1\\n\\n## Section 1.1\\n\\n## Section 1.2',
|
||||
controls: {
|
||||
contentsControl: true
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position (Bottom-Left)
|
||||
|
||||
```javascript
|
||||
// Move to southwest (bottom-left)
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
contentsControl: 'sw'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Documentation Viewer Setup
|
||||
|
||||
```javascript
|
||||
// Perfect for long documentation
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#viewer',
|
||||
mode: 'view', // Read-only
|
||||
controls: {
|
||||
editControl: false,
|
||||
statusControl: false,
|
||||
contentsControl: true, // Only show TOC
|
||||
debugControl: false
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Programmatic Navigation
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Navigate to specific heading by ID
|
||||
editor.contentsControl.navigateToHeading('installation-steps');
|
||||
|
||||
// Or find and navigate by text
|
||||
const heading = editor.contentsControl.headings.find(h =>
|
||||
h.text.includes('Installation')
|
||||
);
|
||||
if (heading) {
|
||||
editor.contentsControl.navigateToHeading(heading.id);
|
||||
}
|
||||
```
|
||||
|
||||
### Track Navigation Events
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Monitor which sections users visit
|
||||
const originalNavigate = editor.contentsControl.navigateToHeading.bind(editor.contentsControl);
|
||||
editor.contentsControl.navigateToHeading = function(headingId) {
|
||||
const heading = this.headings.find(h => h.id === headingId);
|
||||
console.log(`User navigated to: ${heading?.text || headingId}`);
|
||||
|
||||
// Analytics
|
||||
fetch('/api/analytics', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
event: 'toc_navigation',
|
||||
heading: heading?.text,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
|
||||
return originalNavigate(headingId);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Properties
|
||||
|
||||
Access via `editor.contentsControl`:
|
||||
|
||||
```javascript
|
||||
const contentsCtrl = editor.contentsControl;
|
||||
|
||||
// Array of extracted headings
|
||||
contentsCtrl.headings = [
|
||||
{
|
||||
id: 'getting-started',
|
||||
text: 'Getting Started',
|
||||
level: 1,
|
||||
element: HTMLElement, // Reference to heading element
|
||||
index: 0
|
||||
},
|
||||
// ... more headings
|
||||
];
|
||||
|
||||
// Current search query
|
||||
contentsCtrl.searchQuery = 'install';
|
||||
|
||||
// Last scan timestamp
|
||||
contentsCtrl.lastScanTime = 1702742452123;
|
||||
|
||||
// Auto-refresh interval ID
|
||||
contentsCtrl.updateInterval = 12345;
|
||||
|
||||
// Configuration
|
||||
contentsCtrl.config.position = 'nw'; // Compass position
|
||||
contentsCtrl.config.icon = '📋'; // Panel icon
|
||||
contentsCtrl.config.title = 'Contents'; // Panel title
|
||||
contentsCtrl.isExpanded; // true if expanded
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
```javascript
|
||||
const contentsCtrl = editor.contentsControl;
|
||||
|
||||
// Extract headings from document
|
||||
const headings = contentsCtrl.extractHeadings();
|
||||
// Returns: Array of heading objects
|
||||
|
||||
// Filter headings by search query
|
||||
const filtered = contentsCtrl.filterHeadings(headings, 'install');
|
||||
// Returns: Array of matching headings
|
||||
|
||||
// Navigate to heading with smooth scroll
|
||||
const success = contentsCtrl.navigateToHeading('installation-steps');
|
||||
// Returns: true if heading found, false otherwise
|
||||
|
||||
// Handle search input
|
||||
contentsCtrl.handleSearch('configuration');
|
||||
// Updates searchQuery and rebuilds content
|
||||
|
||||
// Refresh contents manually
|
||||
contentsCtrl.refreshContents();
|
||||
// Re-scans document and updates display
|
||||
|
||||
// Generate content HTML
|
||||
const html = contentsCtrl.generateContent();
|
||||
// Returns: HTML string for panel content
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Heading ID Format
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Override ID generation
|
||||
const originalExtract = editor.contentsControl.extractHeadings.bind(editor.contentsControl);
|
||||
editor.contentsControl.extractHeadings = function() {
|
||||
const result = originalExtract();
|
||||
|
||||
// Custom ID format: section-1-2-3
|
||||
result.forEach((heading, index) => {
|
||||
heading.id = `section-${index + 1}`;
|
||||
heading.element.id = heading.id;
|
||||
});
|
||||
|
||||
this.headings = result;
|
||||
return result;
|
||||
};
|
||||
```
|
||||
|
||||
### Collapse All Sections Except One
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
function focusOnSection(headingId) {
|
||||
// Navigate to heading
|
||||
editor.contentsControl.navigateToHeading(headingId);
|
||||
|
||||
// Highlight in TOC
|
||||
const tocItems = document.querySelectorAll('.contents-item a');
|
||||
tocItems.forEach(item => {
|
||||
if (item.getAttribute('href') === `#${headingId}`) {
|
||||
item.style.fontWeight = 'bold';
|
||||
item.style.backgroundColor = '#e7f3ff';
|
||||
} else {
|
||||
item.style.fontWeight = 'normal';
|
||||
item.style.backgroundColor = 'transparent';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
focusOnSection('installation-steps');
|
||||
```
|
||||
|
||||
### Export Table of Contents
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
function exportTOC() {
|
||||
const toc = editor.contentsControl.headings.map(h => ({
|
||||
level: h.level,
|
||||
text: h.text,
|
||||
id: h.id
|
||||
}));
|
||||
|
||||
// As JSON
|
||||
const json = JSON.stringify(toc, null, 2);
|
||||
|
||||
// As Markdown
|
||||
const markdown = toc.map(h => {
|
||||
const indent = ' '.repeat(h.level - 1);
|
||||
return `${indent}- [${h.text}](#${h.id})`;
|
||||
}).join('\\n');
|
||||
|
||||
console.log('JSON:', json);
|
||||
console.log('Markdown:', markdown);
|
||||
|
||||
return { json, markdown };
|
||||
}
|
||||
|
||||
exportTOC();
|
||||
```
|
||||
|
||||
### Custom Search Logic
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Override filter to search by level too
|
||||
const originalFilter = editor.contentsControl.filterHeadings.bind(editor.contentsControl);
|
||||
editor.contentsControl.filterHeadings = function(headings, query) {
|
||||
if (!query || query.trim() === '') {
|
||||
return headings;
|
||||
}
|
||||
|
||||
// Support "h1", "h2" prefixes
|
||||
const levelMatch = query.match(/^h([1-6])\s*/i);
|
||||
if (levelMatch) {
|
||||
const level = parseInt(levelMatch[1]);
|
||||
const textQuery = query.substring(levelMatch[0].length);
|
||||
|
||||
let results = headings.filter(h => h.level === level);
|
||||
if (textQuery) {
|
||||
results = results.filter(h =>
|
||||
h.text.toLowerCase().includes(textQuery.toLowerCase())
|
||||
);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// Default text search
|
||||
return originalFilter(headings, query);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Headings Found
|
||||
|
||||
**Problem**: Contents panel shows "No headings found in document"
|
||||
|
||||
**Causes & Solutions**:
|
||||
|
||||
1. **Document has no headings**
|
||||
- Add headings to your markdown: `# Heading`, `## Subheading`
|
||||
- Click "🔄 Refresh" after adding headings
|
||||
|
||||
2. **Headings not rendered yet**
|
||||
- Wait for markdown rendering to complete
|
||||
- Use manual refresh button
|
||||
|
||||
3. **Wrong selector**
|
||||
- Verify headings are actual `<h1>` - `<h6>` elements (not styled divs)
|
||||
- Check browser console for errors
|
||||
|
||||
**Debug**:
|
||||
```javascript
|
||||
// Check if headings exist in DOM
|
||||
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
||||
console.log('Headings found:', headings.length);
|
||||
```
|
||||
|
||||
### Navigation Not Working
|
||||
|
||||
**Problem**: Clicking headings in TOC doesn't navigate
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check for errors**:
|
||||
```javascript
|
||||
// Test navigation programmatically
|
||||
editor.contentsControl.navigateToHeading('your-heading-id');
|
||||
```
|
||||
|
||||
2. **Verify heading IDs**:
|
||||
```javascript
|
||||
// List all heading IDs
|
||||
console.log(editor.contentsControl.headings.map(h => h.id));
|
||||
```
|
||||
|
||||
3. **Scroll container issues**:
|
||||
- Ensure content is in scrollable container
|
||||
- Check CSS `overflow` properties
|
||||
- Try without smooth scroll:
|
||||
```javascript
|
||||
const elem = document.getElementById('heading-id');
|
||||
elem.scrollIntoView({ behavior: 'auto' });
|
||||
```
|
||||
|
||||
### Search Not Working
|
||||
|
||||
**Problem**: Typing in search box doesn't filter headings
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check console for errors**
|
||||
2. **Verify control reference**:
|
||||
```javascript
|
||||
console.log(editor.contentsControl); // Should not be undefined
|
||||
```
|
||||
|
||||
3. **Test search manually**:
|
||||
```javascript
|
||||
editor.contentsControl.handleSearch('your query');
|
||||
```
|
||||
|
||||
4. **Clear search**:
|
||||
```javascript
|
||||
editor.contentsControl.searchQuery = '';
|
||||
editor.contentsControl.buildContent();
|
||||
```
|
||||
|
||||
### Duplicate Headings
|
||||
|
||||
**Problem**: Multiple headings with same text cause navigation issues
|
||||
|
||||
**Solution**: The control auto-generates unique IDs by appending counters:
|
||||
```
|
||||
heading-text → heading-text
|
||||
heading-text → heading-text-1
|
||||
heading-text → heading-text-2
|
||||
```
|
||||
|
||||
To use custom IDs:
|
||||
```html
|
||||
<h2 id="custom-id-1">Same Text</h2>
|
||||
<h2 id="custom-id-2">Same Text</h2>
|
||||
```
|
||||
|
||||
### Auto-Refresh Not Working
|
||||
|
||||
**Problem**: TOC doesn't update when headings change
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check if interval is running**:
|
||||
```javascript
|
||||
console.log(editor.contentsControl.updateInterval); // Should be a number
|
||||
```
|
||||
|
||||
2. **Restart auto-refresh**:
|
||||
```javascript
|
||||
clearInterval(editor.contentsControl.updateInterval);
|
||||
editor.contentsControl.updateInterval = setInterval(() => {
|
||||
const currentCount = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length;
|
||||
if (currentCount !== editor.contentsControl.headings.length) {
|
||||
editor.contentsControl.refreshContents();
|
||||
}
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
3. **Use manual refresh**: Click the "🔄 Refresh Contents" button
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Writers
|
||||
|
||||
1. **Use logical heading hierarchy** - Don't skip levels (h1 → h3)
|
||||
2. **Keep headings concise** - Long headings clutter the TOC
|
||||
3. **Use descriptive text** - Helps readers and search functionality
|
||||
4. **Refresh after major edits** - Ensure TOC stays current
|
||||
|
||||
### For Readers
|
||||
|
||||
1. **Use search** - Quickly find sections in long documents
|
||||
2. **Hover for highlights** - See which section each link goes to
|
||||
3. **Leave panel expanded** - Keep TOC visible for quick navigation
|
||||
4. **Bookmark important sections** - Use browser bookmarks with heading IDs
|
||||
|
||||
### For Developers
|
||||
|
||||
1. **Provide heading IDs** - Don't rely on auto-generation for critical links
|
||||
2. **Test navigation** - Verify smooth scroll works across browsers
|
||||
3. **Monitor performance** - Disable auto-refresh for very large documents (500+ headings)
|
||||
4. **Integrate analytics** - Track which sections users visit most
|
||||
|
||||
Example analytics integration:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Track TOC usage
|
||||
const originalNav = editor.contentsControl.navigateToHeading.bind(editor.contentsControl);
|
||||
let navCount = 0;
|
||||
|
||||
editor.contentsControl.navigateToHeading = function(headingId) {
|
||||
navCount++;
|
||||
console.log(`TOC navigation #${navCount} to: ${headingId}`);
|
||||
|
||||
// Send to analytics service
|
||||
if (window.analytics) {
|
||||
analytics.track('TOC Navigation', {
|
||||
headingId,
|
||||
headingText: this.headings.find(h => h.id === headingId)?.text,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
return originalNav(headingId);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### For Large Documents (100+ headings)
|
||||
|
||||
**Impact**: Auto-refresh and search may slow down
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Increase refresh interval**:
|
||||
```javascript
|
||||
clearInterval(editor.contentsControl.updateInterval);
|
||||
editor.contentsControl.updateInterval = setInterval(() => {
|
||||
// Check logic
|
||||
}, 15000); // 15 seconds instead of 5
|
||||
```
|
||||
|
||||
2. **Disable auto-refresh**:
|
||||
```javascript
|
||||
clearInterval(editor.contentsControl.updateInterval);
|
||||
editor.contentsControl.updateInterval = null;
|
||||
```
|
||||
|
||||
3. **Lazy rendering** - Only render visible TOC items (not currently implemented)
|
||||
|
||||
### Memory Usage
|
||||
|
||||
Each heading stores:
|
||||
- ID string (~20 bytes)
|
||||
- Text string (~50 bytes)
|
||||
- Element reference (8 bytes)
|
||||
- Level + index (8 bytes)
|
||||
|
||||
**Estimate**: ~86 bytes per heading
|
||||
- 100 headings: ~8.6 KB
|
||||
- 1000 headings: ~86 KB
|
||||
|
||||
Negligible for most documents. No memory leaks if control is properly destroyed.
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Section Editing](section-editing.md)** - Edit headings, triggers TOC refresh
|
||||
- **[Status Control](status-control.md)** - Shows heading count statistics
|
||||
- **[Edit Control](edit-control.md)** - Go to line feature (complementary navigation)
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [API Reference](../api/contents-control.md)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
785
docs/features/debug-control.md
Normal file
785
docs/features/debug-control.md
Normal file
@@ -0,0 +1,785 @@
|
||||
# Debug Control
|
||||
|
||||
**Development and debugging tools** 🐛
|
||||
|
||||
The Debug Control provides comprehensive debugging capabilities including real-time console message capture, error tracking, performance monitoring, and system information display. Essential for development, troubleshooting, and quality assurance workflows. Positioned in the west by default. **Disabled by default** - enable explicitly for development.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Debug Control serves as a central hub for all debugging activities, capturing console messages, tracking errors, monitoring performance, and displaying system information. Perfect for developers troubleshooting issues or optimizing performance.
|
||||
|
||||
### Position
|
||||
- **Default**: West (w) - middle-left side
|
||||
- **Appearance**: 🐛 icon when collapsed
|
||||
- **Title**: "Debug"
|
||||
- **Status**: **Disabled by default** (enable for development)
|
||||
|
||||
### Key Features
|
||||
|
||||
- 📝 **Console capture** - Records all console.log, error, warn, info, debug
|
||||
- 🚨 **Error tracking** - Captures global errors and unhandled promises
|
||||
- 📊 **Performance metrics** - Page load times, session duration
|
||||
- 💻 **System information** - Browser, viewport, memory, language
|
||||
- 🔍 **Message filtering** - Filter by error/warn/info/debug levels
|
||||
- 💾 **Export logs** - Download debug session as JSON
|
||||
- ⏸️ **Pause/Resume** - Control message recording
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable Debug Control
|
||||
|
||||
**Important**: Debug control is **disabled by default**. You must explicitly enable it:
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
debugControl: true // Enable debug panel (default: false)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
debugControl: true
|
||||
},
|
||||
controlPositions: {
|
||||
debugControl: 'w' // West (default), or: nw, ne, e, se, s, sw
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Console Message Capture
|
||||
|
||||
The Debug Control automatically captures all console output.
|
||||
|
||||
#### Captured Methods
|
||||
|
||||
- `console.log()` → INFO messages
|
||||
- `console.error()` → ERROR messages
|
||||
- `console.warn()` → WARN messages
|
||||
- `console.info()` → INFO messages
|
||||
- `console.debug()` → DEBUG messages
|
||||
|
||||
#### How It Works
|
||||
|
||||
**Initialization**:
|
||||
1. Saves original console methods
|
||||
2. Overrides each method with custom wrapper
|
||||
3. Wrapper calls original method (preserves normal console behavior)
|
||||
4. Wrapper also logs to Debug Control
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
console.log('Application started');
|
||||
// ✅ Shows in browser console (normal)
|
||||
// ✅ Shows in Debug Control (captured)
|
||||
```
|
||||
|
||||
**Restoration**:
|
||||
When Debug Control is destroyed, original console methods are restored.
|
||||
|
||||
#### Message Structure
|
||||
|
||||
Each captured message includes:
|
||||
- **Category**: LOG, ERROR, WARN, INFO, DEBUG
|
||||
- **Timestamp**: Absolute time (HH:MM:SS)
|
||||
- **Relative time**: Milliseconds since session start
|
||||
- **Message**: Combined text from all arguments
|
||||
- **Level**: error, warn, info, debug (for filtering)
|
||||
|
||||
---
|
||||
|
||||
### 2. Error Tracking
|
||||
|
||||
Captures errors automatically without requiring try/catch blocks.
|
||||
|
||||
#### Global Error Capture
|
||||
|
||||
**Window errors**:
|
||||
```javascript
|
||||
window.addEventListener('error', (event) => {
|
||||
// Captured: message, filename, line number
|
||||
});
|
||||
```
|
||||
|
||||
**Example captured error**:
|
||||
```
|
||||
ERROR: Uncaught TypeError: Cannot read property 'foo' of undefined at script.js:42
|
||||
```
|
||||
|
||||
#### Unhandled Promise Rejections
|
||||
|
||||
**Promise rejections**:
|
||||
```javascript
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
// Captured: rejection reason
|
||||
});
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
fetch('/api/data')
|
||||
.then(res => res.json())
|
||||
// No .catch() - rejection captured automatically
|
||||
```
|
||||
|
||||
**Captured message**:
|
||||
```
|
||||
PROMISE_REJECT: Unhandled promise rejection: NetworkError: Failed to fetch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. System Information
|
||||
|
||||
Displays comprehensive browser and environment details.
|
||||
|
||||
#### Displayed Information
|
||||
|
||||
| Property | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| **Markitect** | Version number | 1.0.0 |
|
||||
| **Viewport** | Window dimensions | 1920x1080 |
|
||||
| **Screen** | Physical display size | 2560x1440 |
|
||||
| **Memory** | JavaScript heap usage | Used: 45MB |
|
||||
| **Language** | Browser language | en-US |
|
||||
| **Status** | Online/offline | Online |
|
||||
| **Protocol** | HTTP/HTTPS | https: |
|
||||
|
||||
**Additional info** (not displayed but available):
|
||||
- User agent string
|
||||
- Color depth
|
||||
- Timezone
|
||||
- Cookies enabled
|
||||
|
||||
#### Memory Information
|
||||
|
||||
**Note**: `performance.memory` is only available in Chrome/Edge with `--enable-precise-memory-info` flag.
|
||||
|
||||
**Fallback**: Shows "Not available" if memory API unavailable
|
||||
|
||||
---
|
||||
|
||||
### 4. Performance Metrics
|
||||
|
||||
Real-time performance monitoring.
|
||||
|
||||
#### Metrics Displayed
|
||||
|
||||
| Metric | Description | Calculation |
|
||||
|--------|-------------|-------------|
|
||||
| **Page Load** | Total page load time | loadEventEnd - navigationStart |
|
||||
| **DOM Ready** | DOM parsing complete | domContentLoadedEventEnd - navigationStart |
|
||||
| **First Byte** | Time to first response byte | responseStart - navigationStart |
|
||||
| **Session Time** | Time since Debug Control started | Current time - startTime |
|
||||
| **Debug Messages** | Total messages captured | messages.length |
|
||||
|
||||
**Units**: Milliseconds for load metrics, seconds for session time
|
||||
|
||||
**Example display**:
|
||||
```
|
||||
Page Load: 1247ms
|
||||
DOM Ready: 892ms
|
||||
First Byte: 124ms
|
||||
Session Time: 45s
|
||||
Debug Messages: 37
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Message Filtering
|
||||
|
||||
Filter messages by level to focus on specific types.
|
||||
|
||||
#### Filter Options
|
||||
|
||||
- **ALL** - Show all messages (default)
|
||||
- **ERROR** - Only error messages
|
||||
- **WARN** - Only warnings
|
||||
- **INFO** - Only info messages
|
||||
- **DEBUG** - Only debug messages
|
||||
|
||||
#### Usage
|
||||
|
||||
Click filter button in Debug Control panel.
|
||||
|
||||
**Visual feedback**:
|
||||
- Active filter: Blue button
|
||||
- Inactive filters: Gray buttons
|
||||
|
||||
**Status display**: Shows "Filter: ERROR | Messages: 5/37"
|
||||
- 5 = filtered count
|
||||
- 37 = total count
|
||||
|
||||
---
|
||||
|
||||
### 6. Message Display
|
||||
|
||||
Shows last 20 messages in scrollable container.
|
||||
|
||||
#### Message Appearance
|
||||
|
||||
**Color coding**:
|
||||
- **Error**: Red border, red badge (#dc3545)
|
||||
- **Warn**: Yellow border, yellow badge (#ffc107)
|
||||
- **Info**: Teal border, teal badge (#17a2b8)
|
||||
- **Debug**: Gray border, gray badge (#6c757d)
|
||||
|
||||
**Message format**:
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ [ERROR] 14:32:15 │
|
||||
│ Cannot read property 'x' │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
**Auto-scroll**: Enabled by default, scrolls to newest message
|
||||
|
||||
#### Message Limit
|
||||
|
||||
**Max messages**: 100 (oldest messages are discarded)
|
||||
|
||||
**Displayed**: Last 20 messages visible in panel
|
||||
|
||||
**Reason**: Prevent memory issues with long sessions
|
||||
|
||||
---
|
||||
|
||||
### 7. Control Actions
|
||||
|
||||
Four action buttons for managing debug session.
|
||||
|
||||
#### 🗑️ Clear
|
||||
|
||||
Removes all captured messages.
|
||||
|
||||
**Usage**: Click "🗑️ Clear" button
|
||||
|
||||
**Effect**:
|
||||
- Empties messages array
|
||||
- Clears display
|
||||
- Also clears MarkitectDebugSystem if present
|
||||
|
||||
**Use case**: Start fresh debugging session
|
||||
|
||||
#### 💾 Export
|
||||
|
||||
Download debug log as JSON file.
|
||||
|
||||
**Usage**: Click "💾 Export" button
|
||||
|
||||
**File contents**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-16T14:30:52.123Z",
|
||||
"session": {
|
||||
"startTime": "2025-12-16T14:25:12.456Z",
|
||||
"duration": 340000,
|
||||
"messageCount": 37
|
||||
},
|
||||
"system": {
|
||||
"userAgent": "Mozilla/5.0...",
|
||||
"viewport": "1920x1080",
|
||||
"url": "http://localhost:8080/editor.html"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"id": 1702742452123.456,
|
||||
"timestamp": 1702742452123,
|
||||
"category": "ERROR",
|
||||
"message": "Cannot read property...",
|
||||
"level": "error",
|
||||
"displayTime": "14:32:15",
|
||||
"relativeTime": 123456
|
||||
}
|
||||
// ... more messages
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Filename**: `debug-log-YYYY-MM-DD.json`
|
||||
|
||||
**Use cases**:
|
||||
- Share logs with team
|
||||
- Attach to bug reports
|
||||
- Archive for analysis
|
||||
|
||||
#### ⏸️ Pause / ▶️ Record
|
||||
|
||||
Toggle message capture on/off.
|
||||
|
||||
**Usage**: Click "⏸️ Pause" or "▶️ Record" button
|
||||
|
||||
**States**:
|
||||
- **Recording** (▶️): Yellow button, captures messages
|
||||
- **Paused** (⏸️): Gray button, ignores new messages
|
||||
|
||||
**Use case**: Pause during noisy operations, resume for specific testing
|
||||
|
||||
**Status indicator**: Shows "Recording: 🟢 Active" or "🔴 Paused" at bottom
|
||||
|
||||
#### 🧪 Test
|
||||
|
||||
Add random test message to verify Debug Control is working.
|
||||
|
||||
**Usage**: Click "🧪 Test" button
|
||||
|
||||
**Generates**: Random message from:
|
||||
- "This is a test info message" (INFO)
|
||||
- "This is a test warning message" (WARN)
|
||||
- "This is a test error message" (ERROR)
|
||||
- "This is a test debug message" (DEBUG)
|
||||
|
||||
**Use case**: Verify Debug Control is capturing and displaying correctly
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage (Development Mode)
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
markdown: '# My Document',
|
||||
controls: {
|
||||
editControl: true,
|
||||
statusControl: true,
|
||||
contentsControl: true,
|
||||
debugControl: true // Enable for development
|
||||
}
|
||||
});
|
||||
|
||||
// Debug messages will be captured
|
||||
console.log('Editor initialized');
|
||||
console.error('Oops, something went wrong');
|
||||
```
|
||||
|
||||
### Production Mode (Debug Disabled)
|
||||
|
||||
```javascript
|
||||
// Default: debug control is OFF
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
debugControl: false // Explicit disable (default)
|
||||
}
|
||||
});
|
||||
|
||||
// Console still works normally, just not captured
|
||||
console.log('Normal console output');
|
||||
```
|
||||
|
||||
### Environment-Based Configuration
|
||||
|
||||
```javascript
|
||||
const isDevelopment = window.location.hostname === 'localhost';
|
||||
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
debugControl: isDevelopment // Auto-enable in dev
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Error Reporting
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: { debugControl: true }
|
||||
});
|
||||
|
||||
// Add custom error handler
|
||||
window.addEventListener('error', (event) => {
|
||||
// Send to analytics
|
||||
fetch('/api/errors', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
message: event.message,
|
||||
filename: event.filename,
|
||||
lineno: event.lineno,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Properties
|
||||
|
||||
Access via `editor.debugControl`:
|
||||
|
||||
```javascript
|
||||
const debugCtrl = editor.debugControl;
|
||||
|
||||
// Message storage
|
||||
debugCtrl.messages = [
|
||||
{
|
||||
id: 1702742452123.456,
|
||||
timestamp: 1702742452123,
|
||||
category: 'ERROR',
|
||||
message: 'Error text',
|
||||
level: 'error',
|
||||
displayTime: '14:32:15',
|
||||
relativeTime: 123456
|
||||
},
|
||||
// ... more messages
|
||||
];
|
||||
|
||||
// Configuration
|
||||
debugCtrl.maxMessages = 100; // Message limit
|
||||
debugCtrl.messageFilter = 'all'; // Current filter
|
||||
debugCtrl.autoScroll = true; // Auto-scroll enabled
|
||||
debugCtrl.isRecording = true; // Recording state
|
||||
debugCtrl.startTime = 1702742452000; // Session start
|
||||
|
||||
// Original console methods (for restoration)
|
||||
debugCtrl.originalConsole = {
|
||||
log: Function,
|
||||
error: Function,
|
||||
warn: Function,
|
||||
info: Function,
|
||||
debug: Function
|
||||
};
|
||||
|
||||
// Performance marks
|
||||
debugCtrl.performanceMarks = new Map();
|
||||
|
||||
// Control config
|
||||
debugCtrl.config.position = 'w'; // Compass position
|
||||
debugCtrl.config.icon = '🐛'; // Panel icon
|
||||
debugCtrl.config.title = 'Debug'; // Panel title
|
||||
debugCtrl.isExpanded; // true if expanded
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
```javascript
|
||||
const debugCtrl = editor.debugControl;
|
||||
|
||||
// Add debug message programmatically
|
||||
debugCtrl.addDebugMessage('CUSTOM', 'Custom message text', 'info');
|
||||
// Parameters: category, message, level
|
||||
|
||||
// Get filtered messages
|
||||
const filtered = debugCtrl.getFilteredMessages();
|
||||
// Returns: Array of messages matching current filter
|
||||
|
||||
// Clear all messages
|
||||
debugCtrl.clearMessages();
|
||||
|
||||
// Export messages to JSON file
|
||||
debugCtrl.exportMessages();
|
||||
|
||||
// Toggle recording on/off
|
||||
debugCtrl.toggleRecording();
|
||||
|
||||
// Add test message
|
||||
debugCtrl.addTestMessage();
|
||||
|
||||
// Set message filter
|
||||
debugCtrl.setMessageFilter('error'); // 'all', 'error', 'warn', 'info', 'debug'
|
||||
|
||||
// Generate HTML components
|
||||
const systemInfoHTML = debugCtrl.generateSystemInfoHTML();
|
||||
const performanceHTML = debugCtrl.generatePerformanceHTML();
|
||||
const messagesHTML = debugCtrl.generateMessagesHTML();
|
||||
const buttonsHTML = debugCtrl.generateControlButtonsHTML();
|
||||
const filterHTML = debugCtrl.generateFilterControlsHTML();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Message Categories
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: { debugControl: true }
|
||||
});
|
||||
|
||||
// Add custom category messages
|
||||
editor.debugControl.addDebugMessage('DATABASE', 'Query executed in 45ms', 'info');
|
||||
editor.debugControl.addDebugMessage('API', 'Request to /api/users completed', 'info');
|
||||
editor.debugControl.addDebugMessage('AUTH', 'User authentication failed', 'error');
|
||||
```
|
||||
|
||||
### Performance Marking
|
||||
|
||||
```javascript
|
||||
const debugCtrl = editor.debugControl;
|
||||
|
||||
// Mark start of operation
|
||||
debugCtrl.performanceMarks.set('render-start', Date.now());
|
||||
|
||||
// ... perform rendering ...
|
||||
|
||||
// Mark end and calculate duration
|
||||
const startTime = debugCtrl.performanceMarks.get('render-start');
|
||||
const duration = Date.now() - startTime;
|
||||
debugCtrl.addDebugMessage('PERF', `Rendering took ${duration}ms`, 'debug');
|
||||
```
|
||||
|
||||
### Conditional Logging
|
||||
|
||||
```javascript
|
||||
const DEBUG_ENABLED = true;
|
||||
|
||||
function debugLog(message) {
|
||||
if (DEBUG_ENABLED && editor.debugControl) {
|
||||
editor.debugControl.addDebugMessage('APP', message, 'debug');
|
||||
}
|
||||
}
|
||||
|
||||
debugLog('User clicked save button');
|
||||
debugLog('Validation passed');
|
||||
```
|
||||
|
||||
### Batch Export on Error
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: { debugControl: true }
|
||||
});
|
||||
|
||||
// Auto-export logs when critical error occurs
|
||||
window.addEventListener('error', (event) => {
|
||||
if (event.message.includes('Critical')) {
|
||||
editor.debugControl.exportMessages();
|
||||
alert('Critical error logged. Debug log downloaded.');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Monitor Specific Functions
|
||||
|
||||
```javascript
|
||||
function monitorFunction(fn, name) {
|
||||
return function(...args) {
|
||||
const startTime = performance.now();
|
||||
editor.debugControl.addDebugMessage('CALL', `${name} called with args: ${JSON.stringify(args)}`, 'debug');
|
||||
|
||||
try {
|
||||
const result = fn.apply(this, args);
|
||||
const duration = performance.now() - startTime;
|
||||
editor.debugControl.addDebugMessage('RESULT', `${name} completed in ${duration.toFixed(2)}ms`, 'info');
|
||||
return result;
|
||||
} catch (error) {
|
||||
editor.debugControl.addDebugMessage('ERROR', `${name} failed: ${error.message}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Use monitored function
|
||||
const saveDocument = monitorFunction(originalSaveFunction, 'saveDocument');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Debug Control Not Appearing
|
||||
|
||||
**Problem**: Panel doesn't show even when enabled
|
||||
|
||||
**Solutions**:
|
||||
1. Verify configuration:
|
||||
```javascript
|
||||
console.log(editor.config.controls.debugControl); // Should be true
|
||||
```
|
||||
|
||||
2. Check if DebugControl is loaded:
|
||||
```javascript
|
||||
console.log(typeof DebugControl); // Should be 'function'
|
||||
```
|
||||
|
||||
3. Verify instance exists:
|
||||
```javascript
|
||||
console.log(editor.debugControl); // Should be object
|
||||
```
|
||||
|
||||
4. Check browser console for errors
|
||||
|
||||
### Messages Not Captured
|
||||
|
||||
**Problem**: Console messages don't appear in Debug Control
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check recording status**:
|
||||
```javascript
|
||||
console.log(editor.debugControl.isRecording); // Should be true
|
||||
```
|
||||
|
||||
2. **Verify console override**:
|
||||
```javascript
|
||||
console.log(typeof editor.debugControl.originalConsole); // Should be 'object'
|
||||
```
|
||||
|
||||
3. **Test manually**:
|
||||
```javascript
|
||||
editor.debugControl.addDebugMessage('TEST', 'Manual test', 'info');
|
||||
```
|
||||
|
||||
4. **Check if panel is expanded**: Click the 🐛 icon to expand
|
||||
|
||||
### Performance Issues
|
||||
|
||||
**Problem**: Debug Control slows down application
|
||||
|
||||
**Causes & Solutions**:
|
||||
|
||||
1. **Too many messages**:
|
||||
- Clear messages regularly
|
||||
- Reduce maxMessages:
|
||||
```javascript
|
||||
editor.debugControl.maxMessages = 50; // Lower limit
|
||||
```
|
||||
|
||||
2. **Noisy logging**:
|
||||
- Pause recording during intensive operations:
|
||||
```javascript
|
||||
editor.debugControl.toggleRecording(); // Pause
|
||||
// ... intensive work ...
|
||||
editor.debugControl.toggleRecording(); // Resume
|
||||
```
|
||||
|
||||
3. **Disable in production**:
|
||||
```javascript
|
||||
controls: {
|
||||
debugControl: process.env.NODE_ENV === 'development'
|
||||
}
|
||||
```
|
||||
|
||||
### Export Not Working
|
||||
|
||||
**Problem**: Export button doesn't download file
|
||||
|
||||
**Solutions**:
|
||||
1. Check browser download permissions
|
||||
2. Verify popup/download blocker settings
|
||||
3. Test programmatically:
|
||||
```javascript
|
||||
editor.debugControl.exportMessages();
|
||||
```
|
||||
4. Check browser console for errors
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Development
|
||||
|
||||
1. **Enable only in development**:
|
||||
```javascript
|
||||
debugControl: window.location.hostname === 'localhost'
|
||||
```
|
||||
|
||||
2. **Use meaningful categories**:
|
||||
```javascript
|
||||
addDebugMessage('USER_ACTION', 'Clicked save', 'info');
|
||||
addDebugMessage('VALIDATION', 'Email format invalid', 'warn');
|
||||
```
|
||||
|
||||
3. **Export before refreshing**: Save logs if you need to refresh page
|
||||
|
||||
4. **Clear between tests**: Start fresh for each test scenario
|
||||
|
||||
### For QA/Testing
|
||||
|
||||
1. **Enable for bug reproduction**:
|
||||
```javascript
|
||||
controls: { debugControl: true }
|
||||
```
|
||||
|
||||
2. **Export logs with bug reports**: Include debug-log.json
|
||||
|
||||
3. **Filter by ERROR**: Focus on failures
|
||||
|
||||
4. **Track timing**: Monitor performance metrics
|
||||
|
||||
### For Production Debugging
|
||||
|
||||
**Generally**: Keep debug control **disabled** in production
|
||||
|
||||
**Exception**: Enable temporarily for specific user sessions:
|
||||
|
||||
```javascript
|
||||
// Enable debug for admin users only
|
||||
const isAdmin = checkUserRole();
|
||||
const editor = new TestDriveJSUI({
|
||||
controls: {
|
||||
debugControl: isAdmin
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Security note**: Debug logs may contain sensitive information (URLs, user actions). Don't expose in production.
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Memory Usage
|
||||
|
||||
**Per message**: ~200 bytes (category, message, timestamps)
|
||||
- 100 messages: ~20 KB
|
||||
- 1000 messages: ~200 KB
|
||||
|
||||
**Max limit**: Default 100 messages prevents unbounded growth
|
||||
|
||||
### CPU Impact
|
||||
|
||||
**Console override**: Minimal overhead (~0.1ms per message)
|
||||
|
||||
**Display updates**: Only when panel is expanded
|
||||
|
||||
**Auto-scroll**: Negligible performance impact
|
||||
|
||||
### Recommendations
|
||||
|
||||
1. **Disable in production**: Saves memory and CPU
|
||||
2. **Lower maxMessages for long sessions**: Prevent accumulation
|
||||
3. **Pause during intensive operations**: Reduce overhead
|
||||
4. **Export and clear periodically**: Free memory
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Edit Control](edit-control.md)** - Document actions
|
||||
- **[Status Control](status-control.md)** - Document statistics
|
||||
- **[Contents Control](contents-control.md)** - Navigation
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [API Reference](../api/debug-control.md)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
458
docs/features/edit-control.md
Normal file
458
docs/features/edit-control.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# Edit Control
|
||||
|
||||
**Document actions and editing tools** 📝
|
||||
|
||||
The Edit Control provides comprehensive document-level actions including save, export, print, navigation tools, text formatting, and markdown shortcuts. Positioned in the northeast by default.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Edit Control is your command center for document-wide operations. It groups related actions into organized sections for easy access.
|
||||
|
||||
### Position
|
||||
- **Default**: Northeast (ne) - top-right corner
|
||||
- **Appearance**: ✏️ icon when collapsed
|
||||
- **Title**: "Edit"
|
||||
|
||||
### Key Features
|
||||
|
||||
- 📄 Document actions (save, print, export, reset)
|
||||
- 🧭 Navigation tools (scroll to top/bottom, go to line)
|
||||
- 🔍 Text tools (find & replace, font size)
|
||||
- ✍️ Markdown shortcuts (bold, italic, headers, links)
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable/Disable
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
editControl: true // Enable (default: true)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
editControl: 'ne' // Northeast (default), or: nw, e, se, s, sw, w
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Document Actions
|
||||
|
||||
#### 🖨️ Print Document
|
||||
Opens browser print dialog for the current document.
|
||||
|
||||
**Usage**:
|
||||
- Click "Print Document" button
|
||||
- Or use keyboard shortcut: `Ctrl+P`
|
||||
|
||||
**What happens**:
|
||||
- Formats document for printing
|
||||
- Opens browser print dialog
|
||||
- Preserves markdown formatting
|
||||
|
||||
#### 💾 Save Changes
|
||||
Downloads the current document as a markdown file.
|
||||
|
||||
**Usage**:
|
||||
- Click "Save Changes" button
|
||||
- Or use keyboard shortcut: `Ctrl+S`
|
||||
|
||||
**Behavior**:
|
||||
- Generates timestamped filename
|
||||
- Downloads as `.md` file
|
||||
- Includes all accepted edits
|
||||
|
||||
**Example filename**: `document-edited-2025-12-16-143052.md`
|
||||
|
||||
#### 📄 Export Document
|
||||
Export document in various formats.
|
||||
|
||||
**Usage**:
|
||||
- Click "Export Document" button
|
||||
- Choose format in dialog
|
||||
|
||||
**Formats** (coming soon):
|
||||
- Markdown (`.md`)
|
||||
- HTML (`.html`)
|
||||
- PDF (`.pdf`)
|
||||
- Plain text (`.txt`)
|
||||
|
||||
#### 🔄 Reset All
|
||||
Resets all sections to their original content.
|
||||
|
||||
**Usage**:
|
||||
- Click "Reset All" button
|
||||
- Confirm in dialog
|
||||
|
||||
**Warning**: This discards ALL changes! Cannot be undone.
|
||||
|
||||
---
|
||||
|
||||
### 2. Navigation Tools
|
||||
|
||||
#### ⬆️ Scroll to Top
|
||||
Instantly scrolls to the beginning of the document.
|
||||
|
||||
**Usage**:
|
||||
- Click "Top" button
|
||||
- Smooth scroll animation
|
||||
|
||||
#### ⬇️ Scroll to Bottom
|
||||
Instantly scrolls to the end of the document.
|
||||
|
||||
**Usage**:
|
||||
- Click "Bottom" button
|
||||
- Smooth scroll animation
|
||||
|
||||
#### 🎯 Go to Line
|
||||
Jump to a specific line or section in the document.
|
||||
|
||||
**Usage**:
|
||||
- Click "Go to Line" button
|
||||
- Enter line number or section name
|
||||
- Press Enter to navigate
|
||||
|
||||
---
|
||||
|
||||
### 3. Text Tools
|
||||
|
||||
#### 🔍 Find & Replace
|
||||
Search and replace text across the document.
|
||||
|
||||
**Usage**:
|
||||
- Click "Find & Replace" button
|
||||
- Or use keyboard shortcut: `Ctrl+F`
|
||||
|
||||
**Features**:
|
||||
- Case-sensitive option
|
||||
- Replace one or all occurrences
|
||||
- Regex support (coming soon)
|
||||
- Highlight matches
|
||||
|
||||
#### 🔍+ / 🔍- Font Size
|
||||
Adjust document font size for better readability.
|
||||
|
||||
**Usage**:
|
||||
- Click "🔍+ Font" to increase
|
||||
- Click "🔍- Font" to decrease
|
||||
|
||||
**Range**: 12px - 24px
|
||||
|
||||
**Tip**: Useful for presentations or accessibility
|
||||
|
||||
#### 📋 Copy Page Link
|
||||
Copies the current page URL to clipboard.
|
||||
|
||||
**Usage**:
|
||||
- Click "Copy Page Link" button
|
||||
- Link copied to clipboard
|
||||
- Paste anywhere with `Ctrl+V`
|
||||
|
||||
---
|
||||
|
||||
### 4. Markdown Tools
|
||||
|
||||
Quick markdown formatting shortcuts.
|
||||
|
||||
#### **B** Bold
|
||||
Wraps selected text in `**bold**` markers.
|
||||
|
||||
**Usage**:
|
||||
- Select text
|
||||
- Click "B" button
|
||||
- Or use: `Ctrl+B`
|
||||
|
||||
**Result**: `**selected text**`
|
||||
|
||||
#### *I* Italic
|
||||
Wraps selected text in `*italic*` markers.
|
||||
|
||||
**Usage**:
|
||||
- Select text
|
||||
- Click "I" button
|
||||
- Or use: `Ctrl+I`
|
||||
|
||||
**Result**: `*selected text*`
|
||||
|
||||
#### # Header
|
||||
Converts line to heading.
|
||||
|
||||
**Levels**:
|
||||
- H1: `# Heading`
|
||||
- H2: `## Heading`
|
||||
- H3: `### Heading`
|
||||
|
||||
#### 🔗 Link
|
||||
Inserts markdown link format.
|
||||
|
||||
**Usage**:
|
||||
- Click "Link" button
|
||||
- Inserts: `[text](url)`
|
||||
|
||||
#### 📋 Code
|
||||
Wraps text in code markers.
|
||||
|
||||
**Inline**: `` `code` ``
|
||||
**Block**:
|
||||
```
|
||||
```language
|
||||
code block
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
markdown: '# My Document\n\nContent here...',
|
||||
controls: {
|
||||
editControl: true
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position
|
||||
|
||||
```javascript
|
||||
// Move to northwest (top-left)
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
editControl: 'nw' // Top-left instead of top-right
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### With Event Tracking
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: { editControl: true }
|
||||
});
|
||||
|
||||
// Listen to save events
|
||||
editor.on('save', (data) => {
|
||||
console.log('Document saved:', data.markdown);
|
||||
// Send to backend, update UI, etc.
|
||||
});
|
||||
|
||||
// Access edit control directly
|
||||
if (editor.editControl) {
|
||||
// Programmatically trigger actions
|
||||
editor.editControl.saveDocument();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Methods
|
||||
|
||||
Access via `editor.editControl`:
|
||||
|
||||
```javascript
|
||||
const editCtrl = editor.editControl;
|
||||
|
||||
// Document actions
|
||||
editCtrl.printDocument(); // Open print dialog
|
||||
editCtrl.saveDocument(); // Download as .md
|
||||
editCtrl.exportDocument(); // Export in format
|
||||
editCtrl.resetAll(); // Reset all sections
|
||||
|
||||
// Navigation
|
||||
editCtrl.scrollToTop(); // Scroll to top
|
||||
editCtrl.scrollToBottom(); // Scroll to bottom
|
||||
editCtrl.showGoToLine(); // Show go-to dialog
|
||||
|
||||
// Text tools
|
||||
editCtrl.showFindReplace(); // Open find & replace
|
||||
editCtrl.increaseFontSize(); // Increase font
|
||||
editCtrl.decreaseFontSize(); // Decrease font
|
||||
editCtrl.copyLink(); // Copy page URL
|
||||
|
||||
// Markdown tools
|
||||
editCtrl.insertMarkdown(before, after, placeholder);
|
||||
// Example: insertMarkdown('**', '**', 'bold text')
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
```javascript
|
||||
editCtrl.config.position // Current position (e.g., 'ne')
|
||||
editCtrl.config.icon // Icon emoji ('✏️')
|
||||
editCtrl.config.title // Panel title ('Edit')
|
||||
editCtrl.isExpanded // true if panel expanded
|
||||
editCtrl.fontSize // Current font size (px)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
The Edit Control provides these shortcuts:
|
||||
|
||||
| Shortcut | Action |
|
||||
|----------|--------|
|
||||
| `Ctrl+S` | Save document |
|
||||
| `Ctrl+P` | Print document |
|
||||
| `Ctrl+F` | Find & replace |
|
||||
| `Ctrl+B` | Bold selected text |
|
||||
| `Ctrl+I` | Italic selected text |
|
||||
| `Escape` | Exit edit mode |
|
||||
|
||||
**Enable/disable**:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
shortcuts: true // Enable shortcuts (default: true)
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
### Disable Specific Actions
|
||||
|
||||
Currently, all Edit Control actions are enabled by default. To hide the control entirely:
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
editControl: false // Hide completely
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Future: Granular Control
|
||||
|
||||
Planned for v1.1:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
editControl: {
|
||||
enabled: true,
|
||||
actions: {
|
||||
print: true,
|
||||
save: true,
|
||||
export: false, // Hide export
|
||||
reset: false // Hide reset
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Writers
|
||||
|
||||
1. **Save frequently** - Use `Ctrl+S` or Save button regularly
|
||||
2. **Use shortcuts** - Learn `Ctrl+B`, `Ctrl+I` for quick formatting
|
||||
3. **Navigate efficiently** - Use Top/Bottom for long documents
|
||||
4. **Find & Replace** - Bulk edit repetitive content
|
||||
|
||||
### For Developers
|
||||
|
||||
1. **Listen to events** - Track saves for auto-sync
|
||||
2. **Custom save handlers** - Override default behavior
|
||||
3. **Programmatic control** - Trigger actions via API
|
||||
4. **Error handling** - Catch save failures
|
||||
|
||||
Example custom save:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
editor.on('save', async (data) => {
|
||||
try {
|
||||
// Send to backend
|
||||
await fetch('/api/save', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ markdown: data.markdown })
|
||||
});
|
||||
alert('Saved to server!');
|
||||
} catch (error) {
|
||||
alert('Save failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Save Changes" Not Working
|
||||
|
||||
**Problem**: Clicking save does nothing
|
||||
|
||||
**Solutions**:
|
||||
1. Check browser console for errors
|
||||
2. Verify EditControl is loaded: `typeof EditControl !== 'undefined'`
|
||||
3. Check if control is enabled in config
|
||||
4. Test programmatically: `editor.editControl.saveDocument()`
|
||||
|
||||
### Print Dialog Not Opening
|
||||
|
||||
**Problem**: Print button doesn't open dialog
|
||||
|
||||
**Solutions**:
|
||||
1. Check browser pop-up blocker
|
||||
2. Test with `Ctrl+P` keyboard shortcut
|
||||
3. Verify browser print permissions
|
||||
4. Try programmatically: `window.print()`
|
||||
|
||||
### Font Size Not Changing
|
||||
|
||||
**Problem**: Font buttons don't affect text size
|
||||
|
||||
**Solutions**:
|
||||
1. Check CSS conflicts with `font-size: inherit`
|
||||
2. Inspect element to verify font-size style applied
|
||||
3. Clear browser cache
|
||||
4. Test with browser zoom instead
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Section Editing](section-editing.md)** - Edit individual sections
|
||||
- **[Keyboard Shortcuts](keyboard-shortcuts.md)** - All available shortcuts
|
||||
- **[Status Control](status-control.md)** - Track editing progress
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [API Reference](../api/edit-control.md)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
673
docs/features/keyboard-shortcuts.md
Normal file
673
docs/features/keyboard-shortcuts.md
Normal file
@@ -0,0 +1,673 @@
|
||||
# Keyboard Shortcuts
|
||||
|
||||
**Quick actions via keyboard** ⌨️
|
||||
|
||||
TestDrive-JSUI provides comprehensive keyboard shortcuts for efficient document editing and navigation. All shortcuts are enabled by default and work across all browsers. Keyboard shortcuts improve accessibility and productivity for power users.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Keyboard shortcuts provide fast access to common actions without reaching for the mouse. They're organized by context: global shortcuts, section editing shortcuts, and control-specific shortcuts.
|
||||
|
||||
### Quick Reference
|
||||
|
||||
| Shortcut | Action | Context |
|
||||
|----------|--------|---------|
|
||||
| `Ctrl+S` | Save document | Global |
|
||||
| `Escape` | Close editor/dialog | Global |
|
||||
| `Ctrl+Enter` | Accept changes | Section editing |
|
||||
| `Ctrl+P` | Print document | Document (planned) |
|
||||
| `Ctrl+F` | Find & replace | Document (planned) |
|
||||
| `Ctrl+B` | Bold text | Text editing (planned) |
|
||||
| `Ctrl+I` | Italic text | Text editing (planned) |
|
||||
| `Tab` | Indent | Section editing |
|
||||
|
||||
**Note**: On macOS, `Ctrl` can be replaced with `Cmd` (⌘) for most shortcuts.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable/Disable Shortcuts
|
||||
|
||||
Keyboard shortcuts are **enabled by default**. To disable:
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
shortcuts: false // Disable all keyboard shortcuts
|
||||
});
|
||||
```
|
||||
|
||||
**When to disable**:
|
||||
- Conflict with existing application shortcuts
|
||||
- Custom keyboard handling required
|
||||
- Accessibility requirement for specific workflow
|
||||
|
||||
### Check Shortcut Status
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
console.log(editor.config.shortcuts); // true or false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Global Shortcuts
|
||||
|
||||
Available throughout the application, regardless of focus.
|
||||
|
||||
### Ctrl+S (Save Document)
|
||||
|
||||
**Action**: Save/download current document as markdown file
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+S`
|
||||
- macOS: `Cmd+S` (⌘S)
|
||||
|
||||
**Behavior**:
|
||||
1. Prevents browser's default save behavior
|
||||
2. Calls `editor.save()` method
|
||||
3. Downloads file with timestamped name: `document-edited-YYYY-MM-DD-HHMMSS.md`
|
||||
4. Triggers `save` event for custom handlers
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Listen to save event
|
||||
editor.on('save', (data) => {
|
||||
console.log('Document saved via Ctrl+S');
|
||||
console.log('Content:', data.markdown);
|
||||
});
|
||||
|
||||
// User presses Ctrl+S → save event fires
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Quick save during writing
|
||||
- Prevent accidental data loss
|
||||
- Trigger auto-upload to server
|
||||
|
||||
---
|
||||
|
||||
### Escape (Close Editor/Dialog)
|
||||
|
||||
**Action**: Close active floating editor or dialog
|
||||
|
||||
**Platforms**: All (no modifier key needed)
|
||||
|
||||
**Behavior**:
|
||||
1. Checks for active floating menu
|
||||
2. Closes section editor if open
|
||||
3. Cancels current edit operation
|
||||
4. Returns focus to document
|
||||
|
||||
**Contexts**:
|
||||
- **Section editing**: Cancels edit, discards changes
|
||||
- **Find & replace**: Closes find dialog (planned)
|
||||
- **Go to line**: Closes navigation dialog (planned)
|
||||
- **Image editor**: Closes image editor (planned)
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
// User clicks section to edit
|
||||
// Section editor opens with textarea
|
||||
// User presses Escape
|
||||
// → Editor closes, changes discarded
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Quick cancel during editing
|
||||
- Close dialogs without mouse
|
||||
- Keyboard-only workflow
|
||||
|
||||
---
|
||||
|
||||
## Section Editing Shortcuts
|
||||
|
||||
Active when editing a section (textarea has focus).
|
||||
|
||||
### Ctrl+Enter (Accept Changes)
|
||||
|
||||
**Action**: Accept changes and close section editor
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+Enter`
|
||||
- macOS: `Cmd+Enter` (⌘Enter)
|
||||
|
||||
**Behavior**:
|
||||
1. Prevents default Enter behavior (new line)
|
||||
2. Applies changes to section
|
||||
3. Closes floating editor
|
||||
4. Updates rendered markdown
|
||||
5. Triggers `changes-accepted` event
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
editor.sectionManager.on('changes-accepted', (data) => {
|
||||
console.log('Section updated via Ctrl+Enter');
|
||||
console.log('New content:', data.content);
|
||||
});
|
||||
|
||||
// User edits section, presses Ctrl+Enter
|
||||
// → Changes applied, editor closes
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Fast editing workflow
|
||||
- Apply changes without clicking Accept button
|
||||
- Keyboard-only editing
|
||||
|
||||
**Alternative**: Click "✓ Accept" button
|
||||
|
||||
---
|
||||
|
||||
### Escape (Cancel Section Edit)
|
||||
|
||||
**Action**: Cancel editing and discard changes
|
||||
|
||||
**Platforms**: All
|
||||
|
||||
**Behavior**:
|
||||
1. Restores original section content
|
||||
2. Closes floating editor
|
||||
3. No changes applied
|
||||
4. Triggers `changes-cancelled` event
|
||||
|
||||
**Example**:
|
||||
```javascript
|
||||
// User clicks section, makes edits
|
||||
// User presses Escape
|
||||
// → Editor closes, original content restored
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Discard unwanted changes quickly
|
||||
- Exit edit mode without saving
|
||||
- Keyboard-only workflow
|
||||
|
||||
**Alternative**: Click "✗ Cancel" button
|
||||
|
||||
---
|
||||
|
||||
### Tab (Indent)
|
||||
|
||||
**Action**: Insert tab character (4 spaces)
|
||||
|
||||
**Platforms**: All
|
||||
|
||||
**Behavior**:
|
||||
1. Inserts 4 spaces at cursor position
|
||||
2. Does not move focus to next element
|
||||
3. Useful for code blocks and lists
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
Before: |cursor here
|
||||
|
||||
After pressing Tab:
|
||||
|cursor here
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Indent code in code blocks
|
||||
- Create nested lists
|
||||
- Format markdown content
|
||||
|
||||
**Note**: Most browsers use Tab to move focus. TestDrive-JSUI overrides this behavior within textareas.
|
||||
|
||||
---
|
||||
|
||||
## Document Actions (Planned)
|
||||
|
||||
These shortcuts are planned for future releases.
|
||||
|
||||
### Ctrl+P (Print Document)
|
||||
|
||||
**Action**: Open browser print dialog
|
||||
|
||||
**Status**: 🔜 **Planned for v1.1**
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+P`
|
||||
- macOS: `Cmd+P` (⌘P)
|
||||
|
||||
**Expected behavior**:
|
||||
1. Prevents browser's default print
|
||||
2. Formats document for printing
|
||||
3. Opens print preview dialog
|
||||
|
||||
**Use cases**:
|
||||
- Quick print from editor
|
||||
- Print formatted markdown
|
||||
- Generate PDF via print
|
||||
|
||||
---
|
||||
|
||||
### Ctrl+F (Find & Replace)
|
||||
|
||||
**Action**: Open find and replace dialog
|
||||
|
||||
**Status**: 🔜 **Planned for v1.1**
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+F`
|
||||
- macOS: `Cmd+F` (⌘F)
|
||||
|
||||
**Expected behavior**:
|
||||
1. Prevents browser's default find
|
||||
2. Opens TestDrive-JSUI find dialog
|
||||
3. Focuses search input field
|
||||
4. Highlights matches in document
|
||||
|
||||
**Use cases**:
|
||||
- Search for text across document
|
||||
- Replace repetitive content
|
||||
- Navigate long documents
|
||||
|
||||
---
|
||||
|
||||
## Text Formatting (Planned)
|
||||
|
||||
These shortcuts will be available when text is selected or cursor is in text.
|
||||
|
||||
### Ctrl+B (Bold)
|
||||
|
||||
**Action**: Wrap selected text in `**bold**` markers
|
||||
|
||||
**Status**: 🔜 **Planned for v1.1**
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+B`
|
||||
- macOS: `Cmd+B` (⌘B)
|
||||
|
||||
**Expected behavior**:
|
||||
```
|
||||
Before: Selected text
|
||||
After: **Selected text**
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Quick markdown formatting
|
||||
- Bold emphasis in writing
|
||||
- Keyboard-only formatting
|
||||
|
||||
**Alternative**: Click "B" button in Edit Control
|
||||
|
||||
---
|
||||
|
||||
### Ctrl+I (Italic)
|
||||
|
||||
**Action**: Wrap selected text in `*italic*` markers
|
||||
|
||||
**Status**: 🔜 **Planned for v1.1**
|
||||
|
||||
**Platforms**:
|
||||
- Windows/Linux: `Ctrl+I`
|
||||
- macOS: `Cmd+I` (⌘I)
|
||||
|
||||
**Expected behavior**:
|
||||
```
|
||||
Before: Selected text
|
||||
After: *Selected text*
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Quick markdown formatting
|
||||
- Italic emphasis in writing
|
||||
- Keyboard-only formatting
|
||||
|
||||
**Alternative**: Click "I" button in Edit Control
|
||||
|
||||
---
|
||||
|
||||
## Browser vs. Application Shortcuts
|
||||
|
||||
### Conflicts
|
||||
|
||||
Some shortcuts conflict with browser defaults:
|
||||
|
||||
| Shortcut | Browser Default | TestDrive-JSUI |
|
||||
|----------|-----------------|----------------|
|
||||
| `Ctrl+S` | Browser save dialog | Document save |
|
||||
| `Ctrl+P` | Browser print | Document print (planned) |
|
||||
| `Ctrl+F` | Browser find | Document find (planned) |
|
||||
| `Ctrl+B` | Bookmarks sidebar | Bold text (planned) |
|
||||
| `Ctrl+I` | Open DevTools | Italic text (planned) |
|
||||
|
||||
**Solution**: TestDrive-JSUI calls `event.preventDefault()` to override browser behavior.
|
||||
|
||||
### Preserving Browser Shortcuts
|
||||
|
||||
Some browser shortcuts remain available:
|
||||
|
||||
- `Ctrl+Z` / `Cmd+Z` - Undo (within textareas)
|
||||
- `Ctrl+Y` / `Cmd+Shift+Z` - Redo (within textareas)
|
||||
- `Ctrl+C` / `Cmd+C` - Copy
|
||||
- `Ctrl+V` / `Cmd+V` - Paste
|
||||
- `Ctrl+X` / `Cmd+X` - Cut
|
||||
- `Ctrl+A` / `Cmd+A` - Select all
|
||||
- `F5` / `Ctrl+R` - Refresh page
|
||||
- `F11` - Fullscreen
|
||||
- `F12` - DevTools
|
||||
|
||||
---
|
||||
|
||||
## Custom Shortcuts
|
||||
|
||||
You can add custom shortcuts by listening to keyboard events:
|
||||
|
||||
### Example: Ctrl+E (Export)
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// Ctrl+E or Cmd+E
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'e') {
|
||||
event.preventDefault();
|
||||
|
||||
// Custom export action
|
||||
const markdown = editor.getMarkdown();
|
||||
console.log('Export triggered:', markdown);
|
||||
|
||||
// Trigger export
|
||||
if (editor.editControl) {
|
||||
editor.editControl.exportDocument();
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Example: Ctrl+Shift+D (Debug Toggle)
|
||||
|
||||
```javascript
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// Ctrl+Shift+D
|
||||
if (event.ctrlKey && event.shiftKey && event.key === 'D') {
|
||||
event.preventDefault();
|
||||
|
||||
// Toggle debug control
|
||||
if (editor.debugControl) {
|
||||
if (editor.debugControl.isExpanded) {
|
||||
editor.debugControl.collapse();
|
||||
} else {
|
||||
editor.debugControl.expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Example: Ctrl+K (Insert Link)
|
||||
|
||||
```javascript
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
|
||||
event.preventDefault();
|
||||
|
||||
// Get active textarea
|
||||
const activeTextarea = document.activeElement;
|
||||
if (activeTextarea.tagName === 'TEXTAREA') {
|
||||
// Insert link markdown
|
||||
const selectedText = activeTextarea.value.substring(
|
||||
activeTextarea.selectionStart,
|
||||
activeTextarea.selectionEnd
|
||||
);
|
||||
|
||||
const linkMarkdown = selectedText
|
||||
? `[${selectedText}](url)`
|
||||
: '[text](url)';
|
||||
|
||||
// Insert at cursor
|
||||
const start = activeTextarea.selectionStart;
|
||||
const end = activeTextarea.selectionEnd;
|
||||
const text = activeTextarea.value;
|
||||
|
||||
activeTextarea.value = text.substring(0, start) + linkMarkdown + text.substring(end);
|
||||
|
||||
// Select 'url' part
|
||||
const urlStart = start + linkMarkdown.indexOf('(') + 1;
|
||||
const urlEnd = urlStart + 3;
|
||||
activeTextarea.setSelectionRange(urlStart, urlEnd);
|
||||
activeTextarea.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Keyboard-Only Operation
|
||||
|
||||
All TestDrive-JSUI features are accessible via keyboard:
|
||||
|
||||
1. **Navigation**: Tab through interactive elements
|
||||
2. **Section editing**: Enter to open, Escape to close
|
||||
3. **Controls**: Tab to reach, Space/Enter to activate
|
||||
4. **Shortcuts**: All documented shortcuts work
|
||||
|
||||
### Screen Reader Support
|
||||
|
||||
Keyboard shortcuts work with screen readers:
|
||||
|
||||
- **ARIA labels**: All buttons have descriptive labels
|
||||
- **Focus management**: Proper focus order maintained
|
||||
- **Announcements**: State changes announced to screen readers
|
||||
|
||||
**Example**:
|
||||
```html
|
||||
<button aria-label="Accept changes (Ctrl+Enter)">✓ Accept</button>
|
||||
```
|
||||
|
||||
### Custom Key Bindings
|
||||
|
||||
For users with accessibility needs:
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
shortcuts: false // Disable defaults
|
||||
});
|
||||
|
||||
// Implement custom shortcuts matching user's needs
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// Custom bindings here
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Shortcut Not Working
|
||||
|
||||
**Problem**: Pressing shortcut does nothing
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check if shortcuts enabled**:
|
||||
```javascript
|
||||
console.log(editor.config.shortcuts); // Should be true
|
||||
```
|
||||
|
||||
2. **Check browser extension conflicts**:
|
||||
- Disable extensions like Vimium, Shortkeys
|
||||
- Test in incognito/private mode
|
||||
|
||||
3. **Check operating system conflicts**:
|
||||
- Some OS shortcuts override browser shortcuts
|
||||
- Example: Windows `Ctrl+S` might open system save dialog
|
||||
|
||||
4. **Test with different modifier**:
|
||||
- Try `Cmd` instead of `Ctrl` on macOS
|
||||
- Try `Ctrl` instead of `Cmd` on Windows
|
||||
|
||||
5. **Verify focus**:
|
||||
```javascript
|
||||
console.log(document.activeElement); // Check what has focus
|
||||
```
|
||||
|
||||
### Shortcut Conflicts
|
||||
|
||||
**Problem**: Shortcut triggers wrong action
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Disable TestDrive-JSUI shortcuts**:
|
||||
```javascript
|
||||
new TestDriveJSUI({ shortcuts: false });
|
||||
```
|
||||
|
||||
2. **Implement custom shortcuts**:
|
||||
```javascript
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// Your custom logic
|
||||
});
|
||||
```
|
||||
|
||||
3. **Check browser extensions**: Disable conflicting extensions
|
||||
|
||||
### macOS Specific Issues
|
||||
|
||||
**Problem**: `Ctrl` shortcuts don't work on macOS
|
||||
|
||||
**Solution**: Use `Cmd` (⌘) key instead:
|
||||
- `Cmd+S` instead of `Ctrl+S`
|
||||
- `Cmd+Enter` instead of `Ctrl+Enter`
|
||||
|
||||
**Code detects platform automatically**:
|
||||
```javascript
|
||||
if (event.ctrlKey || event.metaKey) { // metaKey = Cmd on Mac
|
||||
// Handle shortcut
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Users
|
||||
|
||||
1. **Learn core shortcuts first**: Ctrl+S, Escape, Ctrl+Enter
|
||||
2. **Use shortcuts consistently**: Build muscle memory
|
||||
3. **Combine with mouse**: Use whichever is faster for context
|
||||
4. **Customize if needed**: Add shortcuts for frequent actions
|
||||
|
||||
### For Developers
|
||||
|
||||
1. **Document custom shortcuts**: Provide cheat sheet to users
|
||||
2. **Avoid conflicts**: Check existing shortcuts before adding new
|
||||
3. **Provide alternatives**: Always offer mouse-based alternative
|
||||
4. **Test across platforms**: Verify shortcuts work on Windows, Mac, Linux
|
||||
5. **Respect user settings**: Allow disabling shortcuts if needed
|
||||
|
||||
### Example: Shortcut Cheat Sheet
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Add help button that shows shortcuts
|
||||
const helpButton = document.createElement('button');
|
||||
helpButton.textContent = 'Keyboard Shortcuts (?)';
|
||||
helpButton.onclick = () => {
|
||||
alert(`
|
||||
TestDrive-JSUI Keyboard Shortcuts:
|
||||
|
||||
Ctrl+S - Save document
|
||||
Escape - Close editor
|
||||
Ctrl+Enter - Accept changes
|
||||
Tab - Indent
|
||||
|
||||
More shortcuts: /docs/keyboard-shortcuts
|
||||
`);
|
||||
};
|
||||
|
||||
document.body.appendChild(helpButton);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Platform Differences
|
||||
|
||||
### Windows/Linux
|
||||
|
||||
- Uses `Ctrl` key for shortcuts
|
||||
- `Alt` key for alternative shortcuts
|
||||
- Standard keyboard layout
|
||||
|
||||
### macOS
|
||||
|
||||
- Uses `Cmd` (⌘) key instead of `Ctrl`
|
||||
- `Option` (⌥) key instead of `Alt`
|
||||
- `Control` key rarely used for app shortcuts
|
||||
|
||||
### Detection in Code
|
||||
|
||||
```javascript
|
||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
const modifierPressed = isMac ? event.metaKey : event.ctrlKey;
|
||||
|
||||
if (modifierPressed && event.key === 's') {
|
||||
// Save action
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Future Shortcuts (Roadmap)
|
||||
|
||||
Planned for future versions:
|
||||
|
||||
### Version 1.1
|
||||
- ✅ `Ctrl+P` - Print document
|
||||
- ✅ `Ctrl+F` - Find & replace
|
||||
- ✅ `Ctrl+B` - Bold text
|
||||
- ✅ `Ctrl+I` - Italic text
|
||||
- ✅ `Ctrl+K` - Insert link
|
||||
- ✅ `Ctrl+Shift+C` - Insert code block
|
||||
|
||||
### Version 1.2
|
||||
- 🔜 `Ctrl+H` - Insert heading
|
||||
- 🔜 `Ctrl+L` - Insert list
|
||||
- 🔜 `Ctrl+Shift+I` - Insert image
|
||||
- 🔜 `Ctrl+G` - Go to line
|
||||
- 🔜 `Ctrl+D` - Duplicate line
|
||||
|
||||
### Version 2.0
|
||||
- 🔜 `Ctrl+/` - Toggle comment
|
||||
- 🔜 `Ctrl+Shift+K` - Delete line
|
||||
- 🔜 `Ctrl+[` / `Ctrl+]` - Indent/unindent
|
||||
- 🔜 `Ctrl+Space` - Autocomplete
|
||||
- 🔜 `F3` - Find next
|
||||
|
||||
**Request features**: Submit suggestions at [GitHub Issues](https://github.com/anthropics/testdrive-jsui/issues)
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Section Editing](section-editing.md)** - Edit sections with keyboard
|
||||
- **[Edit Control](edit-control.md)** - Document actions and shortcuts
|
||||
- **[Accessibility](accessibility.md)** - Keyboard-only operation (coming soon)
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [Configuration](../api/configuration.md)
|
||||
- [Events](../api/events.md)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
613
docs/features/status-control.md
Normal file
613
docs/features/status-control.md
Normal file
@@ -0,0 +1,613 @@
|
||||
# Status Control
|
||||
|
||||
**Real-time document statistics and change tracking** 📊
|
||||
|
||||
The Status Control provides comprehensive document analytics including word count, character count, reading time estimation, document structure analysis, and change tracking. Monitor your document metrics in real-time as you write and edit. Positioned in the east by default.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Status Control continuously monitors your document and provides detailed statistics about content, structure, and reading metrics. Perfect for writers, editors, and content creators who need to track document metrics.
|
||||
|
||||
### Position
|
||||
- **Default**: East (e) - middle-right side
|
||||
- **Appearance**: 📊 icon when collapsed
|
||||
- **Title**: "Status"
|
||||
|
||||
### Key Features
|
||||
|
||||
- 📊 **Real-time statistics** - Word/character count, reading time
|
||||
- 📈 **Change tracking** - Visual indicators for increases/decreases
|
||||
- 📐 **Document structure** - Paragraphs, headings, lists, images, links
|
||||
- 🔄 **Auto-refresh** - Updates every 10 seconds automatically
|
||||
- 📤 **Export functionality** - Download statistics as JSON
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable/Disable
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
statusControl: true // Enable (default: true)
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
statusControl: 'e' // East (default), or: nw, ne, se, s, sw, w
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Content Statistics
|
||||
|
||||
#### Word Count
|
||||
Shows total words in the document, calculated by splitting text on whitespace and filtering empty strings.
|
||||
|
||||
**Display**: Large, blue-colored number with change indicator
|
||||
|
||||
**Example**: `1,247 (+23)` - Document has 1,247 words, increased by 23 since last update
|
||||
|
||||
#### Character Count
|
||||
Total characters including spaces.
|
||||
|
||||
**Display**: Formatted with thousand separators
|
||||
|
||||
**Also tracks**: Characters without spaces (internal metric)
|
||||
|
||||
#### Reading Time
|
||||
Estimated reading time in minutes based on average reading speed.
|
||||
|
||||
**Calculation**: Total words ÷ 200 words per minute (configurable)
|
||||
|
||||
**Display**: `5 min (+1)` - Takes 5 minutes to read, increased by 1 minute
|
||||
|
||||
**Tip**: Useful for blog posts, articles, and documentation to estimate reader time investment
|
||||
|
||||
#### Sentence Count
|
||||
Approximate sentence count based on punctuation (., !, ?).
|
||||
|
||||
**Use case**: Track writing complexity and paragraph length
|
||||
|
||||
---
|
||||
|
||||
### 2. Document Structure
|
||||
|
||||
The Status Control analyzes your document structure and counts:
|
||||
|
||||
#### Paragraphs
|
||||
Total `<p>` elements in the rendered HTML.
|
||||
|
||||
**Use case**: Ensure proper document segmentation
|
||||
|
||||
#### Headings
|
||||
Total headings (h1-h6) in the document.
|
||||
|
||||
**Use case**: Verify document outline and hierarchy
|
||||
|
||||
**Tip**: Good documents typically have 1 h1 and logical heading progression
|
||||
|
||||
#### Lists
|
||||
Total lists (ordered and unordered).
|
||||
|
||||
**Use case**: Track enumeration and structured content
|
||||
|
||||
#### Images
|
||||
Total images in the document.
|
||||
|
||||
**Use case**: Monitor visual content distribution
|
||||
|
||||
#### Links
|
||||
Total hyperlinks in the document.
|
||||
|
||||
**Use case**: Track references and external resources
|
||||
|
||||
---
|
||||
|
||||
### 3. Change Tracking
|
||||
|
||||
#### Visual Indicators
|
||||
|
||||
Changes since last update are shown with:
|
||||
|
||||
**Positive changes** (increases):
|
||||
- Green color: `#28a745`
|
||||
- Plus sign: `(+5)`
|
||||
- Indicates growth in that metric
|
||||
|
||||
**Negative changes** (decreases):
|
||||
- Red color: `#dc3545`
|
||||
- Minus sign: `(-3)`
|
||||
- Indicates reduction in that metric
|
||||
|
||||
**No change**: No indicator shown
|
||||
|
||||
#### Example Display
|
||||
|
||||
```
|
||||
Words: 1,247 (+23)
|
||||
Characters: 6,543 (+145)
|
||||
Reading Time: 6 min
|
||||
Sentences: 89 (+2)
|
||||
```
|
||||
|
||||
The green numbers show the document grew by 23 words, 145 characters, and 2 sentences.
|
||||
|
||||
---
|
||||
|
||||
### 4. Actions
|
||||
|
||||
#### 🔄 Refresh
|
||||
Manually refresh statistics immediately.
|
||||
|
||||
**Usage**:
|
||||
- Click "🔄 Refresh" button
|
||||
- Shows "✅ Updated" confirmation for 1 second
|
||||
|
||||
**When to use**:
|
||||
- After making significant edits
|
||||
- When you want immediate feedback
|
||||
- To see updated change indicators
|
||||
|
||||
**Note**: Statistics auto-refresh every 10 seconds, so manual refresh is optional
|
||||
|
||||
#### 📊 Export
|
||||
Export statistics to JSON file for external analysis.
|
||||
|
||||
**Usage**:
|
||||
- Click "📊 Export" button
|
||||
- Downloads: `document-stats-YYYY-MM-DD.json`
|
||||
|
||||
**File contents**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-16T14:30:52.123Z",
|
||||
"document": {
|
||||
"title": "My Document",
|
||||
"url": "http://localhost:8080/editor.html"
|
||||
},
|
||||
"statistics": {
|
||||
"characters": 6543,
|
||||
"charactersNoSpaces": 5421,
|
||||
"words": 1247,
|
||||
"sentences": 89,
|
||||
"paragraphs": 34,
|
||||
"headings": 12,
|
||||
"lists": 5,
|
||||
"images": 3,
|
||||
"links": 18,
|
||||
"readingTimeMinutes": 6
|
||||
},
|
||||
"metadata": {
|
||||
"wordsPerMinute": 200,
|
||||
"analysisDate": "2025-12-16T14:30:52.123Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Track document evolution over time
|
||||
- Compare statistics across multiple documents
|
||||
- Generate reports for clients or stakeholders
|
||||
- Integrate with external analytics tools
|
||||
|
||||
---
|
||||
|
||||
### 5. Auto-Refresh
|
||||
|
||||
The Status Control automatically refreshes every **10 seconds** to keep statistics current.
|
||||
|
||||
**Behavior**:
|
||||
- Silent background updates
|
||||
- Preserves change tracking between updates
|
||||
- Minimal performance impact
|
||||
- Continues while control is expanded or collapsed
|
||||
|
||||
**Disable auto-refresh**: Not currently supported via config (always enabled)
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
markdown: '# My Document\\n\\nThis is a sample paragraph.',
|
||||
controls: {
|
||||
statusControl: true
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Position (Top-Right)
|
||||
|
||||
```javascript
|
||||
// Move status control to northeast (top-right)
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controlPositions: {
|
||||
statusControl: 'ne' // Top-right corner
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Blog Post Writer Setup
|
||||
|
||||
```javascript
|
||||
// Emphasize word count for blog writing
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
controls: {
|
||||
editControl: true, // Save and export
|
||||
statusControl: true, // Track word count goal
|
||||
contentsControl: false,
|
||||
debugControl: false
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor word count for target goal
|
||||
setInterval(() => {
|
||||
const stats = editor.statusControl.stats;
|
||||
const targetWords = 1500;
|
||||
|
||||
if (stats.words >= targetWords) {
|
||||
console.log(`🎉 Goal reached! ${stats.words} words written.`);
|
||||
} else {
|
||||
const remaining = targetWords - stats.words;
|
||||
console.log(`✍️ Keep writing! ${remaining} words to go.`);
|
||||
}
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
### Export Statistics for Reporting
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Programmatically export stats
|
||||
document.getElementById('report-btn').addEventListener('click', () => {
|
||||
// Refresh to get latest stats
|
||||
editor.statusControl.refreshStats();
|
||||
|
||||
// Export to JSON
|
||||
setTimeout(() => {
|
||||
editor.statusControl.exportStats();
|
||||
}, 100);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Properties
|
||||
|
||||
Access via `editor.statusControl`:
|
||||
|
||||
```javascript
|
||||
const statusCtrl = editor.statusControl;
|
||||
|
||||
// Current statistics object
|
||||
statusCtrl.stats = {
|
||||
characters: 6543,
|
||||
charactersNoSpaces: 5421,
|
||||
words: 1247,
|
||||
sentences: 89,
|
||||
paragraphs: 34,
|
||||
headings: 12,
|
||||
lists: 5,
|
||||
images: 3,
|
||||
links: 18,
|
||||
readingTimeMinutes: 6
|
||||
};
|
||||
|
||||
// Previous statistics (for change tracking)
|
||||
statusCtrl.previousStats = { /* ... */ };
|
||||
|
||||
// Last update timestamp
|
||||
statusCtrl.lastUpdateTime = 1702742452123;
|
||||
|
||||
// Reading speed setting (words per minute)
|
||||
statusCtrl.wordsPerMinute = 200; // Adjustable
|
||||
|
||||
// Auto-refresh interval ID
|
||||
statusCtrl.updateInterval = 12345;
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
```javascript
|
||||
const statusCtrl = editor.statusControl;
|
||||
|
||||
// Analyze document and update statistics
|
||||
statusCtrl.analyzeDocument();
|
||||
// Returns: stats object
|
||||
|
||||
// Calculate changes since last update
|
||||
const changes = statusCtrl.calculateChanges();
|
||||
// Returns: { words: { current, previous, change, hasChanged }, ... }
|
||||
|
||||
// Format statistics as HTML
|
||||
const html = statusCtrl.formatStatistics();
|
||||
// Returns: HTML string
|
||||
|
||||
// Refresh stats and update display
|
||||
statusCtrl.refreshStats();
|
||||
|
||||
// Export statistics to JSON file
|
||||
statusCtrl.exportStats();
|
||||
|
||||
// Calculate readability score (Flesch Reading Ease)
|
||||
const readability = statusCtrl.calculateReadabilityScore();
|
||||
// Returns: { score: 65, level: 'Standard' }
|
||||
|
||||
// Configuration
|
||||
statusCtrl.config.position = 'e'; // Compass position
|
||||
statusCtrl.config.icon = '📊'; // Panel icon
|
||||
statusCtrl.config.title = 'Status'; // Panel title
|
||||
statusCtrl.isExpanded; // true if expanded
|
||||
```
|
||||
|
||||
### Readability Levels
|
||||
|
||||
The `calculateReadabilityScore()` method returns:
|
||||
|
||||
| Score Range | Level | Description |
|
||||
|-------------|-------|-------------|
|
||||
| 90-100 | Very Easy | 5th grade level |
|
||||
| 80-89 | Easy | 6th grade level |
|
||||
| 70-79 | Fairly Easy | 7th grade level |
|
||||
| 60-69 | Standard | 8th-9th grade level |
|
||||
| 50-59 | Fairly Difficult | 10th-12th grade level |
|
||||
| 30-49 | Difficult | College level |
|
||||
| 0-29 | Very Difficult | College graduate level |
|
||||
|
||||
**Note**: Readability scoring uses simplified Flesch Reading Ease formula with approximated syllable counts.
|
||||
|
||||
---
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Reading Speed
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Adjust for faster readers (250 words per minute)
|
||||
editor.statusControl.wordsPerMinute = 250;
|
||||
editor.statusControl.refreshStats();
|
||||
|
||||
// Or slower readers (150 words per minute)
|
||||
editor.statusControl.wordsPerMinute = 150;
|
||||
editor.statusControl.refreshStats();
|
||||
```
|
||||
|
||||
### Programmatic Access
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Get current word count
|
||||
const wordCount = editor.statusControl.stats.words;
|
||||
console.log(`Current word count: ${wordCount}`);
|
||||
|
||||
// Get reading time
|
||||
const readingTime = editor.statusControl.stats.readingTimeMinutes;
|
||||
console.log(`Estimated reading time: ${readingTime} minutes`);
|
||||
|
||||
// Check if document structure is balanced
|
||||
const stats = editor.statusControl.stats;
|
||||
const avgParasPerHeading = stats.paragraphs / stats.headings;
|
||||
console.log(`Average paragraphs per section: ${avgParasPerHeading.toFixed(1)}`);
|
||||
```
|
||||
|
||||
### Change Detection
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Monitor specific changes
|
||||
const original = editor.statusControl.stats.words;
|
||||
|
||||
// ... user edits document ...
|
||||
|
||||
editor.statusControl.refreshStats();
|
||||
const current = editor.statusControl.stats.words;
|
||||
const delta = current - original;
|
||||
|
||||
if (delta > 0) {
|
||||
console.log(`Added ${delta} words`);
|
||||
} else if (delta < 0) {
|
||||
console.log(`Removed ${Math.abs(delta)} words`);
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Auto-Refresh Interval
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Stop default 10-second refresh
|
||||
clearInterval(editor.statusControl.updateInterval);
|
||||
|
||||
// Set custom 5-second refresh
|
||||
editor.statusControl.updateInterval = setInterval(() => {
|
||||
editor.statusControl.refreshStats();
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Statistics Not Updating
|
||||
|
||||
**Problem**: Numbers don't change after editing
|
||||
|
||||
**Solutions**:
|
||||
1. Click "🔄 Refresh" button manually
|
||||
2. Check if auto-refresh is running: `editor.statusControl.updateInterval`
|
||||
3. Verify StatusControl is loaded: `typeof StatusControl !== 'undefined'`
|
||||
4. Check browser console for JavaScript errors
|
||||
|
||||
### Incorrect Word Count
|
||||
|
||||
**Problem**: Word count seems wrong
|
||||
|
||||
**Causes & Solutions**:
|
||||
1. **Whitespace handling**: Multiple spaces count as one separator (correct behavior)
|
||||
2. **HTML tags**: Only text content is counted, not HTML markup
|
||||
3. **Code blocks**: Code is included in word count
|
||||
4. **Special characters**: Punctuation is included in words
|
||||
|
||||
**Manual verification**:
|
||||
```javascript
|
||||
// Get exact text being counted
|
||||
const contentArea = document.querySelector('#markitect-content');
|
||||
const text = contentArea.textContent;
|
||||
const words = text.trim().split(/\s+/).filter(w => w.length > 0);
|
||||
console.log('Words:', words.length, words);
|
||||
```
|
||||
|
||||
### Export Button Not Working
|
||||
|
||||
**Problem**: Clicking export does nothing
|
||||
|
||||
**Solutions**:
|
||||
1. Check browser's download settings
|
||||
2. Verify pop-up/download permissions
|
||||
3. Test programmatically: `editor.statusControl.exportStats()`
|
||||
4. Check browser console for errors
|
||||
5. Try different browser
|
||||
|
||||
### Reading Time Seems Wrong
|
||||
|
||||
**Problem**: Estimated reading time is too short/long
|
||||
|
||||
**Solution**: Adjust reading speed
|
||||
```javascript
|
||||
// For technical content (slower reading)
|
||||
editor.statusControl.wordsPerMinute = 150;
|
||||
|
||||
// For light reading (faster)
|
||||
editor.statusControl.wordsPerMinute = 250;
|
||||
|
||||
// Refresh to recalculate
|
||||
editor.statusControl.refreshStats();
|
||||
```
|
||||
|
||||
**Factors affecting reading time**:
|
||||
- Technical complexity
|
||||
- Reader expertise level
|
||||
- Language proficiency
|
||||
- Content density
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Writers
|
||||
|
||||
1. **Set word count goals** - Monitor progress toward target lengths
|
||||
2. **Track reading time** - Ensure articles fit time budgets (e.g., 5-minute reads)
|
||||
3. **Balance structure** - Use heading/paragraph ratios to check organization
|
||||
4. **Export regularly** - Save statistics to track writing productivity over time
|
||||
|
||||
### For Editors
|
||||
|
||||
1. **Monitor changes** - Use change indicators to track editing impact
|
||||
2. **Verify readability** - Check `calculateReadabilityScore()` for target audience
|
||||
3. **Structure analysis** - Ensure proper heading hierarchy and paragraph distribution
|
||||
4. **Compare versions** - Export stats before/after editing to quantify improvements
|
||||
|
||||
### For Developers
|
||||
|
||||
1. **Integrate with backend** - Send statistics to server for analytics
|
||||
2. **Custom thresholds** - Set alerts for minimum/maximum word counts
|
||||
3. **Programmatic access** - Use API for automated quality checks
|
||||
4. **Performance** - Monitor update frequency if handling very large documents
|
||||
|
||||
Example integration:
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({ container: '#editor' });
|
||||
|
||||
// Auto-save with statistics
|
||||
editor.on('save', async (data) => {
|
||||
const stats = editor.statusControl.stats;
|
||||
|
||||
await fetch('/api/documents', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
markdown: data.markdown,
|
||||
statistics: stats,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### For Large Documents (10,000+ words)
|
||||
|
||||
**Impact**: Auto-refresh every 10 seconds may cause lag
|
||||
|
||||
**Solutions**:
|
||||
1. Increase refresh interval:
|
||||
```javascript
|
||||
clearInterval(editor.statusControl.updateInterval);
|
||||
editor.statusControl.updateInterval = setInterval(() => {
|
||||
editor.statusControl.refreshStats();
|
||||
}, 30000); // 30 seconds instead
|
||||
```
|
||||
|
||||
2. Disable auto-refresh, use manual only:
|
||||
```javascript
|
||||
clearInterval(editor.statusControl.updateInterval);
|
||||
editor.statusControl.updateInterval = null;
|
||||
// User clicks Refresh button when needed
|
||||
```
|
||||
|
||||
3. Lazy calculation - only analyze visible sections
|
||||
|
||||
### Memory Usage
|
||||
|
||||
Statistics use minimal memory (< 1KB). Change tracking stores two copies of stats object. No memory leaks if control is properly destroyed via `destroy()`.
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Edit Control](edit-control.md)** - Save/export document
|
||||
- **[Contents Control](contents-control.md)** - Navigate document structure
|
||||
- **[Section Editing](section-editing.md)** - Triggers statistics updates
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [API Reference](../api/status-control.md)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
832
docs/features/themes.md
Normal file
832
docs/features/themes.md
Normal file
@@ -0,0 +1,832 @@
|
||||
# Themes
|
||||
|
||||
**Visual theming and customization** 🎨
|
||||
|
||||
TestDrive-JSUI provides a flexible theming system that allows you to customize the visual appearance of the editor. Themes control colors, typography, spacing, and visual style of all components. Built on CSS custom properties for easy customization.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The theming system uses CSS custom properties (CSS variables) to define color schemes and styling. Themes are applied as CSS classes, allowing multiple themes to coexist and switch dynamically.
|
||||
|
||||
### Default Theme
|
||||
|
||||
**GitHub Theme**: The default theme inspired by GitHub's design system
|
||||
- Clean, professional appearance
|
||||
- High contrast for readability
|
||||
- Familiar to developers
|
||||
- WCAG AA compliant colors
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Set Theme
|
||||
|
||||
Specify theme when creating editor:
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'github' // Default theme
|
||||
});
|
||||
```
|
||||
|
||||
### Change Theme Dynamically
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'github'
|
||||
});
|
||||
|
||||
// Change theme later
|
||||
editor.applyTheme('custom-dark');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Built-in Themes
|
||||
|
||||
### GitHub Theme (Default)
|
||||
|
||||
**Name**: `github`
|
||||
|
||||
**Description**: Clean, professional theme inspired by GitHub
|
||||
|
||||
**Colors**:
|
||||
```css
|
||||
--github-primary: #0969da /* Primary blue */
|
||||
--github-border: #d0d7de /* Border gray */
|
||||
--github-bg-subtle: #f6f8fa /* Subtle background */
|
||||
--github-fg-default: #1f2328 /* Default text */
|
||||
--github-fg-muted: #656d76 /* Muted text */
|
||||
--github-success: #1a7f37 /* Success green */
|
||||
--github-danger: #d1242f /* Danger red */
|
||||
--github-warning: #9a6700 /* Warning amber */
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'github'
|
||||
});
|
||||
```
|
||||
|
||||
**Features**:
|
||||
- High contrast text (WCAG AA)
|
||||
- Subtle hover states
|
||||
- Professional color palette
|
||||
- Optimized for long reading sessions
|
||||
|
||||
**Preview**:
|
||||
- Sections: Light gray hover, blue focus
|
||||
- Controls: White backgrounds, gray borders
|
||||
- Buttons: Blue primary, red danger
|
||||
- Debug panel: Dark theme for code readability
|
||||
|
||||
---
|
||||
|
||||
## Custom Themes
|
||||
|
||||
### Creating a Custom Theme
|
||||
|
||||
**Step 1**: Create CSS file `static/css/themes/custom-theme.css`
|
||||
|
||||
```css
|
||||
/**
|
||||
* Custom Theme
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* Define your color palette */
|
||||
--custom-primary: #8b5cf6;
|
||||
--custom-border: #e5e7eb;
|
||||
--custom-bg: #ffffff;
|
||||
--custom-bg-subtle: #f9fafb;
|
||||
--custom-fg: #111827;
|
||||
--custom-fg-muted: #6b7280;
|
||||
}
|
||||
|
||||
/* Editor styles */
|
||||
.theme-custom-theme .markitect-edit-mode {
|
||||
color: var(--custom-fg);
|
||||
background: var(--custom-bg);
|
||||
}
|
||||
|
||||
/* Section styles */
|
||||
.theme-custom-theme .markitect-section:hover {
|
||||
background-color: var(--custom-bg-subtle);
|
||||
border-color: var(--custom-border);
|
||||
}
|
||||
|
||||
.theme-custom-theme .markitect-section.editing {
|
||||
border-color: var(--custom-primary);
|
||||
box-shadow: 0 0 0 0.2rem rgba(139, 92, 246, 0.25);
|
||||
}
|
||||
|
||||
/* Control panels */
|
||||
.theme-custom-theme .markitect-control-panel {
|
||||
background: var(--custom-bg);
|
||||
border: 1px solid var(--custom-border);
|
||||
color: var(--custom-fg);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.theme-custom-theme button {
|
||||
background: var(--custom-primary);
|
||||
color: white;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.theme-custom-theme button:hover {
|
||||
background: #7c3aed; /* Darker shade */
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2**: Load CSS file
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="static/css/themes/custom-theme.css">
|
||||
```
|
||||
|
||||
**Step 3**: Apply theme
|
||||
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'custom-theme'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Theme Examples
|
||||
|
||||
### Dark Theme
|
||||
|
||||
```css
|
||||
/**
|
||||
* Dark Theme
|
||||
*/
|
||||
|
||||
:root {
|
||||
--dark-primary: #3b82f6;
|
||||
--dark-border: #374151;
|
||||
--dark-bg: #1f2937;
|
||||
--dark-bg-subtle: #111827;
|
||||
--dark-fg: #f9fafb;
|
||||
--dark-fg-muted: #9ca3af;
|
||||
}
|
||||
|
||||
.theme-dark .markitect-edit-mode {
|
||||
color: var(--dark-fg);
|
||||
background: var(--dark-bg);
|
||||
}
|
||||
|
||||
.theme-dark .markitect-section:hover {
|
||||
background-color: var(--dark-bg-subtle);
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
.theme-dark .markitect-section.editing {
|
||||
border-color: var(--dark-primary);
|
||||
box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
|
||||
.theme-dark .markitect-control-panel {
|
||||
background: var(--dark-bg-subtle);
|
||||
border: 1px solid var(--dark-border);
|
||||
color: var(--dark-fg);
|
||||
}
|
||||
|
||||
.theme-dark button {
|
||||
background: var(--dark-primary);
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'dark'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Minimal Theme
|
||||
|
||||
```css
|
||||
/**
|
||||
* Minimal Theme
|
||||
*/
|
||||
|
||||
:root {
|
||||
--minimal-primary: #000000;
|
||||
--minimal-border: #e0e0e0;
|
||||
--minimal-bg: #ffffff;
|
||||
--minimal-fg: #000000;
|
||||
}
|
||||
|
||||
.theme-minimal .markitect-edit-mode {
|
||||
color: var(--minimal-fg);
|
||||
background: var(--minimal-bg);
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 18px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.theme-minimal .markitect-section:hover {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.theme-minimal .markitect-section.editing {
|
||||
border-color: var(--minimal-primary);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.theme-minimal .markitect-control-panel {
|
||||
background: var(--minimal-bg);
|
||||
border: 1px solid var(--minimal-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.theme-minimal button {
|
||||
background: var(--minimal-primary);
|
||||
color: white;
|
||||
border-radius: 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'minimal'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### High Contrast Theme
|
||||
|
||||
```css
|
||||
/**
|
||||
* High Contrast Theme (Accessibility)
|
||||
*/
|
||||
|
||||
:root {
|
||||
--hc-primary: #0000ff;
|
||||
--hc-border: #000000;
|
||||
--hc-bg: #ffffff;
|
||||
--hc-fg: #000000;
|
||||
--hc-success: #008000;
|
||||
--hc-danger: #ff0000;
|
||||
}
|
||||
|
||||
.theme-high-contrast .markitect-edit-mode {
|
||||
color: var(--hc-fg);
|
||||
background: var(--hc-bg);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.theme-high-contrast .markitect-section:hover {
|
||||
background-color: #ffff00; /* Yellow highlight */
|
||||
border: 2px solid var(--hc-border);
|
||||
}
|
||||
|
||||
.theme-high-contrast .markitect-section.editing {
|
||||
border: 3px solid var(--hc-primary);
|
||||
}
|
||||
|
||||
.theme-high-contrast .markitect-control-panel {
|
||||
background: var(--hc-bg);
|
||||
border: 2px solid var(--hc-border);
|
||||
}
|
||||
|
||||
.theme-high-contrast button {
|
||||
background: var(--hc-primary);
|
||||
color: white;
|
||||
border: 2px solid var(--hc-border);
|
||||
font-weight: bold;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```javascript
|
||||
new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'high-contrast'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Theme Components
|
||||
|
||||
Themes can style these components:
|
||||
|
||||
### 1. Editor Container
|
||||
|
||||
**Classes**: `.markitect-edit-mode`, `.markitect-view-mode`
|
||||
|
||||
**Styles**:
|
||||
- Background color
|
||||
- Text color
|
||||
- Font family
|
||||
- Line height
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom .markitect-edit-mode {
|
||||
font-family: 'Inter', sans-serif;
|
||||
line-height: 1.7;
|
||||
color: #1a1a1a;
|
||||
background: #fafafa;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Sections
|
||||
|
||||
**Classes**: `.markitect-section`, `.markitect-section:hover`, `.markitect-section.editing`
|
||||
|
||||
**Styles**:
|
||||
- Hover background
|
||||
- Border colors
|
||||
- Focus state
|
||||
- Shadow effects
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom .markitect-section {
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.theme-custom .markitect-section:hover {
|
||||
background: #f0f0f0;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.theme-custom .markitect-section.editing {
|
||||
background: white;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Control Panels
|
||||
|
||||
**Classes**: `.markitect-control-panel`, `.edit-control`, `.status-control`, `.contents-control`, `.debug-control`
|
||||
|
||||
**Styles**:
|
||||
- Panel background
|
||||
- Border style
|
||||
- Shadow
|
||||
- Text colors
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom .markitect-control-panel {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Buttons
|
||||
|
||||
**Classes**: `.control-button`, `.control-button.danger`, `.control-button.success`
|
||||
|
||||
**Styles**:
|
||||
- Button colors
|
||||
- Hover states
|
||||
- Active states
|
||||
- Variants
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom button {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: 600;
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
.theme-custom button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.theme-custom button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Debug Panel
|
||||
|
||||
**Classes**: `.markitect-debug-panel`, `.markitect-debug-error`, `.markitect-debug-warning`
|
||||
|
||||
**Styles**:
|
||||
- Panel background (usually dark)
|
||||
- Message colors
|
||||
- Font (monospace)
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom .markitect-debug-panel {
|
||||
background: #282c34;
|
||||
color: #abb2bf;
|
||||
font-family: 'Fira Code', 'Consolas', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.theme-custom .markitect-debug-error {
|
||||
color: #e06c75;
|
||||
}
|
||||
|
||||
.theme-custom .markitect-debug-warning {
|
||||
color: #e5c07b;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Table of Contents
|
||||
|
||||
**Classes**: `.contents-control`, `.toc-item`, `.toc-item:hover`
|
||||
|
||||
**Styles**:
|
||||
- TOC item colors
|
||||
- Hover effects
|
||||
- Active heading
|
||||
- Indentation
|
||||
|
||||
**Example**:
|
||||
```css
|
||||
.theme-custom .toc-item {
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: 4px;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.theme-custom .toc-item:hover {
|
||||
background: #e8f4f8;
|
||||
color: #0077cc;
|
||||
}
|
||||
|
||||
.theme-custom .toc-item.active {
|
||||
background: #0077cc;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Theming
|
||||
|
||||
### CSS Variables
|
||||
|
||||
Use CSS custom properties for flexible theming:
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Color palette */
|
||||
--color-primary: #3b82f6;
|
||||
--color-secondary: #8b5cf6;
|
||||
--color-success: #10b981;
|
||||
--color-warning: #f59e0b;
|
||||
--color-danger: #ef4444;
|
||||
|
||||
/* Neutral colors */
|
||||
--color-gray-50: #f9fafb;
|
||||
--color-gray-100: #f3f4f6;
|
||||
--color-gray-900: #111827;
|
||||
|
||||
/* Spacing */
|
||||
--spacing-xs: 0.25rem;
|
||||
--spacing-sm: 0.5rem;
|
||||
--spacing-md: 1rem;
|
||||
--spacing-lg: 1.5rem;
|
||||
--spacing-xl: 2rem;
|
||||
|
||||
/* Typography */
|
||||
--font-sans: 'Inter', sans-serif;
|
||||
--font-mono: 'Fira Code', monospace;
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-base: 1rem;
|
||||
--font-size-lg: 1.125rem;
|
||||
|
||||
/* Effects */
|
||||
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
|
||||
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
|
||||
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
|
||||
|
||||
/* Transitions */
|
||||
--transition-fast: 0.15s ease;
|
||||
--transition-base: 0.2s ease;
|
||||
--transition-slow: 0.3s ease;
|
||||
}
|
||||
|
||||
.theme-custom .markitect-section {
|
||||
padding: var(--spacing-md);
|
||||
border-radius: var(--spacing-xs);
|
||||
transition: all var(--transition-base);
|
||||
}
|
||||
|
||||
.theme-custom button {
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-size-sm);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Theme Switcher
|
||||
|
||||
Implement dynamic theme switching:
|
||||
|
||||
```javascript
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: 'github'
|
||||
});
|
||||
|
||||
// Create theme switcher UI
|
||||
const themeSwitcher = document.createElement('select');
|
||||
themeSwitcher.innerHTML = `
|
||||
<option value="github">GitHub</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="minimal">Minimal</option>
|
||||
<option value="high-contrast">High Contrast</option>
|
||||
`;
|
||||
|
||||
themeSwitcher.addEventListener('change', (e) => {
|
||||
editor.applyTheme(e.target.value);
|
||||
|
||||
// Save preference
|
||||
localStorage.setItem('preferred-theme', e.target.value);
|
||||
});
|
||||
|
||||
// Load saved theme
|
||||
const savedTheme = localStorage.getItem('preferred-theme');
|
||||
if (savedTheme) {
|
||||
editor.applyTheme(savedTheme);
|
||||
themeSwitcher.value = savedTheme;
|
||||
}
|
||||
|
||||
document.body.appendChild(themeSwitcher);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### System Theme Detection
|
||||
|
||||
Detect and apply system dark mode preference:
|
||||
|
||||
```javascript
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
const editor = new TestDriveJSUI({
|
||||
container: '#editor',
|
||||
theme: prefersDark ? 'dark' : 'github'
|
||||
});
|
||||
|
||||
// Listen for system theme changes
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
editor.applyTheme(e.matches ? 'dark' : 'github');
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Per-Component Theming
|
||||
|
||||
Theme individual components differently:
|
||||
|
||||
```css
|
||||
.theme-custom .edit-control {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.theme-custom .status-control {
|
||||
background: #f0fdf4;
|
||||
border-color: #86efac;
|
||||
}
|
||||
|
||||
.theme-custom .contents-control {
|
||||
background: #eff6ff;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
.theme-custom .debug-control {
|
||||
background: #282c34;
|
||||
color: #abb2bf;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Theme Creators
|
||||
|
||||
1. **Use CSS variables**: Define colors centrally for consistency
|
||||
2. **Test contrast**: Ensure WCAG AA compliance (4.5:1 minimum)
|
||||
3. **Consider dark mode**: Provide both light and dark variants
|
||||
4. **Test all states**: Hover, focus, active, disabled
|
||||
5. **Responsive**: Test on different screen sizes
|
||||
6. **Accessibility**: High contrast mode, focus indicators
|
||||
|
||||
### For Users
|
||||
|
||||
1. **Choose readable fonts**: Sans-serif for UI, serif/mono for content
|
||||
2. **Adjust for lighting**: Light themes for bright environments, dark for dim
|
||||
3. **Save preferences**: Use localStorage to persist theme choice
|
||||
4. **Test compatibility**: Verify theme works with all controls
|
||||
|
||||
---
|
||||
|
||||
## Accessibility
|
||||
|
||||
### High Contrast
|
||||
|
||||
Themes should provide high contrast variants:
|
||||
|
||||
```css
|
||||
@media (prefers-contrast: high) {
|
||||
.theme-github {
|
||||
--github-fg-default: #000000;
|
||||
--github-bg-subtle: #ffffff;
|
||||
--github-border: #000000;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reduced Motion
|
||||
|
||||
Respect user's motion preferences:
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.theme-custom .markitect-section {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.theme-custom button {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Color Blind Friendly
|
||||
|
||||
Use patterns in addition to color:
|
||||
|
||||
```css
|
||||
.theme-custom .markitect-debug-error::before {
|
||||
content: '❌ '; /* Icon in addition to red color */
|
||||
}
|
||||
|
||||
.theme-custom .markitect-debug-warning::before {
|
||||
content: '⚠️ '; /* Icon in addition to yellow color */
|
||||
}
|
||||
|
||||
.theme-custom .markitect-debug-success::before {
|
||||
content: '✅ '; /* Icon in addition to green color */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Theme Not Applied
|
||||
|
||||
**Problem**: Theme styles don't appear
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check CSS file loaded**:
|
||||
```html
|
||||
<link rel="stylesheet" href="static/css/themes/custom-theme.css">
|
||||
```
|
||||
|
||||
2. **Verify theme name**:
|
||||
```javascript
|
||||
console.log(editor.config.theme); // Should match CSS class
|
||||
```
|
||||
|
||||
3. **Check CSS selector specificity**:
|
||||
```css
|
||||
/* More specific */
|
||||
.theme-custom .markitect-section { }
|
||||
|
||||
/* Less specific - might not work */
|
||||
.markitect-section { }
|
||||
```
|
||||
|
||||
4. **Clear browser cache**: Force refresh with Ctrl+F5
|
||||
|
||||
### Theme Partially Applied
|
||||
|
||||
**Problem**: Some components themed, others not
|
||||
|
||||
**Solution**: Ensure all component classes are styled:
|
||||
|
||||
```css
|
||||
.theme-custom .markitect-edit-mode { /* Editor */ }
|
||||
.theme-custom .markitect-section { /* Sections */ }
|
||||
.theme-custom .markitect-control-panel { /* All controls */ }
|
||||
.theme-custom .edit-control { /* Specific control */ }
|
||||
.theme-custom button { /* Buttons */ }
|
||||
```
|
||||
|
||||
### CSS Variables Not Working
|
||||
|
||||
**Problem**: CSS variables show default values
|
||||
|
||||
**Solution**: Define variables in `:root` or `.theme-*` scope:
|
||||
|
||||
```css
|
||||
/* Correct */
|
||||
:root {
|
||||
--custom-primary: #3b82f6;
|
||||
}
|
||||
|
||||
/* Or scoped to theme */
|
||||
.theme-custom {
|
||||
--custom-primary: #3b82f6;
|
||||
}
|
||||
|
||||
/* Use in components */
|
||||
.theme-custom .markitect-section.editing {
|
||||
border-color: var(--custom-primary);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Future Themes (Roadmap)
|
||||
|
||||
Planned themes for future versions:
|
||||
|
||||
### Version 1.1
|
||||
- ✅ **Dracula**: Popular dark theme
|
||||
- ✅ **Solarized**: Light and dark variants
|
||||
- ✅ **Monokai**: Vibrant syntax colors
|
||||
- ✅ **Nord**: Arctic-inspired palette
|
||||
|
||||
### Version 1.2
|
||||
- 🔜 **Material Design**: Google's design system
|
||||
- 🔜 **Tailwind**: Tailwind CSS inspired
|
||||
- 🔜 **Bootstrap**: Bootstrap color scheme
|
||||
- 🔜 **Cyberpunk**: Neon aesthetic
|
||||
|
||||
### Version 2.0
|
||||
- 🔜 **Theme builder**: Visual theme creator
|
||||
- 🔜 **Theme marketplace**: Share custom themes
|
||||
- 🔜 **Live preview**: Preview themes before applying
|
||||
- 🔜 **Theme export**: Export theme as CSS
|
||||
|
||||
**Request themes**: Submit suggestions at [GitHub Issues](https://github.com/anthropics/testdrive-jsui/issues)
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Configuration](../api/configuration.md)** - Theme configuration options
|
||||
- **[Customization](customization.md)** - Advanced customization (coming soon)
|
||||
- **[Accessibility](accessibility.md)** - Accessible themes (coming soon)
|
||||
|
||||
---
|
||||
|
||||
**See Also**:
|
||||
- [CSS Variables Reference](../api/css-variables.md) (coming soon)
|
||||
- [Theme Gallery](../../examples/themes/) (coming soon)
|
||||
- [Examples](../../examples/)
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-16
|
||||
Reference in New Issue
Block a user