Skip to content

Commit

Permalink
✨Add support for contextual article matching (ampproject#20748)
Browse files Browse the repository at this point in the history
Implements additional attributes to support contextual article matching attributes for amp-jwplayer component
  • Loading branch information
boyntoni authored and bramanudom committed Mar 22, 2019
1 parent a06bc49 commit eba60e6
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 71 deletions.
14 changes: 13 additions & 1 deletion examples/jwplayer.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
<title>JWPlayer AMP Example</title>
<link rel="canonical" href="amps.html" >
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=Georgia|Open+Sans|Roboto' rel='stylesheet' type='text/css'>
<meta property="og:title" content="title_tag" />
<link href='https://fonts.googleapis.com/css?family=Georgia%7COpen+Sans%7CRoboto' rel='stylesheet' type='text/css'>
<script async custom-element="amp-jwplayer" src="https://cdn.ampproject.org/v0/amp-jwplayer-0.1.js"></script>
<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>
Expand All @@ -29,5 +30,16 @@ <h3>Non-responsive, with a playlist</h3>
width="480" height="270">
</amp-jwplayer>

<h3>Responsive contextual</h3>

<amp-jwplayer
data-player-id="uoIbMPm3"
data-media-id="BZ6tc0gy"
data-content-search="__CONTEXTUAL__"
data-content-contextual=true
data-content-recency="9D"
data-content-backfill=true
layout="responsive" width="480" height="270">
</amp-jwplayer>
</body>
</html>
69 changes: 58 additions & 11 deletions extensions/amp-jwplayer/0.1/amp-jwplayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
* limitations under the License.
*/

import {addParamsToUrl} from '../../../src/url';
import {dict} from '../../../src/utils/object';
import {isLayoutSizeDefined} from '../../../src/layout';
import {removeElement} from '../../../src/dom';
import {userAssert} from '../../../src/log';


class AmpJWPlayer extends AMP.BaseElement {

/** @param {!AmpElement} element */
Expand All @@ -30,6 +33,18 @@ class AmpJWPlayer extends AMP.BaseElement {
/** @private {string} */
this.playerid_ = '';

/** @private {string} */
this.contentSearch_ = '';

/** @private {boolean} */
this.contentContextual_ = false;

/** @private {string} */
this.contentRecency_ = '';

/** @private {boolean} */
this.contentBackfill_ = false;

/** @private {?HTMLIFrameElement} */
this.iframe_ = null;
}
Expand All @@ -52,26 +67,45 @@ class AmpJWPlayer extends AMP.BaseElement {

/** @override */
buildCallback() {
const {element} = this;
this.contentid_ = userAssert(
(this.element.getAttribute('data-playlist-id') ||
this.element.getAttribute('data-media-id')),
(element.getAttribute('data-playlist-id') ||
element.getAttribute('data-media-id')),
'Either the data-media-id or the data-playlist-id ' +
'attributes must be specified for <amp-jwplayer> %s',
this.element);
'attributes must be specified for <amp-jwplayer> %s',
element);

this.playerid_ = userAssert(
this.element.getAttribute('data-player-id'),
element.getAttribute('data-player-id'),
'The data-player-id attribute is required for <amp-jwplayer> %s',
this.element);
element);

this.contentSearch_ = element.getAttribute('data-content-search') ||
'';
this.contentContextual_ = element.getAttribute('data-content-contextual') ||
false;
this.contentRecency_ = element.getAttribute('data-content-recency') ||
'';
this.contentBackfill_ = element.getAttribute('data-content-backfill') ||
false;
}


/** @override */
layoutCallback() {
const iframe = this.element.ownerDocument.createElement('iframe');
const src = 'https://content.jwplatform.com/players/' +
encodeURIComponent(this.contentid_) + '-' +
encodeURIComponent(this.playerid_) + '.html';
const cid = encodeURIComponent(this.contentid_);
const pid = encodeURIComponent(this.playerid_);
const queryParams = dict({
'search': this.getContextualVal() || undefined,
'contextual': this.contentContextual_ || undefined,
'recency': this.contentRecency_ || undefined,
'backfill': this.contentBackfill_ || undefined,
});

const baseUrl = `https://content.jwplatform.com/players/${cid}-${pid}.html`;
const src = addParamsToUrl(baseUrl, queryParams);

iframe.setAttribute('frameborder', '0');
iframe.setAttribute('allowfullscreen', 'true');
iframe.src = src;
Expand Down Expand Up @@ -108,7 +142,7 @@ class AmpJWPlayer extends AMP.BaseElement {
const placeholder = this.win.document.createElement('amp-img');
this.propagateAttributes(['aria-label'], placeholder);
placeholder.setAttribute('src', 'https://content.jwplatform.com/thumbs/' +
encodeURIComponent(this.contentid_) + '-720.jpg');
encodeURIComponent(this.contentid_) + '-720.jpg');
placeholder.setAttribute('layout', 'fill');
placeholder.setAttribute('placeholder', '');
placeholder.setAttribute('referrerpolicy', 'origin');
Expand All @@ -121,9 +155,22 @@ class AmpJWPlayer extends AMP.BaseElement {
}
return placeholder;
}
/**
*
*/
getContextualVal() {
if (this.contentSearch_ === '__CONTEXTUAL__') {
const context = this.getAmpDoc().getHeadNode();
const ogTitleElement = context.querySelector('meta[property="og:title"]');
const ogTitle = ogTitleElement ?
ogTitleElement.getAttribute('content') : null;
const title = (context.querySelector('title') || {}).textContent;
return ogTitle || title || '';
}
return this.contentSearch_ ;
}
}


