1/* The MIT License (MIT) 2Copyright (c) 2014-2015 Benoit Tremblay <[email protected]> 3Permission is hereby granted, free of charge, to any person obtaining a copy 4of this software and associated documentation files (the "Software"), to deal 5in the Software without restriction, including without limitation the rights 6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7copies of the Software, and to permit persons to whom the Software is 8furnished to do so, subject to the following conditions: 9The above copyright notice and this permission notice shall be included in 10all copies or substantial portions of the Software. 11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17THE SOFTWARE. */ 18(function() { 19 'use strict'; 20 21 var VimeoState = { 22 UNSTARTED: -1, 23 ENDED: 0, 24 PLAYING: 1, 25 PAUSED: 2, 26 BUFFERING: 3 27 }; 28 29 var Tech = videojs.getComponent('Tech'); 30 31 var Vimeo = videojs.extend(Tech, { 32 constructor: function(options, ready) { 33 Tech.call(this, options, ready); 34 if(options.poster != "") {this.setPoster(options.poster);} 35 this.setSrc(this.options_.source.src, true); 36 37 // Set the vjs-vimeo class to the player 38 // Parent is not set yet so we have to wait a tick 39 setTimeout(function() { 40 this.el_.parentNode.className += ' vjs-vimeo'; 41 42 if (Vimeo.isApiReady) { 43 this.initPlayer(); 44 } else { 45 Vimeo.apiReadyQueue.push(this); 46 } 47 }.bind(this)); 48 49 }, 50 51 dispose: function() { 52 this.el_.parentNode.className = this.el_.parentNode.className.replace(' vjs-vimeo', ''); 53 }, 54 55 createEl: function() { 56 this.vimeo = {}; 57 this.vimeoInfo = {}; 58 this.baseUrl = 'https://player.vimeo.com/video/'; 59 this.baseApiUrl = 'https://www.vimeo.com/api/v2/video/'; 60 this.videoId = Vimeo.parseUrl(this.options_.source.src).videoId; 61 62 this.iframe = document.createElement('iframe'); 63 this.iframe.setAttribute('id', this.options_.techId); 64 this.iframe.setAttribute('title', 'Vimeo Video Player'); 65 this.iframe.setAttribute('class', 'vimeoplayer'); 66 this.iframe.setAttribute('src', this.baseUrl + this.videoId + '?api=1&player_id=' + this.options_.techId); 67 this.iframe.setAttribute('frameborder', '0'); 68 this.iframe.setAttribute('scrolling', 'no'); 69 this.iframe.setAttribute('marginWidth', '0'); 70 this.iframe.setAttribute('marginHeight', '0'); 71 this.iframe.setAttribute('webkitAllowFullScreen', '0'); 72 this.iframe.setAttribute('mozallowfullscreen', '0'); 73 this.iframe.setAttribute('allowFullScreen', '0'); 74 75 if (this.options_.autoplay) { 76 this.iframe.setAttribute('autoplay', 'true'); 77 } 78 79 var divWrapper = document.createElement('div'); 80 divWrapper.setAttribute('style', 'margin:0 auto;padding-bottom:56.25%;width:100%;height:0;position:relative;overflow:hidden;'); 81 divWrapper.setAttribute('class', 'vimeoFrame'); 82 divWrapper.appendChild(this.iframe); 83 84 if (!_isOnMobile && !this.options_.ytControls) { 85 var divBlocker = document.createElement('div'); 86 divBlocker.setAttribute('class', 'vjs-iframe-blocker'); 87 divBlocker.setAttribute('style', 'position:absolute;top:0;left:0;width:100%;height:100%'); 88 89 // In case the blocker is still there and we want to pause 90 divBlocker.onclick = function() { 91 this.onPause(); 92 }.bind(this); 93 94 divWrapper.appendChild(divBlocker); 95 } 96 97 if(this.options_.poster == "" && this.videoId != null) { 98 $.getJSON(this.baseApiUrl + this.videoId + '.json?callback=?', {format: "json"}, (function(_this){ 99 return function(data) { 100 // Set the low resolution first 101 _this.setPoster(data[0].thumbnail_large); 102 }; 103 })(this)); 104 } 105 106 return divWrapper; 107 }, 108 109 initPlayer: function() { 110 var self = this; 111 112 $(self.iframe).load(function(){ 113 var vimeoVideoID = Vimeo.parseUrl(self.options_.source.src).videoId; 114 //load vimeo 115 if (self.vimeo && self.vimeo.api) { 116 self.vimeo.api('unload'); 117 delete self.vimeo; 118 } 119 120 self.vimeo = $f(self.iframe); 121 122 self.vimeoInfo = { 123 state: VimeoState.UNSTARTED, 124 volume: 1, 125 muted: false, 126 muteVolume: 1, 127 time: 0, 128 duration: 0, 129 buffered: 0, 130 url: self.baseUrl + self.videoId, 131 error: null 132 }; 133 134 self.vimeo.addEvent('ready', function(id){ 135 self.onReady(); 136 137 self.vimeo.addEvent('loadProgress', function(data, id){ self.onLoadProgress(data); }); 138 self.vimeo.addEvent('playProgress', function(data, id){ self.onPlayProgress(data); }); 139 self.vimeo.addEvent('play', function(id){ self.onPlay(); }); 140 self.vimeo.addEvent('pause', function(id){ self.onPause(); }); 141 self.vimeo.addEvent('finish', function(id){ self.onFinish(); }); 142 self.vimeo.addEvent('seek', function(data, id){ self.onSeek(data); }); 143 144 }); 145 }); 146 147 }, 148 149 onReady: function(){ 150 this.playerReady_ = true; 151 this.triggerReady(); 152 this.trigger('loadedmetadata'); 153 if (this.startMuted) { 154 this.setMuted(true); 155 this.startMuted = false;
156 } 157 }, 158 159 onLoadProgress: function(data) { 160 var durationUpdate = !this.vimeoInfo.duration; 161 this.vimeoInfo.duration = data.duration; 162 this.vimeoInfo.buffered = data.percent; 163 this.trigger('progress'); 164 if (durationUpdate) this.trigger('durationchange'); 165 }, 166 onPlayProgress: function(data) { 167 this.vimeoInfo.time = data.seconds; 168 this.trigger('timeupdate'); 169 }, 170 onPlay: function() { 171 this.vimeoInfo.state = VimeoState.PLAYING; 172 this.trigger('play'); 173 }, 174 onPause: function() { 175 this.vimeoInfo.state = VimeoState.PAUSED; 176 this.trigger('pause'); 177 }, 178 onFinish: function() { 179 this.vimeoInfo.state = VimeoState.ENDED; 180 this.trigger('ended'); 181 }, 182 onSeek: function(data) { 183 this.trigger('seeking'); 184 this.vimeoInfo.time = data.seconds; 185 this.trigger('timeupdate'); 186 this.trigger('seeked'); 187 }, 188 onError: function(error){ 189 this.error = error; 190 this.trigger('error'); 191 }, 192 193 error: function() { 194 switch (this.errorNumber) { 195 case 2: 196 return { code: 'Unable to find the video' }; 197 198 case 5: 199 return { code: 'Error while trying to play the video' }; 200 201 case 100: 202 return { code: 'Unable to find the video' }; 203 204 case 101: 205 case 150: 206 return { code: 'Playback on other Websites has been disabled by the video owner.' }; 207 } 208 209 return { code: 'Vimeo unknown error (' + this.errorNumber + ')' }; 210 }, 211 212 src: function() { 213 return this.source; 214 }, 215 216 poster: function() { 217 return this.poster_; 218 }, 219 220 setPoster: function(poster) { 221 this.poster_ = poster; 222 }, 223 224 setSrc: function(source) { 225 if (!source || !source.src) { 226 return; 227 } 228 229 this.source = source; 230 this.url = Vimeo.parseUrl(source.src); 231 232 if (!this.options_.poster && this.url.videoId != null) { 233 $.getJSON(this.baseApiUrl + this.videoId + '.json?callback=?', {format: "json"}, (function(_this){ 234 return function(data) { 235 // Set the low resolution first 236 _this.poster_ = data[0].thumbnail_small; 237 }; 238 })(this)); 239 240 // Check if their is a high res 241 this.checkHighResPoster(); 242 } 243 244 if (this.options_.autoplay && !_isOnMobile) { 245 if (this.isReady_) { 246 this.play(); 247 } else { 248 this.playOnReady = true; 249 } 250 } 251 }, 252 253 supportsFullScreen: function() { 254 return true; 255 }, 256 257 //TRIGGER 258 load : function(){}, 259 play : function(){ this.vimeo.api('play'); }, 260 pause : function(){ this.vimeo.api('pause'); }, 261 paused : function(){ 262 return this.vimeoInfo.state !== VimeoState.PLAYING && 263 this.vimeoInfo.state !== VimeoState.BUFFERING; 264 }, 265 266 currentTime : function(){ return this.vimeoInfo.time || 0; }, 267 268 setCurrentTime :function(seconds){ 269 this.vimeo.api('seekTo', seconds); 270 this.player_.trigger('timeupdate'); 271 }, 272 273 duration :function(){ return this.vimeoInfo.duration || 0; }, 274 buffered :function(){ return videojs.createTimeRange(0, (this.vimeoInfo.buffered*this.vimeoInfo.duration) || 0); }, 275 276 volume :function() { return (this.vimeoInfo.muted)? this.vimeoInfo.muteVolume : this.vimeoInfo.volume; }, 277 setVolume :function(percentAsDecimal){ 278 this.vimeo.api('setvolume', percentAsDecimal); 279 this.vimeoInfo.volume = percentAsDecimal; 280 this.player_.trigger('volumechange'); 281 }, 282 currentSrc :function() { 283 return this.el_.src; 284 }, 285 muted :function() { return this.vimeoInfo.muted || false; }, 286 setMuted :function(muted) { 287 if (muted) { 288 this.vimeoInfo.muteVolume = this.vimeoInfo.volume; 289 this.setVolume(0); 290 } else { 291 this.setVolume(this.vimeoInfo.muteVolume); 292 } 293 294 this.vimeoInfo.muted = muted; 295 this.player_.trigger('volumechange'); 296 }, 297 298 // Tries to get the highest resolution thumbnail available for the video 299 checkHighResPoster: function(){ 300 var uri = ''; 301
302 try { 303 if(this.url.videoId != null){ 304 $.getJSON(this.baseApiUrl + this.videoId + '.json?callback=?', {format: "json"}, (function(_uri){ 305 return function(data) { 306 // Set the low resolution first 307 _uri = data[0].thumbnail_large; 308 }; 309 })(uri)); 310 311 var image = new Image(); 312 image.onload = function(){ 313 // Onload thumbnail 314 if('naturalHeight' in this){ 315 if(this.naturalHeight <= 90 || this.naturalWidth <= 120) { 316 this.onerror(); 317 return; 318 } 319 } else if(this.height <= 90 || this.width <= 120) { 320 this.onerror(); 321 return; 322 } 323 324 this.poster_ = uri; 325 this.trigger('posterchange'); 326 }.bind(this); 327 image.onerror = function(){}; 328 image.src = uri; 329 } 330 } 331 catch(e){} 332 } 333 }); 334 335 Vimeo.isSupported = function() { 336 return true; 337 }; 338 339 Vimeo.canPlaySource = function(e) { 340 return (e.type === 'video/vimeo'); 341 }; 342 343 var _isOnMobile = /(iPad|iPhone|iPod|Android)/g.test(navigator.userAgent); 344 345 Vimeo.parseUrl = function(url) { 346 var result = { 347 videoId: null 348 }; 349 350 var regex = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/; 351 var match = url.match(regex); 352 353 if (match) { 354 result.videoId = match[5]; 355 } 356 357 return result; 358 }; 359 360 function injectCss() { 361 var css = // iframe blocker to catch mouse events 362 '.vjs-vimeo .vjs-iframe-blocker { display: none; }' + 363 '.vjs-vimeo.vjs-user-inactive .vjs-iframe-blocker { display: block; }' + 364 '.vjs-vimeo .vjs-poster { background-size: cover; }' + 365 '.vjs-vimeo { height:100%; }' + 366 '.vimeoplayer { width:100%; height:180%; position:absolute; left:0; top:-40%; }'; 367 368 var head = document.head || document.getElementsByTagName('head')[0]; 369 370 var style = document.createElement('style'); 371 style.type = 'text/css'; 372 373 if (style.styleSheet){ 374 style.styleSheet.cssText = css; 375 } else { 376 style.appendChild(document.createTextNode(css)); 377 } 378 379 head.appendChild(style); 380 } 381 382 Vimeo.apiReadyQueue = []; 383 384 var vimeoIframeAPIReady = function() { 385 Vimeo.isApiReady = true; 386 injectCss(); 387 388 for (var i = 0; i < Vimeo.apiReadyQueue.length; ++i) { 389 Vimeo.apiReadyQueue[i].initPlayer(); 390 } 391 }; 392 393 vimeoIframeAPIReady(); 394 395 videojs.registerTech('Vimeo', Vimeo); 396 397 398 399 // Froogaloop API ------------------------------------------------------------- 400 401 // From https://github.com/vimeo/player-api/blob/master/javascript/froogaloop.js 402 // Init style shamelessly stolen from jQuery http://jquery.com 403 var Froogaloop = (function(){ 404 // Define a local copy of Froogaloop 405 function Froogaloop(iframe) { 406 // The Froogaloop object is actually just the init constructor 407 return new Froogaloop.fn.init(iframe); 408 } 409 410 var eventCallbacks = {}, 411 hasWindowEvent = false, 412 isReady = false, 413 slice = Array.prototype.slice, 414 playerOrigin = '*'; 415 416 Froogaloop.fn = Froogaloop.prototype = { 417 element: null, 418 419 init: function(iframe) { 420 if (typeof iframe === "string") { 421 iframe = document.getElementById(iframe); 422 } 423 424 this.element = iframe; 425 426 return this; 427 }, 428 429 /* 430 * Calls a function to act upon the player. 431 * 432 * @param {string} method The name of the Javascript API method to call. Eg: 'play'. 433 * @param {Array|Function} valueOrCallback params Array of parameters to pass when calling an API method 434 * or callback function when the method returns a value. 435 */ 436 api: function(method, valueOrCallback) { 437 if (!this.element || !method) { 438 return false; 439 } 440 441 var self = this, 442 element = self.element,
443 target_id = element.id !== '' ? element.id : null, 444 params = !isFunction(valueOrCallback) ? valueOrCallback : null, 445 callback = isFunction(valueOrCallback) ? valueOrCallback : null; 446 447 // Store the callback for get functions 448 if (callback) { 449 storeCallback(method, callback, target_id); 450 } 451 452 postMessage(method, params, element); 453 return self; 454 }, 455 456 /* 457 * Registers an event listener and a callback function that gets called when the event fires. 458 * 459 * @param eventName (String): Name of the event to listen for. 460 * @param callback (Function): Function that should be called when the event fires. 461 */ 462 addEvent: function(eventName, callback) { 463 if (!this.element) { 464 return false; 465 } 466 467 var self = this, 468 element = self.element, 469 target_id = element.id !== '' ? element.id : null; 470 471 472 storeCallback(eventName, callback, target_id); 473 474 // The ready event is not registered via postMessage. It fires regardless. 475 if (eventName != 'ready') { 476 postMessage('addEventListener', eventName, element); 477 } 478 else if (eventName == 'ready' && isReady) { 479 callback.call(null, target_id); 480 } 481 482 return self; 483 }, 484 485 /* 486 * Unregisters an event listener that gets called when the event fires. 487 * 488 * @param eventName (String): Name of the event to stop listening for. 489 */ 490 removeEvent: function(eventName) { 491 if (!this.element) { 492 return false; 493 } 494 495 var self = this, 496 element = self.element, 497 target_id = element.id !== '' ? element.id : null, 498 removed = removeCallback(eventName, target_id); 499 500 // The ready event is not registered 501 if (eventName != 'ready' && removed) { 502 postMessage('removeEventListener', eventName, element); 503 } 504 } 505 }; 506 507 /** 508 * Handles posting a message to the parent window. 509 * 510 * @param method (String): name of the method to call inside the player. For api calls 511 * this is the name of the api method (api_play or api_pause) while for events this method 512 * is api_addEventListener. 513 * @param params (Object or Array): List of parameters to submit to the method. Can be either 514 * a single param or an array list of parameters. 515 * @param target (HTMLElement): Target iframe to post the message to. 516 */ 517 function postMessage(method, params, target) { 518 if (target.contentWindow == null || !target.contentWindow.postMessage) { 519 return false; 520 } 521 522 var data = JSON.stringify({ 523 method: method, 524 value: params 525 }); 526 527 target.contentWindow.postMessage(data, playerOrigin); 528 } 529 530 /** 531 * Event that fires whenever the window receives a message from its parent 532 * via window.postMessage. 533 */ 534 function onMessageReceived(event) { 535 var data, method; 536 537 try { 538 data = JSON.parse(event.data); 539 method = data.event || data.method; 540 } 541 catch(e) { 542 //fail silently... like a ninja! 543 } 544 545 if (method == 'ready' && !isReady) { 546 isReady = true; 547 } 548 549 // Handles messages from the vimeo player only 550 if (!(/^https?:\/\/player.vimeo.com/).test(event.origin)) { 551 return false; 552 } 553 554 if (playerOrigin === '*') { 555 playerOrigin = event.origin; 556 } 557 558 var value = data.value, 559 eventData = data.data, 560 target_id = target_id === '' ? null : data.player_id, 561 562 callback = getCallback(method, target_id), 563 params = []; 564 565 if (!callback) { 566 return false;
vendor: 2,790 bytes, lines 567-662
567 } 568 569 if (value !== undefined) { 570 params.push(value); 571 } 572 573 if (eventData) { 574 params.push(eventData); 575 } 576 577 if (target_id) { 578 params.push(target_id); 579 } 580 581 return params.length > 0 ? callback.apply(null, params) : callback.call(); 582 } 583 584 585 /** 586 * Stores submitted callbacks for each iframe being tracked and each 587 * event for that iframe. 588 * 589 * @param eventName (String): Name of the event. Eg. api_onPlay 590 * @param callback (Function): Function that should get executed when the 591 * event is fired. 592 * @param target_id (String) [Optional]: If handling more than one iframe then 593 * it stores the different callbacks for different iframes based on the iframe's 594 * id. 595 */ 596 function storeCallback(eventName, callback, target_id) { 597 if (target_id) { 598 if (!eventCallbacks[target_id]) { 599 eventCallbacks[target_id] = {}; 600 } 601 eventCallbacks[target_id][eventName] = callback; 602 } 603 else { 604 eventCallbacks[eventName] = callback; 605 } 606 } 607 608 /** 609 * Retrieves stored callbacks. 610 */ 611 function getCallback(eventName, target_id) { 612 if (target_id && eventCallbacks[target_id]) { 613 return eventCallbacks[target_id][eventName]; 614 } 615 else if (eventCallbacks[eventName]) { 616 return eventCallbacks[eventName]; 617 } 618 } 619 620 function removeCallback(eventName, target_id) { 621 if (target_id && eventCallbacks[target_id]) { 622 if (!eventCallbacks[target_id][eventName]) { 623 return false; 624 } 625 eventCallbacks[target_id][eventName] = null; 626 } 627 else { 628 if (!eventCallbacks[eventName]) { 629 return false; 630 } 631 eventCallbacks[eventName] = null; 632 } 633 634 return true; 635 } 636 637 function isFunction(obj) { 638 return !!(obj && obj.constructor && obj.call && obj.apply); 639 } 640 641 function isArray(obj) { 642 return toString.call(obj) === '[object Array]'; 643 } 644 645 // Give the init function the Froogaloop prototype for later instantiation 646 Froogaloop.fn.init.prototype = Froogaloop.fn; 647 648 // Listens for the message event. 649 // W3C 650 if (window.addEventListener) { 651 window.addEventListener('message', onMessageReceived, false); 652 } 653 // IE 654 else { 655 window.attachEvent('onmessage', onMessageReceived); 656 } 657 658 // Expose froogaloop to the global object 659 return (window.Froogaloop = window.$f = Froogaloop); 660 661 })(); 662})();
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.