#!/usr/bin/env node /** * HVAC Community Events CSS Vendor Prefix Fixes * * This script adds vendor prefixes for cross-browser compatibility * using Autoprefixer patterns to ensure support across all modern browsers. */ const fs = require('fs'); const path = require('path'); const CSS_DIR = './assets/css'; const prefixRules = []; // Vendor prefix patterns - following Autoprefixer standards const VENDOR_PREFIXES = { // Flexbox properties flexbox: { 'display: flex': [ 'display: -webkit-box', 'display: -ms-flexbox', 'display: flex' ], 'flex-direction: column': [ '-webkit-box-orient: vertical', '-webkit-box-direction: normal', '-ms-flex-direction: column', 'flex-direction: column' ], 'flex-direction: row': [ '-webkit-box-orient: horizontal', '-webkit-box-direction: normal', '-ms-flex-direction: row', 'flex-direction: row' ], 'justify-content: space-between': [ '-webkit-box-pack: justify', '-ms-flex-pack: justify', 'justify-content: space-between' ], 'justify-content: center': [ '-webkit-box-pack: center', '-ms-flex-pack: center', 'justify-content: center' ], 'justify-content: flex-start': [ '-webkit-box-pack: start', '-ms-flex-pack: start', 'justify-content: flex-start' ], 'justify-content: flex-end': [ '-webkit-box-pack: end', '-ms-flex-pack: end', 'justify-content: flex-end' ], 'align-items: center': [ '-webkit-box-align: center', '-ms-flex-align: center', 'align-items: center' ], 'align-items: flex-start': [ '-webkit-box-align: start', '-ms-flex-align: start', 'align-items: flex-start' ], 'align-items: flex-end': [ '-webkit-box-align: end', '-ms-flex-align: end', 'align-items: flex-end' ], 'align-items: stretch': [ '-webkit-box-align: stretch', '-ms-flex-align: stretch', 'align-items: stretch' ], 'flex: 1': [ '-webkit-box-flex: 1', '-ms-flex: 1', 'flex: 1' ], 'flex-wrap: wrap': [ '-ms-flex-wrap: wrap', 'flex-wrap: wrap' ] }, // CSS Grid properties grid: { 'display: grid': [ 'display: -ms-grid', 'display: grid' ], 'grid-template-columns': { pattern: /grid-template-columns:\s*([^;]+)/g, replacement: (match, value) => [ `-ms-grid-columns: ${value}`, `grid-template-columns: ${value}` ] }, 'grid-template-rows': { pattern: /grid-template-rows:\s*([^;]+)/g, replacement: (match, value) => [ `-ms-grid-rows: ${value}`, `grid-template-rows: ${value}` ] }, 'gap': { pattern: /gap:\s*([^;]+)/g, replacement: (match, value) => [ `grid-gap: ${value}`, `gap: ${value}` ] } }, // Transform properties transform: { pattern: /transform:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-transform: ${value}`, `-ms-transform: ${value}`, `transform: ${value}` ] }, // Transition properties transition: { pattern: /transition:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-transition: ${value}`, `transition: ${value}` ] }, // Animation properties animation: { pattern: /animation:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-animation: ${value}`, `animation: ${value}` ] }, // Box-shadow property boxShadow: { pattern: /box-shadow:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-box-shadow: ${value}`, `box-shadow: ${value}` ] }, // Border-radius property borderRadius: { pattern: /border-radius:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-border-radius: ${value}`, `border-radius: ${value}` ] }, // Appearance property appearance: { pattern: /appearance:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-appearance: ${value}`, `-moz-appearance: ${value}`, `appearance: ${value}` ] }, // User-select property userSelect: { pattern: /user-select:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-user-select: ${value}`, `-moz-user-select: ${value}`, `-ms-user-select: ${value}`, `user-select: ${value}` ] }, // Background-size property backgroundSize: { pattern: /background-size:\s*([^;]+)/g, replacement: (match, value) => [ `-webkit-background-size: ${value}`, `background-size: ${value}` ] } }; function addVendorPrefixesToFile(filePath) { try { let content = fs.readFileSync(filePath, 'utf8'); let modifications = 0; const fileName = path.basename(filePath); console.log(`\nProcessing: ${fileName}`); // Skip files that already have vendor prefixes if (content.includes('/* Vendor Prefixes Added */')) { console.log(' ✓ Vendor prefixes already exist, skipping'); return 0; } // Process flexbox properties Object.entries(VENDOR_PREFIXES.flexbox).forEach(([property, prefixes]) => { const regex = new RegExp(`${property.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}(?=\\s*;)`, 'g'); const matches = content.match(regex); if (matches && matches.length > 0) { content = content.replace(regex, prefixes.join(';\n ') + ';'); modifications += matches.length; console.log(` ✓ Added ${matches.length} flexbox prefixes for: ${property}`); } }); // Process other properties with regex patterns Object.entries(VENDOR_PREFIXES).forEach(([category, config]) => { if (category === 'flexbox') return; // Already processed above if (config.pattern && config.replacement) { const matches = [...content.matchAll(config.pattern)]; if (matches.length > 0) { matches.forEach(match => { const replacements = typeof config.replacement === 'function' ? config.replacement(match[0], match[1]) : config.replacement; content = content.replace(match[0], replacements.join(';\n ') + ';'); }); modifications += matches.length; console.log(` ✓ Added ${matches.length} ${category} prefixes`); } } }); // Add special handling for CSS Grid fallbacks if (content.includes('display: grid')) { const gridFallbacks = ` /* CSS Grid Fallbacks for IE */ .hvac-stats-row, .hvac-dashboard-stats, .hvac-certificate-stats { display: -ms-grid; -ms-grid-columns: repeat(auto-fit, minmax(200px, 1fr)); } /* Progressive enhancement for modern browsers */ @supports (display: grid) { .hvac-stats-row, .hvac-dashboard-stats, .hvac-certificate-stats { display: grid; } }`; if (!content.includes('/* CSS Grid Fallbacks for IE */')) { content += gridFallbacks; modifications += 3; console.log(' ✓ Added CSS Grid IE fallbacks'); } } // Add feature detection support const featureDetection = ` /* Feature Detection Support */ @supports not (display: flex) { .hvac-content [class*="flex"] { display: table-cell; vertical-align: middle; } } @supports not (display: grid) { .hvac-content [class*="grid"] { display: block; overflow: hidden; } .hvac-content [class*="grid"] > * { float: left; width: 50%; } }`; if (!content.includes('/* Feature Detection Support */') && modifications > 0) { content += featureDetection; modifications += 2; console.log(' ✓ Added feature detection fallbacks'); } // Add vendor prefix marker if (modifications > 0) { content = `/* Vendor Prefixes Added - ${new Date().toISOString().split('T')[0]} */\n${content}`; } // Write the updated content fs.writeFileSync(filePath, content, 'utf8'); if (modifications > 0) { console.log(` ✅ Added ${modifications} vendor prefixes total`); prefixRules.push({ file: fileName, modifications: modifications }); } else { console.log(' • No vendor prefixes needed'); } return modifications; } catch (error) { console.error(`Error processing ${filePath}:`, error.message); return 0; } } function createAutoprefixerConfig() { const configPath = './autoprefixer.config.js'; const configContent = `module.exports = { browsers: [ '> 1%', 'last 2 versions', 'Firefox ESR', 'not dead', 'IE 11' ], grid: 'autoplace', flexbox: 'no-2009' };`; if (!fs.existsSync(configPath)) { fs.writeFileSync(configPath, configContent, 'utf8'); console.log('✓ Created autoprefixer.config.js for future builds'); } } function main() { console.log('HVAC Community Events - CSS Vendor Prefix Fixes'); console.log('='.repeat(60)); if (!fs.existsSync(CSS_DIR)) { console.error(`CSS directory not found: ${CSS_DIR}`); process.exit(1); } // Focus on the main HVAC plugin CSS files const hvacFiles = [ 'hvac-common.css', 'hvac-dashboard.css', 'hvac-registration.css', 'hvac-event-summary.css', 'hvac-email-attendees.css', 'hvac-mobile-nav.css', 'hvac-animations.css', 'hvac-certificates.css', 'hvac-attendee-profile.css', 'hvac-print.css' ].map(file => path.join(CSS_DIR, file)); // Filter to only existing files const existingFiles = hvacFiles.filter(filePath => fs.existsSync(filePath)); let totalModifications = 0; // Process each CSS file existingFiles.forEach(filePath => { totalModifications += addVendorPrefixesToFile(filePath); }); // Create autoprefixer config for future builds createAutoprefixerConfig(); console.log('\n' + '='.repeat(60)); console.log('VENDOR PREFIX FIX SUMMARY'); console.log('='.repeat(60)); if (prefixRules.length > 0) { prefixRules.forEach(rule => { console.log(`${rule.file}: ${rule.modifications} prefixes added`); }); } console.log(`\nTotal files processed: ${existingFiles.length}`); console.log(`Total vendor prefixes added: ${totalModifications}`); if (totalModifications > 0) { console.log('\n✅ Vendor prefix fixes applied successfully!'); console.log('\nKey improvements:'); console.log('• Added -webkit- prefixes for Safari/Chrome'); console.log('• Added -ms- prefixes for IE/Edge'); console.log('• Added -moz- prefixes for Firefox'); console.log('• Added CSS Grid IE fallbacks'); console.log('• Added @supports feature detection'); console.log('• Created autoprefixer.config.js for builds'); console.log('\n📋 Browser Support:'); console.log('• Chrome/Safari: All modern features'); console.log('• Firefox: All modern features'); console.log('• Edge: All modern features'); console.log('• IE 11: Graceful fallbacks provided'); console.log('\n💡 Next Steps:'); console.log('• Test in IE 11 to verify fallbacks'); console.log('• Consider adding PostCSS/Autoprefixer to build process'); console.log('• Validate with BrowserStack or similar tools'); } else { console.log('\n✅ All CSS files already have vendor prefixes'); } } if (require.main === module) { main(); } module.exports = { addVendorPrefixesToFile, VENDOR_PREFIXES };