AMP.extension('amp-jwplayer', '0.1', AMP => {
AMP.registerElement('amp-jwplayer', AmpJWPlayer);
});
138 changes: 96 additions & 42 deletions extensions/amp-jwplayer/0.1/test/test-amp-jwplayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import '../amp-jwplayer';

import {htmlFor} from '../../../../src/static-template';

describes.realWin('amp-jwplayer', {
amp: {
Expand All @@ -37,35 +37,92 @@ describes.realWin('amp-jwplayer', {
jw.setAttribute('width', '320');
jw.setAttribute('height', '180');
jw.setAttribute('layout', 'responsive');
const html = htmlFor(env.win.document);
env.sandbox.stub(env.ampdoc.getHeadNode(), 'querySelector')
.withArgs('meta[property="og:title"]')
.returns(
html`<meta property="og:title" content="title_tag" />`
);
doc.body.appendChild(jw);
return jw.build().then(() => { jw.layoutCallback(); return jw; });
}

it('renders', () => {
return getjwplayer({
it('renders', async() => {
const jw = await getjwplayer({
'data-media-id': 'Wferorsv',
'data-player-id': 'sDZEo0ea',
}).then(jw => {
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/Wferorsv-sDZEo0ea.html');
expect(iframe.className).to.match(/i-amphtml-fill-content/);
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/Wferorsv-sDZEo0ea.html');
expect(iframe.className).to.match(/i-amphtml-fill-content/);
});

it('renders with a playlist', () => {
return getjwplayer({
it('renders with a playlist', async() => {
const jw = await getjwplayer({
'data-playlist-id': '482jsTAr',
'data-player-id': 'sDZEo0ea',
}).then(jw => {
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html');
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html');
});
it('renders with a playlist and parses contextual parameter', async() => {
const jw = await getjwplayer({
'data-playlist-id': '482jsTAr',
'data-player-id': 'sDZEo0ea',
'data-content-search': '__CONTEXTUAL__',
'data-content-contextual': true,
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html?search=title_tag&contextual=true');
});
it('renders with a playlist and all parameters', async() => {
const jw = await getjwplayer({
'data-playlist-id': '482jsTAr',
'data-player-id': 'sDZEo0ea',
'data-content-search': 'dog',
'data-content-contextual': true,
'data-content-recency': '9D',
'data-content-backfill': true,
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html?search=dog&contextual=true&recency=9D&backfill=true');
});
it('renders with a playlist and contextual, backfill parameters', async() => {
const jw = await getjwplayer({
'data-playlist-id': '482jsTAr',
'data-player-id': 'sDZEo0ea',
'data-content-contextual': true,
'data-content-backfill': true,
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html?contextual=true&backfill=true');
});
it('renders with a playlist and contextual parameter', async() => {
const jw = await getjwplayer({
'data-playlist-id': '482jsTAr',
'data-player-id': 'sDZEo0ea',
'data-content-contextual': true,
});
const iframe = jw.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html?contextual=true');
});

it('fails if no media is specified', () => {
Expand Down Expand Up @@ -98,42 +155,39 @@ describes.realWin('amp-jwplayer', {
});

describe('createPlaceholderCallback', () => {
it('should create a placeholder image', () => {
return getjwplayer({
it('should create a placeholder image', async() => {
const jw = await getjwplayer({
'data-media-id': 'Wferorsv',
'data-player-id': 'sDZEo0ea',
}).then(jwp => {
const img = jwp.querySelector('amp-img');
expect(img).to.not.be.null;
expect(img.getAttribute('src')).to.equal(
'https://content.jwplatform.com/thumbs/Wferorsv-720.jpg');
expect(img.getAttribute('layout')).to.equal('fill');
expect(img.hasAttribute('placeholder')).to.be.true;
expect(img.getAttribute('referrerpolicy')).to.equal('origin');
expect(img.getAttribute('alt')).to.equal('Loading video');
});
const img = jw.querySelector('amp-img');
expect(img).to.not.be.null;
expect(img.getAttribute('src')).to.equal(
'https://content.jwplatform.com/thumbs/Wferorsv-720.jpg');
expect(img.getAttribute('layout')).to.equal('fill');
expect(img.hasAttribute('placeholder')).to.be.true;
expect(img.getAttribute('referrerpolicy')).to.equal('origin');
expect(img.getAttribute('alt')).to.equal('Loading video');
});
it('should propagate aria-label to placeholder', () => {
return getjwplayer({
it('should propagate aria-label to placeholder', async() => {
const jw = await getjwplayer({
'data-media-id': 'Wferorsv',
'data-player-id': 'sDZEo0ea',
'aria-label': 'interesting video',
}).then(jwp => {
const img = jwp.querySelector('amp-img');
expect(img).to.not.be.null;
expect(img.getAttribute('aria-label')).to.equal('interesting video');
expect(img.getAttribute('alt'))
.to.equal('Loading video - interesting video');
});
const img = jw.querySelector('amp-img');
expect(img).to.not.be.null;
expect(img.getAttribute('aria-label')).to.equal('interesting video');
expect(img.getAttribute('alt'))
.to.equal('Loading video - interesting video');
});
it('should not create a placeholder for playlists', () => {
return getjwplayer({
it('should not create a placeholder for playlists', async() => {
const jw = await getjwplayer({
'data-playlist-id': 'Wferorsv',
'data-player-id': 'sDZEo0ea',
}).then(jwp => {
const img = jwp.querySelector('amp-img');
expect(img).to.be.null;
});
const img = jw.querySelector('amp-img');
expect(img).to.be.null;
});
});
});
28 changes: 21 additions & 7 deletions extensions/amp-jwplayer/0.1/test/validator-amp-jwplayer.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,44 @@
<meta charset="utf-8">
<link rel="canonical" href="./regular-html-version.html">
<meta name="viewport" content="width=device-width,minimum-scale=1">
<meta property="og:title" content="title_tag" />
<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-jwplayer" src="https://cdn.ampproject.org/v0/amp-jwplayer-0.1.js"></script>
</head>
<body>
<!-- Example of a valid amp-jwplayer. -->
<amp-jwplayer
data-player-id="aBcD1234"
data-media-id="5678WxYz"
data-player-id="BjcwyK37"
data-media-id="BZ6tc0gy"
layout="responsive"
width="160" height="90">
</amp-jwplayer>
<!-- Alternate valid example using a playlist rather than video. -->
<amp-jwplayer
data-player-id="aBcD1234"
data-playlist-id="5678WxYz"
data-player-id="BjcwyK37"
data-playlist-id="482jsTAr"
width="160" height="90">
</amp-jwplayer>
<!-- Invalid example missing a player id. -->
<amp-jwplayer
data-playerlist-id="5678WxYz"
data-playerlist-id="482jsTAr"
width="160" height="90">
</amp-jwplayer>
<!-- Invalid example missing playlist id or media-id. -->
<amp-jwplayer
data-player-id="aBcD1234"
data-player-id="BjcwyK37"
width="160" height="90">
</amp-jwplayer>
<!-- Example of a valid amp-jwplayer with contextual article matching. -->
<amp-jwplayer
data-player-id="BjcwyK37"
data-media-id="BZ6tc0gy"
data-content-search="__CONTEXTUAL__"
data-content-contextual=true
data-content-recency="9D"
data-content-backfill=true
layout="responsive" width="160" height="90">
</amp-jwplayer>
</body>
</html>
</html>
Loading

0 comments on commit eba60e6

Please sign in to comment.