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

youtube component #20

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9a021df
component youtube
jeanrodriguez Feb 28, 2019
732019b
added new files for twitter component
jeanrodriguez Feb 28, 2019
b6b99f1
youtube component
jeanrodriguez Feb 28, 2019
03770ca
Create youtube.css
jeanrodriguez Feb 28, 2019
aa83fc3
added youtube video player js
jeanrodriguez Mar 1, 2019
a20a5bb
yotube component
jeanrodriguez Mar 2, 2019
69379a6
youtube component _layout and _component
jeanrodriguez Mar 3, 2019
c10b45e
fix css
jeanrodriguez Mar 4, 2019
858397e
added YOUTUBE_API_KEY env variable, remove unuse css
jeanrodriguez Mar 4, 2019
f42ee11
Revert "added YOUTUBE_API_KEY env variable, remove unuse css"
jeanrodriguez Mar 4, 2019
5358dc6
fix css and add env variable
jeanrodriguez Mar 4, 2019
21b8185
added YOUTUBE_API_KEY
jeanrodriguez Mar 4, 2019
b36e19a
Update schema.yaml
jeanrodriguez Mar 4, 2019
ab1db28
remove unnecesary description. update youtube css
jeanrodriguez Mar 4, 2019
8ddcc6f
Update client.js
jeanrodriguez Mar 4, 2019
9f192f9
remove unused functions
jeanrodriguez Mar 5, 2019
cf79110
Update visibility.js
jeanrodriguez Mar 5, 2019
5abe5ce
removed getViewportHeight
jeanrodriguez Mar 5, 2019
e468746
Update visibility.js
jeanrodriguez Mar 5, 2019
8dd8f1c
removed _assign visbility.js
jeanrodriguez Mar 5, 2019
52b9202
Update gtm.js
jeanrodriguez Mar 5, 2019
3ec66f5
remove unused code visibility and gtm js
jeanrodriguez Mar 5, 2019
d529ab6
remove unused files
jeanrodriguez Mar 5, 2019
b587e7d
Update youtube-video-player.js
jeanrodriguez Mar 5, 2019
86a4ac4
Update youtube.js
jeanrodriguez Mar 5, 2019
fc5c953
update byline removed join and map lodash
jeanrodriguez Mar 5, 2019
0269a5c
Update byline.js
jeanrodriguez Mar 5, 2019
01540b7
Merge branch 'master' of https://github.com/clay/clay-starter into co…
jeanrodriguez Mar 7, 2019
69208b0
youtube component for clay-starter
jeanrodriguez Feb 28, 2019
fa81bda
Merge branch 'code-component-youtube' of https://github.com/clay/clay…
jeanrodriguez Mar 7, 2019
44870bb
js docs
jeanrodriguez Mar 7, 2019
4b08edf
Update subheader.css
jeanrodriguez Mar 7, 2019
d496d06
Update client.js
jeanrodriguez Mar 8, 2019
2bb136f
destruct visible object
jeanrodriguez Mar 8, 2019
b1559d0
Update youtube.css
jeanrodriguez Mar 8, 2019
c659775
Update client-env.json
jeanrodriguez Mar 8, 2019
1dfefbc
Merge branch 'master' of https://github.com/clay/clay-starter into co…
jeanrodriguez Mar 12, 2019
632f53a
Update client.js
jeanrodriguez Mar 12, 2019
d82a6de
feedbacks
jeanrodriguez Mar 12, 2019
679f8bf
Update model.js
jeanrodriguez Mar 13, 2019
daf4866
Update visibility.js
jeanrodriguez Mar 13, 2019
29d5468
removed analytics and added js docs
jeanrodriguez Mar 13, 2019
b34d3f6
removed gtm.js
jeanrodriguez Mar 13, 2019
88538d8
remove nym reference
jeanrodriguez Mar 13, 2019
cea0b08
Merge branch 'master' of https://github.com/clay/clay-starter into co…
jeanrodriguez Mar 13, 2019
fb0dd95
Update schema.yaml
jeanrodriguez Mar 13, 2019
8fc5739
feedback
jeanrodriguez Mar 13, 2019
da8a9e5
Update template.hbs
jeanrodriguez Mar 13, 2019
dbac03e
Update template.hbs
jeanrodriguez Mar 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/.env
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ CLAY_SCHEDULING_ENABLED=true
GOOGLE_CONSUMER_KEY=646733424261-m084l8oaodaubngvpte7f2hufc62l0d6.apps.googleusercontent.com
GOOGLE_CONSUMER_SECRET=KyWza3ugQbwEvn4J1nVA3RiA
GOOGLE_PROFILE_URL=https://www.googleapis.com/oauth2/v3/userinfo
YOUTUBE_API_KEY=AIzaSyCtD1a3SWW3QFzyfkLi0NpwvHL9InosQi8

