1"use strict"; 2angular.module("com.2fdevs.videogular.plugins.controls", []) 3 .run( 4 ["$templateCache", function ($templateCache) { 5 $templateCache.put("vg-templates/vg-controls", 6 '<div class="controls-container" ng-mousemove="onMouseMove()" ng-class="animationClass" ng-transclude></div>'); 7 }] 8) 9 .directive("vgControls", 10 ["$timeout", "VG_STATES", function ($timeout, VG_STATES) { 11 return { 12 restrict: "E", 13 require: "^videogular", 14 transclude: true, 15 templateUrl: function (elem, attrs) { 16 return attrs.vgTemplate || 'vg-templates/vg-controls'; 17 }, 18 scope: { 19 vgAutohide: "=?", 20 vgAutohideTime: "=?" 21 }, 22 link: function (scope, elem, attr, API) { 23 var w = 0; 24 var h = 0; 25 var autoHideTime = 2000; 26 var hideInterval; 27 28 scope.API = API; 29 30 scope.onMouseMove = function onMouseMove() { 31 if (scope.vgAutohide) scope.showControls(); 32 }; 33 34 scope.setAutohide = function setAutohide(value) { 35 if (value && API.currentState == VG_STATES.PLAY) { 36 hideInterval = $timeout(scope.hideControls, autoHideTime); 37 } 38 else { 39 scope.animationClass = ""; 40 $timeout.cancel(hideInterval); 41 scope.showControls(); 42 } 43 }; 44 45 scope.setAutohideTime = function setAutohideTime(value) { 46 autoHideTime = value; 47 }; 48 49 scope.hideControls = function hideControls() { 50 scope.animationClass = "hide-animation"; 51 }; 52 53 scope.showControls = function showControls() { 54 scope.animationClass = "show-animation"; 55 $timeout.cancel(hideInterval); 56 if (scope.vgAutohide && API.currentState == VG_STATES.PLAY) hideInterval = $timeout(scope.hideControls, autoHideTime); 57 }; 58 59 if (API.isConfig) { 60 scope.$watch("API.config", 61 function () { 62 if (scope.API.config) { 63 var ahValue = scope.API.config.plugins.controls.autohide || false; 64 var ahtValue = scope.API.config.plugins.controls.autohideTime || 2000; 65 scope.vgAutohide = ahValue; 66 scope.vgAutohideTime = ahtValue; 67 scope.setAutohideTime(ahtValue); 68 scope.setAutohide(ahValue); 69 } 70 } 71 ); 72 } 73 else { 74 // If vg-autohide has been set 75 if (scope.vgAutohide != undefined) { 76 scope.$watch("vgAutohide", scope.setAutohide); 77 } 78 79 // If vg-autohide-time has been set 80 if (scope.vgAutohideTime != undefined) { 81 scope.$watch("vgAutohideTime", scope.setAutohideTime); 82 } 83 } 84 85 scope.$watch( 86 function () { 87 return API.currentState; 88 }, 89 function (newVal, oldVal) { 90 if (scope.vgAutohide) scope.showControls(); 91 } 92 ); 93 } 94 } 95 }] 96); 97 98angular.module("com.2fdevs.videogular.plugins.controls") 99 .run( 100 ["$templateCache", function ($templateCache) { 101 $templateCache.put("vg-templates/vg-fullscreen-button", 102 '<button class="iconButton fullscreenIcon" ng-click="onClickFullScreen()" aria-label="Toggle full screen" type="button"><div class="tooltip">Fullscreen</div></button>'); 103 }] 104) 105 .directive("vgFullscreenButton", 106 [function () { 107 return { 108 restrict: "E", 109 require: "^videogular", 110 scope: {}, 111 templateUrl: function (elem, attrs) { 112 return attrs.vgTemplate || 'vg-templates/vg-fullscreen-button'; 113 }, 114 link: function (scope, elem, attr, API) { 115 scope.onChangeFullScreen = function onChangeFullScreen(isFullScreen) { 116 scope.fullscreenIcon = {enter: !isFullScreen, exit: isFullScreen}; 117 }; 118 119 scope.onClickFullScreen = function onClickFullScreen() { 120 API.toggleFullScreen(); 121 }; 122 123 scope.fullscreenIcon = {enter: true}; 124 125 scope.$watch( 126 function () { 127 return API.isFullScreen; 128 }, 129 function (newVal, oldVal) { 130 if (newVal != oldVal) { 131 scope.onChangeFullScreen(newVal); 132 } 133 } 134 ); 135 } 136 } 137 }] 138); 139 140angular.module("com.2fdevs.videogular.plugins.controls") 141 .run( 142 ["$templateCache", function ($templateCache) { 143 $templateCache.put("vg-templates/vg-play-pause-button", 144 '<button class="iconButton" ng-click="onClickPlayPause()" ng-class="playPauseIcon" aria-label="Play/Pause" type="button"></button>'); 145 }] 146) 147 .directive("vgPlayPauseButton", 148 ["VG_STATES", function (VG_STATES) { 149 return { 150 restrict: "E", 151 require: "^videogular", 152 scope: {}, 153 templateUrl: function (elem, attrs) { 154 return attrs.vgTemplate || 'vg-templates/vg-play-pause-button'; 155 }, 156 link: function (scope, elem, attr, API) { 157 scope.setState = function setState(newState) { 158 switch (newState) { 159 case VG_STATES.PLAY: 160 scope.playPauseIcon = {pause: true}; 161 break; 162 163 case VG_STATES.PAUSE: 164 scope.playPauseIcon = {play: true}; 165 break; 166 167 case VG_STATES.STOP: 168 scope.playPauseIcon = {play: true}; 169 break; 170 } 171 }; 172 173 scope.onClickPlayPause = function onClickPlayPause() { 174 API.playPause(); 175 }; 176 177 scope.playPauseIcon = {play: true}; 178 179 scope.$watch( 180 function () { 181 return API.currentState; 182 }, 183 function (newVal, oldVal) { 184 scope.setState(newVal); 185 } 186 ); 187 } 188 }; 189 }] 190); 191 192angular.module("com.2fdevs.videogular.plugins.controls") 193 .run( 194 ["$templateCache", function ($templateCache) { 195 $templateCache.put("vg-templates/vg-playback-button", 196 '<button class="playbackValue iconButton" ng-click="onClickPlayback()">{{playback}}x</button>'); 197 }] 198) 199 .directive("vgPlaybackButton", 200 [function () { 201 return { 202 restrict: "E", 203 require: "^videogular", 204 templateUrl: function (elem, attrs) { 205 return attrs.vgTemplate || 'vg-templates/vg-playback-button'; 206 }, 207 scope: { 208 vgSpeeds: '=?' 209 }, 210 link: function (scope, elem, attr, API) { 211 scope.playback = '1'; 212 213 scope.setPlayback = function(playback) { 214 scope.playback = playback; 215 API.setPlayback(parseFloat(playback)); 216 }; 217 218 scope.onClickPlayback = function onClickPlayback() { 219 var playbackOptions = scope.vgSpeeds || ['0.5', '1', '1.5', '2']; 220 var nextPlaybackRate = playbackOptions.indexOf(scope.playback.toString()) + 1; 221 222 if (nextPlaybackRate >= playbackOptions.length) { 223 scope.playback = playbackOptions[0]; 224 } 225 else { 226 scope.playback = playbackOptions[nextPlaybackRate]; 227 } 228 229 scope.setPlayback(scope.playback); 230 }; 231 232 scope.$watch( 233 function () { 234 return API.playback; 235 }, 236 function(newVal, oldVal) { 237 if (newVal != oldVal) { 238 scope.setPlayback(newVal); 239 } 240 } 241 ); 242 } 243 } 244 }] 245); 246 247angular.module("com.2fdevs.videogular.plugins.controls") 248 .directive("vgScrubBarBuffer", 249 [function () { 250 return { 251 restrict: "E", 252 require: "^videogular", 253 link: function (scope, elem, attr, API) { 254 var percentTime = 0; 255 256 scope.onUpdateBuffer = function onUpdateBuffer(newBuffer) { 257 if (typeof newBuffer === 'number' && API.totalTime) { 258 percentTime = 100 * (newBuffer / API.totalTime); 259 elem.css("width", percentTime + "%"); 260 } else { 261 elem.css("width", 0); 262 } 263 }; 264 265 scope.$watch( 266 function () { 267 return API.bufferEnd; 268 }, 269 function (newVal, oldVal) { 270 scope.onUpdateBuffer(newVal); 271 } 272 ); 273 } 274 } 275 }] 276); 277 278angular.module("com.2fdevs.videogular.plugins.controls") 279 .directive("vgScrubBarCurrentTime", 280 [function () { 281 return { 282 restrict: "E", 283 require: "^videogular", 284 link: function (scope, elem, attr, API) { 285 var percentTime = 0; 286 287 scope.onUpdateTime = function onUpdateTime(newCurrentTime) { 288 if (typeof newCurrentTime === 'number' && API.totalTime) { 289 percentTime = 100 * (newCurrentTime / API.totalTime); 290 elem.css("width", percentTime + "%"); 291 } else { 292 elem.css("width", 0); 293 } 294 }; 295 296 scope.$watch( 297 function () { 298 return API.currentTime; 299 }, 300 function (newVal, oldVal) { 301 scope.onUpdateTime(newVal); 302 } 303 ); 304 } 305 } 306 }] 307); 308 309angular.module("com.2fdevs.videogular.plugins.controls") 310 .run(["$templateCache", 311 function ($templateCache) { 312 $templateCache.put("vg-templates/vg-scrub-bar", 313 '<div role="slider" ' + 314 'aria-valuemax="{{ariaTime(API.totalTime)}}" ' + 315 'aria-valuenow="{{ariaTime(API.currentTime)}}" ' + 316 'aria-valuemin="0" ' + 317 'aria-label="Time scrub bar" ' + 318 'tabindex="0" ' + 319 'ng-keydown="onScrubBarKeyDown($event)">' + 320 '</div>' +
321 '<div ng-class="{\'showtime\' : showTimecode && hoverTime && !cueHover}" class="timecode" ng-style="hoverTimeStyles"><span>{{hoverTime | date:"mm:ss":"+0000" }}</span></div>' + 322 '<div class="container" ng-transclude analytics-on="click" analytics-event="Seek: {{ariaTime(API.currentTime)*1000 | date:\'mm:ss\':\'+0000\'}}" analytics-category="Video: {{controller.videos[controller.currentVideo].title}}"></div>' 323 ); 324 }] 325 ) 326 .directive("vgScrubBar", ["VG_STATES", "VG_UTILS", 327 function (VG_STATES, VG_UTILS) { 328 return { 329 restrict: "E", 330 require: "^videogular", 331 transclude: true, 332 templateUrl: function (elem, attrs) { 333 return attrs.vgTemplate || 'vg-templates/vg-scrub-bar'; 334 }, 335 scope: { 336 vgThumbnails: "=", 337 cueHover: "=", 338 controller: "=" 339 }, 340 link: function (scope, elem, attr, API) { 341 var isSeeking = false; 342 var isPlaying = false; 343 var isPlayingWhenSeeking = false; 344 var LEFT = 37; 345 var RIGHT = 39; 346 var NUM_PERCENT = 5; 347 var thumbnailsWidth = 0; 348 var thumbWidth = 0; 349 var slider = elem[0].querySelector("div[role=slider]"); 350 351 scope.thumbnails = false; 352 scope.thumbnailContainer = {}; 353 354 scope.API = API; 355 scope.hoverTime = ''; 356 scope.hoverTimeStyles = {}; 357 scope.showTimecode = false; 358 359 scope.onLoadThumbnails = function(event) { 360 thumbnailsWidth = event.path[0].naturalWidth; 361 thumbWidth = thumbnailsWidth / 100; 362 }; 363 364 scope.ariaTime = function (time) { 365 return Math.round(time / 1000); 366 }; 367 368 scope.getOffset = function getOffset(event) { 369 var el = event.target, 370 x = 0; 371 372 while (el && !isNaN(el.offsetLeft)) { 373 x += el.offsetLeft - el.scrollLeft; 374 el = el.offsetParent; 375 } 376 377 return event.clientX - x; 378 }; 379 380 scope.onScrubBarTouchStart = function onScrubBarTouchStart($event) { 381 var event = $event.originalEvent || $event; 382 var touches = event.touches; 383 var touchX = scope.getOffset(touches[0]); 384 385 isSeeking = true; 386 if (isPlaying) isPlayingWhenSeeking = true; 387 API.pause(); 388 API.seekTime(touchX * API.mediaElement[0].duration / slider.scrollWidth); 389 390 scope.$digest(); 391 }; 392 393 scope.onScrubBarTouchEnd = function onScrubBarTouchEnd($event) { 394 var event = $event.originalEvent || $event; 395 if (isPlayingWhenSeeking) { 396 isPlayingWhenSeeking = false; 397 API.play(); 398 } 399 isSeeking = false; 400 401 scope.$digest(); 402 }; 403 404 scope.onScrubBarTouchMove = function onScrubBarTouchMove($event) { 405 var event = $event.originalEvent || $event; 406 var touches = event.touches; 407 var touchX = scope.getOffset(touches[0]); 408 409 if (scope.vgThumbnails && scope.vgThumbnails.length) { 410 var second = Math.round(touchX * API.mediaElement[0].duration / slider.scrollWidth); 411 var percentage = Math.round(second * 100 / (API.totalTime / 1000)); 412 413 scope.updateThumbnails(percentage); 414 } 415 416 if (isSeeking) { 417 API.seekTime(touchX * API.mediaElement[0].duration / slider.scrollWidth); 418 } 419 420 scope.$digest(); 421 }; 422 423 scope.onScrubBarTouchLeave = function onScrubBarTouchLeave(event) { 424 isSeeking = false; 425 scope.thumbnails = false; 426 427 scope.$digest(); 428 }; 429 430 scope.onScrubBarMouseDown = function onScrubBarMouseDown(event) { 431 event = VG_UTILS.fixEventOffset(event); 432 433 isSeeking = true; 434 if (isPlaying) isPlayingWhenSeeking = true; 435 API.pause(); 436 437 API.seekTime(event.offsetX * API.mediaElement[0].duration / slider.scrollWidth); 438 439 scope.$digest(); 440 }; 441 442 scope.onScrubBarMouseUp = function onScrubBarMouseUp(event) { 443 //event = VG_UTILS.fixEventOffset(event); 444 445 if (isPlayingWhenSeeking) { 446 isPlayingWhenSeeking = false; 447 API.play(); 448 } 449 isSeeking = false; 450 //API.seekTime(event.offsetX * API.mediaElement[0].duration / slider.scrollWidth); 451 452 scope.$digest(); 453 }; 454 455 scope.onScrubBarMouseMove = function onScrubBarMouseMove(event) { 456 457 var second = Math.round(event.offsetX * API.mediaElement[0].duration / slider.scrollWidth); 458 var percentage = Math.round(second * 100 / (API.totalTime / 1000)); 459 scope.hoverTime = second*1000; 460 461 var thPos = (slider.scrollWidth * percentage / 100) - (52 / 2); 462 463 if (thPos < 0) { 464 thPos = 0; 465 } else if (thPos > slider.scrollWidth - 52) { 466 // console.log(thPos + ' vs ' + slider.scrollWidth); 467 thPos = slider.scrollWidth - 52; 468 } 469 // console.log(thPos + ' vs ' + slider.scrollWidth); 470 471 scope.hoverTimeStyles = { 472 "left": thPos + "px" 473 };
474 scope.showTimecode = true; 475 476 if (scope.vgThumbnails && scope.vgThumbnails.length) { 477 var second = Math.round(event.offsetX * API.mediaElement[0].duration / slider.scrollWidth); 478 var percentage = Math.round(second * 100 / (API.totalTime / 1000)); 479 480 scope.updateThumbnails(percentage); 481 } 482 483 if (isSeeking) { 484 event = VG_UTILS.fixEventOffset(event); 485 API.seekTime(event.offsetX * API.mediaElement[0].duration / slider.scrollWidth); 486 } 487 488 scope.$digest(); 489 }; 490 491 scope.onScrubBarMouseLeave = function onScrubBarMouseLeave(event) { 492 isSeeking = false; 493 scope.thumbnails = false; 494 scope.showTimecode = false; 495 scope.$digest(); 496 }; 497 498 scope.onScrubBarKeyDown = function onScrubBarKeyDown(event) { 499 var currentPercent = (API.currentTime / API.totalTime) * 100; 500 501 if (event.which === LEFT || event.keyCode === LEFT) { 502 API.seekTime(currentPercent - NUM_PERCENT, true); 503 event.preventDefault(); 504 } 505 else if (event.which === RIGHT || event.keyCode === RIGHT) { 506 API.seekTime(currentPercent + NUM_PERCENT, true); 507 event.preventDefault(); 508 } 509 }; 510 511 scope.updateThumbnails = function updateThumbnails(percentage) { 512 var bgPos = Math.round(thumbnailsWidth * percentage / 100); 513 var thPos = (slider.scrollWidth * percentage / 100) - (thumbWidth / 2); 514 515 scope.thumbnailContainer = { 516 "width": thumbWidth + "px", 517 "left": thPos + "px" 518 }; 519 520 scope.thumbnails = { 521 "background-image": 'url("' + scope.vgThumbnails + '")', 522 "background-position": -bgPos + "px 0px" 523 }; 524 }; 525 526 scope.setState = function setState(newState) { 527 if (!isSeeking) { 528 switch (newState) { 529 case VG_STATES.PLAY: 530 isPlaying = true; 531 break; 532 533 case VG_STATES.PAUSE: 534 isPlaying = false; 535 break; 536 537 case VG_STATES.STOP: 538 isPlaying = false; 539 break; 540 } 541 } 542 }; 543 544 scope.onDestroy = function() { 545 elem.unbind("touchstart", scope.onScrubBarTouchStart); 546 elem.unbind("touchend", scope.onScrubBarTouchEnd); 547 elem.unbind("touchmove", scope.onScrubBarTouchMove); 548 elem.unbind("touchleave", scope.onScrubBarTouchLeave); 549 elem.unbind("mousedown", scope.onScrubBarMouseDown); 550 elem.unbind("mouseup", scope.onScrubBarMouseUp); 551 elem.unbind("mousemove", scope.onScrubBarMouseMove); 552 elem.unbind("mouseleave", scope.onScrubBarMouseLeave); 553 }; 554 555 scope.$watch( 556 function () { 557 return API.currentState; 558 }, 559 function (newVal, oldVal) { 560 if (newVal != oldVal) { 561 scope.setState(newVal); 562 } 563 } 564 ); 565 566 if (scope.vgThumbnails) { 567 var thLoader = new Image(); 568 thLoader.onload = scope.onLoadThumbnails.bind(scope); 569 thLoader.src = scope.vgThumbnails; 570 } 571 572 // Touch move is really buggy in Chrome for Android, maybe we could use mouse move that works ok 573 if (VG_UTILS.isMobileDevice()) { 574 elem.bind("touchstart", scope.onScrubBarTouchStart); 575 elem.bind("touchend", scope.onScrubBarTouchEnd); 576 elem.bind("touchmove", scope.onScrubBarTouchMove); 577 elem.bind("touchleave", scope.onScrubBarTouchLeave); 578 } 579 else { 580 elem.bind("mousedown", scope.onScrubBarMouseDown); 581 elem.bind("mouseup", scope.onScrubBarMouseUp); 582 // console.log(elem); 583 elem.bind("mousemove", scope.onScrubBarMouseMove); 584 elem.bind("mouseleave", scope.onScrubBarMouseLeave); 585 } 586 587 scope.$on('destroy', scope.onDestroy.bind(scope)); 588 } 589 } 590 } 591 ]); 592 593angular.module("com.2fdevs.videogular.plugins.controls") 594 .directive("vgTimeDisplay", 595 [function () { 596 return { 597 require: "^videogular", 598 restrict: "E", 599 link: function (scope, elem, attr, API) { 600 scope.currentTime = API.currentTime; 601 scope.timeLeft = API.timeLeft; 602 scope.totalTime = API.totalTime; 603 scope.isLive = API.isLive; 604 605 scope.$watch( 606 function () { 607 return API.currentTime; 608 }, 609 function (newVal, oldVal) { 610 scope.currentTime = newVal; 611 } 612 ); 613 614 scope.$watch( 615 function () { 616 return API.timeLeft; 617 }, 618 function (newVal, oldVal) { 619 scope.timeLeft = newVal; 620 } 621 ); 622 623 scope.$watch( 624 function () { 625 return API.totalTime; 626 }, 627 function (newVal, oldVal) { 628 scope.totalTime = newVal; 629 } 630 ); 631 632 scope.$watch( 633 function () { 634 return API.isLive; 635 }, 636 function (newVal, oldVal) { 637 scope.isLive = newVal; 638 } 639 ); 640 } 641 } 642 }] 643); 644 645angular.module("com.2fdevs.videogular.plugins.controls") 646 .run( 647 ["$templateCache", function ($templateCache) { 648 $templateCache.put("vg-templates/vg-mute-button", 649 '<button type="button" class="iconButton" ng-class="muteIcon" ng-click="onClickMute()" ng-focus="onMuteButtonFocus()" ng-blur="onMuteButtonLoseFocus()" ng-mouseleave="onMuteButtonLeave()" ng-keydown="onMuteButtonKeyDown($event)" aria-label="Volume, Click to Mute"></button>'); 650 }] 651 ) 652 .directive("vgMuteButton", 653 [function () { 654 return { 655 restrict: "E", 656 require: "^videogular", 657 templateUrl: function (elem, attrs) { 658 return attrs.vgTemplate || 'vg-templates/vg-mute-button'; 659 }, 660 link: function (scope, elem, attr, API) { 661 var isMuted = false;
662 var UP = 38; 663 var DOWN = 40; 664 var CHANGE_PER_PRESS = 0.05; 665 666 scope.onClickMute = function onClickMute() { 667 if (isMuted) { 668 scope.currentVolume = scope.defaultVolume; 669 } 670 else { 671 scope.currentVolume = 0; 672 scope.muteIcon = {mute: true}; 673 } 674 675 isMuted = !isMuted; 676 677 API.setVolume(scope.currentVolume); 678 }; 679 680 scope.onMuteButtonFocus = function onMuteButtonFocus() { 681 scope.volumeVisibility = "visible"; 682 }; 683 684 scope.onMuteButtonLoseFocus = function onMuteButtonLoseFocus() { 685 scope.volumeVisibility = "hidden"; 686 }; 687 688 scope.onMuteButtonLeave = function onMuteButtonLeave() { 689 document.activeElement.blur(); 690 }; 691 692 scope.onMuteButtonKeyDown = function onMuteButtonKeyDown(event) { 693 var currentVolume = (API.volume != null) ? API.volume : 1; 694 var newVolume; 695 696 if (event.which === UP || event.keyCode === UP) { 697 newVolume = currentVolume + CHANGE_PER_PRESS; 698 if (newVolume > 1) newVolume = 1; 699 700 API.setVolume(newVolume); 701 event.preventDefault(); 702 } 703 else if (event.which === DOWN || event.keyCode === DOWN) { 704 newVolume = currentVolume - CHANGE_PER_PRESS; 705 if (newVolume < 0) newVolume = 0; 706 707 API.setVolume(newVolume); 708 event.preventDefault(); 709 } 710 }; 711 712 scope.onSetVolume = function onSetVolume(newVolume) { 713 scope.currentVolume = newVolume; 714 715 isMuted = (scope.currentVolume === 0); 716 717 // if it's not muted we save the default volume 718 if (!isMuted) { 719 scope.defaultVolume = newVolume; 720 } 721 else { 722 // if was muted but the user changed the volume 723 if (newVolume > 0) { 724 scope.defaultVolume = newVolume; 725 } 726 } 727 728 var percentValue = Math.round(newVolume * 100); 729 if (percentValue == 0) { 730 scope.muteIcon = {mute: true}; 731 } 732 else if (percentValue > 0 && percentValue < 25) { 733 scope.muteIcon = {level0: true}; 734 } 735 else if (percentValue >= 25 && percentValue < 50) { 736 scope.muteIcon = {level1: true}; 737 } 738 else if (percentValue >= 50 && percentValue < 75) { 739 scope.muteIcon = {level2: true}; 740 } 741 else if (percentValue >= 75) { 742 scope.muteIcon = {level3: true}; 743 } 744 }; 745 746 scope.defaultVolume = 1; 747 scope.currentVolume = scope.defaultVolume; 748 scope.muteIcon = {level3: true}; 749 750 //Update the mute button on initialization, then watch for changes 751 scope.onSetVolume(API.volume); 752 scope.$watch( 753 function () { 754 return API.volume; 755 }, 756 function (newVal, oldVal) { 757 if (newVal != oldVal) { 758 scope.onSetVolume(newVal); 759 } 760 } 761 ); 762 } 763 } 764 }] 765); 766 767angular.module("com.2fdevs.videogular.plugins.controls") 768 .run( 769 ["$templateCache", function ($templateCache) { 770 $templateCache.put("vg-templates/vg-volume-bar", 771 '<div class="horizontalVolumeBar">\ 772 <div class="volumeBackground" ng-click="onClickVolume($event)" ng-mousedown="onMouseDownVolume()" ng-mouseup="onMouseUpVolume()" ng-mousemove="onMouseMoveVolume($event)" ng-mouseleave="onMouseLeaveVolume()" tabindex="-1">\ 773 <div class="volumeValue" tabindex="-1"></div>\ 774 <div class="volumeClickArea" tabindex="-1"><div class="knob"></div></div>\ 775 </div>\ 776 </div>'); 777 }] 778) 779 .directive("vgVolumeBar", 780 ["VG_UTILS", function (VG_UTILS) { 781 return { 782 restrict: "E", 783 require: "^videogular", 784 templateUrl: function (elem, attrs) { 785 return attrs.vgTemplate || 'vg-templates/vg-volume-bar'; 786 }, 787 link: function (scope, elem, attr, API) { 788 var isChangingVolume = false; 789 var volumeBackElem = angular.element(elem[0].getElementsByClassName("volumeBackground")); 790 var volumeValueElem = angular.element(elem[0].getElementsByClassName("volumeValue")); 791 var knob = angular.element(elem[0].getElementsByClassName("knob")); 792 793 scope.onClickVolume = function onClickVolume(event) { 794 // console.log('here'); 795 event = VG_UTILS.fixEventOffset(event); 796 var volumeWidth = parseInt(volumeBackElem.prop("offsetWidth")); 797 var value = (volumeWidth - event.offsetX) * 100 / volumeWidth; 798 var volValue = 1 - (value / 100); 799 API.setVolume(volValue); 800 }; 801 802 scope.onMouseDownVolume = function onMouseDownVolume() { 803 isChangingVolume = true; 804 }; 805 806 scope.onMouseUpVolume = function onMouseUpVolume() { 807 isChangingVolume = false;
808 }; 809 810 scope.onMouseLeaveVolume = function onMouseLeaveVolume() { 811 isChangingVolume = false; 812 }; 813 814 scope.onMouseMoveVolume = function onMouseMoveVolume(event) { 815 if (isChangingVolume) { 816 event = VG_UTILS.fixEventOffset(event); 817 var volumeWidth = parseInt(volumeBackElem.prop("offsetWidth")); 818 var value = (volumeWidth - event.offsetX) * 100 / volumeWidth; 819 var volValue = 1 - (value / 100); 820 821 API.setVolume(volValue); 822 } 823 }; 824 825 scope.updateVolumeView = function updateVolumeView(value) { 826 value = value * 100; 827 volumeValueElem.css("width", (100 - value) + "%"); 828 volumeValueElem.css("right", "0%"); 829 knob.css("right", (100 - value - 5) + "%"); 830 }; 831 832 scope.onChangeVisibility = function onChangeVisibility(value) { 833 elem.css("visibility", value); 834 }; 835 836 elem.css("visibility", scope.volumeVisibility); 837 838 scope.$watch("volumeVisibility", scope.onChangeVisibility); 839 840 //Update the volume bar on initialization, then watch for changes 841 scope.updateVolumeView(API.volume); 842 scope.$watch( 843 function () { 844 return API.volume; 845 }, 846 function (newVal, oldVal) { 847 if (newVal != oldVal) { 848 scope.updateVolumeView(newVal); 849 } 850 } 851 ); 852 } 853 } 854 }] 855); 856 857angular.module("com.2fdevs.videogular.plugins.controls") 858 .directive("vgVolume", 859 ["VG_UTILS", function (VG_UTILS) { 860 return { 861 restrict: "E", 862 link: function (scope, elem, attr) { 863 scope.onMouseOverVolume = function onMouseOverVolume() { 864 scope.$evalAsync(function () { 865 scope.volumeVisibility = "visible"; 866 }); 867 }; 868 869 scope.onMouseLeaveVolume = function onMouseLeaveVolume() { 870 scope.$evalAsync(function () { 871 scope.volumeVisibility = "hidden"; 872 }); 873 }; 874 875 scope.onDestroy = function() { 876 elem.unbind("mouseover", scope.onScrubBarTouchStart); 877 elem.unbind("mouseleave", scope.onScrubBarTouchEnd); 878 }; 879 880 // We hide volume controls on mobile devices 881 if (VG_UTILS.isMobileDevice()) { 882 elem.css("display", "none"); 883 } 884 else { 885 scope.volumeVisibility = "hidden"; 886 887 elem.bind("mouseover", scope.onMouseOverVolume); 888 elem.bind("mouseleave", scope.onMouseLeaveVolume); 889 } 890 891 scope.$on('destroy', scope.onDestroy.bind(scope)); 892 } 893 } 894 }] 895); 896 897angular.module("com.2fdevs.videogular.plugins.controls") 898 .run( 899 ["$templateCache", function ($templateCache) { 900 $templateCache.put("vg-templates/vg-captions-toggle-button", 901 '<div class="iconButton captionToggleIcon {{hasGradient}}" tabindex="0" aria-label="Toggle Captions" type="button"><div class="tooltip"><div class="captions-bridge"><div class="tt-gradient top"></div><div class="tt-gradient bottom"></div><ul><li ng-click="toggleCaption(\'off\')" ng-class="{\'active\' : activeCaption == \'off\'}">Captions off</li><li ng-class="{\'active\' : activeCaption == track.srclang}" ng-click="toggleCaption(track.srclang);" aria-label="Closed Captions: {{track.label}}" ng-repeat="track in vgTracks">{{track.label}}</li></ul></div></div></div>'); 902 }] 903) 904 .directive("vgCaptionsToggle", 905 ["VG_STATES", "store", "$timeout", function (VG_STATES, store, $timeout) { 906 return { 907 restrict: "E", 908 require: "^videogular", 909 scope: { 910 vgTracks: '=' 911 }, 912 templateUrl: function (elem, attrs) { 913 return attrs.vgTemplate || 'vg-templates/vg-captions-toggle-button'; 914 }, 915 link: function (scope, elem, attr, API) { 916 917 scope.hasGradient = ""; 918 $timeout(function(){ 919 scope.API = API; 920 scope.activeCaption = 'off'; 921 scope.previousIndex = 'off'; 922 scope.v = $("vg-media video")[0]; 923 if(scope.v.textTracks.length > 4) { 924 scope.hasGradient = "has-gradient" 925 } 926 // console.log(scope.v.textTracks); 927 angular.forEach(scope.v.textTracks, function(val, key) { 928 scope.v.textTracks[key].mode = "hidden"; 929 // console.log(scope.v.textTracks[key].language,scope.v.textTracks[key].label); 930 if(scope.v.textTracks[key].language === 'en' && scope.v.textTracks[key].label !== 'English'){ 931 if(scope.v.textTracks[key].label === 'Chinese, Simplified'){ 932 scope.v.textTracks[key].language === 'cn' 933 } else if(scope.v.textTracks[key].label === 'Chinese'){ 934 scope.v.textTracks[key].language === 'cn' 935 } else { 936 scope.v.textTracks[key].language === scope.v.textTracks[key].label 937 } 938 } 939 if (scope.v.textTracks[key].language == store.get("captionLang")) { 940 // console.log('found: ' + store.get("captionLang")); 941 scope.activeCaption = scope.v.textTracks[key].language; 942 scope.v.textTracks[key].mode = "showing"; 943 // console.log(scope.v.textTracks[key]); 944 } 945 }); 946 console.log(scope.v.textTracks); 947 948 if($("body").hasClass("postid-105060") || $("body").hasClass("postid-105059") || $("body").hasClass("postid-105057") || $("body").hasClass("postid-105055")){ 949 scope.activeCaption = 'off'; 950 var lang = 'en'; 951 // store.set("captionLang", 'off'); 952 angular.forEach(scope.v.textTracks, function(val, key) { 953 scope.v.textTracks[key].mode = "disabled"; 954 }); 955 scope.activeCaption = lang; 956 // store.set("captionLang", lang); 957 958 angular.forEach(scope.v.textTracks, function(val, key) { 959 if (scope.v.textTracks[key].language == lang) { 960 scope.v.textTracks[key].mode = "showing"; 961 // console.log('showing: ' + scope.v.textTracks[key].language) 962 } 963 964 }); 965 966 967 } 968 },1000); 969 970 971 scope.toggleCaption = function(lang) { 972 scope.activeCaption = 'off'; 973 store.set("captionLang", 'off'); 974 if(typeof(scope.v) !== "undefined" && typeof(scope.v.textTracks) !== "undefined" && scope.v.textTracks.length > 0){ 975 angular.forEach(scope.v.textTracks, function(val, key) { 976 scope.v.textTracks[key].mode = "disabled"; 977 }); 978 if (lang !== 'off') { 979 scope.activeCaption = lang; 980 store.set("captionLang", lang); 981 982 angular.forEach(scope.v.textTracks, function(val, key) { 983 if (scope.v.textTracks[key].language == lang) { 984 scope.v.textTracks[key].mode = "showing"; 985 // console.log('showing: ' + scope.v.textTracks[key].language) 986 } 987 988 }); 989 990 } else { 991 992 } 993 } else { 994 $timeout(function(){ 995 scope.toggleCaption(lang); 996 },3000); 997 } 998 } 999 } 1000 } 1001 }] 1002); 1003 1004angular.module("com.2fdevs.videogular.plugins.controls") 1005.run( 1006["$templateCache", function ($templateCache) { 1007 $templateCache.put("vg-templates/vg-size-toggle-button", 1008 '<button class="iconButton sizeToggleIcon" ng-click="toggleSize()" aria-label="Toggle Size" type="button"></svg><div class="tooltip"><span> video</span></div></button>'); 1009}] 1010) 1011.directive("vgSizeToggle", 1012["VG_STATES", "store", function (VG_STATES, store) { 1013 return { 1014 restrict: "E", 1015 require: "^videogular", 1016 scope: { 1017 size: '=' 1018 }, 1019 templateUrl: function (elem, attrs) { 1020 return attrs.vgTemplate || 'vg-templates/vg-size-toggle-button'; 1021 }, 1022 link: function (scope, elem, attr, API) { 1023 scope.API = API; 1024 scope.toggleSize = function() { 1025 scope.size = !scope.size; 1026 if(store.get('sizeOverride') !== null && store.get('sizeOverride') === true){ 1027 store.set('sizeOverride', false); 1028 } else { 1029 store.set('sizeOverride', true); 1030 } 1031 var vidSizeEl = angular.element(document.querySelector('.player-controller')); 1032 angular.element(vidSizeEl).toggleClass("sizeOverride"); 1033 }; 1034 } 1035 }; 1036}] 1037); 1038 1039angular.module("com.2fdevs.videogular.plugins.controls") 1040.run( 1041["$templateCache", function ($templateCache) { 1042 $templateCache.put("vg-templates/vg-rewind-button", 1043 '<button class="iconButton rewindButton" ng-click="rewindVideo()" aria-label="Rewind Button" type="button"><div class="tooltip">Rewind 10 seconds</div></button>'); 1044}] 1045) 1046.directive("vgRewindButton", 1047["VG_STATES", "$timeout", function (VG_STATES, $timeout) { 1048 return { 1049 restrict: "E", 1050 require: "^videogular", 1051 scope: { 1052 controller: '=' 1053 }, 1054 templateUrl: function (elem, attrs) { 1055 return attrs.vgTemplate || 'vg-templates/vg-rewind-button'; 1056 }, 1057 link: function (scope, elem, attr, API) { 1058 scope.API = API; 1059 scope.rewindVideo = function() { 1060 scope.API.seekTime(Math.floor(scope.API.currentTime/1000) - 10); 1061 scope.API.play(); 1062 } 1063 1064 } 1065 } 1066}] 1067);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.