You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
9.0 KiB

2 years ago
  1. /*
  2. * YoutubeBackground - A wrapper for the Youtube API - Great for fullscreen background videos or just regular videos.
  3. *
  4. * Licensed under the MIT license:
  5. * http://www.opensource.org/licenses/mit-license.php
  6. *
  7. *
  8. * Version: 1.0.5
  9. *
  10. */
  11. // Chain of Responsibility pattern. Creates base class that can be overridden.
  12. if (typeof Object.create !== "function") {
  13. Object.create = function(obj) {
  14. function F() {}
  15. F.prototype = obj;
  16. return new F();
  17. };
  18. }
  19. (function($, window, document) {
  20. var
  21. loadAPI = function loadAPI(callback) {
  22. // Load Youtube API
  23. var tag = document.createElement('script'),
  24. head = document.getElementsByTagName('head')[0];
  25. if(window.location.origin == 'file://') {
  26. tag.src = 'http://www.youtube.com/iframe_api';
  27. } else {
  28. tag.src = '//www.youtube.com/iframe_api';
  29. }
  30. head.appendChild(tag);
  31. // Clean up Tags.
  32. head = null;
  33. tag = null;
  34. iframeIsReady(callback);
  35. },
  36. iframeIsReady = function iframeIsReady(callback) {
  37. // Listen for Gobal YT player callback
  38. if (typeof YT === 'undefined' && typeof window.loadingPlayer === 'undefined') {
  39. // Prevents Ready Event from being called twice
  40. window.loadingPlayer = true;
  41. // Creates deferred so, other players know when to wait.
  42. window.dfd = $.Deferred();
  43. window.onYouTubeIframeAPIReady = function() {
  44. window.onYouTubeIframeAPIReady = null;
  45. window.dfd.resolve( "done" );
  46. callback();
  47. };
  48. } else if (typeof YT === 'object') {
  49. callback();
  50. } else {
  51. window.dfd.done(function( name ) {
  52. callback();
  53. });
  54. }
  55. };
  56. // YTPlayer Object
  57. YTPlayer = {
  58. player: null,
  59. // Defaults
  60. defaults: {
  61. ratio: 16 / 9,
  62. videoId: 'LSmgKRx5pBo',
  63. mute: true,
  64. repeat: true,
  65. width: $(window).width(),
  66. playButtonClass: 'YTPlayer-play',
  67. pauseButtonClass: 'YTPlayer-pause',
  68. muteButtonClass: 'YTPlayer-mute',
  69. volumeUpClass: 'YTPlayer-volume-up',
  70. volumeDownClass: 'YTPlayer-volume-down',
  71. start: 0,
  72. pauseOnScroll: false,
  73. fitToBackground: true,
  74. playerVars: {
  75. iv_load_policy: 3,
  76. modestbranding: 1,
  77. autoplay: 1,
  78. controls: 0,
  79. showinfo: 0,
  80. wmode: 'opaque',
  81. branding: 0,
  82. autohide: 0
  83. },
  84. events: null
  85. },
  86. /**
  87. * @function init
  88. * Intializes YTPlayer object
  89. */
  90. init: function init(node, userOptions) {
  91. var self = this;
  92. self.userOptions = userOptions;
  93. self.$body = $('body'),
  94. self.$node = $(node),
  95. self.$window = $(window);
  96. // Setup event defaults with the reference to this
  97. self.defaults.events = {
  98. 'onReady': function(e) {
  99. self.onPlayerReady(e);
  100. // setup up pause on scroll
  101. if (self.options.pauseOnScroll) {
  102. self.pauseOnScroll();
  103. }
  104. // Callback for when finished
  105. if (typeof self.options.callback == 'function') {
  106. self.options.callback.call(this);
  107. }
  108. },
  109. 'onStateChange': function(e) {
  110. if (e.data === 1) {
  111. self.$node.find('img').fadeOut(400);
  112. self.$node.addClass('loaded');
  113. } else if (e.data === 0 && self.options.repeat) { // video ended and repeat option is set true
  114. self.player.seekTo(self.options.start);
  115. }
  116. }
  117. }
  118. self.options = $.extend(true, {}, self.defaults, self.userOptions);
  119. self.options.height = Math.ceil(self.options.width / self.options.ratio);
  120. self.ID = (new Date()).getTime();
  121. self.holderID = 'YTPlayer-ID-' + self.ID;
  122. if (self.options.fitToBackground) {
  123. self.createBackgroundVideo();
  124. } else {
  125. self.createContainerVideo();
  126. }
  127. // Listen for Resize Event
  128. self.$window.on('resize.YTplayer' + self.ID, function() {
  129. self.resize(self);
  130. });
  131. loadAPI(self.onYouTubeIframeAPIReady.bind(self));
  132. self.resize(self);
  133. return self;
  134. },
  135. /**
  136. * @function pauseOnScroll
  137. * Adds window events to pause video on scroll.
  138. */
  139. pauseOnScroll: function pauseOnScroll() {
  140. var self = this;
  141. self.$window.on('scroll.YTplayer' + self.ID, function() {
  142. var state = self.player.getPlayerState();
  143. if (state === 1) {
  144. self.player.pauseVideo();
  145. }
  146. });
  147. self.$window.scrollStopped(function(){
  148. var state = self.player.getPlayerState();
  149. if (state === 2) {
  150. self.player.playVideo();
  151. }
  152. });
  153. },
  154. /**
  155. * @function createContainerVideo
  156. * Adds HTML for video in a container
  157. */
  158. createContainerVideo: function createContainerVideo() {
  159. var self = this;
  160. /*jshint multistr: true */
  161. var $YTPlayerString = $('<div id="ytplayer-container' + self.ID + '" >\
  162. <div id="' + self.holderID + '" class="ytplayer-player-inline"></div> \
  163. </div> \
  164. <div id="ytplayer-shield" class="ytplayer-shield"></div>');
  165. self.$node.append($YTPlayerString);
  166. self.$YTPlayerString = $YTPlayerString;
  167. $YTPlayerString = null;
  168. },
  169. /**
  170. * @function createBackgroundVideo
  171. * Adds HTML for video background
  172. */
  173. createBackgroundVideo: function createBackgroundVideo() {
  174. /*jshint multistr: true */
  175. var self = this,
  176. $YTPlayerString = $('<div id="ytplayer-container' + self.ID + '" class="ytplayer-container background">\
  177. <div id="' + self.holderID + '" class="ytplayer-player"></div>\
  178. </div>\
  179. <div id="ytplayer-shield" class="ytplayer-shield"></div>');
  180. self.$node.append($YTPlayerString);
  181. self.$YTPlayerString = $YTPlayerString;
  182. $YTPlayerString = null;
  183. },
  184. /**
  185. * @function resize
  186. * Resize event to change video size
  187. */
  188. resize: function resize(self) {
  189. //var self = this;
  190. var container = $(window);
  191. if (!self.options.fitToBackground) {
  192. container = self.$node;
  193. }
  194. var width = container.width(),
  195. pWidth, // player width, to be defined
  196. height = container.height(),
  197. pHeight, // player height, tbd
  198. $YTPlayerPlayer = $('#' + self.holderID);
  199. // when screen aspect ratio differs from video, video must center and underlay one dimension
  200. if (width / self.options.ratio < height) {
  201. pWidth = Math.ceil(height * self.options.ratio); // get new player width
  202. $YTPlayerPlayer.width(pWidth).height(height).css({
  203. left: (width - pWidth) / 2,
  204. top: 0
  205. }); // player width is greater, offset left; reset top
  206. } else { // new video width < window width (gap to right)
  207. pHeight = Math.ceil(width / self.options.ratio); // get new player height
  208. $YTPlayerPlayer.width(width).height(pHeight).css({
  209. left: 0,
  210. top: (height - pHeight) / 2
  211. }); // player height is greater, offset top; reset left
  212. }
  213. $YTPlayerPlayer = null;
  214. container = null;
  215. },
  216. /**
  217. * @function onYouTubeIframeAPIReady
  218. * @ params {object} YTPlayer object for access to options
  219. * Youtube API calls this function when the player is ready.
  220. */
  221. onYouTubeIframeAPIReady: function onYouTubeIframeAPIReady() {
  222. var self = this;
  223. self.player = new window.YT.Player(self.holderID, self.options);
  224. },
  225. /**
  226. * @function onPlayerReady
  227. * @ params {event} window event from youtube player
  228. */
  229. onPlayerReady: function onPlayerReady(e) {
  230. if (this.options.mute) {
  231. e.target.mute();
  232. }
  233. e.target.playVideo();
  234. },
  235. /**
  236. * @function getPlayer
  237. * returns youtube player
  238. */
  239. getPlayer: function getPlayer() {
  240. return this.player;
  241. },
  242. /**
  243. * @function destroy
  244. * destroys all!
  245. */
  246. destroy: function destroy() {
  247. var self = this;
  248. self.$node
  249. .removeData('yt-init')
  250. .removeData('ytPlayer')
  251. .removeClass('loaded');
  252. self.$YTPlayerString.remove();
  253. $(window).off('resize.YTplayer' + self.ID);
  254. $(window).off('scroll.YTplayer' + self.ID);
  255. self.$body = null;
  256. self.$node = null;
  257. self.$YTPlayerString = null;
  258. self.player.destroy();
  259. self.player = null;
  260. }
  261. };
  262. // Scroll Stopped event.
  263. $.fn.scrollStopped = function(callback) {
  264. var $this = $(this), self = this;
  265. $this.scroll(function(){
  266. if ($this.data('scrollTimeout')) {
  267. clearTimeout($this.data('scrollTimeout'));
  268. }
  269. $this.data('scrollTimeout', setTimeout(callback,250,self));
  270. });
  271. };
  272. // Create plugin
  273. $.fn.YTPlayer = function(options) {
  274. return this.each(function() {
  275. var el = this;
  276. $(el).data("yt-init", true);
  277. var player = Object.create(YTPlayer);
  278. player.init(el, options);
  279. $.data(el, "ytPlayer", player);
  280. });
  281. };
  282. })(jQuery, window, document);