1import { FranklinBlock, throttle, blockColorThemeStructure, awaitChildBlocksReady, addThemingToBlock } from '../../scripts/lib-franklin.js'; 2 3export default class ImageContainer extends FranklinBlock { 4 variants = [ 5 { 6 name: 'bottom', 7 test: this.block.classList.contains('bottom'), 8 }, 9 { 10 name: 'top', 11 test: true, 12 }, 13 ]; 14 15 /** 16 * Get the color theme configuration for the image container 17 * This is used by both beforeBlockRenderColorThemingChildren and afterBlockRenderColorTheming 18 * @returns {Object} The collection block configuration object 19 */ 20 getCollectionBlockConfiguration() { 21 const parentCollectionSection = this.block?.parentElement; 22 const parentThemeAttr = Array.from(parentCollectionSection?.attributes || []).find((attr) => attr.name.includes('data-collection-color-theme')); 23 24 const themeOneWhiteClasses = ['color-theme-1-white']; 25 const hasThemeOneWhite = themeOneWhiteClasses.includes(parentThemeAttr?.value); 26 const themeOneCoreTintedClasses = ['color-theme-1-core-tinted']; 27 const hasThemeOneCoreTinted = themeOneCoreTintedClasses.includes(parentThemeAttr?.value); 28 const themeOneCoreSeedClasses = ['color-theme-1-core-seed']; 29 const hasThemeOneCoreSeed = themeOneCoreSeedClasses.includes(parentThemeAttr?.value); 30 31 return { 32 'color-theme-1-white': { 33 isMatch: hasThemeOneWhite, 34 colorThemeCollection: 'data-color-theme-one', 35 colorModeValue: 'white', 36 collectionWrappers: [{ target: ':scope > .core-image-container', classToAdd: 'surface' }], 37 }, 38 'color-theme-1-core-tinted': { 39 isMatch: hasThemeOneCoreTinted, 40 colorThemeCollection: 'data-color-theme-one', 41 colorModeValue: 'core-tinted', 42 collectionWrappers: [{ target: ':scope > .core-image-container', classToAdd: 'surface' }], 43 }, 44 'color-theme-1-core-seed': { 45 isMatch: hasThemeOneCoreSeed, 46 colorThemeCollection: 'data-color-theme-one', 47 colorModeValue: 'core-seed', 48 collectionWrappers: [{ target: ':scope > .core-image-container', classToAdd: 'surface' }], 49 }, 50 }; 51 } 52 53 beforeBlockRender() { 54 // Build initial inputData with image blocks 55 this.inputData = { 56 imageBlocks: this.config.imageBlocks.map((blockHTML) => { 57 const template = document.createElement('template'); 58 template.innerHTML = blockHTML; 59 const imageBlock = template.content.querySelector('.core-image'); 60 imageBlock?.classList.add('image-container-item'); 61 imageBlock?.classList.remove('top', 'bottom'); 62 imageBlock?.classList.add(this.variant === 'bottom' ? 'bottom' : 'top'); 63 if (this.block.classList.contains('has-divider')) { 64 imageBlock?.classList.add('has-divider'); 65 } 66 return template.innerHTML; 67 }), 68 textBlock: this.config.textBlock, 69 }; 70 71 // Try to get the theme from parent section if not already set on the block 72 // This handles the case where the collection container hasn't set it yet 73 if (!this.block.dataset.collectionColorTheme) { 74 const parentSection = this.block.closest('.section'); 75 const parentThemeAttr = Array.from(parentSection?.attributes || []).find((attr) => attr.name.includes('data-collection-color-theme')); 76 if (parentThemeAttr) { 77 this.block.dataset.collectionColorTheme = parentThemeAttr.value; 78 } 79 } 80 81 this.inputData = this.beforeBlockRenderColorThemingChildren(this.inputData, this.block.dataset.collectionColorTheme); 82 } 83 84 beforeBlockRenderColorThemingChildren(inputData, isActive = false) { 85 if (isActive) { 86 const { imageBlocks, textBlock } = inputData; 87 const themedImageBlocks = imageBlocks.map((blockHTML) => addThemingToBlock(blockHTML, 'core-image', this.block.dataset.collectionColorTheme)); 88 const themedTextBlock = textBlock ? addThemingToBlock(textBlock, 'core-text', this.block.dataset.collectionColorTheme) : null; 89 return { ...inputData, imageBlocks: themedImageBlocks, textBlock: themedTextBlock }; 90 } 91 return inputData; 92 } 93 94 /** 95 * Function to construct and target the proper DOM elements based on variant for color theming 96 */ 97 async afterBlockRenderColorTheming() { 98 const parentCollectionSection = this.block?.parentElement; 99 const parentThemeAttr = Array.from(parentCollectionSection?.attributes || []).find((attr) => attr.name.includes('data-collection-color-theme')); 100 if (!parentThemeAttr) return; 101 102 const collectionBlockConfiguration = this.getCollectionBlockConfiguration(); 103 blockColorThemeStructure(this.block, collectionBlockConfiguration, true); 104 } 105 106 afterBlockRender() { 107 // global standard rules for block padding 108 this.block.classList.add('block-padding-standard'); 109 110 awaitChildBlocksReady(this.block).then(() => { 111 this.calculateContentHeight(); 112 this.calculateImageHeight(); 113 }); 114 115 // Recalculate height on window resize 116 window.addEventListener( 117 'resize', 118 throttle(() => { 119 this.calculateContentHeight(); 120 this.calculateImageHeight(); 121 }, 100) 122 ); 123 124 // Apply color theming after render 125 // Double-check if theme attribute exists, fallback to parent section if needed 126 if (!this.block?.dataset?.collectionColorTheme) { 127 const parentSection = this.block.closest('.section'); 128 const parentThemeAttr = Array.from(parentSection?.attributes || []).find((attr) => attr.name.includes('data-collection-color-theme')); 129 130 if (parentThemeAttr) this.block.dataset.collectionColorTheme = parentThemeAttr.value; 131 132 this.afterBlockRenderColorTheming(); 133 this.block.setAttribute('data-color-theming-activated', 'true'); 134 } 135 136 if (this.block.classList.contains('editorial')) { 137 this.block.classList.add('block-padding-desktop-x-190'); 138 } 139 } 140 141 calculateImageHeight() { 142 this.block.style.removeProperty('--image-container-image-height'); 143 const maxImageHeight = Math.max(...Array.from(this.block.querySelectorAll('.core-image-image-container')).map((img) => img.offsetHeight)); 144 this.block.style.setProperty('--image-container-image-height', `${maxImageHeight}px`); 145 } 146 147 calculateContentHeight() { 148 this.block.style.removeProperty('--image-container-content-height'); 149 const maxContentHeight = Math.max(...Array.from(this.block.querySelectorAll('.core-image-content')).map((img) => img.offsetHeight)); 150 this.block.style.setProperty('--image-container-content-height', `${maxContentHeight}px`); 151 } 152}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.