ng-youtube-embed
Version:
AngularJS module to embed Youtube videos with support for Youtube player parameters and JavaScript API for iframe embeds. Superlight (less than 5KB) and easy to use! Supports Youtube video URLs and IDs. No 3rd party JS dependencies.
290 lines (244 loc) • 13.8 kB
JavaScript
/*
ng-youtube-embed v1.7.17
Copyright (c) 2015 Arun Michael Dsouza (amdsouza92@gmail.com)
Licence: MIT
Demo on CodePen - http://codepen.io/amdsouza92/pen/yNxyJV
*/
(function () {
'use strict';
// ng-youtube-embed main module
var ngYoutubeEmbed = angular.module('ngYoutubeEmbed', []);
// Module globals
var VIDEO_IDS = [],
YOUTUBE_IFRAME_EMBED_API = 'https://www.youtube.com/iframe_api',
YOUTUBE_VIDEO_ID_REGEX = /^(?:https?:\/\/)?(?:www\.|m\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/,
YOUTUBE_VIDEO_ID_REGEX_GAMING = /^(?:https?:\/\/)?(?:www\.)?(?:gaming.youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
// Function to load youtube iframe embed api
function loadYoutubeIframeEmbedApi() {
var iframeEmbedScript = document.createElement('script'),
firstScript = document.getElementsByTagName('script')[0];
iframeEmbedScript.src = YOUTUBE_IFRAME_EMBED_API;
firstScript.parentNode.insertBefore(iframeEmbedScript, firstScript);
}
// Function to check whether youtube iframe embed api has been loaded or not
function youtubeIframeEmbedApiLoaded() {
var url = YOUTUBE_IFRAME_EMBED_API,
scripts = document.getElementsByTagName('script');
for (var i = scripts.length; i--;) {
if (scripts[i].src == url) return true;
}
return false;
}
// Function to generate iframe embed player template
function generateEmbedIframeTemplate(options, scope, videoId) {
var youtubeVideoId = videoId ? videoId : '';
// Modified to set the default origin
if (!options.origin) {
var protocol = location.protocol;
var slashes = protocol.concat("//");
var host = slashes.concat(window.location.hostname);
options.origin = host;
}
//Modified to sanitize the URL parameters
var urlParams = 'enablejsapi=' + options.enablejsapi + '&autoplay=' + options.autoplay + '&cc_load_policy=' + options.ccloadpolicy + '&color=' + options.color + '&controls=' + options.controls + '&disablekb=' + options.disablekb + '&end=' + options.end + '&fs=' + options.fs + '&hl=' + options.hl + '&iv_load_policy=' + options.ivloadpolicy + '&playlist=' + scope.playlistArray + '&playsinline=' + options.playsinline + '&rel=' + options.rel + '&showinfo=' + options.showinfo + '&start=' + options.start + '&modestbranding=' + options.modestbranding + '&loop=' + options.loop + '&listType=' + options.listType + '&list=' + options.list + '&origin=' + options.origin;
urlParams = urlParams.replace(/([a-zA-Z_]+=&)/g, '').replace(/&$/, '').replace(/([a-zA-Z_]+=$)/g, '');
// Modified to forcefully add the event listners after tab switching/using ng-if directive
var onLoadEvent = '';
if (window.onNgYtIframeLoad) {
onLoadEvent = 'onLoad="onNgYtIframeLoad()"';
}
var iFrame = '<iframe id="' + options.videoid + '" width="' + options.width + '" height="' + options.height + '" src="https://www.youtube.com/embed/' + youtubeVideoId + '?' + urlParams + '" frameborder="0" allowfullscreen ' + onLoadEvent + '></iframe>';
if (!window.onNgYtIframeLoad) {
// Modified event was getting triggered automaticaly for the first time, by using this function we are externaly triggering the event
window.onNgYtIframeLoad = function () {
window.onYouTubeIframeAPIReady();
}
}
return iFrame;
}
// Function to render iframe embed player template
function renderIframeEmbedPlayer(options, scope, $sce, youtubeVideoId) {
// Creating iframe template for video playback
var iframe = generateEmbedIframeTemplate(options, scope, youtubeVideoId);
// Sanitizing and rendering iframe
scope.youtubeEmbedFrame = $sce.trustAsHtml(iframe);
};
// ng-youtube-embed events + utils service
ngYoutubeEmbed.service('ngYoutubeEmbedService', ['$window', '$rootScope', function ($window, $rootScope) {
// Function to set ready state when youtube iframe embed api has been loaded
this.setReadyState = function () {
$window.onYouTubeIframeAPIReady = function () {
VIDEO_IDS.forEach(function (id) {
// Emit youtube iframe embed api load event
$rootScope.$emit('youtubeIframeEmbedApiLoaded', id);
});
};
};
var videoPlayers = [];
// New video player addition event listener
$rootScope.$on('addNewPlayer', function (event, args) {
videoPlayers[args.id] = args.player;
});
// Function to return iframe player instance based on video id
this.getPlayerById = function (id) {
return videoPlayers[id];
};
// Function to get youtube video id by url
this.getVideoIdByUrl = function (url) {
// Reset youtube video id regex when gaming.youtube url is found and vice versa
var ytVideoRegex = (url.indexOf('gaming') !== -1) ? YOUTUBE_VIDEO_ID_REGEX_GAMING : YOUTUBE_VIDEO_ID_REGEX,
id = url.match(ytVideoRegex);
return id !== null ? id[1] : url;
};
}]);
// ng-youtube-embed directive
ngYoutubeEmbed.directive('ngYoutubeEmbed', ['$sce', 'ngYoutubeEmbedService', '$rootScope', function ($sce, ngYoutubeEmbedService, $rootScope) {
return {
restrict: 'E',
template: '<div ng-bind-html="youtubeEmbedFrame"></div>',
scope: {
video: '=',
onready: '=',
onstatechange: '=',
onplaybackqualitychange: '=',
onplaybackratechange: '=',
onerror: '=',
onapichange: '=',
autoplay: '@',
ccloadpolicy: '@',
color: '@',
controls: '@',
disablekb: '@',
end: '@end',
fs: '@',
hl: '@',
ivloadpolicy: '@',
playlist: '@',
playsinline: '@',
rel: '@',
showinfo: '@',
start: '@',
width: '@',
height: '@',
enablejsapi: '@',
videoid: '@',
modestbranding: '@',
loop: '@',
listtype: '@',
list: '@',
origin: '@'
},
link: function (scope, elem, attr) {
// Remove id attribute from directive wrapper element
elem[0].removeAttribute('id');
// Generate iframe options object
var options = {
width: scope.width ? scope.width : 500,
height: scope.height ? scope.height : 350,
autoplay: scope.autoplay == 'true' ? 1 : 0,
ccloadpolicy: scope.ccloadpolicy == 'true' ? 1 : 0,
color: scope.color == 'white' ? 'white' : 'red',
controls: scope.controls == 'false' ? 0 : 1,
disablekb: scope.disablekb == 'false' ? 1 : 0,
end: scope.end ? scope.end : '',
fs: scope.fs == 'false' ? 0 : 1,
hl: scope.hl ? scope.hl : '',
ivloadpolicy: scope.ivloadpolicy == 'false' ? 3 : 1,
playlist: scope.playlist ? scope.playlist : '',
playsinline: scope.playsinline == 'true' ? 1 : 0,
rel: scope.rel == 'false' ? 0 : 1,
showinfo: scope.showinfo == 'false' ? 0 : 1,
start: scope.start ? scope.start : '',
enablejsapi: scope.enablejsapi === 'true' ? 1 : 0,
videoid: scope.videoid ? scope.videoid : '',
modestbranding: scope.modestbranding === 'true' ? 1 : 0,
loop: scope.loop === 'true' ? 1 : '',
listType: scope.listtype ? scope.listtype : '',
list: scope.list ? scope.list : '',
origin: scope.origin ? scope.origin : ''
};
// All available youtube iframe embed player parameters - https://developers.google.com/youtube/player_parameters
// Load youtube iframe embed api only if the option is present and it has not been loaded already
if (options.enablejsapi && !youtubeIframeEmbedApiLoaded()) {
loadYoutubeIframeEmbedApi();
ngYoutubeEmbedService.setReadyState();
}
// Listen to youtubeIframeEmbedApiLoaded event and use youtube iframe embed api to create video player
if (options.enablejsapi) {
$rootScope.$on('youtubeIframeEmbedApiLoaded', function (event, videoId) {
if (videoId === options.videoid) {
// Create youtube iframe embed video player instance and attach relevant events
// Modified to remove the errors in console if events are undefined
var events = {};
if (scope.onready) {
events['onReady'] = scope.onready;
}
if (scope.onstatechange) {
events['onStateChange'] = scope.onstatechange;
}
if (scope.onplaybackqualitychange) {
events['onPlaybackQualityChange'] = scope.onplaybackqualitychange;
}
if (scope.onplaybackratechange) {
events['onPlaybackRateChange'] = scope.onplaybackratechange;
}
if (scope.onerror) {
events['onError'] = scope.onerror;
}
if (scope.onapichange) {
events['onApiChange'] = scope.onapichange;
}
var player = new YT.Player(videoId, {
events: events
// All available youtube iframe embed player events - https://developers.google.com/youtube/iframe_api_reference#Events
});
// Emit addNewPlayer event once video player has been craeted
$rootScope.$emit('addNewPlayer', {
player: player,
id: videoId
});
}
});
}
// Detecting playlist option and retrieving video ids
scope.playlistArray = [];
if (options.playlist) {
var playlistArray = scope.playlist.split(',');
for (var i = 0; i < playlistArray.length; i++) {
scope.playlistArray.push(ngYoutubeEmbedService.getVideoIdByUrl(playlistArray[i])); // Scope variable to store playlist ids
}
}
// Detecting enablejsapi option and adding video ids to global list
options.videoid && options.enablejsapi ? VIDEO_IDS.push(options.videoid) : null;
// Check for list parameter and log warning if listype is not present
if (options.list) {
if (!options.listType) {
console.warn('The list parameter works in conjunction with the listtype parameter, please provide a valid value for the listtype parameter in order to render a list. Read documentation here - https://github.com/ArunMichaelDsouza/ng-youtube-embed#list-string');
} else {
renderIframeEmbedPlayer(options, scope, $sce);
}
}
// Check for listtype parameter and log warning if list is not present
if (options.listType) {
if (!options.list) {
console.warn('The listtype parameter works in conjunction with the list parameter, please provide a valid value for the list parameter in order to render a list. Read documentation here - https://github.com/ArunMichaelDsouza/ng-youtube-embed#listtype-string');
} else {
renderIframeEmbedPlayer(options, scope, $sce);
}
}
// If neither listtype/list and video parameters are present, then log embed player warning
if ((!options.listType && !options.list) && !scope.video) {
console.warn('Please provide a valid youtube video URL or ID to render the iframe embed player. Read documentation here - https://github.com/ArunMichaelDsouza/ng-youtube-embed');
}
// Update iframe when video parameter changes
scope.$watch('video', function (newVal) {
if (newVal) {
// Saving id for youtube video link
var youtubeVideoId = ngYoutubeEmbedService.getVideoIdByUrl(newVal);
renderIframeEmbedPlayer(options, scope, $sce, youtubeVideoId);
}
});
}
};
}]);
})();