PageSourceSearch

https://brontosaurus.cz/wp-content/themes/brontosaurus-theme/scripts/references.js?ver=1787685656

js brontosaurus.cz collected 2026-09-24 09:06:10 UTC 6,957 bytes, 311 lines download raw bytes

1const selectors = {
2	BUTTON_HIDDEN: 'hb-references__button--hidden',
3	DOTS: 'hb-references__dots',
4	DOT: 'hb-references__dot',
5	DOT_ACTIVE: 'hb-references__dot--active',
6}
7
8document.addEventListener('DOMContentLoaded', () =>
9	document.querySelectorAll('[data-references]')
10		.forEach(el => initialize(el)));
11
12function initialize(rootEl) {
13	const CarousePositionPropertyName = '--carouselPosition';
14
15	const slidesEl = rootEl.querySelector('[data-references-slides]');
16	const previousButtonEl = rootEl.querySelector('[data-references-button="previous"]');
17	const nextButtonEl = rootEl.querySelector('[data-references-button="next"]');
18	if (slidesEl === null || previousButtonEl === null || nextButtonEl === null) {
19		return;
20	}
21
22	const slidesCount = slidesEl.children.length;
23	const defaultPosition = parseInt(window.getComputedStyle(slidesEl).getPropertyValue(CarousePositionPropertyName));
24	const allowInfinite = typeof rootEl.dataset.referencesInfinite !== 'undefined';
25	const allowAutoplay = typeof rootEl.dataset.referencesAutoplay !== 'undefined';
26	const noDots = typeof rootEl.dataset.referencesNoDots !== 'undefined';
27
28	const elementsInView = new ElementsInView(slidesEl);
29	const position = new Position(slidesCount, defaultPosition, allowInfinite, elementsInView);
30	const dots = noDots
31		? DotsFactory.disabled() // todo listen to elements in view, display only if count == 1
32		: DotsFactory.enabled(slidesEl, position, slidesCount);
33	const autoplay = new Autoplay(position);
34
35	position.addPositionChangedSubscriber((newPosition) => {
36		slidesEl.style.setProperty(CarousePositionPropertyName, newPosition.toString());
37		updateButtonVisibility();
38		dots.repaint(newPosition);
39	});
40
41	previousButtonEl.addEventListener('click', () => {
42		if (position.isAtFirst()) {
43			return;
44		}
45
46		autoplay.disable();
47		position.moveToPrevious();
48	});
49
50	nextButtonEl.addEventListener('click', () => {
51		if (position.isAtLast()) {
52			return;
53		}
54
55		autoplay.disable();
56		position.moveToNext();
57	});
58
59	const updateButtonVisibility = () => {
60		previousButtonEl.classList.remove(selectors.BUTTON_HIDDEN);
61		nextButtonEl.classList.remove(selectors.BUTTON_HIDDEN);
62
63		if (position.isAtFirst()) {
64			previousButtonEl.classList.add(selectors.BUTTON_HIDDEN);
65		}
66
67		if (position.isAtLast()) {
68			nextButtonEl.classList.add(selectors.BUTTON_HIDDEN);
69		}
70	};
71
72	// todo: resize, orientationchange
73
74
75	// on init
76	updateButtonVisibility();
77	dots.repaint(defaultPosition);
78
79	if (allowAutoplay) {
80		autoplay.enable();
81	}
82}
83
84
85/* ELEMENTS IN VIEW */
86
87class ElementsInView {
88
89    /** @private */
90    slidesEl;
91
92    constructor(slidesEl) {
93        this.slidesEl = slidesEl;
94    }
95
96    count() {
97        const containerWidth = this.slidesEl.getBoundingClientRect().width;
98        const slideWidth = this.slidesEl.children[0].getBoundingClientRect().width;
99        const ratio = containerWidth / slideWidth;
100        const count = ratio < 1 ? 1 : Math.floor(ratio);
101        return count;
102    }
103
104}
105
106
107/* POSITION */
108
109class Position {
110    /** @private */
111    slidesCount; // number
112	currentPosition; // number
113    /** @private */
114    allowInfinite; // boolean
115    /** @private */
116    elementsInView;
117
118	constructor(slidesCount, defaultPosition, allowInfinite, elementsInView) {
119        this.slidesCount = slidesCount;
120		this.currentPosition = defaultPosition;
121        this.allowInfinite = allowInfinite;
122        this.elementsInView = elementsInView;
123	}
124
125	moveToNext() {
126		if (this.currentPosition === this.getLastPosition()) {
127			this.currentPosition = 0;
128		} else {
129			this.currentPosition++;
130		}
131
132		this.positionChangedSubscribers.forEach(subscriber => subscriber(this.currentPosition));
133	}
134
135	moveToPrevious() {
136		if (this.currentPosition === 0) {
137			this.currentPosition = this.getLastPosition();
138		} else {
139			this.currentPosition--;
140		}
141
142		this.positionChangedSubscribers.forEach(subscriber => subscriber(this.currentPosition));
143	}
144
145	moveTo(position) {
146		if (position < 0 || position > (this.slidesCount - 1)) {
147			throw new Error('Position out of range');
148		}
149
150		const lastPosition = this.getLastPosition()
151		this.currentPosition = position > lastPosition
152			? lastPosition
153			: position;
154
155		this.positionChangedSubscribers.forEach(subscriber => subscriber(this.currentPosition));
156	}
157
158    /** @private */
159	positionChangedSubscribers = [];
160
161	addPositionChangedSubscriber(callback) {
162		this.positionChangedSubscribers.push(callback);
163	}
164
165	isAtFirst() {
166		if (this.allowInfinite) {
167			return false;
168		}
169
170		return this.currentPosition === 0;
171	}
172
173	isAtLast() {
174		if (this.allowInfinite) {
175			return false;
176		}
177
178		const lastPosition = this.getLastPosition();
179		return this.currentPosition >= lastPosition;
180	}
181
182    /** @private */
183	getLastPosition()
184	{
185		/**
186		 * example:
187		 * slides	at once		last position (we always want to render whole group)
188		 * 5		1			4
189		 * 5		2			3
190		 * 5		3			2
191		 * 5		4			1
192		 * 5		5			0
193		 */
194		return this.slidesCount - this.elementsInView.count();
195	}
196}
197
198
199/* DOTS */
200
201/**
202@interface Dots {
203	repaint(newPosition: number): void,
204}
205*/
206
207class DotsFactory
208{
209	static enabled(dataStorageEl, position, totalSlides) {
210		return new OnePerSlide(dataStorageEl, position, totalSlides);
211	}
212
213	static disabled() {
214		return new Noop();
215	}
216}
217
218/** @implements Dots */
219class OnePerSlide {
220    /** @private */
221	dots = [];
222    /** @private */
223    position;
224
225	constructor(dataStorageEl, position, totalSlides) {
226        this.position = position;
227
228		const containerEl = document.createElement('div');
229		containerEl.classList.add(selectors.DOTS);
230
231		for (let i = 0; i < totalSlides; i++) {
232			this.dots.push(new Dot(containerEl, this.position, i));
233		}
234
235		dataStorageEl.insertAdjacentElement("afterend", containerEl);
236	}
237
238	repaint(newPosition) {
239		this.dots.forEach(dot => dot.repaint(newPosition));
240	}
241}
242
243/**
244 * When no dots are needed
245 * @implements Dots
246 */
247class Noop {
248	constructor() {}
249	repaint(newPosition) {}
250}
251
252class Dot
253{
254    /** @private @readonly */
255	el;
256    /** @private */
257    position;
258    /** @private */
259    offset;
260
261	constructor(containerEl, position, offset) {
262        this.position = position;
263        this.offset = offset;
264
265		this.el = document.createElement('div');
266		this.el.classList.add(selectors.DOT);
267		containerEl.appendChild(this.el);
268
269		this.el.addEventListener('click', () => position.moveTo(this.offset));
270	}
271
272	repaint(newPosition) {
273		if (this.offset === newPosition) {
274			this.el.classList.add(selectors.DOT_ACTIVE);
275		} else {
276			this.el.classList.remove(selectors.DOT_ACTIVE);
277		}
278	}
279}
280
281
282/* AUTOPLAY */
283
284class Autoplay {
285    /** @private */
286	intervalId = null;
287    /** @private */
288	seconds = 5;
289    /** @private */
290    position;
291
292	constructor(position) {
293        this.position = position;
294    }
295
296	enable() {
297		this.intervalId = window.setInterval(
298			() => this.position.moveToNext(),
299			this.seconds * 1000,
300		);
301	}
302
303	disable() {
304		if (this.intervalId === null) {
305			return;
306		}
307
308		window.clearInterval(this.intervalId);
309		this.intervalId = null;
310	}
311}

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.