Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds AmpAdTemplate #16593

Merged
merged 39 commits into from Aug 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0a7170f
init
glevitzky Jun 18, 2018
ed0f68e
Tests + more.
glevitzky Jun 18, 2018
6d707c4
Lint + types
glevitzky Jul 2, 2018
6103088
First test now passing.
glevitzky Jul 2, 2018
b3e53e4
More tests.
glevitzky Jul 2, 2018
8eacbe1
Removing erronesouly added file.
glevitzky Jul 2, 2018
088f916
Inserting element rather than overriding innerHTML.
glevitzky Jul 2, 2018
6e64ce9
Another erroneously added file.
glevitzky Jul 2, 2018
1da9ee1
Added amp-template-ad
glevitzky Jul 6, 2018
ba74ebe
Basic functionality in place.
glevitzky Jul 6, 2018
0b92d7f
Reseting yarn.lock
glevitzky Jul 6, 2018
2443152
Lint.
glevitzky Jul 9, 2018
bb2eceb
Fixed tests + types.
glevitzky Jul 9, 2018
b25dcc5
Lint
glevitzky Jul 9, 2018
76fedaf
Added test-amp-ad-template.js + dep-check fix.
glevitzky Jul 9, 2018
b530106
Merges.
glevitzky Jul 9, 2018
f20f042
Using replaceChild + parent of templateElement rather than body.
glevitzky Jul 9, 2018
9334686
Added NameFrameRenderer as non-AMP rendering mode + additional test.
glevitzky Jul 12, 2018
6d9bc8b
Added URL expansion.
glevitzky Jul 13, 2018
39fb400
More tests.
glevitzky Jul 13, 2018
2ee5c1a
Added amp-ad test + fixed template-validator test.
glevitzky Jul 13, 2018
e549835
Cleaning up added element in test-tempate-renderer.
glevitzky Jul 16, 2018
3c4581c
Restructring how query params are added to request.
glevitzky Jul 17, 2018
c5afc8e
Minor feedback changes.
glevitzky Jul 23, 2018
e568c63
Added amp-ad-custom extension.
glevitzky Jul 24, 2018
b81cbd2
Restoring to previous commit.
glevitzky Aug 17, 2018
841b343
Fixing template-renderer.
glevitzky Aug 17, 2018
4c0365c
Removing amp-ad changes.
glevitzky Aug 17, 2018
a7de768
Things back in functional state.
glevitzky Aug 17, 2018
6c7f51c
Moving amp-ad-template to amp-ad-custom.
glevitzky Aug 17, 2018
d189f3e
Fixed accidentally reverted header.
glevitzky Aug 17, 2018
dc8ff38
Factored out friendly-frame-util + minor fixes.
glevitzky Aug 20, 2018
d5da03e
Adding test to ff util.
glevitzky Aug 20, 2018
183d76e
XHR type decl fix.
glevitzky Aug 27, 2018
666aaa0
One more XHR type decl fix.
glevitzky Aug 27, 2018
85b27b8
One more XHR type decl fix.
glevitzky Aug 27, 2018
516e39e
Minor type + dep fixes.
glevitzky Aug 27, 2018
fe4133c
Test fix.
glevitzky Aug 27, 2018
a093c7a
Test fix.
glevitzky Aug 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion build-system/app.js
Expand Up @@ -932,7 +932,8 @@ app.get('/adzerk/*', (req, res) => {
pc.cwd() + '/extensions/amp-ad-network-adzerk-impl/0.1/data/' + match[1];
fs.readFileAsync(filePath).then(file => {
res.setHeader('Content-Type', 'application/json');
res.setHeader('AMP-template-amp-creative', 'amp-mustache');
res.setHeader('AMP-Ad-Template-Extension', 'amp-mustache');
res.setHeader('AMP-Ad-Response-Type', 'template');
res.end(file);
}).error(() => {
res.status(404);
Expand Down
2 changes: 2 additions & 0 deletions build-system/dep-check-config.js
Expand Up @@ -222,6 +222,8 @@ exports.rules = [
'extensions/amp-gfycat/0.1/amp-gfycat.js->' +
'src/service/video-manager-impl.js',
'extensions/amp-a4a/0.1/amp-a4a.js->src/service/variable-source.js',
'extensions/amp-a4a/0.1/friendly-frame-util.js->' +
'src/service/url-replacements-impl.js',
'extensions/amp-nexxtv-player/0.1/amp-nexxtv-player.js->' +
'src/service/video-manager-impl.js',
'extensions/amp-3q-player/0.1/amp-3q-player.js->' +
Expand Down
1 change: 1 addition & 0 deletions bundles.config.js
Expand Up @@ -49,6 +49,7 @@ exports.extensionBundles = [
},
{name: 'amp-accordion',version: '0.1',type: TYPES.MISC},
{name: 'amp-ad', version: '0.1', options: {hasCss: true}, type: TYPES.AD},
{name: 'amp-ad-custom', version: '0.1', type: TYPES.AD},
{name: 'amp-ad-network-adsense-impl', version: '0.1', type: TYPES.AD},
{name: 'amp-ad-network-adzerk-impl', version: '0.1', type: TYPES.AD},
{name: 'amp-ad-network-doubleclick-impl', version: '0.1', type: TYPES.AD},
Expand Down
17 changes: 17 additions & 0 deletions examples/amp-ad-template.amp.html
@@ -0,0 +1,17 @@
<!doctype html>
<html ⚡>
<head>
<meta charset="utf-8">
<title>Amp Ad Common Example/Debug</title>
<link rel="canonical" href="http://nonblocking.io/">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=Questrial' rel='stylesheet' type='text/css'>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-ad-custom" src="https://cdn.ampproject.org/v0/amp-ad-custom-0.1.js"></script>
</head>
<body>
<h1>Amp Ad Template Example/Debug</h1>
<amp-ad-custom width=300 height=250 src="/adzerk/1"></amp-ad-custom>
</body>
</html>
6 changes: 3 additions & 3 deletions extensions/amp-a4a/0.1/amp-ad-network-base.js
Expand Up @@ -38,7 +38,7 @@ export class AmpAdNetworkBase extends AMP.BaseElement {
constructor(element) {
super(element);

/** @private {?Promise<!../../../src/service/xhr-impl.FetchResponse>} */
/** @private {?Promise<!../../../src/utils/xhr-utils.FetchResponse>} */
this.adResponsePromise_ = null;

/** @private {Object<string, !./amp-ad-type-defs.Validator>} */
Expand Down Expand Up @@ -156,7 +156,7 @@ export class AmpAdNetworkBase extends AMP.BaseElement {

/**
* Processes the ad response as soon as the XHR request returns.
* @param {?../../../src/service/xhr-impl.FetchResponse} response
* @param {?../../../src/utils/xhr-utils.FetchResponse} response
* @return {!Promise}
* @private
*/
Expand Down Expand Up @@ -200,7 +200,7 @@ export class AmpAdNetworkBase extends AMP.BaseElement {
if (error) {
dev().warn(TAG, error);
}
switch (recoveryMode.type) {
switch (recoveryMode) {
case RecoveryModeType.COLLAPSE:
this.forceCollapse_();
break;
Expand Down
21 changes: 15 additions & 6 deletions extensions/amp-a4a/0.1/amp-ad-type-defs.js
Expand Up @@ -21,12 +21,6 @@
}} */
export let LayoutInfoDef;

/** @typedef {{
templateUrl: string,
data: (JsonObject|undefined),
}} */
export let AmpTemplateCreativeDef;

/** @enum {string} */
export const FailureType = {
REQUEST_ERROR: 'REQUEST_ERROR',
Expand Down Expand Up @@ -69,6 +63,21 @@ export let ValidatorOutput;
}} */
export let CreativeMetaDataDef;

/** @typedef {{
templateUrl: string,
data: (JsonObject|undefined),
analytics: (JsonObject|undefined),
}} */
export let AmpTemplateCreativeDef;

/** @typedef {{
creative: (string|undefined),
rawCreativeBytes: (!ArrayBuffer|undefined),
sentinel: (string|undefined),
additionalContextMetadata: (!JsonObject|undefined),
}} */
export let CrossDomainDataDef;

/**
* @abstract
*/
Expand Down
2 changes: 1 addition & 1 deletion extensions/amp-a4a/0.1/amp-ad-utils.js
Expand Up @@ -25,7 +25,7 @@ const TAG = 'amp-ad-util';
* Sends a CORS XHR request to the given URL.
* @param {!Window} win
* @param {string} url Request URL to send XHR to.
* @return {!Promise<!../../../src/service/xhr-impl.FetchResponse>}
* @return {!Promise<!../../../src/utils/xhr-utils.FetchResponse>}
*/
export function sendXhrRequest(win, url) {
return Services.xhrFor(win).fetch(url, {
Expand Down
68 changes: 5 additions & 63 deletions extensions/amp-a4a/0.1/friendly-frame-renderer.js
Expand Up @@ -14,21 +14,13 @@
* limitations under the License.
*/

import {A4AVariableSource} from '../../amp-a4a/0.1/a4a-variable-source';
import {Renderer} from './amp-ad-type-defs';
import {createElementWithAttributes} from '../../../src/dom';
import {dev} from '../../../src/log';
import {dict} from '../../../src/utils/object';
import {
installFriendlyIframeEmbed,
setFriendlyIframeEmbedVisible,
} from '../../../src/friendly-iframe-embed';
import {installUrlReplacementsForEmbed} from '../../../src/service/url-replacements-impl';
import {setStyle} from '../../../src/style';
import {renderCreativeIntoFriendlyFrame} from './friendly-frame-util';

/**
* @typedef {{
* creativeMetaData: ./amp-ad-type-defs.CreativeMetaDataDef,
* creativeMetadata: ./amp-ad-type-defs.CreativeMetaDataDef,
* }}
*/
export let CreativeData;
Expand All @@ -44,70 +36,20 @@ export class FriendlyFrameRenderer extends Renderer {
*/
constructor() {
super();

/**
* @type {?Element}
* @protected
*/
this.iframe = null;
}

/** @override */
render(context, element, creativeData) {

creativeData = /** @type {CreativeData} */ (creativeData);

const {size, requestUrl: adUrl} = context;
const {size, adUrl} = context;
const {creativeMetadata} = creativeData;

dev().assert(size, 'missing creative size');
dev().assert(adUrl, 'missing ad request url');

// Create and setup friendly iframe.
this.iframe = /** @type {!HTMLIFrameElement} */(
createElementWithAttributes(
/** @type {!Document} */(element.ownerDocument),
'iframe',
dict({
// NOTE: It is possible for either width or height to be 'auto',
// a non-numeric value.
'height': size.height,
'width': size.width,
'frameborder': '0',
'allowfullscreen': '',
'allowtransparency': '',
'scrolling': 'no',
})));
// TODO(glevitzky): Ensure that applyFillContent or equivalent is called.

const fontsArray = [];
if (creativeMetadata.customStylesheets) {
creativeMetadata.customStylesheets.forEach(s => {
const href = s['href'];
if (href) {
fontsArray.push(href);
}
});
}

return installFriendlyIframeEmbed(
this.iframe, element, {
host: element,
url: /** @type {string} */ (adUrl),
html: creativeMetadata.minifiedCreative,
extensionIds: creativeMetadata.customElementExtensions || [],
fonts: fontsArray,
}, embedWin => {
installUrlReplacementsForEmbed(context.ampDoc, embedWin,
new A4AVariableSource(context.ampDoc, embedWin));
})
.then(friendlyIframeEmbed => {
setFriendlyIframeEmbedVisible(
friendlyIframeEmbed, element.isInViewport());
// Ensure visibility hidden has been removed (set by boilerplate).
const frameDoc = friendlyIframeEmbed.iframe.contentDocument ||
friendlyIframeEmbed.win.document;
setStyle(frameDoc.body, 'visibility', 'visible');
});
return renderCreativeIntoFriendlyFrame(
adUrl, size, element, creativeMetadata);
}
}
88 changes: 88 additions & 0 deletions extensions/amp-a4a/0.1/friendly-frame-util.js
@@ -0,0 +1,88 @@
/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {A4AVariableSource} from '../../amp-a4a/0.1/a4a-variable-source';
import {createElementWithAttributes} from '../../../src/dom';
import {dict} from '../../../src/utils/object';
import {
installFriendlyIframeEmbed,
setFriendlyIframeEmbedVisible,
} from '../../../src/friendly-iframe-embed';
import {installUrlReplacementsForEmbed} from '../../../src/service/url-replacements-impl';
import {setStyle} from '../../../src/style';

/**
* Renders a creative into a "NameFrame" iframe.
*
* @param {string} adUrl The ad request URL.
* @param {!./amp-ad-type-defs.LayoutInfoDef} size The size and layout of the
* element.
* @param {!Element} element The ad slot element.
* @param {!./amp-ad-type-defs.CreativeMetaDataDef} creativeMetadata Metadata
* for the creative. Contains information like required extensions, fonts, and
* of course the creative itself.
* @return {!Promise<!Element>} The iframe into which the creative was rendered.
*/
export function renderCreativeIntoFriendlyFrame(
adUrl, size, element, creativeMetadata) {
// Create and setup friendly iframe.
const iframe = /** @type {!HTMLIFrameElement} */(
createElementWithAttributes(
/** @type {!Document} */(element.ownerDocument),
'iframe',
dict({
// NOTE: It is possible for either width or height to be 'auto',
// a non-numeric value.
'height': size.height,
'width': size.width,
'frameborder': '0',
'allowfullscreen': '',
'allowtransparency': '',
'scrolling': 'no',
})));
// TODO(glevitzky): Ensure that applyFillContent or equivalent is called.

const fontsArray = [];
if (creativeMetadata.customStylesheets) {
creativeMetadata.customStylesheets.forEach(s => {
const href = s['href'];
if (href) {
fontsArray.push(href);
}
});
}

return installFriendlyIframeEmbed(
iframe, element, {
host: element,
url: /** @type {string} */ (adUrl),
html: creativeMetadata.minifiedCreative,
extensionIds: creativeMetadata.customElementExtensions || [],
fonts: fontsArray,
}, embedWin => {
installUrlReplacementsForEmbed(element.getAmpDoc(), embedWin,
new A4AVariableSource(element.getAmpDoc(), embedWin));
})
.then(friendlyIframeEmbed => {
setFriendlyIframeEmbedVisible(
friendlyIframeEmbed, element.isInViewport());
// Ensure visibility hidden has been removed (set by boilerplate).
const frameDoc = friendlyIframeEmbed.iframe.contentDocument ||
friendlyIframeEmbed.win.document;
setStyle(frameDoc.body, 'visibility', 'visible');
return iframe;
});
}
19 changes: 14 additions & 5 deletions extensions/amp-a4a/0.1/name-frame-renderer.js
Expand Up @@ -16,7 +16,6 @@

import {Renderer} from './amp-ad-type-defs';
import {createElementWithAttributes} from '../../../src/dom';
import {dev} from '../../../src/log';
import {dict} from '../../../src/utils/object';
import {getContextMetadata} from '../../../src/iframe-attributes';
import {getDefaultBootstrapBaseUrl} from '../../../src/3p-frame';
Expand All @@ -27,11 +26,21 @@ import {utf8Decode} from '../../../src/utils/bytes';
*/
export class NameFrameRenderer extends Renderer {
/** @override */
render(context, element, creativeData) {
const {crossDomainData} = creativeData;
dev().assert(crossDomainData, 'CrossDomain data undefined!');
render(context, element, crossDomainData) {
crossDomainData = /** @type {!./amp-ad-type-defs.CrossDomainDataDef} */ (
crossDomainData);

const creative = utf8Decode(crossDomainData.rawCreativeBytes);
if (!crossDomainData.creative && !crossDomainData.rawCreativeBytes) {
// No creative, nothing to do.
return Promise.resolve();
}

const creative = crossDomainData.creative ||
// rawCreativeBytes must exist; if we're here, then `creative` must not
// exist, but the if-statement above guarantees that at least one of
// `creative` || `rawCreativeBytes` exists.
utf8Decode(/** @type {!ArrayBuffer} */ (
crossDomainData.rawCreativeBytes));
const srcPath =
getDefaultBootstrapBaseUrl(context.win, 'nameframe');
const contextMetadata = getContextMetadata(
Expand Down