pyc-website

main website for pyc inc.

git clone https://9o.is/git/pyc-website.git

videogular.js

(25248B)


      1 /**
      2  * @license Videogular v0.4.0 http://videogular.com
      3  * Two Fucking Developers http://twofuckingdevelopers.com
      4  * License: MIT
      5  */
      6 "use strict";
      7 angular.module("com.2fdevs.videogular", [])
      8 	.constant("VG_STATES", {
      9 		PLAY: "play",
     10 		PAUSE: "pause",
     11 		STOP: "stop"
     12 	})
     13 	.constant("VG_EVENTS", {
     14 		ON_PLAY: "onVgPlay",
     15 		ON_PAUSE: "onVgPause",
     16 		ON_PLAY_PAUSE: "onVgPlayPause",
     17 		ON_START_PLAYING: "onVgStartPlaying",
     18 		ON_COMPLETE: "onVgComplete",
     19 		ON_SET_STATE: "onVgSetState",
     20 		ON_SET_VOLUME: "onVgSetVolume",
     21 		ON_TOGGLE_FULLSCREEN: "onVgToggleFullscreen",
     22 		ON_ENTER_FULLSCREEN: "onVgEnterFullscreen",
     23 		ON_EXIT_FULLSCREEN: "onVgExitFullscreen",
     24 		ON_BUFFERING: "onVgBuffering",
     25 		ON_UPDATE_TIME: "onVgUpdateTime",
     26 		ON_SEEK_TIME: "onVgSeekTime",
     27 		ON_UPDATE_SIZE: "onVgUpdateSize",
     28 		ON_UPDATE_THEME: "onVgUpdateTheme",
     29 		ON_PLAYER_READY: "onVgPlayerReady",
     30 		ON_LOAD_POSTER: "onVgLoadPoster",
     31 		ON_ERROR: "onVgError"
     32 	})
     33 	.service("VG_UTILS", function() {
     34 		this.fixEventOffset = function($event) {
     35 			/**
     36 			 * There's no offsetX in Firefox, so we fix that.
     37 			 * Solution provided by Jack Moore in this post:
     38 			 * http://www.jacklmoore.com/notes/mouse-position/
     39 			 * @param $event
     40 			 * @returns {*}
     41 			 */
     42 			if (navigator.userAgent.match(/Firefox/i)) {
     43 				var style = $event.currentTarget.currentStyle || window.getComputedStyle($event.target, null);
     44 				var borderLeftWidth = parseInt(style['borderLeftWidth'], 10);
     45 				var borderTopWidth = parseInt(style['borderTopWidth'], 10);
     46 				var rect = $event.currentTarget.getBoundingClientRect();
     47 				var offsetX = $event.clientX - borderLeftWidth - rect.left;
     48 				var offsetY = $event.clientY - borderTopWidth - rect.top;
     49 
     50 				$event.offsetX = offsetX;
     51 				$event.offsetY = offsetY;
     52 			}
     53 
     54 			return $event;
     55 		};
     56 		/**
     57 		 * Inspired by Paul Irish
     58 		 * https://gist.github.com/paulirish/211209
     59 		 * @returns {number}
     60 		 */
     61 		this.getZIndex = function() {
     62 			var zIndex = 1;
     63 
     64 			angular.element('*')
     65 				.filter(function(){ return angular.element(this).css('zIndex') !== 'auto'; })
     66 				.each(function(){
     67 					var thisZIndex = parseInt(angular.element(this).css('zIndex'));
     68 					if (zIndex < thisZIndex) zIndex = thisZIndex + 1;
     69 				});
     70 
     71 			return zIndex;
     72 		};
     73 
     74 		// Very simple mobile detection, not 100% reliable
     75 		this.isMobileDevice = function() {
     76 			return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf("IEMobile") !== -1);
     77 		};
     78 
     79 		this.isiOSDevice = function() {
     80 			return (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i));
     81 		};
     82 	})
     83 	.run(["$window", "VG_UTILS",
     84 		function($window, VG_UTILS) {
     85 			// Native fullscreen polyfill
     86 			var fullScreenAPI;
     87 			var APIs = {
     88 				w3: {
     89 					enabled: "fullscreenEnabled",
     90 					element: "fullscreenElement",
     91 					request: "requestFullscreen",
     92 					exit:    "exitFullscreen",
     93 					onchange: "fullscreenchange",
     94 					onerror:  "fullscreenerror"
     95 				},
     96 				newWebkit: {
     97 					enabled: "webkitFullscreenEnabled",
     98 					element: "webkitFullscreenElement",
     99 					request: "webkitRequestFullscreen",
    100 					exit:    "webkitExitFullscreen",
    101 					onchange: "webkitfullscreenchange",
    102 					onerror:  "webkitfullscreenerror"
    103 				},
    104 				oldWebkit: {
    105 					enabled: "webkitIsFullScreen",
    106 					element: "webkitCurrentFullScreenElement",
    107 					request: "webkitRequestFullScreen",
    108 					exit:    "webkitCancelFullScreen",
    109 					onchange: "webkitfullscreenchange",
    110 					onerror:  "webkitfullscreenerror"
    111 				},
    112 				moz: {
    113 					enabled: "mozFullScreen",
    114 					element: "mozFullScreenElement",
    115 					request: "mozRequestFullScreen",
    116 					exit:    "mozCancelFullScreen",
    117 					onchange: "mozfullscreenchange",
    118 					onerror:  "mozfullscreenerror"
    119 				},
    120 				ios: {
    121 					enabled: "webkitFullscreenEnabled",
    122 					element: "webkitFullscreenElement",
    123 					request: "webkitEnterFullscreen",
    124 					exit: undefined,
    125 					onexit: "webkitendfullscreen",
    126 					onchange: "webkitfullscreenchange",
    127 					onerror:  "webkitfullscreenerror"
    128 				},
    129 				ms: {
    130 					enabled: "msFullscreenEnabled",
    131 					element: "msFullscreenElement",
    132 					request: "msRequestFullscreen",
    133 					exit:    "msExitFullscreen",
    134 					onchange: "msfullscreenchange",
    135 					onerror:  "msfullscreenerror"
    136 				}
    137 			};
    138 
    139 			for (var browser in APIs) {
    140 				if (APIs[browser].enabled in document) {
    141 					fullScreenAPI = APIs[browser];
    142 					fullScreenAPI.isFullScreen = function () {
    143 						return (document[this.element] != null);
    144 					};
    145 
    146 					break;
    147 				}
    148 			}
    149 
    150 			// Override APIs on iOS
    151 			if (VG_UTILS.isiOSDevice()) {
    152 				fullScreenAPI = APIs.ios;
    153 				fullScreenAPI.isFullScreen = function () {
    154 					return (document[this.element] != null);
    155 				};
    156 			}
    157 
    158 			angular.element($window)[0].fullScreenAPI = fullScreenAPI;
    159 		}
    160 	])
    161 	/**
    162 	 * @ngdoc directive
    163 	 * @name com.2fdevs.videogular.videogular:videogular
    164 	 * @restrict E
    165 	 * @description
    166 	 * Main directive that must wrap a &lt;video&gt; tag and all plugins.
    167 	 *
    168 	 * &lt;video&gt; tag usually will be above plugin tags, that's because plugins should be in a layer over the &lt;video&gt;.
    169 	 *
    170 	 * You can customize `videogular` with these attributes:
    171 	 *
    172 	 * @param {number or string} vgWidth This directive sets width for the entire player. Passing a number will set the width normally. Passing a string will create a binding with a scope variable in case it exists.
    173 	 *
    174 	 * If `vgWidth` or `vgHeight` are not declared, or `vgResponsive` is `"true"`, player will enter in a responsive mode and width will be 100% and height will be calculated through video metadata to preserve aspect ratio.
    175 	 *
    176 	 * @param {number or string} vgHeight This directive sets height for the entire player. Passing a number will set the height normally. Passing a string will create a binding with a scope variable in case it exists.
    177 	 *
    178 	 * If `vgWidth` or `vgHeight` are not declared, or `vgResponsive` is `"true"`, player will enter in a responsive mode and width will be 100% and height will be calculated through video metadata to preserve aspect ratio.
    179 	 *
    180 	 * @param {string} vgTheme String with a scope name variable. This directive will inject a CSS link in the header of your page.
    181 	 * **This parameter is required.**
    182 	 *
    183 	 * @param {boolean or string} [autoPlay=false] vgAutoplay Boolean value or a String with a scope name variable to auto start playing video when it is initialized.
    184 	 *
    185 	 * **This parameter is disabled in mobile devices** because user must click on content to prevent consuming mobile data plans.
    186 	 *
    187 	 * @param {string} [stretch=none] vgStretch String value representing a stretch mode. This value controls how image will scale inside its container. Stretch modes available are "none", "fit" or "fill".
    188 	 *
    189 	 * - **"none"**: Will set the image in its original size.
    190 	 * - **"fit"**: Will try to show always all the image leaving black bars above and below.
    191 	 * - **"fill"**: Will try to cover all video player area to never show black bars above and below.
    192 	 *
    193 	 * Content will always appear centered.
    194 	 *
    195 	 * @param {boolean or string} [isResponsive=false] vgResponsive Boolean value or a String with a scope name variable to auto start playing video when it is initialized.
    196 	 *
    197 	 * @param {function} vgComplete Function name in controller's scope to call when video have been completed.
    198 	 * @param {function} vgUpdateVolume Function name in controller's scope to call when volume changes. Receives a param with the new volume.
    199 	 * @param {function} vgUpdateTime Function name in controller's scope to call when video playback time is updated. Receives two params with current time and duration in milliseconds.
    200 	 * @param {function} vgUpdateSize Function name in controller's scope to call when videogular size is updated. Receives two param with the new width and height.
    201 	 * @param {function} vgUpdateState Function name in controller's scope to call when video state changes. Receives a param with the new state. Possible values are "play", "stop" or "pause".
    202 	 * @param {function} vgPlayerReady Function name in controller's scope to call when video have been initialized. Receives a param with the videogular API.
    203 	 * @param {function} vgChangeSource Function name in controller's scope to change current video source. Receives a param with the new video.
    204 	 * This is a free parameter and it could be values like "new.mp4", "320" or "sd". This will allow you to use this to change a video or video quality.
    205 	 * This callback will not change the video, you should do that by updating your sources scope variable.
    206 	 *
    207 	 */
    208 	.directive(
    209 		"videogular",
    210 		["$window", "VG_STATES", "VG_EVENTS", "VG_UTILS", function($window, VG_STATES, VG_EVENTS, VG_UTILS) {
    211 			return {
    212 				restrict: "E",
    213 				scope: {
    214 					playerWidth: "=vgWidth",
    215 					playerHeight: "=vgHeight",
    216 					theme: "=vgTheme",
    217 					autoPlay: "=vgAutoplay",
    218 					responsive: "=vgResponsive",
    219 					stretch: "=vgStretch",
    220 					vgComplete: "&",
    221 					vgUpdateVolume: "&",
    222 					vgUpdateTime: "&",
    223 					vgUpdateSize: "&",
    224 					vgUpdateState: "&",
    225 					vgPlayerReady: "&",
    226 					vgChangeSource: "&"
    227 				},
    228 				controller: ['$scope','$timeout', function($scope,$timeout) {
    229 					var currentTheme = null;
    230 					var currentWidth = null;
    231 					var currentHeight = null;
    232 
    233 					var currentStretch = $scope.stretch;
    234 					var playerWidth = 0;
    235 					var playerHeight = 0;
    236 					var isFullScreenPressed = false;
    237 					var isFullScreen = false;
    238 					var isMetaDataLoaded = false;
    239 					var isElementReady = false;
    240 					var isVideoReady = false;
    241 					var isPlayerReady = false;
    242 					var isResponsive = false;
    243 					var vg = this;
    244 
    245 					var vgCompleteCallBack = $scope.vgComplete();
    246 					var vgUpdateVolumeCallBack = $scope.vgUpdateVolume();
    247 					var vgUpdateTimeCallBack = $scope.vgUpdateTime();
    248 					var vgUpdateSizeCallBack = $scope.vgUpdateSize();
    249 					var vgUpdateStateCallBack = $scope.vgUpdateState();
    250 					var vgPlayerReadyCallBack = $scope.vgPlayerReady();
    251 					var vgChangeSourceCallBack = $scope.vgChangeSource();
    252 
    253 					$scope.currentState = VG_STATES.STOP;
    254 
    255 					// PUBLIC $API
    256 					this.$on = function() {
    257 						$scope.$on.apply($scope, arguments);
    258 					};
    259 
    260 					this.isPlayerReady = function() {
    261 						return isPlayerReady;
    262 					};
    263 
    264 					this.seekTime = function(value, byPercent) {
    265                         var second;
    266                         if (byPercent) {
    267                             second = value * this.videoElement[0].duration / 100;
    268                             this.videoElement[0].currentTime = second;
    269                         }
    270                         else {
    271                             second = value;
    272                             this.videoElement[0].currentTime = second;
    273                         }
    274 
    275                         $scope.$emit(VG_EVENTS.ON_SEEK_TIME, [second]);
    276 					};
    277 
    278 					this.playPause = function() {
    279 						if (this.videoElement[0].paused) {
    280 							this.play();
    281 						}
    282 						else {
    283 							this.pause();
    284 						}
    285 					};
    286 
    287 					this.setState = function(newState) {
    288 						if (newState && newState != $scope.currentState) {
    289 							if ($scope.vgUpdateState()) {
    290 								vgUpdateStateCallBack = $scope.vgUpdateState();
    291 								vgUpdateStateCallBack(newState);
    292 							}
    293 
    294 							$scope.currentState = newState;
    295 							$scope.$emit(VG_EVENTS.ON_SET_STATE, [$scope.currentState]);
    296 						}
    297 
    298 						return $scope.currentState;
    299 					};
    300 
    301 					this.play = function() {
    302 						this.videoElement[0].play();
    303 						this.setState(VG_STATES.PLAY);
    304 						$scope.$emit(VG_EVENTS.ON_PLAY);
    305 					};
    306 
    307 					this.pause = function() {
    308 						this.videoElement[0].pause();
    309 						this.setState(VG_STATES.PAUSE);
    310 						$scope.$emit(VG_EVENTS.ON_PAUSE);
    311 					};
    312 
    313 					this.stop = function() {
    314 						this.videoElement[0].pause();
    315 						this.videoElement[0].currentTime = 0;
    316 						this.setState(VG_STATES.STOP);
    317 						$scope.$emit(VG_EVENTS.ON_COMPLETE);
    318 					};
    319 
    320 					this.toggleFullScreen = function() {
    321 						// There is no native full screen support
    322 						if (!angular.element($window)[0].fullScreenAPI) {
    323 							if (isFullScreen) {
    324 								this.videogularElement.removeClass("fullscreen");
    325 								this.videogularElement.css("z-index", 0);
    326 							}
    327 							else {
    328 								this.videogularElement.addClass("fullscreen");
    329 								this.videogularElement.css("z-index", VG_UTILS.getZIndex());
    330 							}
    331 
    332 							isFullScreen = !isFullScreen;
    333 
    334 							$scope.updateSize();
    335 						}
    336 						// Perform native full screen support
    337 						else {
    338 							if (angular.element($window)[0].fullScreenAPI.isFullScreen()) {
    339 								if (!VG_UTILS.isMobileDevice()) {
    340 									document[angular.element($window)[0].fullScreenAPI.exit]();
    341 								}
    342 							}
    343 							else {
    344 								// On mobile devices we should make fullscreen only the video object
    345 								if (VG_UTILS.isMobileDevice()) {
    346 									// On iOS we should check if user pressed before fullscreen button
    347 									// and also if metadata is loaded
    348 									if (VG_UTILS.isiOSDevice()) {
    349 										if (isMetaDataLoaded) {
    350 											this.enterElementInFullScreen(this.videoElement[0]);
    351 										}
    352 										else {
    353 											isFullScreenPressed = true;
    354 											this.play();
    355 										}
    356 									}
    357 									else {
    358 										this.enterElementInFullScreen(this.videoElement[0]);
    359 									}
    360 								}
    361 								else {
    362 									this.enterElementInFullScreen(this.elementScope[0]);
    363 								}
    364 							}
    365 						}
    366 					};
    367 
    368 					this.enterElementInFullScreen = function(element) {
    369 						element[angular.element($window)[0].fullScreenAPI.request]();
    370 					};
    371 
    372 					this.changeSource = function(newValue) {
    373 						if ($scope.vgChangeSource()) {
    374 							vgChangeSourceCallBack = $scope.vgChangeSource();
    375 							vgChangeSourceCallBack(newValue);
    376 						}
    377 					};
    378 
    379 					this.setVolume = function(newVolume) {
    380 						if ($scope.vgUpdateVolume()) {
    381 							vgUpdateVolumeCallBack = $scope.vgUpdateVolume();
    382 							vgUpdateVolumeCallBack(newVolume);
    383 						}
    384 
    385 						this.videoElement[0].volume = newVolume;
    386 						$scope.$emit(VG_EVENTS.ON_SET_VOLUME, [newVolume]);
    387 					};
    388 
    389 					this.updateTheme = function(value) {
    390 						if (currentTheme) {
    391 							// Remove previous theme
    392 							var links = document.getElementsByTagName("link");
    393 							for (var i=0, l=links.length; i<l; i++) {
    394 								if (links[i].outerHTML.indexOf(currentTheme) >= 0) {
    395 									links[i].parentNode.removeChild(links[i]);
    396 								}
    397 							}
    398 						}
    399 
    400 						if (value) {
    401 							var headElem = angular.element(document).find("head");
    402 							headElem.append("<link rel='stylesheet' href='" + value + "'>");
    403 
    404 							currentTheme = value;
    405 						}
    406 					};
    407 
    408 					this.updateStretch = function(value) {
    409 						currentStretch = value;
    410 						$scope.updateSize();
    411 					};
    412 
    413 					this.setSize = function(newWidth, newHeight) {
    414 						currentWidth = newWidth;
    415 						currentHeight = newHeight;
    416 
    417 						$scope.updateSize();
    418 					};
    419 
    420 					this.getSize = function() {
    421 						return {width: currentWidth, height: currentHeight};
    422 					};
    423 
    424 					// PRIVATE FUNCTIONS
    425 					$scope.API = this;
    426 
    427 					$scope.init = function() {
    428 						vg.updateTheme($scope.theme);
    429 						$scope.addBindings();
    430 
    431 						if ($scope.playerWidth == undefined || $scope.playerHeight == undefined || $scope.responsive == true) {
    432 							isResponsive = true;
    433 							angular.element($window).bind("resize", $scope.onResizeBrowser);
    434 						}
    435 						else {
    436 							playerWidth = $scope.playerWidth;
    437 							playerHeight = $scope.playerHeight;
    438 
    439 							vg.setSize(playerWidth, playerHeight);
    440 						}
    441 
    442 						if (angular.element($window)[0].fullScreenAPI) {
    443 							document.addEventListener(angular.element($window)[0].fullScreenAPI.onchange, $scope.onFullScreenChange);
    444 						}
    445 					};
    446 
    447 					$scope.addBindings = function() {
    448 						$scope.$watch("playerWidth", function(newValue, oldValue) {
    449 							if (newValue != oldValue){
    450 								vg.setSize(newValue, currentHeight);
    451 							}
    452 						});
    453 
    454 						$scope.$watch("playerHeight", function(newValue, oldValue) {
    455 							if (newValue != oldValue){
    456 								vg.setSize(currentWidth, newValue);
    457 							}
    458 						});
    459 
    460 						$scope.$watch("theme", function(newValue, oldValue) {
    461 							if (newValue != oldValue){
    462 								vg.updateTheme(newValue);
    463 							}
    464 						});
    465 
    466 						$scope.$watch("stretch", function(newValue, oldValue) {
    467 							if (newValue != oldValue){
    468 								vg.updateStretch(newValue);
    469 							}
    470 						});
    471 
    472 						$scope.$watch("autoPlay", function(newValue, oldValue) {
    473 							if (newValue != oldValue){
    474 								vg.play();
    475 							}
    476 						});
    477 
    478 						$scope.$watch("responsive", function(newValue, oldValue) {
    479 							if (newValue != oldValue){
    480 								isResponsive = newValue;
    481 
    482 								if (isResponsive) {
    483 									angular.element($window).bind("resize", $scope.onResizeBrowser);
    484 									$scope.onResizeBrowser();
    485 								}
    486 								else {
    487 									angular.element($window).unbind("resize", $scope.onResizeBrowser);
    488 									currentWidth = $scope.playerWidth;
    489 									currentHeight = $scope.playerHeight;
    490 									$scope.updateSize();
    491 								}
    492 							}
    493 						});
    494 					};
    495 
    496 					$scope.onElementReady = function() {
    497 						isElementReady = true;
    498 
    499 						if (isVideoReady) {
    500 							$scope.onPlayerReady();
    501 						}
    502 					};
    503 
    504 					$scope.onVideoReady = function() {
    505 						isVideoReady = true;
    506 
    507 						if (isElementReady){
    508 							$scope.onPlayerReady();
    509 						}
    510 					};
    511 
    512 					$scope.onPlayerReady = function() {
    513 						vg.videoElement[0].addEventListener("loadedmetadata", $scope.onLoadedMetaData);
    514 
    515 						$scope.doPlayerReady();
    516 					};
    517 
    518 					$scope.onLoadedMetaData = function() {
    519 						isMetaDataLoaded = true;
    520 						$scope.doPlayerReady();
    521 					};
    522 
    523 					$scope.doPlayerReady = function() {
    524 						if (isResponsive) {
    525 							var percentWidth = vg.elementScope[0].parentNode.clientWidth * 100 / vg.videoElement[0].videoWidth;
    526 							var videoHeight = vg.videoElement[0].videoHeight * percentWidth / 100;
    527 							currentWidth = vg.elementScope[0].parentNode.clientWidth;
    528 							currentHeight = videoHeight;
    529 						}
    530 
    531 						isPlayerReady = true;
    532 						$scope.updateSize();
    533 						if ($scope.vgPlayerReady()) {
    534 							vgPlayerReadyCallBack = $scope.vgPlayerReady();
    535 							vgPlayerReadyCallBack(vg);
    536 						}
    537 						$scope.$emit(VG_EVENTS.ON_PLAYER_READY);
    538 
    539 						if ($scope.autoPlay && !VG_UTILS.isMobileDevice() || $scope.currentState === VG_STATES.PLAY){
    540 							$timeout(function() {
    541 								vg.play();
    542 							})
    543 						}
    544 					};
    545 
    546 					$scope.updateSize = function() {
    547 						if (isPlayerReady) {
    548 							var videoSize;
    549 							var videoTop;
    550 							var videoLeft;
    551 
    552 							if (angular.element($window)[0].fullScreenAPI && angular.element($window)[0].fullScreenAPI.isFullScreen() || isFullScreen) {
    553 								vg.elementScope.css("width", parseInt(window.screen.width, 10) + "px");
    554 								vg.elementScope.css("height", parseInt(window.screen.height, 10) + "px");
    555 
    556 								videoSize = $scope.getVideoSize(window.screen.width, window.screen.height);
    557 
    558 								if (isFullScreen) {
    559 									playerWidth = $window.innerWidth;
    560 									playerHeight = $window.innerHeight;
    561 								}
    562 								else {
    563 									playerWidth = $window.screen.width;
    564 									playerHeight = $window.screen.height;
    565 								}
    566 							}
    567 							else {
    568 								vg.elementScope.css("width", parseInt(currentWidth, 10) + "px");
    569 								vg.elementScope.css("height", parseInt(currentHeight, 10) + "px");
    570 
    571 								videoSize = $scope.getVideoSize(currentWidth, currentHeight);
    572 
    573 								playerWidth = currentWidth;
    574 								playerHeight = currentHeight;
    575 							}
    576 
    577 							if (currentHeight == 0 || isNaN(currentHeight)) {
    578 								playerWidth = videoSize.width;
    579 								playerHeight = videoSize.height;
    580 							}
    581 
    582 							if (videoSize.width == 0 || isNaN(videoSize.width)) videoSize.width = currentWidth;
    583 							if (videoSize.height == 0 || isNaN(videoSize.height)) videoSize.height = currentHeight;
    584 
    585 							videoLeft = (playerWidth - videoSize.width) / 2;
    586 							videoTop = (playerHeight - videoSize.height) / 2;
    587 
    588 							vg.videoElement.attr("width", parseInt(videoSize.width, 10));
    589 							vg.videoElement.attr("height", parseInt(videoSize.height, 10));
    590 							vg.videoElement.css("width", parseInt(videoSize.width, 10) + "px");
    591 							vg.videoElement.css("height", parseInt(videoSize.height, 10) + "px");
    592 							vg.videoElement.css("top", videoTop + "px");
    593 							vg.videoElement.css("left", videoLeft + "px");
    594 
    595 							vg.elementScope.css("width", parseInt(playerWidth, 10) + "px");
    596 							vg.elementScope.css("height", parseInt(playerHeight, 10) + "px");
    597 
    598 							if ($scope.vgUpdateSize()) {
    599 								vgUpdateSizeCallBack = $scope.vgUpdateSize();
    600 								vgUpdateSizeCallBack(playerWidth, playerHeight);
    601 							}
    602 
    603 							$scope.$emit(VG_EVENTS.ON_UPDATE_SIZE, [playerWidth, playerHeight]);
    604 						}
    605 					};
    606 
    607 					$scope.onResizeBrowser = function() {
    608 						var percentWidth = vg.elementScope[0].parentNode.clientWidth * 100 / vg.videoElement[0].videoWidth;
    609 						var videoHeight = vg.videoElement[0].videoHeight * percentWidth / 100;
    610 
    611 						currentWidth = vg.elementScope[0].parentNode.clientWidth;
    612 						currentHeight = videoHeight;
    613 
    614 						$scope.updateSize();
    615 					};
    616 
    617 					$scope.onFullScreenChange = function(event) {
    618 						if (angular.element($window)[0].fullScreenAPI.isFullScreen()) {
    619 							$scope.$emit(VG_EVENTS.ON_ENTER_FULLSCREEN);
    620 						}
    621 						else {
    622 							$scope.$emit(VG_EVENTS.ON_EXIT_FULLSCREEN);
    623 						}
    624 
    625 						$scope.updateSize();
    626 					};
    627 
    628 					$scope.onComplete = function(event) {
    629 						if ($scope.vgComplete()) {
    630 							vgCompleteCallBack = $scope.vgComplete();
    631 							vgCompleteCallBack();
    632 						}
    633 
    634 						vg.setState(VG_STATES.STOP);
    635 						$scope.$emit(VG_EVENTS.ON_COMPLETE);
    636 					};
    637 
    638 					$scope.onStartBuffering = function(event) {
    639 						$scope.$emit(VG_EVENTS.ON_BUFFERING);
    640 					};
    641 
    642 					$scope.onStartPlaying = function(event) {
    643 						// Chrome fix: Chrome needs to update the video tag size or it will show a white screen
    644 						event.target.width++;
    645 						event.target.width--;
    646 
    647 						$scope.$emit(VG_EVENTS.ON_START_PLAYING, [event.target.duration]);
    648 					};
    649 
    650 					$scope.onUpdateTime = function(event) {
    651 						if ($scope.vgUpdateTime()) {
    652 							vgUpdateTimeCallBack = $scope.vgUpdateTime();
    653 							vgUpdateTimeCallBack(event.target.currentTime, event.target.duration);
    654 						}
    655 
    656 						$scope.$emit(VG_EVENTS.ON_UPDATE_TIME, [event.target.currentTime, event.target.duration]);
    657 					};
    658 
    659 					$scope.getVideoSize = function(w, h) {
    660 						var percentageWidth;
    661 						var percentageHeight;
    662 						var result = {};
    663 						var wider = vg.videoElement[0].videoWidth / vg.videoElement[0].videoHeight > w / h;
    664 						result.width = w;
    665 						result.height = h;
    666 
    667 						if (currentStretch == "fit" && wider || currentStretch == "fill" && !wider) {
    668 							percentageWidth = w * 100 / vg.videoElement[0].videoWidth;
    669 							result.height = vg.videoElement[0].videoHeight * percentageWidth / 100;
    670 						} else if (currentStretch == "fill" && wider || currentStretch == "fit" && !wider) {
    671 							percentageHeight = h * 100 / vg.videoElement[0].videoHeight;
    672 							result.width = vg.videoElement[0].videoWidth * percentageHeight / 100;
    673 						} else {
    674 							result.width = vg.videoElement[0].videoWidth;
    675 							result.height = vg.videoElement[0].videoHeight;
    676 						}
    677 
    678 						// Metadata has not been loaded or any problem has been happened
    679 						if (result.height == 0 || isNaN(result.height)) {
    680 							result.width = vg.elementScope[0].parentElement.clientWidth;
    681 							result.height = result.width * 9 / 16;
    682 						}
    683 
    684 						return result;
    685 					};
    686 
    687 					$scope.init();
    688 				}],
    689 				link: {
    690 					pre: function(scope, elem, attr, controller) {
    691 						controller.videogularElement = elem;
    692 						controller.elementScope = angular.element(elem);
    693 						controller.videoElement = controller.elementScope.find("video");
    694 
    695 						controller.videoElement[0].addEventListener("waiting", scope.onStartBuffering, false);
    696 						controller.videoElement[0].addEventListener("ended", scope.onComplete, false);
    697 						controller.videoElement[0].addEventListener("playing", scope.onStartPlaying, false);
    698 						controller.videoElement[0].addEventListener("timeupdate", scope.onUpdateTime, false);
    699 
    700 						controller.elementScope.ready(scope.onElementReady);
    701 						controller.videoElement.ready(scope.onVideoReady);
    702 					}
    703 				}
    704 			}
    705 		}
    706 	])
    707 	.directive("vgSrc",
    708 		["VG_EVENTS", "VG_UTILS", function(VG_EVENTS, VG_UTILS) {
    709 			return {
    710 				restrict: "A",
    711 				link: {
    712 					pre: function(scope, elem, attr) {
    713 						var element = elem;
    714 						var sources;
    715 						var canPlay;
    716 
    717 						function changeSource() {
    718 							canPlay = "";
    719 
    720 							// It's a cool browser
    721 							if (element[0].canPlayType) {
    722 								for (var i = 0, l = sources.length; i < l; i++) {
    723 									canPlay = element[0].canPlayType(sources[i].type);
    724 
    725 									if (canPlay == "maybe" || canPlay == "probably") {
    726 										element.attr("src", sources[i].src);
    727 										element.attr("type", sources[i].type);
    728 										break;
    729 									}
    730 								}
    731 							}
    732 							// It's a crappy browser and it doesn't deserve any respect
    733 							else {
    734 								// Get H264 or the first one
    735 								element.attr("src", sources[0].src);
    736 								element.attr("type", sources[0].type);
    737 							}
    738 
    739 							if (canPlay == "") {
    740 								scope.$broadcast(VG_EVENTS.ON_ERROR, {type: "Can't play file"})
    741 							}
    742 						}
    743 
    744 						scope.$watch(attr.vgSrc, function(newValue, oldValue) {
    745 							if (!sources || newValue != oldValue) {
    746 								sources = newValue;
    747 								changeSource();
    748 							}
    749 						});
    750 					}
    751 				}
    752 			}
    753 		}
    754 	]);