PageSourceSearch

https://www.equilar.com/js/sa.js

js equilar.com collected 2026-09-24 08:45:46 UTC 12,073 bytes, 273 lines download raw bytes

1// Function to fetch the latest articles from the API
2async function fetchLatestArticles() {
3    const urls = [
4        'https://www.equilar.com/wp-json/wp/v2/publication?offset=0',
5        'https://www.equilar.com/wp-json/wp/v2/posts?offset=0',
6        'https://www.equilar.com/wp-json/wp/v2/event?offset=0',
7        'https://www.equilar.com/wp-json/wp/v2/webinar?offset=0'
8    ];
9
10    try {
11        const [publicationResponse, blogResponse, eventResponse, webinarResponse] = await Promise.all(urls.map(url => fetch(url)));
12
13        const publicationData = await publicationResponse.json();
14        const blogData = await blogResponse.json();
15        const eventData = await eventResponse.json();
16        const webinarData = await webinarResponse.json();
17
18        // Filter and sort events
19        const filteredEventData = eventData.filter(event => 
20            event.acf.register_now_link || event.title.rendered.toLowerCase().includes('save the date')
21        ).sort((a, b) => new Date(a.acf.event_date) - new Date(b.acf.event_date)).slice(0, 2);
22
23        // Filter webinars with register_now_link
24        const filteredWebinarData = webinarData.filter(webinar => webinar.acf.register_now_link);
25
26        const selectedWebinarEventData = [...filteredEventData, ...filteredWebinarData];
27
28        const allArticles = [...selectedWebinarEventData, ...publicationData, ...blogData].sort((a, b) => new Date(b.date) - new Date(a.date));
29
30        return allArticles;
31    } catch (error) {
32        console.error('No content available', error);
33        return [];
34    }
35}
36
37// Function to format the date
38function formatDate(dateString, isWebinar = false) {
39    const options = { month: 'long', day: 'numeric', year: 'numeric' };
40    return new Date(dateString).toLocaleDateString('en-US', options);
41}
42
43// Function to format the date for events
44function formatDateEvent(dateString) {
45    const parts = dateString.match(/(\w+), (\w+) (\d+), (\d+)/);
46    if (!parts) {
47        return dateString;
48    }
49
50    const [, , month, day, year] = parts;
51    const options = { year: 'numeric', month: 'long', day: 'numeric' };
52
53    return new Date(`${month} ${day}, ${year}`).toLocaleDateString('en-US', options);
54}
55
56// Function to generate HTML for each article
57function generateArticleHtml(article, index, isMobile = false) {
58    const typeClass = `horizontal-article-type-${index}`;
59    const imageClass = `horizontal-article-image-${index}`;
60    const linkClass = `horizontal-article-link-${index}`;
61    const titleClass = `horizontal-article-title-${index}`;
62    const dateClass = `horizontal-article-date-${index}`;
63
64    const coreClass = isMobile ? 'horizontal-article-core-mobile' : 'horizontal-article-core';
65
66    const type = determineArticleType(article);
67    const imageSrc = article.acf.feature_listing_image;
68    const linkHref = determineArticleLink(article);
69    const title = article.title.rendered;
70    const date = type === 'Event' ? formatDateEvent(article.acf.event_date) : (type === 'Webinar' ? formatDate(article.acf.webinar_date, true) : formatDate(article.date));
71
72    return `
73<div class="${coreClass}">
74    <p class="horizontal-article-type-text ${typeClass}">${type}</p>
75    <a class="${linkClass}" href="${linkHref}">
76        <img class="${imageClass}" src="${imageSrc}" alt="${title}">
77    </a>
78    <a class="${linkClass}" href="${linkHref}">
79        <h3 class="${titleClass}">${title}</h3>
80    </a>
81    <p class="${dateClass}">${date}</p>
82</div>
83`;
84}
85
86// Function to determine the article type
87function determineArticleType(article) {
88    if (article.type === 'post') {
89        return 'Blog';
90    } else if (article.type === 'event') {
91        return 'Event';
92    } else if (article.type === 'webinar' && article.acf.register_now_link) {
93        return 'Webinar';
94    } else if (article.type === 'publication' && !article.acf.request_report_button_link) {
95        return 'Report';
96    } else {
97        return 'Publication';
98    }
99}
100
101// Function to determine the appropriate link for each article type
102function determineArticleLink(article) {
103    if (article.type === 'event') {
104        return article.title.rendered.toLowerCase().includes('save the date') ? article.acf.learn_more : article.acf.register_now_link;
105    } else if (article.type === 'webinar') {
106        return article.acf.register_now_link;
107    } else {
108        return article.acf.cta_link || article.acf.read_more_button_link || article.acf.request_report_button_link || '';
109    }
110}
111
112// Function to apply opacity with delay
113function applyOpacityWithDelay(selector, delay) {
114    setTimeout(() => {
115        document.querySelectorAll(selector).forEach(element => {
116            element.style.opacity = 1;
117        });
118    });
119}
120
121// Function to get the current og:url from meta tag
122function getOgUrl() {
123    const metaOgUrl = document.querySelector('meta[property="og:url"]');
124    return metaOgUrl ? metaOgUrl.getAttribute('content') : '';
125}
126
127// Function to populate the slider with articles
128async function populateSlider(startIndex = 0) {
129    const metaRoles = document.querySelector('meta[name="data-roles"]');
130    const roles = metaRoles ? JSON.parse(metaRoles.getAttribute('content')) : [];
131    const ogUrl = getOgUrl();
132
133    const latestArticles = await fetchLatestArticles();
134
135    if (latestArticles.length === 0) {
136        console.error('No articles found.');
137        return;
138    }
139
140    // Filter out articles with URLs matching og:url
141    const filteredArticles = latestArticles.filter(article => determineArticleLink(article) !== ogUrl);
142
143    // Separate events and other articles
144    const events = filteredArticles.filter(article => article.type === 'event' && (article.acf.register_now_link || article.title.rendered.toLowerCase().includes('save the date')));
145    const otherArticles = filteredArticles.filter(article => article.type !== 'event');
146
147    // Ensure to take top 1 event
148    const topEvents = events.slice(0, 2).reverse();
149
150    // Filter other articles based on roles if roles are defined
151    const filteredOtherArticles = roles.length > 0 ? otherArticles.filter(article => {
152        if (article.acf.roles) {
153            return article.acf.roles.some(role => roles.includes(role));
154        }
155        return false; // If roles are defined but article has no roles, it won't be included
156    }) : otherArticles;
157
158    // Combine top events with the filtered other articles
159    let combinedArticles = [...topEvents, ...filteredOtherArticles];
160
161    // If there aren't enough articles, add non-matching articles
162    if (combinedArticles.length < 8) {
163        // Sort articles by date
164        const sortedFilteredOtherArticles = otherArticles
165            .filter(article => !filteredOtherArticles.includes(article))
166            .sort((a, b) => new Date(b.date) - new Date(a.date));
167        
168        // Exclude newer articles
169        const oldestMatchingDate = combinedArticles.length > 0 ? new Date(combinedArticles[combinedArticles.length - 1].date) : new Date();
170        const additionalArticles = sortedFilteredOtherArticles.filter(article => new Date(article.date) < oldestMatchingDate);
171        
172        // Add additional articles to fill the slots
173        combinedArticles = [...combinedArticles, ...additionalArticles.slice(0, 8 - combinedArticles.length)];
174    }
175
176    // Limit to a maximum of 8 articles
177    const limitedArticles = combinedArticles.slice(0, 8);
178    const articlesToShow = limitedArticles.slice(startIndex, startIndex + 4);
179
180    // Container for desktop view
181    const desktopContainer = document.querySelector('.horizontal-article-slider-boxes');
182    // Container for mobile view
183    const mobileOuterContainer = document.querySelector('.horizontal-article-slider-outer-container-mobile');
184    const mobileContainer = mobileOuterContainer.querySelector('.horizontal-article-slider-boxes');
185
186    // Populate desktop slider
187    desktopContainer.innerHTML = articlesToShow.map((article, index) => generateArticleHtml(article, startIndex + index + 1)).join('');
188    // Populate mobile slider
189    mobileContainer.innerHTML = articlesToShow.map((article, index) => generateArticleHtml(article, startIndex + index + 1, true)).join('');
190
191    // Apply opacity with a delay for specified images
192    applyOpacityWithDelay('.horizontal-article-image-1, .horizontal-article-image-2, .horizontal-article-image-3, .horizontal-article-image-4, .horizontal-article-image-5, .horizontal-article-image-6, .horizontal-article-image-7, .horizontal-article-image-8', 0);
193}
194
195// Variables to track the current start index
196let startIndex = 0;
197
198// Event listener for right arrow button
199document.querySelector('.horizontal-right-arrow-container').addEventListener('click', async () => {
200    const latestArticles = await fetchLatestArticles();
201    const rightArrow = document.querySelector('.fa-arrow-right');
202    const leftArrow = document.querySelector('.fa-arrow-left');
203    const overlayLine = document.querySelector('.horizontal-overlay-line');
204
205    if (startIndex + 4 < Math.min(latestArticles.length, 8)) {
206        overlayLine.addEventListener('transitionend', () => {
207            rightArrow.style.transition = 'color 300ms';
208            rightArrow.style.color = '#d4d4d4';
209            leftArrow.style.transition = 'color 300ms';
210            leftArrow.style.color = 'rgb(50, 50, 50)';
211        }, { once: true });
212
213        startIndex += 4;
214        populateSlider(startIndex);
215        overlayLine.style.transition = 'left 300ms';
216        overlayLine.style.left = '80px';
217
218        applyOpacityWithDelay('.horizontal-article-image-2, .horizontal-article-link-2, .horizontal-article-title-2, .horizontal-article-date-2, .horizontal-overlay-line > .horizontal-overlay-line-inner > div:nth-child(2)', 0);
219    }
220});
221
222// Event listener for left arrow button
223document.querySelector('.horizontal-left-arrow-container').addEventListener('click', () => {
224    const leftArrow = document.querySelector('.fa-arrow-left');
225    const rightArrow = document.querySelector('.fa-arrow-right');
226    const overlayLine = document.querySelector('.horizontal-overlay-line');
227
228    if (startIndex - 4 >= 0) {
229        overlayLine.addEventListener('transitionend', () => {
230            leftArrow.style.transition = 'color 300ms';
231            leftArrow.style.color = '#d4d4d4';
232            rightArrow.style.transition = 'color 300ms';
233            rightArrow.style.color = 'rgb(50, 50, 50)';
234        }, { once: true });
235
236        startIndex -= 4;
237        populateSlider(startIndex);
238        overlayLine.style.transition = 'left 300ms';
239        overlayLine.style.left = '0px';
240
241        applyOpacityWithDelay('.horizontal-article-image-1, .horizontal-article-link-1, .horizontal-article-title-1, .horizontal-article-date-1, .horizontal-overlay-line > .horizontal-overlay-line-inner > div:nth-child(1)', 0);
242    }
243});
244
245// Initialize slider
246populateSlider();
247
248function addImageLinks(linkElements, imageElements) {
249  for (let i = 0; i < linkElements.length; i++) {
250    const link = linkElements[i];
251    const image = imageElements[i];
252
253    const imageLink = link.cloneNode(true);
254    imageLink.innerHTML = '';
255    imageLink.appendChild(image);
256
257    link.parentNode.insertBefore(imageLink, link);
258  }
259}
260
261// Get all the desktop link and image elements
262const desktopLinkElements = document.querySelectorAll('.horizontal-article-core a');
263const desktopImageElements = document.querySelectorAll('.horizontal-article-core img');
264
265// Add image links for desktop version
266addImageLinks(desktopLinkElements, desktopImageElements);
267
268// Get all the mobile link and image elements
269const mobileLinkElements = document.querySelectorAll('.horizontal-article-core-mobile a');
270const mobileImageElements = document.querySelectorAll('.horizontal-article-core-mobile img');
271
272// Add image links for mobile version
273addImageLinks(mobileLinkElements, mobileImageElements);

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.