docs: Update skeleton loader implementation from hyperscript to JavaScript
MIGRATION SUMMARY: - Moved skeleton loader logic from hyperscript to JavaScript (main.js) - Changed from htmx:oobAfterSwap to htmx:afterSettle event - Changed OOB swap from innerHTML to outerHTML for proper element replacement - Added languageSwitching flag for state tracking - Added 100ms delay after afterSettle for final render completion DOCUMENTATION UPDATES: - 2-MODERN-WEB-TECHNIQUES.md: Updated skeleton loader section with
This commit is contained in:
@@ -86,45 +86,27 @@ async function testSkeletonLoaders() {
|
||||
// ========================================================================
|
||||
console.log("\n4️⃣ Testing First Language Switch (EN → ES)...");
|
||||
|
||||
// Set up monitoring
|
||||
await page.evaluate(() => {
|
||||
window.loadingEvents = [];
|
||||
|
||||
const containers = [
|
||||
document.querySelector('#cv-inner-content-page-1'),
|
||||
document.querySelector('#cv-inner-content-page-2')
|
||||
];
|
||||
|
||||
containers.forEach((container, index) => {
|
||||
if (container) {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === 'class') {
|
||||
window.loadingEvents.push({
|
||||
time: Date.now(),
|
||||
container: index + 1,
|
||||
hasLoading: mutation.target.classList.contains('loading')
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(container, { attributes: true });
|
||||
}
|
||||
});
|
||||
// Set up console log monitoring to track our JavaScript skeleton loader messages
|
||||
const consoleMessages = [];
|
||||
page.on('console', msg => {
|
||||
const text = msg.text();
|
||||
if (text.includes('Skeleton loader:')) {
|
||||
consoleMessages.push(text);
|
||||
}
|
||||
});
|
||||
|
||||
// Click Spanish button
|
||||
await page.click('.selector-btn[aria-label="Español"]');
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
const switch1 = await page.evaluate(() => window.loadingEvents || []);
|
||||
const loadingAdded1 = switch1.filter(e => e.hasLoading).length;
|
||||
const loadingRemoved1 = switch1.filter(e => !e.hasLoading).length;
|
||||
// Check the console messages
|
||||
const addedMessages1 = consoleMessages.filter(m => m.includes('Added .loading')).length;
|
||||
const removedMessages1 = consoleMessages.filter(m => m.includes('Removed .loading')).length;
|
||||
|
||||
console.log(` Parent containers got .loading: ${loadingAdded1 > 0 ? '✅' : '❌'} (${loadingAdded1} events)`);
|
||||
console.log(` Parent containers lost .loading: ${loadingRemoved1 > 0 ? '✅' : '❌'} (${loadingRemoved1} events)`);
|
||||
console.log(` Skeleton loader added .loading: ${addedMessages1 > 0 ? '✅' : '❌'} (${addedMessages1} events)`);
|
||||
console.log(` Skeleton loader removed .loading: ${removedMessages1 > 0 ? '✅' : '❌'} (${removedMessages1} events)`);
|
||||
|
||||
const switch1Passed = loadingAdded1 > 0 && loadingRemoved1 > 0;
|
||||
const switch1Passed = addedMessages1 > 0 && removedMessages1 > 0;
|
||||
console.log(` ${switch1Passed ? '✅ PASS' : '❌ FAIL'} - Skeleton displayed during transition`);
|
||||
testResults.push({ test: 'First Language Switch', passed: switch1Passed });
|
||||
|
||||
@@ -133,21 +115,22 @@ async function testSkeletonLoaders() {
|
||||
// ========================================================================
|
||||
console.log("\n5️⃣ Testing Second Language Switch (ES → EN)...");
|
||||
|
||||
// Clear events
|
||||
await page.evaluate(() => { window.loadingEvents = []; });
|
||||
// Clear console messages
|
||||
const beforeSwitch2 = consoleMessages.length;
|
||||
|
||||
// Click English button
|
||||
await page.click('.selector-btn[aria-label="English"]');
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
const switch2 = await page.evaluate(() => window.loadingEvents || []);
|
||||
const loadingAdded2 = switch2.filter(e => e.hasLoading).length;
|
||||
const loadingRemoved2 = switch2.filter(e => !e.hasLoading).length;
|
||||
// Check new console messages since last switch
|
||||
const newMessages2 = consoleMessages.slice(beforeSwitch2);
|
||||
const addedMessages2 = newMessages2.filter(m => m.includes('Added .loading')).length;
|
||||
const removedMessages2 = newMessages2.filter(m => m.includes('Removed .loading')).length;
|
||||
|
||||
console.log(` Parent containers got .loading: ${loadingAdded2 > 0 ? '✅' : '❌'} (${loadingAdded2} events)`);
|
||||
console.log(` Parent containers lost .loading: ${loadingRemoved2 > 0 ? '✅' : '❌'} (${loadingRemoved2} events)`);
|
||||
console.log(` Skeleton loader added .loading: ${addedMessages2 > 0 ? '✅' : '❌'} (${addedMessages2} events)`);
|
||||
console.log(` Skeleton loader removed .loading: ${removedMessages2 > 0 ? '✅' : '❌'} (${removedMessages2} events)`);
|
||||
|
||||
const switch2Passed = loadingAdded2 > 0 && loadingRemoved2 > 0;
|
||||
const switch2Passed = addedMessages2 > 0 && removedMessages2 > 0;
|
||||
console.log(` ${switch2Passed ? '✅ PASS' : '❌ FAIL'} - Skeleton still works on second switch`);
|
||||
testResults.push({ test: 'Second Language Switch', passed: switch2Passed });
|
||||
|
||||
@@ -156,18 +139,22 @@ async function testSkeletonLoaders() {
|
||||
// ========================================================================
|
||||
console.log("\n6️⃣ Testing Third Language Switch (EN → ES)...");
|
||||
|
||||
await page.evaluate(() => { window.loadingEvents = []; });
|
||||
// Clear console messages
|
||||
const beforeSwitch3 = consoleMessages.length;
|
||||
|
||||
// Click Spanish button
|
||||
await page.click('.selector-btn[aria-label="Español"]');
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
const switch3 = await page.evaluate(() => window.loadingEvents || []);
|
||||
const loadingAdded3 = switch3.filter(e => e.hasLoading).length;
|
||||
const loadingRemoved3 = switch3.filter(e => !e.hasLoading).length;
|
||||
// Check new console messages since last switch
|
||||
const newMessages3 = consoleMessages.slice(beforeSwitch3);
|
||||
const addedMessages3 = newMessages3.filter(m => m.includes('Added .loading')).length;
|
||||
const removedMessages3 = newMessages3.filter(m => m.includes('Removed .loading')).length;
|
||||
|
||||
console.log(` Parent containers got .loading: ${loadingAdded3 > 0 ? '✅' : '❌'} (${loadingAdded3} events)`);
|
||||
console.log(` Parent containers lost .loading: ${loadingRemoved3 > 0 ? '✅' : '❌'} (${loadingRemoved3} events)`);
|
||||
console.log(` Skeleton loader added .loading: ${addedMessages3 > 0 ? '✅' : '❌'} (${addedMessages3} events)`);
|
||||
console.log(` Skeleton loader removed .loading: ${removedMessages3 > 0 ? '✅' : '❌'} (${removedMessages3} events)`);
|
||||
|
||||
const switch3Passed = loadingAdded3 > 0 && loadingRemoved3 > 0;
|
||||
const switch3Passed = addedMessages3 > 0 && removedMessages3 > 0;
|
||||
console.log(` ${switch3Passed ? '✅ PASS' : '❌ FAIL'} - Consistent behavior on third switch`);
|
||||
testResults.push({ test: 'Third Language Switch', passed: switch3Passed });
|
||||
|
||||
@@ -197,31 +184,29 @@ async function testSkeletonLoaders() {
|
||||
testResults.push({ test: 'No Stuck Loading States', passed: noStuckStates });
|
||||
|
||||
// ========================================================================
|
||||
// TEST 7: Hyperscript event delegation works
|
||||
// TEST 7: JavaScript event handlers work
|
||||
// ========================================================================
|
||||
console.log("\n8️⃣ Testing Hyperscript Event Delegation...");
|
||||
console.log("\n8️⃣ Testing JavaScript Event Handlers...");
|
||||
|
||||
const hyperscriptCheck = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const hasHyperscript = body.hasAttribute('_');
|
||||
const hyperscriptContent = body.getAttribute('_') || '';
|
||||
const hasBeforeRequest = hyperscriptContent.includes('htmx:beforeRequest');
|
||||
const hasOobAfterSwap = hyperscriptContent.includes('htmx:oobAfterSwap');
|
||||
const jsCheck = await page.evaluate(() => {
|
||||
// Check if main.js loaded and languageSwitching variable exists
|
||||
const hasLanguageSwitchingFlag = typeof window.languageSwitching !== 'undefined';
|
||||
|
||||
// Verify the flag is in clean state (false)
|
||||
const flagIsClean = window.languageSwitching === false;
|
||||
|
||||
return {
|
||||
hasHyperscript,
|
||||
hasBeforeRequest,
|
||||
hasOobAfterSwap
|
||||
hasLanguageSwitchingFlag,
|
||||
flagIsClean
|
||||
};
|
||||
});
|
||||
|
||||
console.log(` Body has _hyperscript: ${hyperscriptCheck.hasHyperscript ? '✅' : '❌'}`);
|
||||
console.log(` Listens for htmx:beforeRequest: ${hyperscriptCheck.hasBeforeRequest ? '✅' : '❌'}`);
|
||||
console.log(` Listens for htmx:oobAfterSwap: ${hyperscriptCheck.hasOobAfterSwap ? '✅' : '❌'}`);
|
||||
console.log(` JavaScript languageSwitching flag exists: ${jsCheck.hasLanguageSwitchingFlag ? '✅' : '❌'}`);
|
||||
console.log(` Flag is in clean state (false): ${jsCheck.flagIsClean ? '✅' : '❌'}`);
|
||||
|
||||
const hyperscriptPassed = hyperscriptCheck.hasHyperscript && hyperscriptCheck.hasBeforeRequest && hyperscriptCheck.hasOobAfterSwap;
|
||||
console.log(` ${hyperscriptPassed ? '✅ PASS' : '❌ FAIL'} - Global event delegation configured`);
|
||||
testResults.push({ test: 'Hyperscript Event Delegation', passed: hyperscriptPassed });
|
||||
const jsPassed = jsCheck.hasLanguageSwitchingFlag && jsCheck.flagIsClean;
|
||||
console.log(` ${jsPassed ? '✅ PASS' : '❌ FAIL'} - JavaScript event handlers configured`);
|
||||
testResults.push({ test: 'JavaScript Event Handlers', passed: jsPassed });
|
||||
|
||||
// ========================================================================
|
||||
// FINAL SUMMARY
|
||||
|
||||
Reference in New Issue
Block a user