Add ad to the homepage as a card (#362)
* coming along well * coming along well * adding custom react element * coming along well * coming along well * coming along well * working pretty well * almost done * essentially working just could use a couple touchups * cleanup and lint errors * fix lint errors * fix flow errors * possible bugfix * dynamically set width and height * only run when rowdata is populated * trying using ref * better way to check for card population * working implementation * working implementation * clean up flow and clean up script * fix typo in comment and logs
This commit is contained in:
parent
873ac4dc5d
commit
1e071550ae
2 changed files with 172 additions and 33 deletions
|
@ -1,8 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import { SITE_NAME, SIMPLE_SITE, ENABLE_NO_SOURCE_CLAIMS } from 'config';
|
import { SHOW_ADS, SITE_NAME, SIMPLE_SITE, ENABLE_NO_SOURCE_CLAIMS } from 'config';
|
||||||
import React from 'react';
|
import Ads from 'web/component/ads';
|
||||||
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import ClaimTilesDiscover from 'component/claimTilesDiscover';
|
import ClaimTilesDiscover from 'component/claimTilesDiscover';
|
||||||
|
@ -74,6 +75,7 @@ function HomePage(props: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={title} className="claim-grid__wrapper">
|
<div key={title} className="claim-grid__wrapper">
|
||||||
|
{/* category header */}
|
||||||
{index !== 0 && title && typeof title === 'string' && (
|
{index !== 0 && title && typeof title === 'string' && (
|
||||||
<h1 className="claim-grid__header">
|
<h1 className="claim-grid__header">
|
||||||
<Button navigate={route || link} button="link">
|
<Button navigate={route || link} button="link">
|
||||||
|
@ -91,6 +93,7 @@ function HomePage(props: Props) {
|
||||||
</WaitUntilOnPage>
|
</WaitUntilOnPage>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* view more button */}
|
||||||
{(route || link) && (
|
{(route || link) && (
|
||||||
<Button
|
<Button
|
||||||
className="claim-grid__title--secondary"
|
className="claim-grid__title--secondary"
|
||||||
|
@ -108,6 +111,135 @@ function HomePage(props: Props) {
|
||||||
doFetchActiveLivestreams();
|
doFetchActiveLivestreams();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// returns true if passed element is fully visible on screen
|
||||||
|
function isScrolledIntoView(el) {
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const elemTop = rect.top;
|
||||||
|
const elemBottom = rect.bottom;
|
||||||
|
|
||||||
|
// Only completely visible elements return true:
|
||||||
|
const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
|
||||||
|
return isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (authenticated || !SHOW_ADS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function() {
|
||||||
|
// test if adblock is enabled
|
||||||
|
let adBlockEnabled = false;
|
||||||
|
const googleAdUrl = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';
|
||||||
|
try {
|
||||||
|
await fetch(new Request(googleAdUrl)).catch(_ => { adBlockEnabled = true });
|
||||||
|
} catch (e) {
|
||||||
|
adBlockEnabled = true;
|
||||||
|
} finally {
|
||||||
|
if (!adBlockEnabled) {
|
||||||
|
// select the cards on page
|
||||||
|
let cards = document.getElementsByClassName('card claim-preview--tile');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-inner-declarations
|
||||||
|
function checkFlag() {
|
||||||
|
if (cards.length === 0) {
|
||||||
|
window.setTimeout(checkFlag, 100);
|
||||||
|
} else {
|
||||||
|
// find the last fully visible card
|
||||||
|
let lastCard;
|
||||||
|
for (const card of cards) {
|
||||||
|
const isFullyVisible = isScrolledIntoView(card);
|
||||||
|
if (!isFullyVisible) break;
|
||||||
|
lastCard = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone the last card
|
||||||
|
// $FlowFixMe
|
||||||
|
const clonedCard = lastCard.cloneNode(true);
|
||||||
|
|
||||||
|
// insert cloned card
|
||||||
|
// $FlowFixMe
|
||||||
|
lastCard.parentNode.insertBefore(clonedCard, lastCard);
|
||||||
|
|
||||||
|
// delete last card so that it doesn't mess up formatting
|
||||||
|
// $FlowFixMe
|
||||||
|
// lastCard.remove();
|
||||||
|
|
||||||
|
// change the appearance of the cloned card
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim__menu-button').remove();
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.truncated-text').innerHTML = 'Hate these? Login to Odysee for an ad free experience';
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim-tile__info').remove();
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('[role="none"]').removeAttribute('href');
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim-tile__header').firstChild.href = '/$/signin';
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim-tile__title').firstChild.removeAttribute('aria-label');
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim-tile__title').firstChild.removeAttribute('title');
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.claim-tile__header').firstChild.removeAttribute('aria-label');
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
clonedCard.querySelector('.media__thumb').replaceWith(document.getElementsByClassName('homepageAdContainer')[0]);
|
||||||
|
|
||||||
|
// show the homepage ad which is not displayed at first
|
||||||
|
document.getElementsByClassName('homepageAdContainer')[0].style.display = 'block';
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
const imageHeight = window.getComputedStyle(lastCard.querySelector('.media__thumb')).height;
|
||||||
|
// $FlowFixMe
|
||||||
|
const imageWidth = window.getComputedStyle(lastCard.querySelector('.media__thumb')).width;
|
||||||
|
|
||||||
|
var styles = `#av-container, #AVcontent, #aniBox {
|
||||||
|
height: ${imageHeight} !important;
|
||||||
|
width: ${imageWidth} !important;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
var styleSheet = document.createElement('style');
|
||||||
|
styleSheet.type = 'text/css';
|
||||||
|
styleSheet.innerText = styles;
|
||||||
|
// $FlowFixMe
|
||||||
|
document.head.appendChild(styleSheet);
|
||||||
|
|
||||||
|
clonedCard.style.display = 'none';
|
||||||
|
|
||||||
|
let timeoutCount = 0;
|
||||||
|
// eslint-disable-next-line no-inner-declarations
|
||||||
|
function checkForAniview() {
|
||||||
|
const aniBoxDiv = document.getElementsByClassName('homepageAdContainer')[0].querySelector('#aniBox');
|
||||||
|
|
||||||
|
if (!aniBoxDiv) {
|
||||||
|
timeoutCount += 100;
|
||||||
|
if (timeoutCount < 500) {
|
||||||
|
window.setTimeout(checkForAniview, 100);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clonedCard.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkForAniview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkFlag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page fullWidthPage>
|
<Page fullWidthPage>
|
||||||
{!SIMPLE_SITE && (authenticated || !IS_WEB) && !subscribedChannels.length && (
|
{!SIMPLE_SITE && (authenticated || !IS_WEB) && !subscribedChannels.length && (
|
||||||
|
@ -126,6 +258,7 @@ function HomePage(props: Props) {
|
||||||
)}
|
)}
|
||||||
{/* @if TARGET='web' */}
|
{/* @if TARGET='web' */}
|
||||||
{SIMPLE_SITE && <Meme />}
|
{SIMPLE_SITE && <Meme />}
|
||||||
|
<Ads type="homepage" />
|
||||||
{/* @endif */}
|
{/* @endif */}
|
||||||
{rowData.map(({ title, route, link, icon, help, pinnedUrls: pinUrls, options = {} }, index) => {
|
{rowData.map(({ title, route, link, icon, help, pinnedUrls: pinUrls, options = {} }, index) => {
|
||||||
// add pins here
|
// add pins here
|
||||||
|
|
|
@ -6,9 +6,6 @@ import { withRouter } from 'react-router';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
// $FlowFixMe
|
|
||||||
|
|
||||||
const IS_MOBILE = typeof window.orientation !== 'undefined';
|
|
||||||
|
|
||||||
const ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_DFP_Rev70_1011.js';
|
const ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_DFP_Rev70_1011.js';
|
||||||
const ADS_TAG = 'vidcrunchJS537102317';
|
const ADS_TAG = 'vidcrunchJS537102317';
|
||||||
|
@ -16,6 +13,9 @@ const ADS_TAG = 'vidcrunchJS537102317';
|
||||||
const IOS_ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Mobile_Floating_DFP_Rev70_1611.js';
|
const IOS_ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Mobile_Floating_DFP_Rev70_1611.js';
|
||||||
const IOS_ADS_TAG = 'vidcrunchJS199212779';
|
const IOS_ADS_TAG = 'vidcrunchJS199212779';
|
||||||
|
|
||||||
|
const HOMEPAGE_ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_300x169_DFP_Rev70_1211.js';
|
||||||
|
const HOMEPAGE_ADS_TAG = 'vidcrunchJS330442776';
|
||||||
|
|
||||||
const IS_IOS =
|
const IS_IOS =
|
||||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||||
// for iOS 13+ , platform is MacIntel, so use this to test
|
// for iOS 13+ , platform is MacIntel, so use this to test
|
||||||
|
@ -33,22 +33,29 @@ type Props = {
|
||||||
function Ads(props: Props) {
|
function Ads(props: Props) {
|
||||||
const {
|
const {
|
||||||
location: { pathname },
|
location: { pathname },
|
||||||
type = 'sidebar',
|
type = 'video',
|
||||||
small,
|
small,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
// load ad and tags here
|
||||||
let scriptUrlToUse;
|
let scriptUrlToUse;
|
||||||
let tagNameToUse;
|
let tagNameToUse;
|
||||||
if (IS_IOS) {
|
if (type === 'video') {
|
||||||
tagNameToUse = IOS_ADS_TAG;
|
if (IS_IOS) {
|
||||||
scriptUrlToUse = IOS_ADS_URL;
|
tagNameToUse = IOS_ADS_TAG;
|
||||||
} else {
|
scriptUrlToUse = IOS_ADS_URL;
|
||||||
tagNameToUse = ADS_TAG;
|
} else {
|
||||||
scriptUrlToUse = ADS_URL;
|
tagNameToUse = ADS_TAG;
|
||||||
|
scriptUrlToUse = ADS_URL;
|
||||||
|
}
|
||||||
|
} else if (type === 'homepage') {
|
||||||
|
tagNameToUse = HOMEPAGE_ADS_TAG;
|
||||||
|
scriptUrlToUse = HOMEPAGE_ADS_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add script to DOM
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (SHOW_ADS && type === 'video') {
|
if (SHOW_ADS) {
|
||||||
let script;
|
let script;
|
||||||
try {
|
try {
|
||||||
let fjs = document.getElementsByTagName('script')[0];
|
let fjs = document.getElementsByTagName('script')[0];
|
||||||
|
@ -56,30 +63,18 @@ function Ads(props: Props) {
|
||||||
script.src = scriptUrlToUse;
|
script.src = scriptUrlToUse;
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
fjs.parentNode.insertBefore(script, fjs);
|
fjs.parentNode.insertBefore(script, fjs);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// $FlowFixMe
|
||||||
|
document.head.removeChild(script);
|
||||||
|
};
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove the script when it exists?
|
||||||
}, [type]);
|
}, [type]);
|
||||||
|
|
||||||
useEffect(() => {
|
// display to say "sign up to not see these"
|
||||||
if (SHOW_ADS && !IS_MOBILE && type === 'sidebar') {
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = ADS_URL;
|
|
||||||
script.defer = true;
|
|
||||||
// $FlowFixMe
|
|
||||||
document.body.appendChild(script);
|
|
||||||
return () => {
|
|
||||||
// $FlowFixMe
|
|
||||||
document.body.removeChild(script);
|
|
||||||
// if user navigates too rapidly, <style> tags can build up
|
|
||||||
// $FlowFixMe
|
|
||||||
if (document.body.getElementsByTagName('style').length) {
|
|
||||||
// $FlowFixMe
|
|
||||||
document.body.getElementsByTagName('style')[0].remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, [type]);
|
|
||||||
|
|
||||||
const adsSignInDriver = (
|
const adsSignInDriver = (
|
||||||
<I18nMessage
|
<I18nMessage
|
||||||
tokens={{
|
tokens={{
|
||||||
|
@ -96,6 +91,7 @@ function Ads(props: Props) {
|
||||||
</I18nMessage>
|
</I18nMessage>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ad shown in the related videos area
|
||||||
const videoAd = (
|
const videoAd = (
|
||||||
<div className="ads__claim-item">
|
<div className="ads__claim-item">
|
||||||
<div id={tagNameToUse} className="ads__injected-video" style={{display: 'none'}} />
|
<div id={tagNameToUse} className="ads__injected-video" style={{display: 'none'}} />
|
||||||
|
@ -110,12 +106,22 @@ function Ads(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// homepage ad in a card
|
||||||
|
const homepageCardAd = (
|
||||||
|
<div className="homepageAdContainer media__thumb" style={{display: 'none'}}>
|
||||||
|
<div id={tagNameToUse} className="homepageAdDiv media__thumb" style={{display: 'none'}} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
if (!SHOW_ADS) {
|
if (!SHOW_ADS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type === 'video') {
|
if (type === 'video') {
|
||||||
return videoAd;
|
return videoAd;
|
||||||
}
|
}
|
||||||
|
if (type === 'homepage') {
|
||||||
|
return homepageCardAd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(Ads);
|
export default withRouter(Ads);
|
||||||
|
|
Loading…
Reference in a new issue