PageSourceSearch

https://northeastnews.net/pages/wp-content/themes/newsmash/assets/js/popular-categories-stories.js?ver=1.0.0

js northeastnews.net collected 2026-10-02 06:58:11 UTC 9,871 bytes, 399 lines download raw bytes

1(function ($) {
2	'use strict';
3
4	var PopularCategoryStories = {
5		modal: null,
6		innerStories: null,
7		actionButtons: null,
8		storyArrows: null,
9		progressWrap: null,
10		categoryOrder: [],
11		activeIndex: -1,
12		cache: {},
13		autoplaySpeed: 5000,
14		isPaused: false,
15		timer: null,
16		busy: false,
17		busyFailsafeTimer: null,
18		prefetching: {},
19
20		setBusy: function (value) {
21			var self = this;
22			this.busy = value;
23			clearTimeout(this.busyFailsafeTimer);
24			if (value) {
25				this.busyFailsafeTimer = setTimeout(function () {
26					self.busy = false;
27				}, 4000);
28			}
29		},
30
31		init: function () {
32			this.modal = $('.stories-cat');
33			if (!this.modal.length) {
34				return;
35			}
36
37			this.innerStories = this.modal.find('.inner-stories');
38			this.actionButtons = this.modal.find('.action-buttons');
39			this.storyArrows = this.modal.find('.story-arrows');
40			this.progressWrap = this.modal.find('.story-progress');
41
42			var self = this;
43			$('.popular-cat-story').not('.slick-cloned').each(function () {
44				self.categoryOrder.push(String($(this).data('id')));
45			});
46
47			this.bindTrigger();
48			this.bindClose();
49			this.bindPause();
50			this.bindArrows();
51			this.bindTapZones();
52			this.bindEsc();
53		},
54
55		bindTrigger: function () {
56			var self = this;
57			$(document).on('click', '.popular-cat-trigger', function (e) {
58				e.preventDefault();
59				var storyEl = $(this).closest('.popular-cat-story'),
60					catId = String(storyEl.data('id')),
61					index = self.categoryOrder.indexOf(catId);
62				self.activeIndex = index > -1 ? index : 0;
63				self.open(catId);
64			});
65		},
66
67		open: function (catId) {
68			var self = this;
69			$('body').addClass('cat-stories--open');
70			this.modal.addClass('open');
71			this.isPaused = false;
72			this.setBusy(false);
73			this.actionButtons
74				.find('.action-btn.pause')
75				.removeClass('paused')
76				.find('i')
77				.removeClass('fa-play')
78				.addClass('fa-pause');
79			this.load(catId, function () {
80				self.render(catId, false);
81			});
82		},
83
84		fallbackHtml: function (catId, message) {
85			return (
86				'<div class="inner-story-wrap" data-id="' + catId + '">' +
87				'<div class="story-item no-thumb"><div class="content-wrap"><p class="no-posts">' +
88				message +
89				'</p></div></div></div>'
90			);
91		},
92
93		load: function (catId, callback) {
94			var self = this;
95			if (this.cache[catId]) {
96				callback();
97				return;
98			}
99			this.modal.addClass('loading');
100			$.ajax({
101				url: newsmashStories.ajaxUrl,
102				method: 'POST',
103				data: {
104					action: 'newsmash_category_stories',
105					nonce: newsmashStories.nonce,
106					cat_id: catId
107				},
108				success: function (response) {
109					if (response && response.success && response.data) {
110						self.cache[catId] = response.data;
111					} else {
112						self.cache[catId] = self.fallbackHtml(catId, newsmashStories.noPosts);
113					}
114				},
115				error: function () {
116					self.cache[catId] = self.fallbackHtml(catId, newsmashStories.noPosts);
117				},
118				complete: function () {
119					self.modal.removeClass('loading');
120					callback();
121				}
122			});
123		},
124
125		prefetch: function (catId) {
126			var self = this;
127			if (!catId || this.cache[catId] || this.prefetching[catId]) {
128				return;
129			}
130			this.prefetching[catId] = true;
131			$.ajax({
132				url: newsmashStories.ajaxUrl,
133				method: 'POST',
134				data: {
135					action: 'newsmash_category_stories',
136					nonce: newsmashStories.nonce,
137					cat_id: catId
138				},
139				success: function (response) {
140					if (response && response.success && response.data) {
141						self.cache[catId] = response.data;
142					}
143				},
144				complete: function () {
145					delete self.prefetching[catId];
146				}
147			});
148		},
149
150		prefetchNeighbors: function () {
151			this.prefetch(this.categoryOrder[this.activeIndex + 1]);
152			this.prefetch(this.categoryOrder[this.activeIndex - 1]);
153		},
154
155		render: function (catId, startAtEnd) {
156			var self = this;
157			this.innerStories.empty().append(this.cache[catId] || this.fallbackHtml(catId, newsmashStories.noPosts));
158
159			var wrap = this.innerStories.find('.inner-story-wrap'),
160				slideCount = wrap.find('.story-item').length,
161				initialSlide = startAtEnd ? Math.max(0, slideCount - 1) : 0;
162
163			if (!wrap.length) {
164				this.setBusy(false);
165				return;
166			}
167
168			wrap.on('init', function () {
169				self.buildProgress(wrap);
170				self.setActiveProgress(initialSlide);
171				self.setAmbient(wrap, initialSlide);
172				self.setBusy(false);
173				self.prefetchNeighbors();
174				if (!self.isPaused) {
175					self.scheduleAdvance();
176				}
177			});
178
179			wrap.on('beforeChange', function (e, slick, currentSlide, nextSlide) {
180				self.setActiveProgress(nextSlide);
181				self.setAmbient(wrap, nextSlide);
182			});
183
184			wrap.on('afterChange', function () {
185				self.setBusy(false);
186				if (!self.isPaused) {
187					self.scheduleAdvance();
188				}
189			});
190
191			try {
192				wrap.slick({
193					autoplay: false,
194					fade: true,
195					infinite: false,
196					speed: 300,
197					arrows: false,
198					dots: false,
199					adaptiveHeight: false,
200					initialSlide: initialSlide
201				});
202			} catch (e) {
203				self.setBusy(false);
204			}
205		},
206
207		scheduleAdvance: function () {
208			var self = this;
209			clearTimeout(this.timer);
210			this.timer = setTimeout(function () {
211				self.goNext();
212			}, this.autoplaySpeed);
213		},
214
215		goNext: function () {
216			if (this.busy) {
217				return;
218			}
219			clearTimeout(this.timer);
220			var wrap = this.innerStories.find('.inner-story-wrap');
221			if (wrap.hasClass('slick-initialized')) {
222				var slick = wrap.slick('getSlick');
223				if (slick.currentSlide < slick.slideCount - 1) {
224					this.setBusy(true);
225					wrap.slick('slickNext');
226					return;
227				}
228			}
229			this.nextCategory();
230		},
231
232		goPrev: function () {
233			if (this.busy) {
234				return;
235			}
236			clearTimeout(this.timer);
237			var wrap = this.innerStories.find('.inner-story-wrap');
238			if (wrap.hasClass('slick-initialized')) {
239				var slick = wrap.slick('getSlick');
240				if (slick.currentSlide > 0) {
241					this.setBusy(true);
242					wrap.slick('slickPrev');
243					return;
244				}
245			}
246			this.prevCategory(true);
247		},
248
249		buildProgress: function (wrap) {
250			var count = wrap.find('.story-item').length;
251			this.progressWrap.empty();
252			for (var i = 0; i < count; i++) {
253				this.progressWrap.append('<span class="segment"><em></em></span>');
254			}
255		},
256
257		setActiveProgress: function (index) {
258			var self = this,
259				segments = this.progressWrap.find('.segment');
260			segments.removeClass('active done');
261			segments.find('em').css('animation', 'none');
262			segments.each(function (i) {
263				if (i < index) {
264					$(this).addClass('done');
265				}
266			});
267			var active = segments.eq(index).addClass('active');
268			if (!self.isPaused) {
269				window.requestAnimationFrame(function () {
270					active
271						.find('em')
272						.css('animation', 'newsmash-story-progress ' + self.autoplaySpeed / 1000 + 's linear forwards');
273				});
274			}
275		},
276
277		setAmbient: function (wrap, index) {
278			var img = wrap.find('.story-item').eq(index).find('.story-cover img').attr('src');
279			this.modal.find('.ambient-bg').css('background-image', img ? 'url(' + img + ')' : 'none');
280		},
281
282		nextCategory: function () {
283			clearTimeout(this.timer);
284			if (this.activeIndex < this.categoryOrder.length - 1) {
285				this.setBusy(true);
286				this.activeIndex++;
287				this.switchTo(this.categoryOrder[this.activeIndex], false);
288			} else {
289				this.close();
290			}
291		},
292
293		prevCategory: function (landOnLastPost) {
294			clearTimeout(this.timer);
295			if (this.activeIndex > 0) {
296				this.setBusy(true);
297				this.activeIndex--;
298				this.switchTo(this.categoryOrder[this.activeIndex], !!landOnLastPost);
299			}
300		},
301
302		switchTo: function (catId, startAtEnd) {
303			var self = this,
304				wrap = this.innerStories.find('.inner-story-wrap');
305			try {
306				if (wrap.hasClass('slick-initialized')) {
307					wrap.slick('unslick');
308				}
309			} catch (e) {}
310			this.innerStories.empty();
311			this.progressWrap.empty();
312			this.load(catId, function () {
313				self.render(catId, startAtEnd);
314			});
315		},
316
317		bindArrows: function () {
318			var self = this;
319			this.storyArrows.on('click', '.prev-cat', function () {
320				self.goPrev();
321			});
322			this.storyArrows.on('click', '.next-cat', function () {
323				self.goNext();
324			});
325		},
326
327		bindTapZones: function () {
328			var self = this;
329			this.innerStories.on('click', function (e) {
330				if ($(e.target).closest('a, button').length) {
331					return;
332				}
333				var offsetX = e.pageX - $(this).offset().left,
334					width = $(this).outerWidth();
335				if (offsetX < width / 2) {
336					self.goPrev();
337				} else {
338					self.goNext();
339				}
340			});
341		},
342
343		bindPause: function () {
344			var self = this;
345			this.actionButtons.on('click', '.action-btn.pause', function () {
346				var btn = $(this);
347				self.isPaused = !self.isPaused;
348				btn.toggleClass('paused', self.isPaused);
349				btn.find('i').toggleClass('fa-pause fa-play');
350
351				var activeEm = self.progressWrap.find('.segment.active em');
352				if (self.isPaused) {
353					clearTimeout(self.timer);
354					activeEm.css('animation-play-state', 'paused');
355				} else {
356					activeEm.css('animation-play-state', 'running');
357					self.scheduleAdvance();
358				}
359			});
360		},
361
362		bindClose: function () {
363			var self = this;
364			this.modal.on('click', '.action-btn.close, .stories-cat-overlay, .ambient-bg', function () {
365				self.close();
366			});
367		},
368
369		bindEsc: function () {
370			var self = this;
371			$(document).on('keydown', function (e) {
372				if (e.keyCode === 27 && self.modal.hasClass('open')) {
373					self.close();
374				}
375			});
376		},
377
378		close: function () {
379			clearTimeout(this.timer);
380			var wrap = this.innerStories.find('.inner-story-wrap');
381			try {
382				if (wrap.hasClass('slick-initialized')) {
383					wrap.slick('unslick');
384				}
385			} catch (e) {}
386			this.modal.removeClass('open');
387			$('body').removeClass('cat-stories--open');
388			this.innerStories.empty();
389			this.progressWrap.empty();
390			this.activeIndex = -1;
391			this.isPaused = false;
392			this.setBusy(false);
393		}
394	};
395
396	$(function () {
397		PopularCategoryStories.init();
398	});
399})(jQuery);

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.