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

Initial smatr-ads-net #27382

Merged
merged 4 commits into from Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
1 change: 1 addition & 0 deletions build-system/test-configs/dep-check-config.js
Expand Up @@ -183,6 +183,7 @@ exports.rules = [
// a4a ads depend on a4a.
'extensions/amp-ad-network-fake-impl/0.1/amp-ad-network-fake-impl.js->extensions/amp-a4a/0.1/amp-a4a.js',
'extensions/amp-ad-network-adzerk-impl/0.1/amp-ad-network-adzerk-impl.js->extensions/amp-a4a/0.1/amp-a4a.js',
'extensions/amp-ad-network-smartads-impl/0.1/amp-ad-network-smartads-impl.js->extensions/amp-a4a/0.1/amp-a4a.js',
'extensions/amp-ad-network-doubleclick-impl/0.1/sra-utils.js->extensions/amp-a4a/0.1/amp-a4a.js',
'extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js->extensions/amp-a4a/0.1/amp-a4a.js',
'extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js->extensions/amp-a4a/0.1/amp-a4a.js',
Expand Down
@@ -0,0 +1,59 @@
/**
* Copyright 2020 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 {AmpA4A} from '../../amp-a4a/0.1/amp-a4a';
import {startsWith} from '../../../src/string';

/**
* Base URL
*
* @type {string}
* @private
*/
const BASE_URL_ = 'https://smart-ads.biz/_amp';

/**
* A4A base URL
*
* @type {string}
* @private
*/
const BASE_A4A_URL_ = 'https://smart-ads.biz/_a4a';

export class AmpAdNetworkSmartAdsImpl extends AmpA4A {
/** @override */
getAdUrl(unusedConsentState, opt_rtcResponsesPromise) {
return this.element.getAttribute('src').replace(BASE_URL_, BASE_A4A_URL_);
}

/** @override */
getSigningServiceNames() {
return ['cloudflare'];
}

/** @override */
isValidElement() {
const src = this.element.getAttribute('src') || '';
return (
this.isAmpAdElement() &&
(startsWith(src, BASE_URL_) || startsWith(src, BASE_A4A_URL_))
);
}
}

AMP.extension('amp-ad-network-smartads-impl', '0.1', AMP => {
AMP.registerElement('amp-ad-network-smartads-impl', AmpAdNetworkSmartAdsImpl);
});
39 changes: 39 additions & 0 deletions extensions/amp-ad-network-smartads-impl/0.1/smartads-a4a-config.js
@@ -0,0 +1,39 @@
/**
* Copyright 2020 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 {startsWith} from '../../../src/string';

/** @const @private {string} */
const SRC_PREFIX_ = 'https://smart-ads.biz/_amp';

/** @const @private {string} */
const SRC_A4A_PREFIX_ = 'https://smart-ads.biz/_a4a';

/**
* @param {!Window} win
* @param {!Element} element
* @param {boolean} useRemoteHtml
* @return {boolean}
*/
export function smartAdsIsA4AEnabled(win, element, useRemoteHtml) {
const src = element.getAttribute('src');
return (
!useRemoteHtml &&
!!src &&
!!element.getAttribute('data-use-a4a') &&
(startsWith(src, SRC_PREFIX_) || startsWith(src, SRC_A4A_PREFIX_))
);
}
@@ -0,0 +1,143 @@
/**
* Copyright 2020 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 {AmpAdNetworkSmartAdsImpl} from '../../../amp-ad-network-smartads-impl/0.1/amp-ad-network-smartads-impl';
import {
AmpAdUIHandler, // eslint-disable-line no-unused-vars
} from '../../../amp-ad/0.1/amp-ad-ui';
import {
AmpAdXOriginIframeHandler, // eslint-disable-line no-unused-vars
} from '../../../amp-ad/0.1/amp-ad-xorigin-iframe-handler';
import {createElementWithAttributes} from '../../../../src/dom';
import {smartAdsIsA4AEnabled} from '../../../amp-ad-network-smartads-impl/0.1/smartads-a4a-config';

describes.realWin('smartads-a4a-config', {amp: false}, env => {
let win, doc;
beforeEach(() => {
win = env.win;
doc = win.document;
});
it('should pass a4a config predicate', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
src: 'https://smart-ads.biz/_amp',
'data-use-a4a': 'true',
});
expect(smartAdsIsA4AEnabled(win, element)).to.be.true;
});
it('should pass a4a config predicate', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
src: 'https://smart-ads.biz/_a4a',
'data-use-a4a': 'true',
});
expect(smartAdsIsA4AEnabled(win, element)).to.be.true;
});
it('should fail a4a config predicate due to useRemoteHtml', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
src: 'https://smart-ads.biz/_a4a',
'data-use-a4a': 'true',
});
const useRemoteHtml = true;
expect(smartAdsIsA4AEnabled(win, element, useRemoteHtml)).to.be.false;
});
it('should fail a4a config predicate due to missing use-a4a', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
src: 'https://smart-ads.biz/_amp',
});
expect(smartAdsIsA4AEnabled(win, element)).to.be.false;
});
it('should fail a4a config predicate due to missing src', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
'data-use-a4a': 'true',
});
expect(smartAdsIsA4AEnabled(win, element)).to.be.false;
});
it('should fail a4a config predicate due to invalid src', () => {
const element = createElementWithAttributes(doc, 'amp-ad', {
src: 'https://evil.com?hello=world&https://smart-ads.biz',
'data-use-a4a': 'true',
});
expect(smartAdsIsA4AEnabled(win, element)).to.be.false;
});
});

describes.realWin(
'amp-ad-network-smartads-impl',
{
amp: {
extensions: ['amp-ad-network-smartads-impl'],
},
},
env => {
let win, doc;
let impl;
let implElem;
beforeEach(() => {
win = env.win;
doc = win.document;
implElem = doc.createElement('amp-ad');
implElem.setAttribute('type', 'smartads');
implElem.setAttribute('data-use-a4a', 'true');
env.sandbox
.stub(AmpAdNetworkSmartAdsImpl.prototype, 'getSigningServiceNames')
.callsFake(() => {
return ['google'];
});
impl = new AmpAdNetworkSmartAdsImpl(implElem);
});

describe('#isValidElement', () => {
it('should be valid', () => {
implElem.setAttribute(
'src',
'https://smart-ads.biz/_a4a?buid=1&is_a4a=1'
);
expect(impl.isValidElement()).to.be.true;
});
it('should be valid', () => {
implElem.setAttribute(
'src',
'https://smart-ads.biz/_amp?buid=1&is_a4a=1'
);
expect(impl.isValidElement()).to.be.true;
});
it('should NOT be valid (impl tag name)', () => {
implElem = doc.createElement('amp-ad-network-smartads-impl');
implElem.setAttribute('type', 'smartads');
impl = new AmpAdNetworkSmartAdsImpl(implElem);
expect(impl.isValidElement()).to.be.false;
});
});

describe('#getAdUrl', () => {
it('should be valid', () => {
implElem.setAttribute(
'src',
'https://smart-ads.biz/_a4a?buid=1&is_a4a=1'
);
const base = 'https://smart-ads.biz/_a4a';
expect(impl.getAdUrl().substring(0, base.length)).to.equal(base);
});
it('should be valid', () => {
implElem.setAttribute(
'src',
'https://smart-ads.biz/_amp?buid=1&is_a4a=1'
);
const base = 'https://smart-ads.biz/_a4a';
expect(impl.getAdUrl().substring(0, base.length)).to.equal(base);
});
});
}
);
10 changes: 10 additions & 0 deletions extensions/amp-ad-network-smartads-impl/OWNERS
@@ -0,0 +1,10 @@
// For an explanation of the OWNERS rules and syntax, see:
// https://github.com/ampproject/amp-github-apps/blob/master/owners/OWNERS.example

{
rules: [
{
owners: [{name: 'ampproject/wg-ads-reviewers'}, {name: 'approslab'}],
},
],
}
@@ -0,0 +1,61 @@
<!---
Copyright 2020 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.
-->

# amp-ad-network-smartads-impl

SmartAds implementation of AMP Ad tag which requests early by XHR and renders natively within the page if a valid AMP Ad is returned. Should not be directly referenced by pages and instead is dynamically loaded via the amp-ad tag. However, in order to remove an async script load of this library, publishers can include its script declaration.

<table>
<tr>
<td class="col-fourty" width="40%"><strong>Availability</strong></td>
<td>In Development</td>
</tr>
<tr>
<td class="col-fourty"><strong>Required Script</strong></td>
<td><code>&lt;script async custom-element="amp-ad" src="https://cdn.ampproject.org/v0/amp-ad-0.1.js">&lt;/script></code></td>
</tr>
</table>

## Example

```html
<amp-ad
width="300"
height="250"
type="smartads"
data-use-a4a="true"
data-buid="123"
src="https://smart-ads.biz/_a4a"
>
</amp-ad>
```

## Attributes

SmartAds impl uses the same attributes as `<amp-ad>` .

<table>
<tr>
<td width="40%"><strong>data-use-a4a</strong></td>
<td>If non-empty, SmartAds will attempt to render via the A4A
pathway (i.e., fast rendering for AMP creatives). Otherwise, it will attempt
to render via the delayed iframe path.</td>
</tr>
<tr>
<td width="40%"><strong>data-buid</strong></td>
<td>Unique block id</td>
</tr>
</table>