1import {parsePixelValue} from '../core/measure.js'; 2import {createRafScheduler} from '../core/rafScheduler.js'; 3 4const DYNAMIC_CROPPING_MIN_WIDTH = 768; 5const CLAMP_TOLERANCE_LINES = 0.75; 6 7const getLineHeight = (element) => { 8 const computedStyle = window.getComputedStyle(element); 9 const declaredLineHeight = parsePixelValue(computedStyle.lineHeight); 10 if (declaredLineHeight > 0) { 11 return declaredLineHeight; 12 } 13 14 const fontSize = parsePixelValue(computedStyle.fontSize); 15 return fontSize > 0 ? fontSize * 1.2 : 19.2; 16}; 17 18const supportsDynamicCropping = (cardLink, contentWrap) => { 19 const cardStyle = window.getComputedStyle(cardLink); 20 const contentStyle = window.getComputedStyle(contentWrap); 21 22 return window.innerWidth >= DYNAMIC_CROPPING_MIN_WIDTH 23 && cardStyle.display === 'grid' 24 && contentStyle.overflow === 'hidden'; 25}; 26 27const getMainArticleCards = () => 28 Array.from(document.querySelectorAll('.article-box-large__main-article > .article-card__link')); 29 30const resetDesktopCropping = (cardLink, contentWrap, perex) => { 31 cardLink.style.removeProperty('--article-box-large-main-image-height'); 32 contentWrap.style.removeProperty('height'); 33 perex.style.removeProperty('max-height'); 34 perex.style.removeProperty('-webkit-line-clamp'); 35}; 36 37const updateMainArticleCard = (cardLink) => { 38 const imageWrap = cardLink.querySelector(':scope > .article-card__image-wrap'); 39 const contentWrap = cardLink.querySelector(':scope > .article-card__content-wrap'); 40 const heading = contentWrap?.querySelector('.article-card__heading'); 41 const perex = contentWrap?.querySelector('.article-box-large__main-perex'); 42 43 if (!(imageWrap instanceof HTMLElement) || !(contentWrap instanceof HTMLElement) || !(perex instanceof HTMLElement)) { 44 return; 45 } 46 47 if (!supportsDynamicCropping(cardLink, contentWrap)) { 48 resetDesktopCropping(cardLink, contentWrap, perex); 49 return; 50 } 51 52 const imageHeight = Math.round(imageWrap.getBoundingClientRect().height); 53 if (imageHeight <= 0) { 54 return; 55 } 56 57 const rowGap = parsePixelValue(window.getComputedStyle(contentWrap).rowGap); 58 const headingHeight = heading instanceof HTMLElement ? Math.round(heading.getBoundingClientRect().height) : 0; 59 const availablePerexHeight = Math.max(imageHeight - headingHeight - rowGap, 0); 60 const lineHeight = getLineHeight(perex); 61 const toleranceHeight = lineHeight * CLAMP_TOLERANCE_LINES; 62 const toleratedPerexHeight = availablePerexHeight + toleranceHeight; 63 const visibleLines = Math.max(Math.floor(toleratedPerexHeight / lineHeight), 1); 64 65 cardLink.style.setProperty('--article-box-large-main-image-height', `${imageHeight + toleranceHeight}px`); 66 contentWrap.style.height = `${imageHeight + toleranceHeight}px`; 67 perex.style.maxHeight = `${toleratedPerexHeight}px`; 68 perex.style.setProperty('-webkit-line-clamp', `${visibleLines}`); 69}; 70 71export const initArticleBoxLargePerex = () => { 72 const cards = getMainArticleCards(); 73 if (!cards.length) { 74 return; 75 } 76 77 const recalculate = () => { 78 cards.forEach((card) => updateMainArticleCard(card)); 79 }; 80 const recalculateScheduler = createRafScheduler(recalculate); 81 82 cards.forEach((cardLink) => { 83 const image = cardLink.querySelector(':scope > .article-card__image-wrap > .article-card__image > img, :scope > .article-card__image-wrap > .article-card__image'); 84 if (image instanceof HTMLImageElement) { 85 if (!image.complete) { 86 image.addEventListener('load', recalculateScheduler.schedule, {passive: true}); 87 } 88 image.addEventListener('error', recalculateScheduler.schedule, {passive: true}); 89 } 90 }); 91 92 if (typeof ResizeObserver !== 'undefined') { 93 const resizeObserver = new ResizeObserver(() => { 94 recalculateScheduler.schedule(); 95 }); 96 97 cards.forEach((cardLink) => { 98 const imageWrap = cardLink.querySelector(':scope > .article-card__image-wrap'); 99 const contentWrap = cardLink.querySelector(':scope > .article-card__content-wrap'); 100 101 if (imageWrap instanceof HTMLElement) { 102 resizeObserver.observe(imageWrap); 103 } 104 105 if (contentWrap instanceof HTMLElement) { 106 resizeObserver.observe(contentWrap); 107 } 108 }); 109 } 110 111 window.addEventListener('resize', recalculateScheduler.schedule); 112 recalculateScheduler.schedule(); 113};
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.