Date: January 2026
Analyst: GitHub Copilot Code Agent
Repository: TreeBASE/treebase
This document provides a comprehensive analysis of the TreeBASE web application's user interface, identifying areas for improvement in layout consistency, CSS organization, and JavaScript modernization. The analysis reveals opportunities to significantly enhance maintainability, user experience, and code quality through strategic refactoring.
The TreeBASE application uses a decorator pattern with multiple JSP templates:
- defaultTemplate.jsp - Main application template for authenticated users
- mainTemplate.jsp - Simplified template for public pages
- defaultSearchTemplate.jsp - Search-specific template
- adminTemplate.jsp - Administrative interface template
- testTemplate.jsp - Testing/development template
Standard Layout Structure:
┌─────────────────────────────────────┐
│ Header (logo + gradient) │
├─────────────────────────────────────┤
│ Login/User Info (absolute position) │
├─────────────────────────────────────┤
│ Navigation Tabs (conditional) │
├──────────┬──────────────────────────┤
│ Sidebar │ Main Content │
│ (Left) │ │
│ │ │
│ │ │
├──────────┴──────────────────────────┤
│ Footer │
└─────────────────────────────────────┘
-
treeViewer.jsp
- Location:
/WEB-INF/pages/treeViewer.jsp - Deviation: Completely standalone page with no template inheritance
- Reason: Specialized tree visualization requiring full control of viewport
- Layout: Custom flexbox layout with embedded
<style>tag - Impact: Modern CSS (flexbox), but inconsistent with site-wide styling
- Dependencies: External CDN resources (D3.js v7, phylotree.js)
- Location:
-
mainTemplate.jsp
- Deviation: Minimal navigation, no sidebar, uses 2-column left layout
- Usage: Public-facing pages, information pages
- Content Area ID:
#contentRight(80% width) - Missing: Form submission features, admin navigation
-
testTemplate.jsp
- Deviation: Full-width content area (
#contentAll) - Purpose: Testing and development pages
- Missing: Sidebars, navigation menus
- Issue: References non-existent
menuExpandable2.css
- Deviation: Full-width content area (
-
defaultSearchTemplate.jsp
- Deviation: Full-width search interface (
.contentsearch) - Special Features:
- Conditional login display for both authenticated and anonymous users
- Custom search navigation (
search-topnav.jsp) - Extensive inline JavaScript for citation management
- 120+ lines of embedded JavaScript code
- Deviation: Full-width search interface (
Problems Identified:
-
Inconsistent Width Classes:
#content- 67% width#contentRight- 80% width#contentAll- 95% width.contentsearch- 100% width
-
Sidebar Variations:
#sidebar- Right sidebar (32% width)#sidebarLeft- Left sidebar (20% width)#sidebarLeft-3column- Three-column layout left sidebar (30% width)- Conditional rendering based on user authentication and context
-
Template-Specific CSS:
menuExpandable2.css- Referenced but doesn't exist (404 error)- Templates load different combinations of stylesheets
- Inconsistent media queries (
media="all"vs. no media attribute)
The application uses multiple table rendering approaches:
- Usage: 5+ templates reference displaytag
- CSS: Dedicated
displaytag.css(163 lines) - Features:
- Pagination (
span.pagebanner,span.pagelinks) - Sorting (arrow icons for column headers)
- Row striping (
.even/.oddclasses) - Hover effects
- Pagination (
- Examples: People tables, submission tables (
#sub-table) - Styling: Defined in main
styles.css - Issues: Different border styles, padding, and color schemes
DisplayTag Tables (table.list):
border: 1px solid #808080;
background: white;
th { background-color: silver; }
tr.even { background: #d6cfe6; } /* Purple tint */
tr.odd { background: white; }Submission Tables (#sub-table):
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
th { background: #eee; } /* Light gray */People Tables (table.peopleTable):
/* No border on table itself */
img { border: 1px solid silver; }Analysis Results:
- Total JSP files with inline styles: 82 files
- Total inline style occurrences: 277+ instances
- Common inline styles in tables:
style="text-align:left"/style="text-align:right"style="width:100%"/style="width:150px"style="vertical-align:middle"style="display:none"(for conditional visibility)
Examples from studyList.jsp:
<display:column property="id" title="Study ID"
sortable="true" style="text-align:left: width 10%"/>
<display:column property="citation.title" title="Citation Title"
sortable="true" style="text-align:left; width 50%"/>Findings:
✅ Strengths:
- DisplayTag provides consistent pagination and sorting UI
- Icon buttons have uniform styling via
.iconButtonclass - Hover effects generally consistent across table types
❌ Weaknesses:
- Three distinct table styling patterns with no shared base
- Inconsistent color schemes (purple vs. gray vs. none)
- Mixed use of classes and inline styles
- No responsive design (fixed widths, no mobile consideration)
- Accessibility issues (missing ARIA labels, semantic markup)
CSS Files Inventory:
| File | Size | Lines | Purpose | Issues |
|---|---|---|---|---|
styles.css |
11,152 bytes | 600 | Main stylesheet | Monolithic, no organization |
displaytag.css |
3,143 bytes | 163 | Table styling | Redundant with styles.css |
treebase.css |
868 bytes | ~40 | TreeBASE-specific | Minimal, underutilized |
menuExpandable.css |
1,207 bytes | ~50 | Menu navigation | Single-purpose |
messages.css |
959 bytes | ~40 | Status messages | Could merge |
autocomplete.css |
506 bytes | ~25 | Autocomplete widget | DWR-dependent |
ajaxProgress.css |
566 bytes | ~25 | Progress indicators | Could merge |
submissionSummary.css |
3,163 bytes | ~130 | Submission view | Specific to one page |
reference.css |
2,472 bytes | ~100 | Citations/references | Could merge |
Total: 9 CSS files, ~24KB combined
Problems Identified:
-
No Modular Structure:
- Single monolithic
styles.csswith mixed concerns - Comments divide sections but no file separation
- Difficult to locate specific styles
- Single monolithic
-
Duplicate Rules:
- Table border definitions appear in 3 files
- Link styles repeated across files
- Form styling duplicated
-
Inefficient Selectors:
- Overuse of descendant selectors (
#content a:link) - Lack of reusable utility classes
- Too many ID selectors (low reusability)
- Overuse of descendant selectors (
-
Inline Styles Prevalence:
- 277+ inline style instances across 82 JSP files
- Common patterns that should be classes:
style="text-align:right"→ class.text-rightstyle="width:100%"→ class.w-fullstyle="display:none"→ class.hidden
-
Vendor Prefixes Missing:
- No
-webkit-,-moz-,-ms-prefixes - Limited cross-browser compatibility
- No
-
No CSS Variables:
- Colors hardcoded throughout (e.g.,
#003366,#3863A4) - No centralized theme management
- Colors hardcoded throughout (e.g.,
Phase 1: Audit and Inventory (1-2 weeks)
- Catalog all CSS files ✓
- Document all inline styles by category
- Identify duplicate and conflicting rules
- Map styles to UI components
Phase 2: Create Design System (2-3 weeks)
- Define CSS custom properties (variables) for:
- Color palette (primary, secondary, accent, neutrals)
- Typography (font families, sizes, weights, line heights)
- Spacing scale (margins, padding)
- Breakpoints (responsive design)
- Z-index scale (layering)
Phase 3: Establish Base Styles (1 week)
- Create
_reset.css- Normalize browser defaults - Create
_base.css- HTML element defaults - Create
_typography.css- Font and text styles - Create
_layout.css- Grid and flexbox utilities
Phase 4: Component-Based CSS (3-4 weeks)
- Extract component styles:
_buttons.css- All button variants_forms.css- Input, select, textarea, fieldset_tables.css- Unified table system (merge displaytag.css)_navigation.css- Tabs, menus, breadcrumbs_cards.css- Content containers_modals.css- Dialogs and overlays_messages.css- Alerts and notifications
Phase 5: Utility Classes (1 week)
- Create utility class library:
- Text alignment (
.text-left,.text-center,.text-right) - Display (
.hidden,.block,.inline-block,.flex) - Spacing (
.m-0to.m-5,.p-0to.p-5) - Width (
.w-full,.w-1/2,.w-1/3) - Colors (
.text-primary,.bg-secondary)
- Text alignment (
Phase 6: Eliminate Inline Styles (4-6 weeks)
- Replace inline styles with utility classes
- Create component-specific classes for complex patterns
- Update JSP templates systematically
- Validate visual consistency
Phase 7: Build Pipeline (1-2 weeks)
- Implement CSS preprocessor (Sass/Less) or PostCSS
- Set up autoprefixer for vendor prefixes
- Configure CSS minification
- Implement CSS purging (remove unused styles)
- Create source maps for debugging
Phase 8: Testing and Optimization (2 weeks)
- Cross-browser testing (Chrome, Firefox, Safari, Edge)
- Responsive design testing
- Performance testing (CSS size reduction)
- Accessibility audit (WCAG 2.1 AA compliance)
Proposed File Structure:
styles/
├── main.css # Import orchestration file
├── base/
│ ├── _reset.css # Browser normalization
│ ├── _variables.css # CSS custom properties
│ ├── _typography.css # Font definitions
│ └── _base.css # Element defaults
├── layout/
│ ├── _grid.css # Grid system
│ ├── _header.css # Site header
│ ├── _footer.css # Site footer
│ └── _sidebar.css # Sidebar variations
├── components/
│ ├── _buttons.css # Button styles
│ ├── _forms.css # Form elements
│ ├── _tables.css # Table styles (unified)
│ ├── _navigation.css # Menus and tabs
│ ├── _cards.css # Content containers
│ ├── _modals.css # Dialogs
│ ├── _messages.css # Alerts
│ └── _autocomplete.css # Autocomplete widget
├── utilities/
│ ├── _spacing.css # Margin/padding utilities
│ ├── _text.css # Text utilities
│ ├── _display.css # Display utilities
│ └── _colors.css # Color utilities
└── pages/
└── _tree-viewer.css # Page-specific overrides
Modern CSS Patterns to Adopt:
-
BEM Naming Convention:
.table { } /* Block */ .table__header { } /* Element */ .table--striped { } /* Modifier */ .table__row--highlighted { } /* Element + Modifier */
-
CSS Custom Properties:
:root { --color-primary: #003366; --color-primary-light: #3863A4; --color-accent: #FF4500; --spacing-unit: 0.5rem; --font-family-base: "Helvetica Neue", Arial, sans-serif; } .button--primary { background: var(--color-primary); padding: calc(var(--spacing-unit) * 2); font-family: var(--font-family-base); }
-
Mobile-First Responsive Design:
/* Mobile styles (default) */ .container { width: 100%; } /* Tablet and up */ @media (min-width: 768px) { .container { width: 750px; } } /* Desktop and up */ @media (min-width: 1024px) { .container { width: 960px; } }
-
Flexbox/Grid Layout:
.layout { display: grid; grid-template-columns: 250px 1fr; grid-template-areas: "header header" "sidebar content" "footer footer"; }
-
Component Encapsulation:
- Self-contained components with minimal dependencies
- Consistent spacing and sizing within components
- Predictable state management (hover, focus, active, disabled)
Inventory:
| Library | Version | Size | Usage | Status |
|---|---|---|---|---|
| Prototype.js | 1.6.0.3 (2008) | 126KB | Core DOM manipulation, AJAX | |
| Scriptaculous | 1.9.0 (2010) | ~90KB | Effects, drag-drop, controls | |
| DWR (Direct Web Remoting) | Unknown | N/A | Server-client communication | |
| Raphael.js | 2.x (min) | 54KB | SVG graphics | |
| jsPhyloSVG | Unknown (min) | 34KB | Phylogenetic tree rendering | |
| D3.js | v7 (CDN) | N/A | Data visualization | ✅ MODERN |
| phylotree.js | 1.1.1 (CDN) | N/A | Tree visualization | ✅ MODERN |
Custom JavaScript Files:
| File | Size | Purpose | Modernization Needs |
|---|---|---|---|
common.js |
10KB | TreeBASE utilities, event handlers | High - Uses Prototype/Scriptaculous |
autocomplete.js |
3.7KB | Autocomplete widget | High - Prototype-dependent |
menuExpandable.js |
6.1KB | Expandable menu navigation | Medium - Pure JS possible |
ajaxProgress.js |
1KB | Progress indicators | Medium - Uses DWR |
googleAnalytics.js |
3.4KB | Analytics integration | Low - Standard GA |
multiFileUpload.js |
1KB | File upload handling | Medium |
xp_progress.js |
2.5KB | Progress bars | Medium |
Critical Issues:
-
Obsolete Libraries:
- Prototype.js last updated in 2008 (18 years old)
- Scriptaculous last updated in 2010 (16 years old)
- Security vulnerabilities likely present
- No active maintenance or community support
- Poor performance compared to modern alternatives
-
Multiple Prototype Versions:
<script src="prototype.js"></script> <!-- Older version --> <script src="prototype-1.6.0.3.js"></script> <!-- Newer version --> <script src="prototype-1.6.1.js"></script> <!-- Commented out -->
- Potential conflicts and bloat
- Unclear which version is actually used
-
Global Namespace Pollution:
var newwindow; // Global variable function popup(url) { } // Global function
-
Inline Event Handlers:
<body onload="TreeBASE.initialize()"> <a onclick="openHelp('submissionList')"> <button onclick="location.href='...'">
-
Embedded JavaScript in JSP:
- 120+ lines in
defaultSearchTemplate.jsp - 40+ lines in
defaultTemplate.jsp - Makes maintenance difficult
- No separation of concerns
- 120+ lines in
-
No Module System:
- All scripts loaded globally in
<head> - No code splitting or lazy loading
- No dependency management
- All scripts loaded globally in
-
No Build Process:
- No minification
- No bundling
- No transpilation (ES5 only)
- No tree shaking
-
Legacy Patterns:
// Old-style AJAX var req = new Ajax.Request(url, { 'method':'get', 'onSuccess':function(response){ } }); // Should be: fetch(url) .then(response => response.json()) .then(data => { });
Phase 1: Dependency Analysis (1 week)
- Map all JavaScript dependencies
- Identify Prototype/Scriptaculous usage patterns
- Document DWR endpoints and functionality
- Assess impact on each page/feature
Phase 2: Replace Prototype.js (3-4 weeks)
Replace with vanilla JavaScript and minimal libraries:
| Prototype Feature | Modern Replacement |
|---|---|
$('id') |
document.getElementById('id') or document.querySelector('#id') |
$$('.class') |
document.querySelectorAll('.class') |
Element.observe() |
addEventListener() |
Ajax.Request |
fetch() API |
Element.update() |
innerHTML or textContent |
Element.hasClassName() |
classList.contains() |
Element.addClassName() |
classList.add() |
Element.removeClassName() |
classList.remove() |
$H() (Hash) |
Map or plain objects |
$A() (Array) |
Native arrays with ES6+ methods |
Example Migration:
// OLD: Prototype
var inputs = $$('.textCell');
inputs.each(function(input) {
input.observe('focus', function() {
input.addClassName('focused');
});
});
// NEW: Vanilla JS
const inputs = document.querySelectorAll('.textCell');
inputs.forEach(input => {
input.addEventListener('focus', () => {
input.classList.add('focused');
});
});Phase 3: Replace Scriptaculous (2 weeks)
Replace with CSS transitions and modern libraries:
| Scriptaculous Feature | Modern Replacement |
|---|---|
| Visual effects | CSS transitions/animations |
| Drag and drop | HTML5 Drag & Drop API or SortableJS |
| Autocomplete | Native <datalist> or Choices.js |
| Slider | Native <input type="range"> or noUiSlider |
Example:
// OLD: Scriptaculous
Effect.Fade('element', { duration: 0.5 });
// NEW: CSS + Vanilla JS
element.style.transition = 'opacity 0.5s';
element.style.opacity = '0';Phase 4: Replace DWR (3-4 weeks)
Replace with REST API + fetch():
// OLD: DWR
RemotePersonService.findCompleteEmailAddress(token, function(data) {
autocompleter.setChoices(data);
});
// NEW: Fetch API
async function findCompleteEmailAddress(token) {
const response = await fetch(`/api/person/email?q=${token}`);
const data = await response.json();
return data;
}
// Usage
const emails = await findCompleteEmailAddress(token);
autocompleter.setChoices(emails);Backend Changes Required:
- Create RESTful endpoints for DWR services
- Return JSON responses
- Implement proper CORS if needed
Phase 5: Modernize Custom Scripts (2-3 weeks)
Refactor common.js:
// Convert to ES6 modules
export const TreeBASE = {
init: [],
initialize() {
this.init.forEach(fn => fn());
},
register(fn) {
this.init.push(fn);
}
};
// Convert popup functions to class
export class PopupManager {
constructor() {
this.window = null;
}
open(url, options = {}) {
const defaults = {
width: 600,
height: 400,
scrollbars: 'yes',
resizable: 'yes'
};
const config = { ...defaults, ...options };
const features = Object.entries(config)
.map(([key, value]) => `${key}=${value}`)
.join(',');
if (this.window) this.window.close();
this.window = window.open(url, 'help', features);
}
}Phase 6: Implement Build System (2 weeks)
Recommended Toolchain:
- Package Manager: npm or yarn
- Module Bundler: Webpack 5 or Vite
- Transpiler: Babel (for older browser support) or esbuild
- Linter: ESLint with recommended config
- Formatter: Prettier
Sample webpack.config.js:
module.exports = {
entry: './src/js/main.js',
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, 'dist/js')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
optimization: {
minimize: true,
splitChunks: {
chunks: 'all'
}
}
};Phase 7: Introduce Modern Libraries (1-2 weeks)
Recommended Replacements:
| Need | Library | Size (min+gzip) | Benefits |
|---|---|---|---|
| DOM utilities | Vanilla JS | 0KB | Native browser APIs |
| AJAX | fetch() + polyfill | 3KB | Native, promise-based |
| Autocomplete | Choices.js | 20KB | Modern, accessible |
| Date picker | Flatpickr | 15KB | Lightweight, flexible |
| Drag & drop | SortableJS | 25KB | Maintained, feature-rich |
| Tooltips | Tippy.js | 15KB | Performant, customizable |
| Modals | Micromodal.js | 3KB | Accessible, lightweight |
| Validation | Validator.js | 10KB | Comprehensive validation |
Phase 8: Improve User Experience (2-3 weeks)
Enhancements to Implement:
-
Loading States:
async function loadData() { showLoadingSpinner(); try { const data = await fetch('/api/data'); renderData(data); } catch (error) { showError(error.message); } finally { hideLoadingSpinner(); } }
-
Debouncing/Throttling:
const debounce = (fn, delay) => { let timeout; return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => fn(...args), delay); }; }; searchInput.addEventListener('input', debounce(performSearch, 300));
-
Optimistic Updates:
- Update UI immediately for better perceived performance
- Roll back on error
-
Progressive Enhancement:
- Core functionality works without JavaScript
- Enhanced features added with JavaScript
- Graceful degradation
-
Accessibility:
- Keyboard navigation
- ARIA labels and roles
- Focus management
- Screen reader support
Safe Removal Process:
-
Identify All Usage (Week 1):
# Find Prototype usage grep -r "\.observe\|\.update\|\$\$\|Ajax\.Request" src/ # Find Scriptaculous usage grep -r "Effect\.\|Draggable\|Autocompleter" src/
-
Create Abstraction Layer (Week 2-3):
- Write wrapper functions that work with both old and new code
- Gradually migrate pages one at a time
-
Page-by-Page Migration (Week 4-8):
- Start with low-traffic pages
- Test thoroughly before moving to high-traffic pages
- Use feature flags to toggle between old/new implementations
-
Remove Dead Code (Week 9):
- Once all pages migrated, remove old libraries
- Clean up abstraction layer
- Update documentation
Migration Priority:
High Priority (Security/Performance):
- Prototype.js → Vanilla JS (security vulnerabilities)
- DWR → REST API (better architecture)
- Scriptaculous → CSS animations (performance)
Medium Priority (Maintainability): 4. Inline scripts → External modules 5. Custom autocomplete → Modern library 6. Build process implementation
Low Priority (Nice-to-Have): 7. Raphael.js → SVG + CSS (if still needed) 8. jsPhyloSVG → Modern alternatives
Current State:
- Monolithic JSP files mixing HTML, CSS, and JavaScript
- No clear separation of concerns
- Duplicated code across pages
Proposed Structure:
webapp/
├── assets/
│ ├── css/ # Consolidated CSS
│ ├── js/ # Modern JavaScript modules
│ └── images/ # Optimized images
├── components/ # Reusable JSP fragments
│ ├── tables/
│ ├── forms/
│ └── navigation/
├── templates/ # Base templates only
└── pages/ # Page-specific JSP
JavaScript:
-
Code Splitting:
- Load only what's needed per page
- Lazy load tree visualization libraries
- Use dynamic imports for heavy components
-
Caching Strategy:
- Long-term caching for vendor libraries
- Cache busting with content hashes
- Service worker for offline functionality
-
Minification:
- Reduce JavaScript size by 60-70%
- Current: ~300KB, Target: ~100KB
CSS:
-
Remove Unused Styles:
- Use PurgeCSS to eliminate dead CSS
- Estimated 40% reduction in CSS size
-
Critical CSS:
- Inline critical styles in
<head> - Defer non-critical CSS loading
- Inline critical styles in
-
Minimize Repaints:
- Use CSS transforms instead of position changes
- Batch DOM modifications
Immediate Wins:
-
Responsive Design:
- Mobile-friendly layouts
- Touch-friendly controls (44x44px minimum)
- Readable font sizes on all devices
-
Loading Indicators:
- Show progress for AJAX requests
- Skeleton screens for content loading
- Prevent double-submissions
-
Form Validation:
- Real-time validation feedback
- Clear error messages
- Accessible error handling
-
Keyboard Navigation:
- Skip links for accessibility
- Logical tab order
- Keyboard shortcuts for power users
-
Visual Feedback:
- Hover states on interactive elements
- Focus indicators for keyboard users
- Disabled states clearly distinguished
Advanced Enhancements:
-
Infinite Scroll / Virtual Scrolling:
- For large data tables
- Reduce initial load time
- Better performance with thousands of rows
-
Client-Side Caching:
- Cache API responses
- Reduce server load
- Faster navigation
-
Optimistic UI Updates:
- Immediate feedback on actions
- Better perceived performance
-
Dark Mode:
- CSS custom properties for theming
- Respect user preferences
- Toggle in UI
Total Estimated Time: 20-28 weeks (5-7 months)
| Phase | Duration | Complexity | Risk |
|---|---|---|---|
| 1. CSS Consolidation | 8-12 weeks | Medium | Low |
| 2. JavaScript Modernization | 10-14 weeks | High | Medium |
| 3. Testing & QA | 2-3 weeks | Medium | Low |
| 4. Documentation | 1 week | Low | Low |
Month 1: Foundation
- Week 1-2: Audit and planning ✓
- Week 3-4: Set up build tools, create design system
Month 2: CSS Refactoring
- Week 5-6: Extract CSS variables, create base styles
- Week 7-8: Component CSS development
Month 3: CSS Completion + JS Start
- Week 9-10: Utility classes, eliminate inline styles
- Week 11-12: Begin Prototype.js replacement
Month 4: JavaScript Migration
- Week 13-14: Replace Scriptaculous, DWR
- Week 15-16: Modernize custom scripts
Month 5: Build System + Libraries
- Week 17-18: Implement build pipeline
- Week 19-20: Integrate modern libraries
Month 6: UX Improvements
- Week 21-22: Responsive design, accessibility
- Week 23-24: Performance optimization
Month 7: Testing & Launch
- Week 25-26: Comprehensive testing
- Week 27-28: Bug fixes, documentation, deployment
Technical Risks:
-
Breaking Changes:
- Mitigation: Feature flags, gradual rollout, extensive testing
- Create parallel implementation during transition
-
Browser Compatibility:
- Mitigation: Polyfills, transpilation, automated testing
- Support last 2 versions of major browsers
-
Performance Regression:
- Mitigation: Before/after benchmarks, performance monitoring
- Set performance budgets
-
DWR Replacement Complexity:
- Mitigation: Backend API development may require significant effort
- Consider keeping DWR temporarily if REST migration is complex
Organizational Risks:
-
Resource Availability:
- Requires 1-2 dedicated developers
- QA resources for testing
-
User Disruption:
- Mitigation: Phased rollout, user communication
- Maintain old UI as fallback option
Technical KPIs:
- CSS file count: 9 → 1 (consolidated)
- CSS size: 24KB → ~15KB (after minification)
- JavaScript libraries: 7 → 3-4
- JavaScript size: ~300KB → ~100KB
- Inline styles: 277 → 0
- Page load time: -30%
- Lighthouse score: 70 → 90+
Quality KPIs:
- Code maintainability: Improved by modular structure
- Accessibility: WCAG 2.1 AA compliance
- Browser compatibility: Support for 98%+ of users
- Mobile usability: 100% responsive
-
Layout Inconsistencies:
- 5 different templates with varying layout patterns
- No unified width/spacing system
- Pages like
treeViewer.jspoperate in isolation
-
CSS Fragmentation:
- 9 separate CSS files with overlap
- 277+ inline style instances
- No design system or CSS architecture
-
JavaScript Obsolescence:
- Core libraries 14-18 years old
- Security and performance concerns
- No modern development practices
-
Table Styling:
- Multiple table patterns without standardization
- DisplayTag library used inconsistently
- Extensive inline styling
Immediate Actions (Next 2 Months):
-
✅ Create Design System:
- Define color palette, typography, spacing
- Document in style guide
- Establish CSS custom properties
-
✅ Consolidate CSS:
- Merge 9 files into modular structure
- Create utility class library
- Begin removing inline styles
-
✅ Replace Prototype.js:
- Highest security/performance impact
- Use vanilla JavaScript alternatives
- Start with low-risk pages
Short-term Actions (Months 3-4):
-
✅ Implement Build Pipeline:
- Set up bundling and minification
- Add linting and formatting
- Establish CI/CD for frontend
-
✅ Standardize Tables:
- Create unified table component
- Replace DisplayTag styling inconsistencies
- Add responsive table patterns
Medium-term Actions (Months 5-7):
-
✅ Complete JavaScript Migration:
- Remove all Scriptaculous dependencies
- Replace DWR with REST API
- Modernize all custom scripts
-
✅ Enhance User Experience:
- Responsive design for mobile
- Improved accessibility
- Performance optimization
Year 1 Goals:
- Modern, maintainable codebase
- Excellent user experience across devices
- High performance and accessibility scores
- Strong foundation for future enhancements
Year 2+ Possibilities:
- Progressive Web App (PWA) capabilities
- Real-time collaboration features
- Advanced data visualization
- Machine learning integration for search
The TreeBASE web UI has significant technical debt accumulated over 15+ years. However, the application has a solid foundation and clear structure that will support systematic modernization. By following the recommended pathway, TreeBASE can achieve:
- Better Maintainability: Modular, well-organized code
- Improved Performance: Faster load times, better interactivity
- Enhanced Accessibility: WCAG compliance, mobile-friendly
- Future-Proof Architecture: Modern standards, active libraries
- Developer Experience: Better tooling, easier onboarding
The key is to approach this as an incremental transformation rather than a complete rewrite, minimizing risk while delivering continuous value.
- Server: Java/Spring Framework
- View Layer: JSP with SiteMesh decorators
- CSS: Plain CSS (9 files)
- JavaScript: Prototype.js, Scriptaculous, DWR
Maintain (Core):
- Java/Spring Framework (backend)
- JSP (view technology)
- SiteMesh decorators (layout)
Upgrade (Frontend):
-
CSS: Vanilla CSS with PostCSS
- Autoprefixer
- CSS Nano (minification)
- PurgeCSS (unused style removal)
-
JavaScript: ES6+ with modern tooling
- No framework required (vanilla JS sufficient)
- Fetch API for AJAX
- Native web components for complex widgets
-
Build Tools:
- Webpack 5 or Vite (bundling)
- Babel or esbuild (transpilation)
- ESLint + Prettier (quality)
- npm/yarn (package management)
Optional Enhancements:
- CSS Framework: Tailwind CSS or custom utility framework
- Component Library: Consider for complex UI components
- State Management: If application complexity grows
- Unknown (no documented browser requirements)
- Likely IE 6-8 era code patterns
Tier 1 (Full Support):
- Chrome/Edge (last 2 versions)
- Firefox (last 2 versions)
- Safari (last 2 versions)
- iOS Safari (last 2 versions)
- Android Chrome (last 2 versions)
Tier 2 (Graceful Degradation):
- IE 11 (if still required)
- Older mobile browsers
Coverage: ~98% of global users
Polyfills Needed:
- fetch() for older browsers
- Promises for IE 11
- Array methods (ES6+) for IE 11
- CSS custom properties for IE 11 (or use fallbacks)
HTML:
<table class="table table--striped table--sortable">
<thead>
<tr>
<th class="table__header table__header--sortable" data-sort="id">
ID
<span class="sort-icon"></span>
</th>
<th class="table__header table__header--sortable" data-sort="title">
Title
<span class="sort-icon"></span>
</th>
<th class="table__header">Actions</th>
</tr>
</thead>
<tbody class="table__body">
<!-- Data rows -->
</tbody>
</table>CSS:
:root {
--table-border-color: #ddd;
--table-header-bg: #f5f5f5;
--table-row-hover-bg: #f0f8ff;
--table-row-even-bg: #fafafa;
}
.table {
width: 100%;
border-collapse: collapse;
border: 1px solid var(--table-border-color);
}
.table__header {
background: var(--table-header-bg);
padding: 0.75rem;
text-align: left;
font-weight: 600;
border-bottom: 2px solid var(--table-border-color);
}
.table__header--sortable {
cursor: pointer;
user-select: none;
}
.table__header--sortable:hover {
background: var(--table-row-hover-bg);
}
.table--striped tbody tr:nth-child(even) {
background: var(--table-row-even-bg);
}
.table tbody tr:hover {
background: var(--table-row-hover-bg);
}
.sort-icon::after {
content: '⇅';
margin-left: 0.5rem;
opacity: 0.3;
}
.table__header--sorted-asc .sort-icon::after {
content: '↑';
opacity: 1;
}
.table__header--sorted-desc .sort-icon::after {
content: '↓';
opacity: 1;
}JavaScript:
class SortableTable {
constructor(tableElement) {
this.table = tableElement;
this.headers = tableElement.querySelectorAll('.table__header--sortable');
this.tbody = tableElement.querySelector('tbody');
this.rows = Array.from(this.tbody.querySelectorAll('tr'));
this.currentSort = { column: null, direction: 'asc' };
this.init();
}
init() {
this.headers.forEach(header => {
header.addEventListener('click', () => this.handleSort(header));
});
}
handleSort(header) {
const column = header.dataset.sort;
const direction = this.currentSort.column === column &&
this.currentSort.direction === 'asc' ? 'desc' : 'asc';
this.sortRows(column, direction);
this.updateUI(header, direction);
this.currentSort = { column, direction };
}
sortRows(column, direction) {
const columnIndex = Array.from(this.headers).findIndex(
h => h.dataset.sort === column
);
this.rows.sort((a, b) => {
const aValue = a.cells[columnIndex].textContent.trim();
const bValue = b.cells[columnIndex].textContent.trim();
const comparison = aValue.localeCompare(bValue, undefined, {
numeric: true,
sensitivity: 'base'
});
return direction === 'asc' ? comparison : -comparison;
});
this.tbody.innerHTML = '';
this.rows.forEach(row => this.tbody.appendChild(row));
}
updateUI(activeHeader, direction) {
this.headers.forEach(h => {
h.classList.remove('table__header--sorted-asc', 'table__header--sorted-desc');
});
activeHeader.classList.add(`table__header--sorted-${direction}`);
}
}
// Initialize all sortable tables
document.querySelectorAll('.table--sortable').forEach(table => {
new SortableTable(table);
});Document Version: 1.0
Last Updated: January 10, 2026
Next Review: February 2026