diff --git a/.gitignore b/.gitignore
index ceaca38..1b3f8f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
bower_components/*
+node_modules/
diff --git a/angular-video-bg.js b/angular-video-bg.js
index 3044741..9fd2511 100644
--- a/angular-video-bg.js
+++ b/angular-video-bg.js
@@ -1,523 +1,528 @@
-/**
- * @ngdoc overview
- * @name angularVideoBg
- * @description This module contains a directive that allows you easily make a YouTube video play as the background of
- * any container on your site.
- */
-
-angular.module('angularVideoBg', []);
-
-/**
- * @ngdoc directive
- * @name angularVideoBg.directive:videoBg
- * @description This directive makes it super simple to turn the background of any element on your site into a YouTube
- * video. All you need is the video id! You can place content within the directive and it will be transcluded over top
- * of the video background.
- * @element
- */
-angular.module('angularVideoBg').directive('videoBg', videoBg);
-
-// this obviates using ngAnnotate in the build task
-videoBg.$inject = ['$window', '$q', '$timeout'];
-
-function videoBg($window, $q, $timeout) {
- return {
- restrict: 'EA',
- replace: true,
- scope: {
- videoId: '=?',
- playlist: '=?',
- ratio: '=?',
- loop: '=?',
- mute: '=?',
- start: '=?',
- end: '=?',
- contentZIndex: '=?',
- allowClickEvents: '=?',
- mobileImage: '=?',
- playerCallback: '&?'
- },
- transclude: true,
- template: '
',
- link: function(scope, element) {
-
- var computedStyles,
- ytScript = document.querySelector('script[src="//www.youtube.com/iframe_api"]'),
- $player = element.children().eq(0),
- playerId,
- player,
- parentDimensions,
- playerDimensions,
- playerCallback = scope.playerCallback,
- backgroundImage = scope.mobileImage || '//img.youtube.com/vi/' + scope.videoId + '/maxresdefault.jpg',
- videoArr,
- videoTimeout;
-
- playerId = 'player' + Array.prototype.slice.call(document.querySelectorAll('div[video-id]')).indexOf(element[0]);
- $player.attr('id', playerId);
-
- scope.ratio = scope.ratio || 16/9;
- scope.loop = scope.loop === undefined ? true : scope.loop;
- scope.mute = scope.mute === undefined ? true : scope.mute;
-
- if (!scope.videoId && !scope.playlist) {
- throw new Error('Either video-id or playlist must be defined.');
- }
- if (scope.videoId && scope.playlist) {
- throw new Error('Both video-id and playlist cannot be defined, please choose one or the other.');
- }
- if (scope.playlist) {
- videoArr = scope.playlist.map(function(videoObj) {
- return videoObj.videoId;
- });
- }
+(function (){
+ 'use strict';
+
+ /**
+ * @ngdoc overview
+ * @name angularVideoBg
+ * @description This module contains a directive that allows you easily make a YouTube video play as the background of
+ * any container on your site.
+ */
+
+ angular.module('angularVideoBg', []);
+
+ /**
+ * @ngdoc directive
+ * @name angularVideoBg.directive:videoBg
+ * @description This directive makes it super simple to turn the background of any element on your site into a YouTube
+ * video. All you need is the video id! You can place content within the directive and it will be transcluded over top
+ * of the video background.
+ * @element
+ */
+ angular.module('angularVideoBg').directive('videoBg', videoBg);
+
+ // this obviates using ngAnnotate in the build task
+ videoBg.$inject = ['$window', '$q', '$timeout'];
+
+ function videoBg($window, $q, $timeout) {
+ return {
+ restrict: 'EA',
+ replace: true,
+ scope: {
+ videoId: '=?',
+ playlist: '=?',
+ ratio: '=?',
+ loop: '=?',
+ mute: '=?',
+ start: '=?',
+ end: '=?',
+ contentZIndex: '=?',
+ allowClickEvents: '=?',
+ mobileImage: '=?',
+ playerCallback: '&?'
+ },
+ transclude: true,
+ template: '',
+ link: function(scope, element) {
+
+ var computedStyles,
+ ytScript = document.querySelector('script[src="//www.youtube.com/iframe_api"]'),
+ $player = element.children().eq(0),
+ playerId,
+ player,
+ parentDimensions,
+ playerDimensions,
+ playerCallback = scope.playerCallback,
+ backgroundImage = scope.mobileImage || '//img.youtube.com/vi/' + scope.videoId + '/maxresdefault.jpg',
+ videoArr,
+ videoTimeout;
+
+ playerId = 'player' + Array.prototype.slice.call(document.querySelectorAll('div[video-id]')).indexOf(element[0]);
+ $player.attr('id', playerId);
+
+ scope.ratio = scope.ratio || 16/9;
+ scope.loop = scope.loop === undefined ? true : scope.loop;
+ scope.mute = scope.mute === undefined ? true : scope.mute;
+
+ if (!scope.videoId && !scope.playlist) {
+ throw new Error('Either video-id or playlist must be defined.');
+ }
+ if (scope.videoId && scope.playlist) {
+ throw new Error('Both video-id and playlist cannot be defined, please choose one or the other.');
+ }
+ if (scope.playlist) {
+ videoArr = scope.playlist.map(function(videoObj) {
+ return videoObj.videoId;
+ });
+ }
- // Utility methods
+ // Utility methods
- function debounce(func, wait) {
- var timeout;
- return function() {
- var context = this, args = arguments;
- var later = function() {
- timeout = null;
- func.apply(context, args);
+ function debounce(func, wait) {
+ var timeout;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ func.apply(context, args);
+ };
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
};
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- };
- }
-
- /**
- * detect IE
- * returns version of IE or false, if browser is not Internet Explorer
- */
- function detectIE() {
- var ua = window.navigator.userAgent,
- msie = ua.indexOf('MSIE '),
- trident = ua.indexOf('Trident/'),
- edge = ua.indexOf('Edge/');
-
- if (msie > 0) {
- // IE 10 or older => return version number
- return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
- if (trident > 0) {
- // IE 11 => return version number
- var rv = ua.indexOf('rv:');
- return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
- }
+ /**
+ * detect IE
+ * returns version of IE or false, if browser is not Internet Explorer
+ */
+ function detectIE() {
+ var ua = window.navigator.userAgent,
+ msie = ua.indexOf('MSIE '),
+ trident = ua.indexOf('Trident/'),
+ edge = ua.indexOf('Edge/');
+
+ if (msie > 0) {
+ // IE 10 or older => return version number
+ return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
+ }
- if (edge > 0) {
- // IE 12 => return version number
- return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
- }
+ if (trident > 0) {
+ // IE 11 => return version number
+ var rv = ua.indexOf('rv:');
+ return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
+ }
- // other browser
- return false;
- }
+ if (edge > 0) {
+ // IE 12 => return version number
+ return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
+ }
- /**
- * @ngdoc method
- * @name getPropertyAllSides
- * @methodOf angularVideoBg.directive:videoBg
- * @description This method takes a property such as margin and returns the computed styles for all four
- * sides of the parent container.
- * @param {string} property - the css property to get
- * @param {Function} func - the function to call on computedStyles
- * @returns {object} - object that contains all four property sides (top, right, bottom, top)
- * @example
- * getPropertyAllSides('margin', computedStyles.getPropertyValue);
- * // returns { margin-top: 10, margin-right: 10, margin-bottom: 10, margin-left: 10 }
- */
- function getPropertyAllSides(property, func) {
- var sides = ['top', 'right', 'bottom', 'left'],
- getProperty = function(obj, side) {
- obj[side] = parseInt(func.call(computedStyles, property + '-' + side), 10);
- return obj;
- };
- return sides.reduce(getProperty, {});
- }
+ // other browser
+ return false;
+ }
- /**
- * @ngdoc method
- * @name calculateParentDimensions
- * @methodOf angularVideoBg.directive:videoBg
- * @description This method takes the dimensions (width and height) of the parent, as well as the "spacers"
- * (simply all of the margin, padding and border values) and adds the margin, padding and border values to
- * the dimensions in order to get back the outer dimensions of the parent.
- * @param {object} dimensions - width and height of parent container
- * @param {object} spacers - margin, padding and border values of parent container
- * @returns {{width: number, height: number}}
- * @example
- *
- * var dimensions = {
- * width: 1000,
- * height: 400
- * };
- *
- * var spacers = {
- * margin: {
- * top: 10,
- * right: 10,
- * bottom: 10,
- * left: 10
- * },
- * padding: {
- * top: 0,
- * right: 10,
- * bottom: 0,
- * left: 10
- * },
- * border: {
- * top: 0,
- * right: 0,
- * bottom: 0,
- * left: 0
- * }
- * };
- *
- * calculateParentDimensions(dimensions, spacers);
- * // returns { width: 1040, height: 420 }
- *
- */
- function calculateParentDimensions(dimensions, spacers) {
- function calculateSpacerValues() {
- var args = Array.prototype.slice.call(arguments),
- spacer,
- sum = 0,
- sumValues = function(_sum, arg) {
- return spacer[arg] ? _sum + spacer[arg] : _sum;
+ /**
+ * @ngdoc method
+ * @name getPropertyAllSides
+ * @methodOf angularVideoBg.directive:videoBg
+ * @description This method takes a property such as margin and returns the computed styles for all four
+ * sides of the parent container.
+ * @param {string} property - the css property to get
+ * @param {Function} func - the function to call on computedStyles
+ * @returns {object} - object that contains all four property sides (top, right, bottom, top)
+ * @example
+ * getPropertyAllSides('margin', computedStyles.getPropertyValue);
+ * // returns { margin-top: 10, margin-right: 10, margin-bottom: 10, margin-left: 10 }
+ */
+ function getPropertyAllSides(property, func) {
+ var sides = ['top', 'right', 'bottom', 'left'],
+ getProperty = function(obj, side) {
+ obj[side] = parseInt(func.call(computedStyles, property + '-' + side), 10);
+ return obj;
};
- for (var key in spacers) {
- if (spacers.hasOwnProperty(key)) {
- spacer = spacers[key];
- sum += args.reduce(sumValues, 0);
+ return sides.reduce(getProperty, {});
+ }
+
+ /**
+ * @ngdoc method
+ * @name calculateParentDimensions
+ * @methodOf angularVideoBg.directive:videoBg
+ * @description This method takes the dimensions (width and height) of the parent, as well as the "spacers"
+ * (simply all of the margin, padding and border values) and adds the margin, padding and border values to
+ * the dimensions in order to get back the outer dimensions of the parent.
+ * @param {object} dimensions - width and height of parent container
+ * @param {object} spacers - margin, padding and border values of parent container
+ * @returns {{width: number, height: number}}
+ * @example
+ *
+ * var dimensions = {
+ * width: 1000,
+ * height: 400
+ * };
+ *
+ * var spacers = {
+ * margin: {
+ * top: 10,
+ * right: 10,
+ * bottom: 10,
+ * left: 10
+ * },
+ * padding: {
+ * top: 0,
+ * right: 10,
+ * bottom: 0,
+ * left: 10
+ * },
+ * border: {
+ * top: 0,
+ * right: 0,
+ * bottom: 0,
+ * left: 0
+ * }
+ * };
+ *
+ * calculateParentDimensions(dimensions, spacers);
+ * // returns { width: 1040, height: 420 }
+ *
+ */
+ function calculateParentDimensions(dimensions, spacers) {
+ function calculateSpacerValues() {
+ var args = Array.prototype.slice.call(arguments),
+ spacer,
+ sum = 0,
+ sumValues = function(_sum, arg) {
+ return spacer[arg] ? _sum + spacer[arg] : _sum;
+ };
+ for (var key in spacers) {
+ if (spacers.hasOwnProperty(key)) {
+ spacer = spacers[key];
+ sum += args.reduce(sumValues, 0);
+ }
}
+ return sum;
}
- return sum;
+ return {
+ width: dimensions.width + calculateSpacerValues('left', 'right'),
+ height: (detectIE() && detectIE() < 12) ? dimensions.height : dimensions.height + calculateSpacerValues('top', 'bottom')
+ };
}
- return {
- width: dimensions.width + calculateSpacerValues('left', 'right'),
- height: (detectIE() && detectIE() < 12) ? dimensions.height : dimensions.height + calculateSpacerValues('top', 'bottom')
- };
- }
- function styleContentElements() {
- var $content = element.children().eq(1),
- hasContent = !!$content.children().length,
- parentChildren = Array.prototype.slice.call(element.parent().children());
- element.parent().css({
- position: 'relative',
- overflow: 'hidden'
- });
- if (!hasContent) {
- element.css({
- position: 'absolute',
- left: '0',
- top: '0'
+ function styleContentElements() {
+ var $content = element.children().eq(1),
+ hasContent = !!$content.children().length,
+ parentChildren = Array.prototype.slice.call(element.parent().children());
+ element.parent().css({
+ position: 'relative',
+ overflow: 'hidden'
});
- var i = parentChildren.indexOf(element[0]);
- if (i > -1) {
- parentChildren.splice(i, 1);
+ if (!hasContent) {
+ element.css({
+ position: 'absolute',
+ left: '0',
+ top: '0'
+ });
+ var i = parentChildren.indexOf(element[0]);
+ if (i > -1) {
+ parentChildren.splice(i, 1);
+ }
+ $content = angular.element(parentChildren);
}
- $content = angular.element(parentChildren);
+ $content.css({
+ position: 'relative',
+ zIndex: scope.contentZIndex || 99
+ });
}
- $content.css({
- position: 'relative',
- zIndex: scope.contentZIndex || 99
- });
- }
- /**
- * @ngdoc method
- * @name getParentDimensions
- * @methodOf angularVideoBg.directive:videoBg
- * @description This method utilizes the getPropertyAllSides and calculateParentDimensions in order to get
- * the parent container dimensions and return them.
- * @returns {{width: number, height: number}}
- */
- function getParentDimensions() {
- computedStyles = $window.getComputedStyle(element.parent()[0]);
- var dimensionProperties = ['width', 'height'],
- spacerProperties = ['border', 'margin'];
- if (detectIE() && detectIE() < 12) {
- spacerProperties.push('padding');
+ /**
+ * @ngdoc method
+ * @name getParentDimensions
+ * @methodOf angularVideoBg.directive:videoBg
+ * @description This method utilizes the getPropertyAllSides and calculateParentDimensions in order to get
+ * the parent container dimensions and return them.
+ * @returns {{width: number, height: number}}
+ */
+ function getParentDimensions() {
+ computedStyles = $window.getComputedStyle(element.parent()[0]);
+ var dimensionProperties = ['width', 'height'],
+ spacerProperties = ['border', 'margin'];
+ if (detectIE() && detectIE() < 12) {
+ spacerProperties.push('padding');
+ }
+ dimensionProperties = dimensionProperties.reduce(function(obj, property) {
+ obj[property] = parseInt(computedStyles.getPropertyValue(property), 10);
+ return obj;
+ }, {});
+ spacerProperties = spacerProperties.reduce(function(obj, property) {
+ obj[property] = getPropertyAllSides(property, computedStyles.getPropertyValue);
+ return obj;
+ }, {});
+ return calculateParentDimensions(dimensionProperties, spacerProperties);
}
- dimensionProperties = dimensionProperties.reduce(function(obj, property) {
- obj[property] = parseInt(computedStyles.getPropertyValue(property), 10);
- return obj;
- }, {});
- spacerProperties = spacerProperties.reduce(function(obj, property) {
- obj[property] = getPropertyAllSides(property, computedStyles.getPropertyValue);
- return obj;
- }, {});
- return calculateParentDimensions(dimensionProperties, spacerProperties);
- }
-
- /**
- * @ngdoc method
- * @name getPlayerDimensions
- * @methodOf angularVideoBg.directive:videoBg
- * @description This method uses the aspect ratio of the video and the height/width of the parent container
- * in order to calculate the width and height of the video player.
- * @returns {{width: number, height: number}}
- */
- function getPlayerDimensions() {
- var aspectHeight = parseInt(parentDimensions.width / scope.ratio, 10),
- aspectWidth = parseInt(parentDimensions.height * scope.ratio, 10),
- useAspectHeight = parentDimensions.height < aspectHeight;
- return {
- width: useAspectHeight ? parentDimensions.width : aspectWidth,
- height: useAspectHeight ? aspectHeight : parentDimensions.height
- };
- }
- /**
- * This method simply executes getParentDimensions and getPlayerDimensions when necessary.
- */
- function updateDimensions() {
- styleContentElements();
- parentDimensions = getParentDimensions();
- playerDimensions = getPlayerDimensions();
- }
-
- /**
- * This method simply resizes and repositions the player based on the dimensions of the parent and video
- * player, it is called when necessary.
- */
- function resizeAndPositionPlayer() {
- var options = {
- zIndex: 1,
- position: 'absolute',
- width: playerDimensions.width + 'px',
- height: playerDimensions.height + 'px',
- left: parseInt((parentDimensions.width - playerDimensions.width)/2, 10) + 'px',
- top: parseInt((parentDimensions.height - playerDimensions.height)/2, 10) + 'px'
- };
- if (!scope.allowClickEvents) {
- options.pointerEvents = 'none';
+ /**
+ * @ngdoc method
+ * @name getPlayerDimensions
+ * @methodOf angularVideoBg.directive:videoBg
+ * @description This method uses the aspect ratio of the video and the height/width of the parent container
+ * in order to calculate the width and height of the video player.
+ * @returns {{width: number, height: number}}
+ */
+ function getPlayerDimensions() {
+ var aspectHeight = parseInt(parentDimensions.width / scope.ratio, 10),
+ aspectWidth = parseInt(parentDimensions.height * scope.ratio, 10),
+ useAspectHeight = parentDimensions.height < aspectHeight;
+ return {
+ width: useAspectHeight ? parentDimensions.width : aspectWidth,
+ height: useAspectHeight ? aspectHeight : parentDimensions.height
+ };
}
- $player.css(options);
- }
- /**
- * This method simply seeks the video to either the beginning or to the start position (if set).
- */
- function seekToStart(video) {
- video = video || scope;
- player.seekTo(video.start || 0);
- }
-
- /**
- * This method handles looping the video better than the native YT embed API player var "loop", especially
- * when start and end positions are set.
- */
- function loopVideo(video) {
- var duration, msDuration;
- video = video || scope;
- if (video.end) {
- duration = video.end - (video.start || 0);
- } else if (scope.start) {
- duration = player.getDuration() - video.start;
- } else {
- duration = player.getDuration();
+ /**
+ * This method simply executes getParentDimensions and getPlayerDimensions when necessary.
+ */
+ function updateDimensions() {
+ styleContentElements();
+ parentDimensions = getParentDimensions();
+ playerDimensions = getPlayerDimensions();
}
- msDuration = duration * 1000;
- console.log('duration', msDuration);
- videoTimeout = setTimeout(function() {
- if (scope.playlist) {
- player.nextVideo();
- } else {
- seekToStart(video);
- }
- }, msDuration);
- }
- /**
- * This method handles looping the video better than the native YT embed API player var "loop", especially
- * when start and end positions are set.
- */
- function playlistVideoChange() {
- var videoObj = scope.playlist[player.getPlaylistIndex()];
- loopVideo(videoObj);
- }
+ /**
+ * This method simply resizes and repositions the player based on the dimensions of the parent and video
+ * player, it is called when necessary.
+ */
+ function resizeAndPositionPlayer() {
+ var options = {
+ zIndex: 1,
+ position: 'absolute',
+ width: playerDimensions.width + 'px',
+ height: playerDimensions.height + 'px',
+ left: parseInt((parentDimensions.width - playerDimensions.width)/2, 10) + 'px',
+ top: parseInt((parentDimensions.height - playerDimensions.height)/2, 10) + 'px'
+ };
+ if (!scope.allowClickEvents) {
+ options.pointerEvents = 'none';
+ }
+ $player.css(options);
+ }
- /**
- * This is the method called when the "player" object is ready and can be interfaced with.
- */
- function playerReady() {
- if (playerCallback) {
- $timeout(function() {
- playerCallback({ player: player });
- });
+ /**
+ * This method simply seeks the video to either the beginning or to the start position (if set).
+ */
+ function seekToStart(video) {
+ video = video || scope;
+ player.seekTo(video.start || 0);
}
- if (scope.playlist) {
- player.loadPlaylist(videoArr);
- if (scope.loop) {
- player.setLoop(true);
+
+ /**
+ * This method handles looping the video better than the native YT embed API player var "loop", especially
+ * when start and end positions are set.
+ */
+ function loopVideo(video) {
+ var duration, msDuration;
+ video = video || scope;
+ if (video.end) {
+ duration = video.end - (video.start || 0);
+ } else if (scope.start) {
+ duration = player.getDuration() - video.start;
+ } else {
+ duration = player.getDuration();
}
+ msDuration = duration * 1000;
+ console.log('duration', msDuration);
+ videoTimeout = setTimeout(function() {
+ if (scope.playlist) {
+ player.nextVideo();
+ } else {
+ seekToStart(video);
+ }
+ }, msDuration);
}
- if (scope.mute && !player.isMuted()) {
- player.mute();
- } else if (player.isMuted()) {
- player.unMute();
+
+ /**
+ * This method handles looping the video better than the native YT embed API player var "loop", especially
+ * when start and end positions are set.
+ */
+ function playlistVideoChange() {
+ var videoObj = scope.playlist[player.getPlaylistIndex()];
+ loopVideo(videoObj);
}
- seekToStart();
- scope.$on('$destroy', function() {
- if (videoTimeout) {
- clearTimeout(videoTimeout);
- }
- angular.element($window).off('resize', windowResized);
- player.destroy();
- });
- }
- /**
- * This is the method called when the "player" object has changed state. It is used here to toggle the video's
- * display css to block only when the video starts playing, and kick off the video loop (if enabled).
- */
- function playerStateChange(evt) {
- if (evt.data === YT.PlayerState.PLAYING) {
- $player.css('display', 'block');
- if (!scope.playlist && scope.loop) {
- loopVideo();
+ /**
+ * This is the method called when the "player" object is ready and can be interfaced with.
+ */
+ function playerReady() {
+ if (playerCallback) {
+ $timeout(function() {
+ playerCallback({ player: player });
+ });
}
- if (scope.playlist && scope.loop) {
- playlistVideoChange();
+ if (scope.playlist) {
+ player.loadPlaylist(videoArr);
+ if (scope.loop) {
+ player.setLoop(true);
+ }
}
+ if (scope.mute && !player.isMuted()) {
+ player.mute();
+ } else if (player.isMuted()) {
+ player.unMute();
+ }
+ seekToStart();
+ scope.$on('$destroy', function() {
+ if (videoTimeout) {
+ clearTimeout(videoTimeout);
+ }
+ angular.element($window).off('resize', windowResized);
+ player.destroy();
+ });
}
- if (evt.data === YT.PlayerState.UNSTARTED && scope.playlist) {
- var videoObj = scope.playlist[player.getPlaylistIndex()],
- videoMute = videoObj.mute === undefined ? scope.mute : videoObj.mute;
- backgroundImage = videoObj.mobileImage || scope.mobileImage || '//img.youtube.com/vi/' + videoObj.videoId + '/maxresdefault.jpg';
- setBackgroundImage(backgroundImage);
- $player.css('display', 'none');
- seekToStart(videoObj);
- if (videoMute || (videoMute && scope.mute)) {
- console.log('mute');
- if (!player.isMuted()) {
- player.mute();
+
+ /**
+ * This is the method called when the "player" object has changed state. It is used here to toggle the video's
+ * display css to block only when the video starts playing, and kick off the video loop (if enabled).
+ */
+ function playerStateChange(evt) {
+ if (evt.data === YT.PlayerState.PLAYING) {
+ $player.css('display', 'block');
+ if (!scope.playlist && scope.loop) {
+ loopVideo();
}
- } else if (!videoMute || !scope.mute) {
- console.log('unmute');
- if (player.isMuted()) {
- player.unMute();
+ if (scope.playlist && scope.loop) {
+ playlistVideoChange();
}
}
- }
- }
-
- /**
- * This method initializes the video player and updates the dimensions and positions for the first time.
- */
- function initVideoPlayer() {
- updateDimensions();
- var playerOptions = {
- autoplay: 1,
- controls: 0,
- iv_load_policy: 3,
- cc_load_policy: 0,
- modestbranding: 1,
- playsinline: 1,
- rel: 0,
- showinfo: 0,
- playlist: scope.videoId
- };
- player = new YT.Player(playerId, {
- width: playerDimensions.width,
- height: playerDimensions.height,
- videoId: scope.videoId,
- playerVars: playerOptions,
- events: {
- onReady: playerReady,
- onStateChange: playerStateChange
+ if (evt.data === YT.PlayerState.UNSTARTED && scope.playlist) {
+ var videoObj = scope.playlist[player.getPlaylistIndex()],
+ videoMute = videoObj.mute === undefined ? scope.mute : videoObj.mute;
+ backgroundImage = videoObj.mobileImage || scope.mobileImage || '//img.youtube.com/vi/' + videoObj.videoId + '/maxresdefault.jpg';
+ setBackgroundImage(backgroundImage);
+ $player.css('display', 'none');
+ seekToStart(videoObj);
+ if (videoMute || (videoMute && scope.mute)) {
+ console.log('mute');
+ if (!player.isMuted()) {
+ player.mute();
+ }
+ } else if (!videoMute || !scope.mute) {
+ console.log('unmute');
+ if (player.isMuted()) {
+ player.unMute();
+ }
+ }
}
- });
- $player = element.children().eq(0);
- $player.css('display', 'none');
- resizeAndPositionPlayer();
- }
-
- function setBackgroundImage(img) {
- element.parent().css({
- backgroundImage: 'url(' + img + ')',
- backgroundSize: 'cover',
- backgroundPosition: 'center center'
- });
- }
-
- var windowResized = debounce(function() {
- updateDimensions();
- resizeAndPositionPlayer();
- }, 300);
-
- setBackgroundImage(backgroundImage);
-
- /**
- * if it's not mobile or tablet then initialize video
- */
- if( !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
+ }
/**
- * Check to see if YouTube IFrame script is ready, if it is, resolve ytd defer, if not, wait for
- * onYouTubeIframeAPIReady to be called by the script to resolve it.
+ * This method initializes the video player and updates the dimensions and positions for the first time.
*/
- if (!$window.youTubeIframeAPIReady) {
- var ytd = $q.defer();
- $window.youTubeIframeAPIReady = ytd.promise;
- $window.onYouTubeIframeAPIReady = function() {
- ytd.resolve();
+ function initVideoPlayer() {
+ updateDimensions();
+ var playerOptions = {
+ autoplay: 1,
+ controls: 0,
+ iv_load_policy: 3,
+ cc_load_policy: 0,
+ modestbranding: 1,
+ playsinline: 1,
+ rel: 0,
+ showinfo: 0,
+ playlist: scope.videoId
};
+ player = new YT.Player(playerId, {
+ width: playerDimensions.width,
+ height: playerDimensions.height,
+ videoId: scope.videoId,
+ playerVars: playerOptions,
+ events: {
+ onReady: playerReady,
+ onStateChange: playerStateChange
+ }
+ });
+ $player = element.children().eq(0);
+ $player.css('display', 'none');
+ resizeAndPositionPlayer();
}
- /**
- * If YouTube IFrame Script hasn't been loaded, load the library asynchronously
- */
- if (!ytScript) {
- var tag = document.createElement('script');
- tag.src = "//www.youtube.com/iframe_api";
- var firstScriptTag = document.getElementsByTagName('script')[0];
- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+ function setBackgroundImage(img) {
+ element.parent().css({
+ backgroundImage: 'url(' + img + ')',
+ backgroundSize: 'cover',
+ backgroundPosition: 'center center'
+ });
}
- /**
- * When the YouTube IFrame API script is loaded, we initialize the video player.
- */
- $window.youTubeIframeAPIReady.then(initVideoPlayer);
+ var windowResized = debounce(function() {
+ updateDimensions();
+ resizeAndPositionPlayer();
+ }, 300);
+
+ setBackgroundImage(backgroundImage);
/**
- * Anytime the window is resized, update the video player dimensions and position. (this is debounced for
- * performance reasons)
+ * if it's not mobile or tablet then initialize video
*/
- angular.element($window).on('resize', windowResized);
+ if( !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
+
+ /**
+ * Check to see if YouTube IFrame script is ready, if it is, resolve ytd defer, if not, wait for
+ * onYouTubeIframeAPIReady to be called by the script to resolve it.
+ */
+ if (!$window.youTubeIframeAPIReady) {
+ var ytd = $q.defer();
+ $window.youTubeIframeAPIReady = ytd.promise;
+ $window.onYouTubeIframeAPIReady = function() {
+ ytd.resolve();
+ };
+ }
- }
+ /**
+ * If YouTube IFrame Script hasn't been loaded, load the library asynchronously
+ */
+ if (!ytScript) {
+ var tag = document.createElement('script');
+ tag.src = "//www.youtube.com/iframe_api";
+ var firstScriptTag = document.getElementsByTagName('script')[0];
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+ }
+
+ /**
+ * When the YouTube IFrame API script is loaded, we initialize the video player.
+ */
+ $window.youTubeIframeAPIReady.then(initVideoPlayer);
+
+ /**
+ * Anytime the window is resized, update the video player dimensions and position. (this is debounced for
+ * performance reasons)
+ */
+ angular.element($window).on('resize', windowResized);
- scope.$watch('videoId', function(current, old) {
- if (current && old && current !== old) {
- clearTimeout(videoTimeout);
- backgroundImage = scope.mobileImage || '//img.youtube.com/vi/' + current + '/maxresdefault.jpg';
- setBackgroundImage(backgroundImage);
- $player.css('display', 'none');
- player.loadVideoById(current);
}
- });
- scope.$watchCollection('playlist', function(current, old) {
- if (current && old && current !== old) {
- clearTimeout(videoTimeout);
- videoArr = current.map(function(videoObj) {
- return videoObj.videoId;
- });
- player.loadPlaylist(videoArr);
- if (scope.loop) {
- player.setLoop(true);
+ scope.$watch('videoId', function(current, old) {
+ if (current && old && current !== old) {
+ clearTimeout(videoTimeout);
+ backgroundImage = scope.mobileImage || '//img.youtube.com/vi/' + current + '/maxresdefault.jpg';
+ setBackgroundImage(backgroundImage);
+ $player.css('display', 'none');
+ player.loadVideoById(current);
}
- }
- });
+ });
+
+ scope.$watchCollection('playlist', function(current, old) {
+ if (current && old && current !== old) {
+ clearTimeout(videoTimeout);
+ videoArr = current.map(function(videoObj) {
+ return videoObj.videoId;
+ });
+ player.loadPlaylist(videoArr);
+ if (scope.loop) {
+ player.setLoop(true);
+ }
+ }
+ });
+
+ }
+ };
+ }
- }
- };
-}
+})();
diff --git a/angular-video-bg.min.js b/angular-video-bg.min.js
index 559bf9c..dc13fe8 100644
--- a/angular-video-bg.min.js
+++ b/angular-video-bg.min.js
@@ -1 +1 @@
-function videoBg(a,b,c){return{restrict:"EA",replace:!0,scope:{videoId:"=?",playlist:"=?",ratio:"=?",loop:"=?",mute:"=?",start:"=?",end:"=?",contentZIndex:"=?",allowClickEvents:"=?",mobileImage:"=?",playerCallback:"&?"},transclude:!0,template:"",link:function(d,e){function f(a,b){var c;return function(){var d=this,e=arguments,f=function(){c=null,a.apply(d,e)};clearTimeout(c),c=setTimeout(f,b)}}function g(){var a=window.navigator.userAgent,b=a.indexOf("MSIE "),c=a.indexOf("Trident/"),d=a.indexOf("Edge/");if(b>0)return parseInt(a.substring(b+5,a.indexOf(".",b)),10);if(c>0){var e=a.indexOf("rv:");return parseInt(a.substring(e+3,a.indexOf(".",e)),10)}return d>0?parseInt(a.substring(d+5,a.indexOf(".",d)),10):!1}function h(a,b){var c=["top","right","bottom","left"],d=function(c,d){return c[d]=parseInt(b.call(v,a+"-"+d),10),c};return c.reduce(d,{})}function i(a,b){function c(){var a,c=Array.prototype.slice.call(arguments),d=0,e=function(b,c){return a[c]?b+a[c]:b};for(var f in b)b.hasOwnProperty(f)&&(a=b[f],d+=c.reduce(e,0));return d}return{width:a.width+c("left","right"),height:g()&&g()<12?a.height:a.height+c("top","bottom")}}function j(){var a=e.children().eq(1),b=!!a.children().length,c=Array.prototype.slice.call(e.parent().children());if(e.parent().css({position:"relative",overflow:"hidden"}),!b){e.css({position:"absolute",left:"0",top:"0"});var f=c.indexOf(e[0]);f>-1&&c.splice(f,1),a=angular.element(c)}a.css({position:"relative",zIndex:d.contentZIndex||99})}function k(){v=a.getComputedStyle(e.parent()[0]);var b=["width","height"],c=["border","margin"];return g()&&g()<12&&c.push("padding"),b=b.reduce(function(a,b){return a[b]=parseInt(v.getPropertyValue(b),10),a},{}),c=c.reduce(function(a,b){return a[b]=h(b,v.getPropertyValue),a},{}),i(b,c)}function l(){var a=parseInt(y.width/d.ratio,10),b=parseInt(y.height*d.ratio,10),c=y.height",link:function(d,e){function f(a,b){var c;return function(){var d=this,e=arguments,f=function(){c=null,a.apply(d,e)};clearTimeout(c),c=setTimeout(f,b)}}function g(){var a=window.navigator.userAgent,b=a.indexOf("MSIE "),c=a.indexOf("Trident/"),d=a.indexOf("Edge/");if(b>0)return parseInt(a.substring(b+5,a.indexOf(".",b)),10);if(c>0){var e=a.indexOf("rv:");return parseInt(a.substring(e+3,a.indexOf(".",e)),10)}return d>0?parseInt(a.substring(d+5,a.indexOf(".",d)),10):!1}function h(a,b){var c=["top","right","bottom","left"],d=function(c,d){return c[d]=parseInt(b.call(v,a+"-"+d),10),c};return c.reduce(d,{})}function i(a,b){function c(){var a,c=Array.prototype.slice.call(arguments),d=0,e=function(b,c){return a[c]?b+a[c]:b};for(var f in b)b.hasOwnProperty(f)&&(a=b[f],d+=c.reduce(e,0));return d}return{width:a.width+c("left","right"),height:g()&&g()<12?a.height:a.height+c("top","bottom")}}function j(){var a=e.children().eq(1),b=!!a.children().length,c=Array.prototype.slice.call(e.parent().children());if(e.parent().css({position:"relative",overflow:"hidden"}),!b){e.css({position:"absolute",left:"0",top:"0"});var f=c.indexOf(e[0]);f>-1&&c.splice(f,1),a=angular.element(c)}a.css({position:"relative",zIndex:d.contentZIndex||99})}function k(){v=a.getComputedStyle(e.parent()[0]);var b=["width","height"],c=["border","margin"];return g()&&g()<12&&c.push("padding"),b=b.reduce(function(a,b){return a[b]=parseInt(v.getPropertyValue(b),10),a},{}),c=c.reduce(function(a,b){return a[b]=h(b,v.getPropertyValue),a},{}),i(b,c)}function l(){var a=parseInt(y.width/d.ratio,10),b=parseInt(y.height*d.ratio,10),c=y.height