CLAY_SITE_NAME="Clay Demo"
CLAY_SITE_HOST="localhost"
Expand Down
12 changes: 6 additions & 6 deletions app/components/article/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function stripHeadlineTags(oldHeadline) {

/**
* sanitize headline
* @param {object} data
* @param {Object} data
*/
function sanitizeInputs(data) {
if (has(data.headline)) {
Expand All @@ -33,8 +33,8 @@ function sanitizeInputs(data) {
/**
* set the publish date from the locals (even if it's already set),
* and format it correctly
* @param {object} data
* @param {object} locals
* @param {Object} data
* @param {Object} locals
*/
function formatDate(data, locals) {
if (_get(locals, 'date')) {
Expand All @@ -51,8 +51,8 @@ function formatDate(data, locals) {

/**
* set the canonical url from the locals (even if it's already set)
* @param {object} data
* @param {object} locals
* @param {Object} data
* @param {Object} locals
*/
function setCanonicalUrl(data, locals) {
if (_get(locals, 'publishUrl')) {
Expand All @@ -62,7 +62,7 @@ function setCanonicalUrl(data, locals) {

/**
* Set the feed image to the lede url if it isn't already set
* @param {object} data
* @param {Object} data
*/
function generateFeedImage(data) {
if (data.ledeUrl) {
Expand Down
1 change: 1 addition & 0 deletions app/components/article/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ content:
- image
- code-sample
- list
- youtube

ledeUrl:
_label: Lede Image URL
Expand Down
3 changes: 3 additions & 0 deletions app/components/youtube-player-head/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_components:
youtube-player-head:
allowed: true
2 changes: 2 additions & 0 deletions app/components/youtube-player-head/schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
_description: |
Note: Required for `video-player` component. YouTube API scripts, add component to head for best YouTube player performance.
19 changes: 19 additions & 0 deletions app/components/youtube-player-head/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- data-uri="{{ default _ref _self }}" -->
{{#unless @root.locals.edit}}
{{! youtube flags for `video-player` component instances
player instances will first look for `youtubeApiReady` to be `true`
if `false`, player instances will listen for the event `youtube-event:youtube-api-ready` }}
<script>
var youtubeApiReady = false;
window.onYouTubeIframeAPIReady = function () {
{{! when the YouTube API script is ready, dispatch an `youtube-event:youtube-api-ready` event }}
var eventYTApiReady = new Event('youtube-event:youtube-api-ready');
document.dispatchEvent(eventYTApiReady);
{{! change this flag to 'true' when the YouTube api is ready }}
youtubeApiReady = true;
}
</script>

{{! add the YouTube API script to the head for fastest player creation }}
<script type="text/javascript" src="https://www.youtube.com/iframe_api"></script>
{{/unless}}
14 changes: 14 additions & 0 deletions app/components/youtube/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
_components:
youtube:
videoId: ''
videoType: 'editorial'
videoLocation: 'article'
playerCaption: ''
autoPlay: true
autoPlayNextVideo: true
videoPlaylist: ''
playerBorderTopCTA: 'Watch'
playerBorderTop: false
playerBorderBottom: false
previousTypeRelated: false
customPlay: false
75 changes: 75 additions & 0 deletions app/components/youtube/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use strict';

const youtubeVideoPlayer = require('../../services/universal/youtube-video-player'),
{ Visible, isElementNotHidden } = require('../../services/client/visibility');

module.exports = (el) => {
const autoplay = el.getAttribute('data-autoplay-video') === 'true',
videoConfig = {
videoContainerId: el.getAttribute('data-element-id').trim(),
videoId: el.getAttribute('data-video-id').trim(),
// player variables and settings
playerParams: {
loop: 1,
listType: 'playlist',
list: el.getAttribute('data-playlist').trim(),
autoplay: autoplay ? 1 : 0,
controls: 1,
enablejsapi: 1,
modestbranding: 1,
rel: 0,
showinfo: 0,
wmode: 'transparent'
},
customParams: {
autoPlayNextVideo: el.getAttribute('data-autoplay-next-video').trim(),
trackVideoType: el.getAttribute('data-track-video-type').trim(),
customPlayer: el.getAttribute('data-custom-play').trim(),
templateid: el.getAttribute('data-element-id').trim(),
muted: autoplay // always mute autplaying videos
}
},
visible = new Visible(el, { preloadThreshold: 800 });

if (videoConfig.customParams.trackVideoType === 'Sponsored') {
videoConfig.playerParams.list = '';
}

// when the video player element enters the viewport, load the video(s)
if (visible.preload && isElementNotHidden(el)) {
// if the YouTube api is ready the videos(s) can be loaded
if (window.youtubeApiReady === true) {
youtubeVideoPlayer.init(videoConfig);
} else {
// wait and listen for the YouTube api to be ready before loading the video(s)
document.addEventListener('youtube-event:youtube-api-ready', function () {
youtubeVideoPlayer.init(videoConfig);
});
}
} else {
visible.on('preload', function () {
youtubeVideoPlayer.init(videoConfig);
});
}

/**
* Player start event
* we don't need to send an event here, updating the video id for posterity
*/
document.addEventListener('player-start-' + videoConfig.videoContainerId, function (evt) {
const hasChanged = el.getAttribute('data-video-id') !== evt.player.videoId;

if (hasChanged) {
updateElementAttributes(el, evt.player);
}
});
};

/**
* Updates Element attributes
* @param {Object} el - DOM node element
* @param {Object} config - Attributes values from player
*/
function updateElementAttributes(el, config) {
el.setAttribute('data-video-id', config.videoId);
}
69 changes: 69 additions & 0 deletions app/components/youtube/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use strict';

const _get = require('lodash/get'),
{ getVideoDetails } = require('../../services/universal/youtube'),
defaultPlayerBorderTopCTA = 'Watch';

/**
* Override various settings by type of video
* @param {Object} data
*/
function updateSettingsByType(data) {
switch (data.videoType) {
case 'related':
// By default, display borders and CTA when `related` type is first selected, afterwards accept user's selection
data.playerBorderTopCTA = !data.previousTypeRelated && !data.playerBorderTopCTA ? defaultPlayerBorderTopCTA : data.playerBorderTopCTA;
data.playerBorderTop = !data.previousTypeRelated ? true : data.playerBorderTop;
data.playerBorderBottom = !data.previousTypeRelated ? true : data.playerBorderBottom;
data.previousTypeRelated = true;
break;
case 'sponsored':
data.autoPlay = false;
data.autoPlayNextVideo = false;
break;
default:
// Toggle borders off if user previously selected `related` type. `sponsored` and `editorial` types share defaults
data.playerBorderTop = data.previousTypeRelated ? false : data.playerBorderTop;
data.playerBorderBottom = data.previousTypeRelated ? false : data.playerBorderBottom;
data.previousTypeRelated = false;
}
}

function clearVideoId(data) {
data.videoId = (data.videoId || '').split('&')[0];

return data;
}

function setVideoDetails(data, videoDetails) {
if (!videoDetails.title) {
data.videoValid = false;

return data;
}

const maxResThumb = _get(videoDetails, 'thumbnails.maxres.url');

data.videoValid = true;
data.channelName = videoDetails.channelTitle;
data.videoTitle = videoDetails.title;
data.videoThumbnail = maxResThumb ? maxResThumb : _get(videoDetails, 'thumbnails.high.url'); // get the maxres if available, otherwise get the high res which we know will be there
data.videoDuration = videoDetails.duration;

return data;
}

module.exports.save = (uri, data) => {
clearVideoId(data);
updateSettingsByType(data);

if (data.videoId) {
return getVideoDetails(data.videoId)
.then(videoDetails => setVideoDetails(data, videoDetails));
}

data.videoValid = true; // technically not an invalid video because no videoId so we don't want to show an error message in edit mode

return data;
};

143 changes: 143 additions & 0 deletions app/components/youtube/schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
_description: |
Youtube video embed for Clay. For technical reasons, YouTube embeds don't display a preview in edit mode.
Preview the video by previewing the full page (from the Clay toolbar). Embeds can display a specific video ID.
videoId:
_label: YouTube Video ID
_publish: videoPlayerId
_has:
input: text

videoType:
_label: Type
_has:
input: radio
options:
-
name: Editorial (Original)
value: editorial
-
name: Editorial (External)
value: embedded
-
name: Related
value: related
-
name: Sponsored
value: sponsored
validate:
required: true
requiredMessage: Please select a video type

videoSize:
_label: Size
_has:
input: radio
options:
-
name: Column Width
value: column-width
-
name: Break-out
value: break-out
_reveal:
field: videoType
operator: ===
values:
- sponsored
- editorial

playerHeadline:
_label: Video Headline
_has:
input: text
_reveal:
field: videoType
value: related

playerCaption:
_label: Video Caption
_has: text

autoPlay:
_label: Autoplay with muted audio on Page Load
_has: checkbox

autoPlayNextVideo:
_label: Automatically start next video
_has: checkbox
_reveal:
field: videoType
operator: '!=='
value: sponsored

videoPlaylist:
_label: Youtube Playlist (defaults to current site)
_reveal:
field: autoPlayNextVideo
operator: truthy
_has:
input: text
validate:
required:
field: autoPlayNextVideo
operator: truthy
requiredMessage: Video Player should contain video playlist
help: Playlists are used for auto playing additional videos in the YouTube component after the assigned video is finished. Only required for videos that are selected to automatically start next video above

playerBorderTopCTA:
_label: Top Border Title
_has: text

playerBorderTop:
_label: Show Top Border
_has: checkbox

playerBorderBottom:
_label: Show Bottom Border
_has: checkbox

customPlay:
_subscribe: customPlay

_groups:
settings:
fields:
- autoPlay (Autoplay)
- autoPlayNextVideo (Autoplay)
- videoPlaylist (Autoplay)
- playerBorderTopCTA (Borders and Border Title)
- playerBorderTop (Borders and Border Title)
- playerBorderBottom (Borders and Border Title)
inline:
fields:
- videoId
- videoType
- videoSize
- playerHeadline
- playerCaption
_label: Youtube Video Player
_placeholder:
text: Youtube Video Player
height: 100px
ifEmpty: videoId

# set by bootstrap or first-run
videoLocation:
help: For analytics, to tell what kind of page the video is on

# non-user-editable fields, set by model.js
previousTypeRelated:
help: Toggle for displaying convenience-based changes to player borders based on previously selected video type. Set by model.js
videoValid:
help: Used to decide whether or not to display a video in the template
_placeholder:
text: Invalid video id ${videoId}. This video will not display.
permanent: true
channelName:
help: Name of the channel the video comes from. Used to decide whether or not to listen to GTM triggers for this video
videoTitle:
help: Title of the video
videoThumbnail:
help: maxres video thumbnail
videoDuration:
help: video duration in seconds
Loading