PageSourceSearch

https://www.elle.cz/js/modules/articleBoxLargePerex.js

js elle.cz collected 2026-10-02 07:55:35 UTC 4,295 bytes, 113 lines download raw bytes

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.