-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ Refactor revcontent logic for new adcode support (#38645)
* Refactor revcontent logic for new adcode support * Update readme to include gdpr consent attributes * Change from intersection entries list to setting bcr as property
- Loading branch information
1 parent
181dc81
commit f8cbfb0
Showing
3 changed files
with
748 additions
and
851 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,250 @@ | ||
import {loadScript, validateData, writeScript} from '#3p/3p'; | ||
import {loadScript, validateData} from '#3p/3p'; | ||
|
||
import {setStyle, setStyles} from '#core/dom/style'; | ||
|
||
// Required/optional parameters for legacy/standard builds are consolidated here | ||
// to provide a more managable way of interacting with them. Most of the legacy | ||
// optional attributes are deprecated but there's still tags live that might have | ||
// them so they'll stay in this list to pass validation | ||
const options = { | ||
endpoints: { | ||
legacy: | ||
'https://labs-cdn.revcontent.com/build/amphtml/revcontent.amp.min.js', | ||
standard: 'https://assets.revcontent.com/master/delivery.js', | ||
evergreen: 'https://delivery.revcontent.com/', | ||
}, | ||
params: { | ||
legacy: { | ||
required: ['id', 'height'], | ||
optional: [ | ||
'wrapper', | ||
'subIds', | ||
'revcontent', | ||
'env', | ||
'loadscript', | ||
'api', | ||
'key', | ||
'ssl', | ||
'adxw', | ||
'adxh', | ||
'rows', | ||
'cols', | ||
'domain', | ||
'source', | ||
'testing', | ||
'endpoint', | ||
'publisher', | ||
'branding', | ||
'font', | ||
'css', | ||
'sizer', | ||
'debug', | ||
'ampcreative', | ||
'gdpr', | ||
'gdprConsent', | ||
'usPrivacy', | ||
'gamEnabled', | ||
], | ||
}, | ||
evergreen: { | ||
required: ['widgetId', 'pubId', 'height'], | ||
optional: ['endpoint'], | ||
}, | ||
}, | ||
}; | ||
|
||
/** | ||
* @param {!Window} global | ||
* Helper function to get endpoint string based on how tag is configured. | ||
* | ||
* @param {!Object} data | ||
* @return {string} | ||
*/ | ||
export function revcontent(global, data) { | ||
let endpoint = | ||
'https://labs-cdn.revcontent.com/build/amphtml/revcontent.amp.min.js'; | ||
|
||
function getEndpoint(data) { | ||
if (typeof data.revcontent !== 'undefined') { | ||
if (typeof data.env === 'undefined') { | ||
endpoint = 'https://assets.revcontent.com/master/delivery.js'; | ||
} else if (data.env == 'dev') { | ||
endpoint = 'https://preact.revcontent.dev/delivery.js'; | ||
} else { | ||
endpoint = 'https://assets.revcontent.com/' + data.env + '/delivery.js'; | ||
return options.endpoints.standard; | ||
} | ||
if (data.env == 'dev') { | ||
return 'https://preact.revcontent.dev/delivery.js'; | ||
} | ||
return `https://assets.revcontent.com/${data.env}/delivery.js`; | ||
} | ||
|
||
const required = ['id', 'height']; | ||
const optional = [ | ||
'wrapper', | ||
'subIds', | ||
'revcontent', | ||
'env', | ||
'loadscript', | ||
'api', | ||
'key', | ||
'ssl', | ||
'adxw', | ||
'adxh', | ||
'rows', | ||
'cols', | ||
'domain', | ||
'source', | ||
'testing', | ||
'endpoint', | ||
'publisher', | ||
'branding', | ||
'font', | ||
'css', | ||
'sizer', | ||
'debug', | ||
'ampcreative', | ||
'gdpr', | ||
'gdprConsent', | ||
'usPrivacy', | ||
'gamEnabled', | ||
]; | ||
if ( | ||
typeof data.placementType !== 'undefined' && | ||
data.placementType === 'evergreen' | ||
) { | ||
if (typeof data.devUrl !== 'undefined') { | ||
return data.devUrl; | ||
} | ||
|
||
data.endpoint = data.endpoint ? data.endpoint : 'trends.revcontent.com'; | ||
return `${options.endpoints.evergreen}/${data.pubId}/${data.widgetId}/widget.js`; | ||
} | ||
|
||
validateData(data, required, optional); | ||
global.data = data; | ||
if (data.loadscript) { | ||
loadScript(window, endpoint); | ||
return options.endpoints.legacy; | ||
} | ||
|
||
/** | ||
* Internal handler for calling requestResize | ||
* @param {!Window} global | ||
* @param {!Element} container | ||
* @param {number} height | ||
*/ | ||
function handleResize(global, container, height) { | ||
global.context | ||
.requestResize(undefined, height, true) | ||
.then(() => { | ||
handleResizeSuccess(global); | ||
//handleResizeDenied(global, container, height); | ||
}) | ||
.catch(() => { | ||
handleResizeDenied(global, container, height); | ||
}); | ||
} | ||
|
||
/** | ||
* Helper function for handling denied resize requests. Creates an overflow element if one does not exist | ||
* @param {!Window} global | ||
* @param {!Element} container | ||
* @param {number} height | ||
*/ | ||
function handleResizeDenied(global, container, height) { | ||
const overflowElement = global.document.getElementById('overflow'); | ||
|
||
if (overflowElement) { | ||
setStyle(overflowElement, 'display', ''); | ||
} else { | ||
writeScript(window, endpoint); | ||
createOverflowElement(global, container, height); | ||
} | ||
} | ||
|
||
/** | ||
* Helper function for handling successful resize requests | ||
* @param {!Window} global | ||
*/ | ||
function handleResizeSuccess(global) { | ||
const overflow = global.document.getElementById('overflow'); | ||
if (overflow) { | ||
setStyle(overflow, 'display', 'none'); | ||
} | ||
} | ||
|
||
/** | ||
* Helper function to create an overflow element if one doesn't exist | ||
* @param {!Window} global | ||
* @param {!Element} container | ||
* @param {number} height | ||
*/ | ||
function createOverflowElement(global, container, height) { | ||
const overflow = global.document.createElement('div'); | ||
overflow.id = 'overflow'; | ||
|
||
overflow.addEventListener('click', () => { | ||
handleResize(global, container, height); | ||
}); | ||
|
||
setStyles(overflow, { | ||
position: 'absolute', | ||
height: `60px`, | ||
bottom: '0', | ||
left: '0', | ||
right: '0', | ||
background: 'green', | ||
cursor: 'pointer', | ||
}); | ||
|
||
const indicator = `<svg id="indicator" fill="#ffffff" width="60" height="60" viewBox="0 0 24.00 24.00" xmlns="http://www.w3.org/2000/svg"><path d="M16.939 7.939 12 12.879l-4.939-4.94-2.122 2.122L12 17.121l7.061-7.06z"></path></svg>`; | ||
|
||
const chevron = global.document.createElement('div'); | ||
setStyles(chevron, { | ||
width: '40px', | ||
height: '40px', | ||
margin: '0 auto', | ||
display: 'block', | ||
}); | ||
|
||
chevron./*OK*/ innerHTML = indicator; | ||
overflow.appendChild(chevron); | ||
container.appendChild(overflow); | ||
} | ||
|
||
/** | ||
* @param {!Window} global | ||
* @param {!Object} data | ||
*/ | ||
export function revcontent(global, data) { | ||
global.revcontent = global.revcontent || { | ||
boundingClientRect: {}, | ||
detectedWidth: 0, | ||
detectedHeight: 0, | ||
widgetData: { | ||
...data, | ||
}, | ||
requestedSize: 0, | ||
}; | ||
|
||
const requiredParams = []; | ||
const optionalParams = []; | ||
const containerDiv = global.document.getElementById('c'); | ||
|
||
if ( | ||
typeof data.placementType !== 'undefined' && | ||
data.placementType === 'evergreen' | ||
) { | ||
// Revcontent evergreen builds do not have an explicit group of optional parameters | ||
// to support configuration flexibility. Add any present attributes that are not | ||
// part of the required ones to the optional list so tag passes validation. | ||
const required = options?.params?.evergreen?.required; | ||
const optional = Object.keys(data).filter((entry) => { | ||
if (!required.includes(entry)) { | ||
return entry; | ||
} | ||
}); | ||
|
||
optional.push(...options?.params?.evergreen?.optional); | ||
requiredParams.push(...required); | ||
optionalParams.push(...optional); | ||
|
||
global.context.observeIntersection(function (changes) { | ||
/** @type {!Array} */ changes.forEach(function (c) { | ||
if (c.intersectionRect.height) { | ||
if (global.revcontent?.boundingClientRect !== c.boundingClientRect) { | ||
Object.assign( | ||
global.revcontent?.boundingClientRect, | ||
c.boundingClientRect | ||
); | ||
} | ||
|
||
if (c.boundingClientRect.height < global.revcontent.requestedSize) { | ||
handleResize(global, containerDiv, global.revcontent.requestedSize); | ||
} | ||
} | ||
}); | ||
}); | ||
} else { | ||
const required = options?.params?.legacy?.required; | ||
const optional = options?.params?.legacy?.optional; | ||
|
||
requiredParams.push(...required); | ||
optionalParams.push(...optional); | ||
} | ||
|
||
const endpoint = getEndpoint(data); | ||
data.endpoint = data.endpoint ? data.endpoint : 'trends.revcontent.com'; | ||
|
||
validateData(data, requiredParams, optionalParams); | ||
|
||
global.data = data; | ||
loadScript(global, endpoint, () => { | ||
window.addEventListener('message', (e) => { | ||
if ( | ||
e.data.source == 'revcontent' && | ||
e.data.action == 'RESIZE_AMP_TAG' && | ||
typeof e.data.height != 'undefined' | ||
) { | ||
global.revcontent.requestedSize = e.data.height; | ||
handleResize(global, containerDiv, e.data.height); | ||
} | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,67 @@ | ||
# Revcontent | ||
|
||
## Example | ||
## Examples | ||
|
||
### Standard Tag | ||
|
||
The standard AMP tag for Revcontent is the basic AMP ads integration and is used as shown here: | ||
|
||
```html | ||
<amp-ad | ||
width="400" | ||
height="260" | ||
width="{APPROPRIATE_WIDTH}" | ||
height="{APPROPRIATE_HEIGHT}" | ||
layout="responsive" | ||
data-revcontent | ||
type="revcontent" | ||
heights="(max-width: 320px) 933px, | ||
(max-width: 360px) 1087px, | ||
(max-width: 375px) 1138px, | ||
(max-width: 412px) 1189px, | ||
(max-width: 414px) 1072px, | ||
(max-width: 568px) 1151px, | ||
(max-width: 640px) 1128px, | ||
(max-width: 667px) 1151px, | ||
(max-width: 732px) 1211px, | ||
(max-width: 736px) 1151px, | ||
(max-width: 768px) 633px, | ||
(max-width: 1024px) 711px, | ||
86vw" | ||
data-wrapper="rcjsload_2ff711" | ||
data-id="203" | ||
> | ||
<div placeholder="">Loading ...</div> | ||
data-id="{YOUR_WIDGET_ID}"> | ||
</amp-ad> | ||
``` | ||
|
||
### Evergreen Tag | ||
|
||
The evergreen AMP tag leverages new and improved ad code from Revcontent and supports greater performance and customization capabilities: | ||
|
||
```html | ||
<amp-ad | ||
data-widget-id="{YOUR_WIDGET_ID}" | ||
data-pub-id="{YOUR_PUB_ID}" | ||
data-placement-type="evergreen" | ||
width="{APPROPRIATE_WIDTH}" | ||
height="{APPROPRIATE_HEIGHT}" | ||
layout="responsive" | ||
type="revcontent"> | ||
</amp-ad> | ||
``` | ||
|
||
## Configuration | ||
|
||
For semantics of configuration, please see [Revcontent's documentation](https://faq.revcontent.com/). | ||
For help with configuration, please contact Revcontent or refer to their documentation. | ||
|
||
Supported parameters: | ||
### Standard Tag Options | ||
|
||
#### Required Parameters | ||
|
||
- `data-id` | ||
- `data-revcontent` | ||
- `data-env` | ||
- `data-wrapper` | ||
- `data-endpoint` | ||
- `data-ssl` | ||
- `data-testing` | ||
- `data-loadscript` | ||
- `width` | ||
- `height` | ||
|
||
#### Optional Parameters | ||
|
||
- `data-sub-ids` | ||
- `data-gam-enabled` | ||
- `data-gdpr` | ||
- `data-gdpr-consent` | ||
- `data-us-privacy` | ||
|
||
### Evergreen Tag Options | ||
|
||
#### Required Parameters | ||
|
||
- `data-widget-id` | ||
- `data-pub-id` | ||
- `width` | ||
- `height` | ||
|
||
## Auto-sizing of Ads | ||
#### Optional Parameters | ||
|
||
Revcontent's AMP service will be updated to support resizing of ads for improved rendering, no additional tag parameters are required at this time. | ||
Please contact Revcontent for more information about optional parameters for evergreen tags. |
Oops, something went wrong.