* feat: fix of there is no article * feat: set the feed order in a data structure rather than in a view * feat: update yarn.lock * feat: push the items to the array * feat: update feed to only show billboards if we have the correct length of items in the feed * fix: organizedFeedItems.legth * feat: rename 'featured' to 'image' * feat: rename 'featured' to 'image' * feat: rename 'featured' to 'image' * feat: add some utilities for the feed that we can use in the FeedTest * feat/WIP: the setup for the feed tests and a first working test * test: imageItem * fix: the podcasts can be passed through as an array of objects in the feedItems so that they can be grouped in one card * feat: remove podcastEpisode state and the attribute in the object * fix: check that the items exist before trying to slice them * feat: setup the userdata and the podcast data in the test * whoops - commit the podcast episodes * feat: write soem more tests for the feed and including the podcasts * feat: add some more tests * feat: add more billboards tests to chcek the order of stuff * feat: set the timeframe not empty * feat: update the logic for organizaed feed by inserting the last on first * doc: jsdoc for functions * refactor: break the code up into smaller functions * refactor: make the code more readable and easier to follow * refactor: pull function out into a utlity * feat: add specs to utility * feat: chcek if pinned post * test the latest timeframe correctly * chore: update var name * move the podcast items out of the object clause * feat: update text * feat: add a pack file that duplicates initializeDisplayAdVisibility * feat: create callbacks that will help us to determine when the feed has been rendered so that we can observe the dsplay ads accordingly * chore: rename to billboards instead of display ad * feat: first pass at some error handling whilst maintaining the order of the items * test: for feed error * feat: abstract out some code * update the feed items for errors * chore: comment * feat: update the variable names * feat: update honeybadger message
117 lines
3 KiB
JavaScript
117 lines
3 KiB
JavaScript
/* global userData */
|
|
// This is currently a duplicate of app/assets/javascript/initializers/initializeDisplayAdVisibility.
|
|
export function initializeDisplayAdVisibility() {
|
|
const displayAds = document.querySelectorAll('[data-display-unit]');
|
|
|
|
if (displayAds && displayAds.length == 0) {
|
|
return;
|
|
}
|
|
|
|
const user = userData();
|
|
|
|
displayAds.forEach((ad) => {
|
|
if (user && !user.display_sponsors && ad.dataset['typeOf'] == 'external') {
|
|
ad.classList.add('hidden');
|
|
} else {
|
|
ad.classList.remove('hidden');
|
|
}
|
|
});
|
|
}
|
|
|
|
export function observeDisplayAds() {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const elem = entry.target;
|
|
if (entry.intersectionRatio >= 0.25) {
|
|
setTimeout(() => {
|
|
trackAdImpression(elem);
|
|
}, 1);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
{
|
|
root: null, // defaults to browser viewport
|
|
rootMargin: '0px',
|
|
threshold: 0.25,
|
|
},
|
|
);
|
|
|
|
document.querySelectorAll('[data-display-unit]').forEach((ad) => {
|
|
observer.observe(ad);
|
|
ad.removeEventListener('click', trackAdClick, false);
|
|
ad.addEventListener('click', () => trackAdClick(ad));
|
|
});
|
|
}
|
|
|
|
function trackAdImpression(adBox) {
|
|
const isBot =
|
|
/bot|google|baidu|bing|msn|duckduckbot|teoma|slurp|yandex/i.test(
|
|
navigator.userAgent,
|
|
); // is crawler
|
|
const adSeen = adBox.dataset.impressionRecorded;
|
|
if (isBot || adSeen) {
|
|
return;
|
|
}
|
|
|
|
const tokenMeta = document.querySelector("meta[name='csrf-token']");
|
|
const csrfToken = tokenMeta && tokenMeta.getAttribute('content');
|
|
|
|
const dataBody = {
|
|
display_ad_event: {
|
|
display_ad_id: adBox.dataset.id,
|
|
context_type: adBox.dataset.contextType,
|
|
category: adBox.dataset.categoryImpression,
|
|
},
|
|
};
|
|
|
|
window
|
|
.fetch('/display_ad_events', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-Token': csrfToken,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(dataBody),
|
|
credentials: 'same-origin',
|
|
})
|
|
.catch((error) => console.error(error));
|
|
|
|
adBox.dataset.impressionRecorded = true;
|
|
}
|
|
|
|
function trackAdClick(adBox) {
|
|
const isBot =
|
|
/bot|google|baidu|bing|msn|duckduckbot|teoma|slurp|yandex/i.test(
|
|
navigator.userAgent,
|
|
); // is crawler
|
|
const adClicked = adBox.dataset.clickRecorded;
|
|
if (isBot || adClicked) {
|
|
return;
|
|
}
|
|
|
|
const tokenMeta = document.querySelector("meta[name='csrf-token']");
|
|
const csrfToken = tokenMeta && tokenMeta.getAttribute('content');
|
|
|
|
const dataBody = {
|
|
display_ad_event: {
|
|
display_ad_id: adBox.dataset.id,
|
|
context_type: adBox.dataset.contextType,
|
|
category: adBox.dataset.categoryClick,
|
|
},
|
|
};
|
|
|
|
window.fetch('/display_ad_events', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-Token': csrfToken,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(dataBody),
|
|
credentials: 'same-origin',
|
|
});
|
|
|
|
adBox.dataset.clickRecorded = true;
|
|
}
|