@temple-wallet/extension-ads 8.1.0 → 9.0.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -3
- package/dist/index.js +12 -14
- package/dist/referrals/index.d.ts +33 -0
- package/dist/referrals/index.js +18 -0
- package/package.json +7 -5
- package/src/ads-actions/helpers.ts +36 -2
- package/src/ads-actions/process-permanent-rule.ts +8 -3
- package/src/ads-actions/process-providers-ads.ts +29 -2
- package/src/ads-actions/process-rule.ts +4 -0
- package/src/ads-configuration.ts +17 -2
- package/src/execute-ads-actions/observing.ts +3 -1
- package/src/execute-ads-actions/process-insert-ad-action.ts +26 -5
- package/src/referrals/index.ts +5 -0
- package/src/referrals/replace.ts +129 -0
- package/src/referrals/takeads.ts +44 -0
- package/src/referrals/utils.ts +14 -0
- package/src/render-ads-stack.ts +218 -102
- package/src/temple-wallet-api.ts +10 -4
- package/src/transform-raw-rules.ts +6 -2
- package/src/types/ads-actions.ts +2 -0
- package/src/types/ads-rules.ts +1 -0
- package/src/types/temple-wallet-api.ts +1 -0
- package/src/utils.ts +4 -0
- package/dist/ads-actions/helpers.d.ts +0 -17
- package/dist/ads-actions/helpers.js +0 -96
- package/dist/ads-actions/helpers.js.map +0 -1
- package/dist/ads-actions/index.d.ts +0 -3
- package/dist/ads-actions/index.js +0 -63
- package/dist/ads-actions/index.js.map +0 -1
- package/dist/ads-actions/process-elements-to-hide-or-remove-rule.d.ts +0 -3
- package/dist/ads-actions/process-elements-to-hide-or-remove-rule.js +0 -19
- package/dist/ads-actions/process-elements-to-hide-or-remove-rule.js.map +0 -1
- package/dist/ads-actions/process-permanent-rule.d.ts +0 -3
- package/dist/ads-actions/process-permanent-rule.js +0 -143
- package/dist/ads-actions/process-permanent-rule.js.map +0 -1
- package/dist/ads-actions/process-providers-ads.d.ts +0 -3
- package/dist/ads-actions/process-providers-ads.js +0 -137
- package/dist/ads-actions/process-providers-ads.js.map +0 -1
- package/dist/ads-actions/process-rule.d.ts +0 -3
- package/dist/ads-actions/process-rule.js +0 -98
- package/dist/ads-actions/process-rule.js.map +0 -1
- package/dist/ads-configuration.d.ts +0 -31
- package/dist/ads-configuration.js +0 -30
- package/dist/ads-configuration.js.map +0 -1
- package/dist/constants.d.ts +0 -11
- package/dist/constants.js +0 -12
- package/dist/constants.js.map +0 -1
- package/dist/execute-ads-actions/ads-views/index.d.ts +0 -3
- package/dist/execute-ads-actions/ads-views/index.js +0 -4
- package/dist/execute-ads-actions/ads-views/index.js.map +0 -1
- package/dist/execute-ads-actions/ads-views/make-ads-tw-view.d.ts +0 -3
- package/dist/execute-ads-actions/ads-views/make-ads-tw-view.js +0 -40
- package/dist/execute-ads-actions/ads-views/make-ads-tw-view.js.map +0 -1
- package/dist/execute-ads-actions/ads-views/make-extension-iframe-view.d.ts +0 -3
- package/dist/execute-ads-actions/ads-views/make-extension-iframe-view.js +0 -22
- package/dist/execute-ads-actions/ads-views/make-extension-iframe-view.js.map +0 -1
- package/dist/execute-ads-actions/ads-views/make-tkey-ad.d.ts +0 -3
- package/dist/execute-ads-actions/ads-views/make-tkey-ad.js +0 -38
- package/dist/execute-ads-actions/ads-views/make-tkey-ad.js.map +0 -1
- package/dist/execute-ads-actions/index.d.ts +0 -2
- package/dist/execute-ads-actions/index.js +0 -23
- package/dist/execute-ads-actions/index.js.map +0 -1
- package/dist/execute-ads-actions/observing.d.ts +0 -1
- package/dist/execute-ads-actions/observing.js +0 -129
- package/dist/execute-ads-actions/observing.js.map +0 -1
- package/dist/execute-ads-actions/override-element-styles.d.ts +0 -2
- package/dist/execute-ads-actions/override-element-styles.js +0 -6
- package/dist/execute-ads-actions/override-element-styles.js.map +0 -1
- package/dist/execute-ads-actions/process-insert-ad-action.d.ts +0 -2
- package/dist/execute-ads-actions/process-insert-ad-action.js +0 -153
- package/dist/execute-ads-actions/process-insert-ad-action.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/render-ads-stack.d.ts +0 -7
- package/dist/render-ads-stack.js +0 -156
- package/dist/render-ads-stack.js.map +0 -1
- package/dist/temple-wallet-api.d.ts +0 -23
- package/dist/temple-wallet-api.js +0 -67
- package/dist/temple-wallet-api.js.map +0 -1
- package/dist/transform-raw-rules.d.ts +0 -3
- package/dist/transform-raw-rules.js +0 -137
- package/dist/transform-raw-rules.js.map +0 -1
- package/dist/types/ad-view.d.ts +0 -7
- package/dist/types/ad-view.js +0 -2
- package/dist/types/ad-view.js.map +0 -1
- package/dist/types/ads-actions.d.ts +0 -56
- package/dist/types/ads-actions.js +0 -15
- package/dist/types/ads-actions.js.map +0 -1
- package/dist/types/ads-meta.d.ts +0 -19
- package/dist/types/ads-meta.js +0 -2
- package/dist/types/ads-meta.js.map +0 -1
- package/dist/types/ads-provider.d.ts +0 -8
- package/dist/types/ads-provider.js +0 -9
- package/dist/types/ads-provider.js.map +0 -1
- package/dist/types/ads-rules.d.ts +0 -26
- package/dist/types/ads-rules.js +0 -2
- package/dist/types/ads-rules.js.map +0 -1
- package/dist/types/temple-wallet-api.d.ts +0 -78
- package/dist/types/temple-wallet-api.js +0 -2
- package/dist/types/temple-wallet-api.js.map +0 -1
- package/dist/utils.d.ts +0 -6
- package/dist/utils.js +0 -4
- package/dist/utils.js.map +0 -1
|
@@ -33,7 +33,16 @@ const processInsertAdActionOnce = async (
|
|
|
33
33
|
insertionPoint: HTMLDivElement | HTMLTableCellElement,
|
|
34
34
|
onAdsStackError: (error: Error) => void
|
|
35
35
|
) => {
|
|
36
|
-
const {
|
|
36
|
+
const {
|
|
37
|
+
elementStyle = {},
|
|
38
|
+
stylesOverrides = [],
|
|
39
|
+
adsMetadata,
|
|
40
|
+
wrapperType,
|
|
41
|
+
originalHeight,
|
|
42
|
+
originalWidth,
|
|
43
|
+
shouldUseBlurredBackground,
|
|
44
|
+
adCategories
|
|
45
|
+
} = action;
|
|
37
46
|
|
|
38
47
|
stylesOverrides.sort((a, b) => a.parentDepth - b.parentDepth);
|
|
39
48
|
|
|
@@ -42,15 +51,15 @@ const processInsertAdActionOnce = async (
|
|
|
42
51
|
const adId = nanoid();
|
|
43
52
|
const adElement = document.createElement('iframe');
|
|
44
53
|
adElement.loading = 'lazy';
|
|
45
|
-
adElement.src = AdsConfiguration.getAdsStackIframeURL(adId, adsMetadata, window.location.href);
|
|
54
|
+
adElement.src = AdsConfiguration.getAdsStackIframeURL(adId, adsMetadata, window.location.href, adCategories);
|
|
46
55
|
adElement.id = adId;
|
|
47
56
|
adElement.allow = IFRAME_ALLOWANCE;
|
|
48
57
|
const firstAdMetadataOrId = adsMetadata[0];
|
|
49
58
|
const { dimensions: minDimensions } =
|
|
50
59
|
typeof firstAdMetadataOrId === 'number' ? AdsConfiguration.bannerAdsMeta[firstAdMetadataOrId] : firstAdMetadataOrId;
|
|
51
60
|
const dimensions = {
|
|
52
|
-
width: Math.max(originalWidth, minDimensions.width),
|
|
53
|
-
height: Math.max(originalHeight, minDimensions.height)
|
|
61
|
+
width: shouldUseBlurredBackground ? Math.max(originalWidth, minDimensions.width) : minDimensions.width,
|
|
62
|
+
height: shouldUseBlurredBackground ? Math.max(originalHeight, minDimensions.height) : minDimensions.height
|
|
54
63
|
};
|
|
55
64
|
adElement.style.width = wrapperType === 'tbody' ? '100%' : `${dimensions.width}px`;
|
|
56
65
|
adElement.style.height = `${dimensions.height}px`;
|
|
@@ -74,11 +83,23 @@ const processInsertAdActionOnce = async (
|
|
|
74
83
|
action.element.replaceWith(wrapperElement);
|
|
75
84
|
break;
|
|
76
85
|
default:
|
|
86
|
+
const nextSibling = action.parent.children[action.insertionIndex];
|
|
77
87
|
if (action.isSiblingReplacement) {
|
|
78
88
|
wrapperElement.setAttribute(SIBLING_REPLACEMENT_ATTRIBUTE_NAME, 'true');
|
|
89
|
+
const observer = new MutationObserver(mutations => {
|
|
90
|
+
const hasRemoveSiblingMutation = mutations.some(mutation =>
|
|
91
|
+
Array.from(mutation.removedNodes).includes(nextSibling)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (hasRemoveSiblingMutation) {
|
|
95
|
+
wrapperElement.remove();
|
|
96
|
+
observer.disconnect();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
observer.observe(action.parent, { childList: true });
|
|
79
100
|
}
|
|
80
101
|
stylesOverridesCurrentElement = action.parent;
|
|
81
|
-
action.parent.insertBefore(wrapperElement,
|
|
102
|
+
action.parent.insertBefore(wrapperElement, nextSibling);
|
|
82
103
|
break;
|
|
83
104
|
}
|
|
84
105
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import browser from 'webextension-polyfill';
|
|
2
|
+
|
|
3
|
+
import { IS_DEV, IS_MAC_OS, isTruthy } from 'src/utils';
|
|
4
|
+
|
|
5
|
+
import type { TekeadsAffiliateResponse } from './takeads';
|
|
6
|
+
import { getCurrentPageDomain, stripSubdomain } from './utils';
|
|
7
|
+
|
|
8
|
+
const TEMPLE_WALLET_ANCHOR_ATTRIBUTE = 'data-tw-referral';
|
|
9
|
+
|
|
10
|
+
export async function processAnchors(
|
|
11
|
+
supportedDomains: Set<string>,
|
|
12
|
+
AdsBrowserExtensionMessageType: AdsBrowserExtensionMessageTypeI
|
|
13
|
+
) {
|
|
14
|
+
const anchors = Array.from(document.querySelectorAll('a'));
|
|
15
|
+
if (!anchors.length) throw new Error('No anchors found');
|
|
16
|
+
|
|
17
|
+
const items = anchors
|
|
18
|
+
.map(aElem => {
|
|
19
|
+
if (aElem.hasAttribute(TEMPLE_WALLET_ANCHOR_ATTRIBUTE)) return null;
|
|
20
|
+
|
|
21
|
+
const urlDomain = getDomain(aElem.href);
|
|
22
|
+
if (!urlDomain || !supportedDomains.has(urlDomain)) return null;
|
|
23
|
+
|
|
24
|
+
const iri = cleanLink(aElem.href);
|
|
25
|
+
if (!iri) return null;
|
|
26
|
+
|
|
27
|
+
return { iri, aElem, urlDomain };
|
|
28
|
+
})
|
|
29
|
+
.filter(isTruthy);
|
|
30
|
+
|
|
31
|
+
if (!items.length) return void (IS_DEV && console.info('Nothing to replace'));
|
|
32
|
+
|
|
33
|
+
const links = items.map(l => l.iri);
|
|
34
|
+
|
|
35
|
+
// Not requesting directly in content script because of CORS.
|
|
36
|
+
const takeadsItems: TekeadsAffiliateResponse = await browser.runtime.sendMessage({
|
|
37
|
+
type: AdsBrowserExtensionMessageType.FetchReferrals,
|
|
38
|
+
links
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (!takeadsItems.data.length) return void (IS_DEV && console.info('No referrals received'));
|
|
42
|
+
|
|
43
|
+
IS_DEV && console.info('Replacing', takeadsItems.data.length, 'referralas');
|
|
44
|
+
|
|
45
|
+
for (const { iri, aElem, urlDomain } of items) {
|
|
46
|
+
const referralUrl = takeadsItems.data.find(item => item.iri === iri)?.trackingLink;
|
|
47
|
+
|
|
48
|
+
if (!referralUrl) {
|
|
49
|
+
IS_DEV && console.warn('No affiliate link for', aElem);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
processAnchorElement({ iri, aElem, urlDomain, referralUrl }, AdsBrowserExtensionMessageType);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface AdsBrowserExtensionMessageTypeI {
|
|
60
|
+
FetchReferrals: string;
|
|
61
|
+
ReferralClick: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface PreppedItem {
|
|
65
|
+
iri: string;
|
|
66
|
+
aElem: HTMLAnchorElement;
|
|
67
|
+
urlDomain: string;
|
|
68
|
+
referralUrl: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function processAnchorElement(item: PreppedItem, AdsBrowserExtensionMessageType: AdsBrowserExtensionMessageTypeI) {
|
|
72
|
+
const { aElem, urlDomain, referralUrl } = item;
|
|
73
|
+
|
|
74
|
+
const showHref = aElem.href;
|
|
75
|
+
|
|
76
|
+
IS_DEV && console.info('Replacing referral:', showHref, 'to', referralUrl, 'for anchor:', aElem);
|
|
77
|
+
|
|
78
|
+
aElem.setAttribute(TEMPLE_WALLET_ANCHOR_ATTRIBUTE, 'set');
|
|
79
|
+
|
|
80
|
+
aElem.onclick = event => {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
|
|
83
|
+
IS_DEV && console.log('Referral clicked:', showHref, '->', referralUrl);
|
|
84
|
+
|
|
85
|
+
browser.runtime.sendMessage({
|
|
86
|
+
type: AdsBrowserExtensionMessageType.ReferralClick,
|
|
87
|
+
urlDomain,
|
|
88
|
+
pageDomain: getCurrentPageDomain()
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const newTab = event.button === 1 || (IS_MAC_OS ? event.metaKey : event.ctrlKey);
|
|
92
|
+
|
|
93
|
+
window.open(referralUrl, newTab ? '_blank' : '_self');
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
aElem.oncontextmenu = () => {
|
|
97
|
+
/*
|
|
98
|
+
Making sure, user opens referral URL via Context Menu's 'Open in new tab' button.
|
|
99
|
+
Note: 'Copy to clipboard' button will also provide referral URL this way.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
aElem.href = referralUrl;
|
|
103
|
+
|
|
104
|
+
const revertHref = () => {
|
|
105
|
+
aElem.href = showHref;
|
|
106
|
+
window.removeEventListener('focus', revertHref);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
window.addEventListener('focus', revertHref);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getDomain(href: string) {
|
|
114
|
+
try {
|
|
115
|
+
return stripSubdomain(new URL(href).hostname, 'www');
|
|
116
|
+
} catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function cleanLink(href: string) {
|
|
122
|
+
try {
|
|
123
|
+
const dirtyLink = new URL(href);
|
|
124
|
+
|
|
125
|
+
return dirtyLink.origin + dirtyLink.pathname;
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
import memoizee from 'memoizee';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* API docs: https://docs.takeads.com
|
|
6
|
+
*/
|
|
7
|
+
export class TakeAdsClient {
|
|
8
|
+
private axios: AxiosInstance;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
private publicKey: string,
|
|
12
|
+
readonly apiUrl: string = 'https://api.takeads.com'
|
|
13
|
+
) {
|
|
14
|
+
this.axios = axios.create({
|
|
15
|
+
baseURL: apiUrl,
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization: `Bearer ${this.publicKey}`
|
|
18
|
+
},
|
|
19
|
+
adapter: 'fetch'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async affiliateLinks(websiteUrls: string[], subId?: string) {
|
|
24
|
+
const response = await this.axios.put<TekeadsAffiliateResponse>('/v1/product/monetize-api/v2/resolve', {
|
|
25
|
+
iris: websiteUrls,
|
|
26
|
+
subId,
|
|
27
|
+
withImages: false
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return response.data;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const buildTakeadsClient = memoizee((publicKey: string) => new TakeAdsClient(publicKey), { max: 2 });
|
|
35
|
+
|
|
36
|
+
export interface TekeadsAffiliateResponse {
|
|
37
|
+
data: AffiliateLink[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface AffiliateLink {
|
|
41
|
+
iri: string;
|
|
42
|
+
trackingLink: string;
|
|
43
|
+
imageUrl: string | null;
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { memoize } from 'lodash';
|
|
2
|
+
|
|
3
|
+
/** Current page's domain with 'www' stripped off */
|
|
4
|
+
export const getCurrentPageDomain = memoize(() => {
|
|
5
|
+
return stripSubdomain(window.location.hostname, 'www');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export function stripSubdomain(hostname: string, subdomain: string) {
|
|
9
|
+
if (hostname.includes(`${subdomain}.`)) {
|
|
10
|
+
return hostname.slice(subdomain.length + 1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return hostname;
|
|
14
|
+
}
|
package/src/render-ads-stack.ts
CHANGED
|
@@ -10,57 +10,178 @@ import {
|
|
|
10
10
|
import { makeAdsTwView, makeExtensionIframeView, makeTKeyAdView } from './execute-ads-actions/ads-views';
|
|
11
11
|
import { overrideElementStyles } from './execute-ads-actions/override-element-styles';
|
|
12
12
|
import { AdView, CreativeSet } from './types/ad-view';
|
|
13
|
-
import { AdMetadata } from './types/ads-meta';
|
|
13
|
+
import { AdMetadata, AdSource } from './types/ads-meta';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
class AdsStack {
|
|
16
|
+
private wasReady = false;
|
|
17
|
+
private messageListener: ((event: MessageEvent<any>) => void) | undefined;
|
|
18
|
+
private responseTimeout: NodeJS.Timeout | undefined;
|
|
19
|
+
private rootElement: HTMLElement = document.getElementById('root')!;
|
|
20
|
+
private validAdsCounter = 0;
|
|
21
|
+
private readonly adsMetadata: AdMetadata[];
|
|
22
|
+
private currentAdMetadata: AdMetadata | undefined;
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
constructor(
|
|
25
|
+
private readonly id: string,
|
|
26
|
+
initialAdsMetadata: (number | AdMetadata)[],
|
|
27
|
+
private readonly origin: string,
|
|
28
|
+
private readonly pageHasPlacesRules: boolean,
|
|
29
|
+
private readonly adCategories: string[],
|
|
30
|
+
private readonly hypelabBlacklistedCampaignsSlugs: string[]
|
|
31
|
+
) {
|
|
32
|
+
this.adsMetadata = initialAdsMetadata.map(adMetadataOrId =>
|
|
33
|
+
typeof adMetadataOrId === 'number' ? AdsConfiguration.bannerAdsMeta[adMetadataOrId] : adMetadataOrId
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
startRendering() {
|
|
38
|
+
if (this.adsMetadata.length === 0) {
|
|
39
|
+
this.broadcastNoMoreAds();
|
|
40
|
+
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.currentAdMetadata = AdsConfiguration.pickNextAdMetadata(
|
|
45
|
+
this.adsMetadata,
|
|
46
|
+
this.currentAdMetadata,
|
|
47
|
+
this.validAdsCounter,
|
|
48
|
+
this.pageHasPlacesRules,
|
|
49
|
+
this.adCategories
|
|
50
|
+
);
|
|
51
|
+
const adMetadata = this.currentAdMetadata;
|
|
52
|
+
|
|
53
|
+
if (!adMetadata) {
|
|
54
|
+
this.broadcastNoMoreAds();
|
|
55
|
+
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.broadcastMessage({ id: this.id, type: AD_RENDER_START_MESSAGE_TYPE, adMetadata: this.currentAdMetadata });
|
|
60
|
+
|
|
61
|
+
const { element, creativeSet: initialCreativeSet } = this.placeNewAd(adMetadata);
|
|
29
62
|
|
|
30
|
-
|
|
63
|
+
if (element instanceof HTMLIFrameElement) {
|
|
64
|
+
this.listenToIframeMessages(element, adMetadata);
|
|
65
|
+
} else {
|
|
66
|
+
this.handleValidAd({ ad: { creative_set: initialCreativeSet } });
|
|
67
|
+
}
|
|
31
68
|
}
|
|
32
69
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
70
|
+
private listenToIframeMessages(element: HTMLIFrameElement, adMetadata: AdMetadata) {
|
|
71
|
+
const nextAdMetadata = AdsConfiguration.pickNextAdMetadata(
|
|
72
|
+
this.adsMetadata,
|
|
73
|
+
adMetadata,
|
|
74
|
+
this.validAdsCounter,
|
|
75
|
+
this.pageHasPlacesRules,
|
|
76
|
+
this.adCategories
|
|
77
|
+
);
|
|
78
|
+
this.responseTimeout = setTimeout(
|
|
79
|
+
() => {
|
|
80
|
+
console.error(`Timeout exceeded for ${this.id}, ad source: ${JSON.stringify(adMetadata.source)}`);
|
|
81
|
+
this.handleInvalidAd();
|
|
82
|
+
},
|
|
83
|
+
(nextAdMetadata ? 10_000 : 20_000) * (AdsConfiguration.IS_MISES_BROWSER ? 2 : 1)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
this.messageListener = (event: MessageEvent<any>) => {
|
|
87
|
+
if (event.source !== element.contentWindow) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
|
|
93
|
+
|
|
94
|
+
switch (data.type) {
|
|
95
|
+
case AD_READY_MESSAGE_TYPE:
|
|
96
|
+
if (
|
|
97
|
+
adMetadata.source.providerName === 'HypeLab' &&
|
|
98
|
+
this.hypelabBlacklistedCampaignsSlugs.includes(data.ad?.campaign_slug) &&
|
|
99
|
+
nextAdMetadata
|
|
100
|
+
) {
|
|
101
|
+
this.handleInvalidAd();
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.handleValidAd(data);
|
|
106
|
+
break;
|
|
107
|
+
case AD_ERROR_MESSAGE_TYPE:
|
|
108
|
+
if (!this.wasReady) {
|
|
109
|
+
this.handleInvalidAd();
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case AD_RESIZE_MESSAGE_TYPE:
|
|
113
|
+
const { width, height } = data;
|
|
114
|
+
if (width > 0 && height > 0) {
|
|
115
|
+
if (adMetadata.source.native) {
|
|
116
|
+
element.style.height = `${height}px`;
|
|
117
|
+
} else {
|
|
118
|
+
extendOrKeepDimension(element, 'width', width);
|
|
119
|
+
extendOrKeepDimension(element, 'height', height);
|
|
120
|
+
}
|
|
121
|
+
this.broadcastMessage({ ...data, id: this.id });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Message handling error:', error);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
window.addEventListener('message', this.messageListener);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private handleInvalidAd() {
|
|
133
|
+
this.removeMessageListener();
|
|
134
|
+
this.clearResponseTimeout();
|
|
135
|
+
this.startRendering();
|
|
136
|
+
this.validAdsCounter = 0;
|
|
50
137
|
}
|
|
51
138
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const templeLabelElement = document.getElementById('temple-label')!;
|
|
55
|
-
rootElement.replaceChildren(element);
|
|
139
|
+
private removeMessageListener() {
|
|
140
|
+
if (!this.messageListener) return;
|
|
56
141
|
|
|
57
|
-
|
|
58
|
-
|
|
142
|
+
window.removeEventListener('message', this.messageListener);
|
|
143
|
+
this.messageListener = undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private placeNewAd(adMetadata: AdMetadata) {
|
|
147
|
+
document.body.style.backgroundColor = adMetadata.source.native ? 'transparent' : '#F2F2F2';
|
|
148
|
+
|
|
149
|
+
const { source, dimensions } = adMetadata;
|
|
150
|
+
let adView: AdView;
|
|
151
|
+
switch (source.providerName) {
|
|
152
|
+
case 'Temple':
|
|
153
|
+
adView = makeTKeyAdView(dimensions.width, dimensions.height, source.native);
|
|
154
|
+
break;
|
|
155
|
+
case 'HypeLab':
|
|
156
|
+
case 'SmartyAds':
|
|
157
|
+
adView = makeAdsTwView(this.id, source, dimensions, this.origin);
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
adView = makeExtensionIframeView(this.id, source, dimensions);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const { element } = adView;
|
|
164
|
+
const templeLabelElement = document.getElementById('temple-label')!;
|
|
165
|
+
this.rootElement.replaceChildren(element);
|
|
166
|
+
|
|
167
|
+
if (!source.native) templeLabelElement.setAttribute('active', '');
|
|
168
|
+
else templeLabelElement.removeAttribute('active');
|
|
169
|
+
|
|
170
|
+
return adView;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private updateBackground(source: AdSource, creativeSet: CreativeSet = {}) {
|
|
174
|
+
const prevBackgroundElement = document.getElementById(BACKGROUND_ELEMENT_ID);
|
|
175
|
+
if (source.native && prevBackgroundElement) {
|
|
176
|
+
this.rootElement.removeChild(prevBackgroundElement);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (source.native) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
59
182
|
|
|
60
|
-
const updateBackground = (creativeSet: CreativeSet = {}) => {
|
|
61
183
|
try {
|
|
62
184
|
const { image, video } = creativeSet;
|
|
63
|
-
const prevBackgroundElement = document.getElementById(BACKGROUND_ELEMENT_ID);
|
|
64
185
|
let backgroundElement: HTMLImageElement | HTMLVideoElement | undefined;
|
|
65
186
|
if (image) {
|
|
66
187
|
backgroundElement = document.createElement('img');
|
|
@@ -77,7 +198,7 @@ export const renderAdsStack = async (
|
|
|
77
198
|
}
|
|
78
199
|
|
|
79
200
|
if (!backgroundElement && prevBackgroundElement) {
|
|
80
|
-
rootElement.removeChild(prevBackgroundElement);
|
|
201
|
+
this.rootElement.removeChild(prevBackgroundElement);
|
|
81
202
|
}
|
|
82
203
|
|
|
83
204
|
if (!backgroundElement) return;
|
|
@@ -96,76 +217,71 @@ export const renderAdsStack = async (
|
|
|
96
217
|
filter: 'blur(12px)'
|
|
97
218
|
});
|
|
98
219
|
if (prevBackgroundElement) {
|
|
99
|
-
rootElement.replaceChild(backgroundElement, prevBackgroundElement);
|
|
220
|
+
this.rootElement.replaceChild(backgroundElement, prevBackgroundElement);
|
|
100
221
|
} else {
|
|
101
|
-
rootElement.
|
|
222
|
+
this.rootElement.prepend(backgroundElement);
|
|
102
223
|
}
|
|
103
224
|
} catch (e) {
|
|
104
225
|
console.error(e);
|
|
105
226
|
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (element instanceof HTMLIFrameElement) {
|
|
109
|
-
return new Promise<void>((resolve, reject) => {
|
|
110
|
-
const responseTimeout = setTimeout(
|
|
111
|
-
() => {
|
|
112
|
-
window.removeEventListener('message', messageListener);
|
|
113
|
-
reject(new Error(`Timeout exceeded for ${adId}, ad source: ${JSON.stringify(source)}`));
|
|
114
|
-
},
|
|
115
|
-
(rest.length === 0 ? 20_000 : 10_000) * (AdsConfiguration.IS_MISES_BROWSER ? 2 : 1)
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
let wasReady = false;
|
|
119
|
-
const messageListener = (event: MessageEvent<any>) => {
|
|
120
|
-
if (event.source !== element.contentWindow) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
227
|
+
}
|
|
123
228
|
|
|
124
|
-
|
|
125
|
-
|
|
229
|
+
private broadcastMessage(content: unknown) {
|
|
230
|
+
window.parent.postMessage(JSON.stringify(content), '*');
|
|
231
|
+
}
|
|
126
232
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
wasReady = true;
|
|
131
|
-
broadcastMessage({ id: adId, type: AD_READY_MESSAGE_TYPE, adMetadata });
|
|
132
|
-
clearTimeout(responseTimeout);
|
|
133
|
-
resolve();
|
|
134
|
-
}
|
|
135
|
-
updateBackground(data.ad?.creative_set);
|
|
136
|
-
break;
|
|
137
|
-
case AD_ERROR_MESSAGE_TYPE:
|
|
138
|
-
if (!wasReady) {
|
|
139
|
-
window.removeEventListener('message', messageListener);
|
|
140
|
-
clearTimeout(responseTimeout);
|
|
141
|
-
reject(new Error(data.reason ?? 'Unknown error'));
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
case AD_RESIZE_MESSAGE_TYPE:
|
|
145
|
-
const { width, height } = data;
|
|
146
|
-
if (width > 0 && height > 0) {
|
|
147
|
-
if (adMetadata.source.native) {
|
|
148
|
-
element.style.height = `${height}px`;
|
|
149
|
-
} else {
|
|
150
|
-
extendOrKeepDimension(element, 'width', width);
|
|
151
|
-
extendOrKeepDimension(element, 'height', height);
|
|
152
|
-
}
|
|
153
|
-
broadcastMessage({ ...data, id: adId });
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error('Observing error:', error);
|
|
158
|
-
}
|
|
159
|
-
};
|
|
233
|
+
private broadcastNoMoreAds() {
|
|
234
|
+
this.broadcastMessage({ id: this.id, type: AD_ERROR_MESSAGE_TYPE, reason: 'No more ads to render' });
|
|
235
|
+
}
|
|
160
236
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
237
|
+
private clearResponseTimeout() {
|
|
238
|
+
if (this.responseTimeout !== undefined) {
|
|
239
|
+
clearTimeout(this.responseTimeout);
|
|
240
|
+
this.responseTimeout = undefined;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
164
243
|
|
|
165
|
-
|
|
166
|
-
|
|
244
|
+
private handleValidAd(data: any) {
|
|
245
|
+
const adMetadata = this.currentAdMetadata;
|
|
246
|
+
|
|
247
|
+
if (!adMetadata) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!this.wasReady) {
|
|
252
|
+
this.wasReady = true;
|
|
253
|
+
this.broadcastMessage({ id: this.id, type: AD_READY_MESSAGE_TYPE, adMetadata });
|
|
254
|
+
}
|
|
255
|
+
this.validAdsCounter++;
|
|
256
|
+
this.clearResponseTimeout();
|
|
257
|
+
this.updateBackground(adMetadata.source, data.ad?.creative_set);
|
|
167
258
|
}
|
|
259
|
+
}
|
|
168
260
|
|
|
169
|
-
|
|
170
|
-
|
|
261
|
+
/**
|
|
262
|
+
* Tries to render specified ads one-by-one until one of them is loaded or loading of all of them failed. Use it
|
|
263
|
+
* in a dedicated iframe. Sends messages to the parent window on an attempt to render an ad, on successful rendering,
|
|
264
|
+
* on ad resize, and on error.
|
|
265
|
+
*/
|
|
266
|
+
export const renderAdsStack = (
|
|
267
|
+
adId: string,
|
|
268
|
+
adsMetadata: (number | AdMetadata)[],
|
|
269
|
+
origin: string,
|
|
270
|
+
pageHasPlacesRules = false,
|
|
271
|
+
adCategories: string[],
|
|
272
|
+
hypelabBlacklistedCampaignsSlugs: string[]
|
|
273
|
+
) => {
|
|
274
|
+
try {
|
|
275
|
+
const adsStack = new AdsStack(
|
|
276
|
+
adId,
|
|
277
|
+
adsMetadata,
|
|
278
|
+
origin,
|
|
279
|
+
pageHasPlacesRules,
|
|
280
|
+
adCategories,
|
|
281
|
+
hypelabBlacklistedCampaignsSlugs
|
|
282
|
+
);
|
|
283
|
+
adsStack.startRendering();
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('Error while rendering ads stack:', error);
|
|
286
|
+
}
|
|
171
287
|
};
|
package/src/temple-wallet-api.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axiosFetchAdapter from '@vespaiach/axios-fetch-adapter';
|
|
2
1
|
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
|
3
2
|
|
|
4
3
|
import {
|
|
@@ -25,7 +24,7 @@ export class TempleWalletApi {
|
|
|
25
24
|
constructor(baseUrl: string) {
|
|
26
25
|
this.api = axios.create({
|
|
27
26
|
baseURL: new URL('/api', baseUrl).href,
|
|
28
|
-
adapter:
|
|
27
|
+
adapter: 'fetch'
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -87,6 +86,10 @@ export class TempleWalletApi {
|
|
|
87
86
|
)
|
|
88
87
|
);
|
|
89
88
|
|
|
89
|
+
getBlacklistedHypelabCampaignsSlugs = withFetchDataExtraction(() =>
|
|
90
|
+
this.api.get<string[]>('/temple-wallet-ads/hypelab-campaigns-blacklist')
|
|
91
|
+
);
|
|
92
|
+
|
|
90
93
|
getAllRules = async (): Promise<RawAllAdsRules> => {
|
|
91
94
|
const [
|
|
92
95
|
adPlacesRulesForAllDomains,
|
|
@@ -98,7 +101,8 @@ export class TempleWalletApi {
|
|
|
98
101
|
adsReplaceUrlsBlacklist,
|
|
99
102
|
providersNegativeSelectors,
|
|
100
103
|
elementsToHideOrRemoveRules,
|
|
101
|
-
providersCategories
|
|
104
|
+
providersCategories,
|
|
105
|
+
blacklistedHypelabCampaignsSlugs
|
|
102
106
|
] = await Promise.all([
|
|
103
107
|
this.getAdPlacesRulesForAllDomains(),
|
|
104
108
|
this.getProvidersRulesForAllDomains(),
|
|
@@ -109,7 +113,8 @@ export class TempleWalletApi {
|
|
|
109
113
|
this.getAdsReplaceUrlsBlacklist(),
|
|
110
114
|
this.getNegativeSelectorsForAllProviders(),
|
|
111
115
|
this.getElementsToHideOrRemoveRules(),
|
|
112
|
-
this.getProvidersCategories()
|
|
116
|
+
this.getProvidersCategories(),
|
|
117
|
+
this.getBlacklistedHypelabCampaignsSlugs()
|
|
113
118
|
]);
|
|
114
119
|
|
|
115
120
|
return {
|
|
@@ -123,6 +128,7 @@ export class TempleWalletApi {
|
|
|
123
128
|
providersNegativeSelectors,
|
|
124
129
|
elementsToHideOrRemoveRules,
|
|
125
130
|
providersCategories,
|
|
131
|
+
blacklistedHypelabCampaignsSlugs,
|
|
126
132
|
timestamp: Date.now()
|
|
127
133
|
};
|
|
128
134
|
};
|