github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/video-js-5.9.0/video.js (about) 1 /** 2 * @license 3 * Video.js 5.9.0 <http://videojs.com/> 4 * Copyright Brightcove, Inc. <https://www.brightcove.com/> 5 * Available under Apache License Version 2.0 6 * <https://github.com/videojs/video.js/blob/master/LICENSE> 7 * 8 * Includes vtt.js <https://github.com/mozilla/vtt.js> 9 * Available under Apache License Version 2.0 10 * <https://github.com/mozilla/vtt.js/blob/master/LICENSE> 11 */ 12 13 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 14 (function (global){ 15 var topLevel = typeof global !== 'undefined' ? global : 16 typeof window !== 'undefined' ? window : {} 17 var minDoc = _dereq_('min-document'); 18 19 if (typeof document !== 'undefined') { 20 module.exports = document; 21 } else { 22 var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; 23 24 if (!doccy) { 25 doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; 26 } 27 28 module.exports = doccy; 29 } 30 31 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 32 //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvZG9jdW1lbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgdG9wTGV2ZWwgPSB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6XG4gICAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB7fVxudmFyIG1pbkRvYyA9IHJlcXVpcmUoJ21pbi1kb2N1bWVudCcpO1xuXG5pZiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZG9jdW1lbnQ7XG59IGVsc2Uge1xuICAgIHZhciBkb2NjeSA9IHRvcExldmVsWydfX0dMT0JBTF9ET0NVTUVOVF9DQUNIRUA0J107XG5cbiAgICBpZiAoIWRvY2N5KSB7XG4gICAgICAgIGRvY2N5ID0gdG9wTGV2ZWxbJ19fR0xPQkFMX0RPQ1VNRU5UX0NBQ0hFQDQnXSA9IG1pbkRvYztcbiAgICB9XG5cbiAgICBtb2R1bGUuZXhwb3J0cyA9IGRvY2N5O1xufVxuIl19 33 },{"min-document":3}],2:[function(_dereq_,module,exports){ 34 (function (global){ 35 if (typeof window !== "undefined") { 36 module.exports = window; 37 } else if (typeof global !== "undefined") { 38 module.exports = global; 39 } else if (typeof self !== "undefined"){ 40 module.exports = self; 41 } else { 42 module.exports = {}; 43 } 44 45 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 46 //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvd2luZG93LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdztcbn0gZWxzZSBpZiAodHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsO1xufSBlbHNlIGlmICh0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIil7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBzZWxmO1xufSBlbHNlIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHt9O1xufVxuIl19 47 },{}],3:[function(_dereq_,module,exports){ 48 49 },{}],4:[function(_dereq_,module,exports){ 50 var getNative = _dereq_('../internal/getNative'); 51 52 /* Native method references for those with the same name as other `lodash` methods. */ 53 var nativeNow = getNative(Date, 'now'); 54 55 /** 56 * Gets the number of milliseconds that have elapsed since the Unix epoch 57 * (1 January 1970 00:00:00 UTC). 58 * 59 * @static 60 * @memberOf _ 61 * @category Date 62 * @example 63 * 64 * _.defer(function(stamp) { 65 * console.log(_.now() - stamp); 66 * }, _.now()); 67 * // => logs the number of milliseconds it took for the deferred function to be invoked 68 */ 69 var now = nativeNow || function() { 70 return new Date().getTime(); 71 }; 72 73 module.exports = now; 74 75 },{"../internal/getNative":20}],5:[function(_dereq_,module,exports){ 76 var isObject = _dereq_('../lang/isObject'), 77 now = _dereq_('../date/now'); 78 79 /** Used as the `TypeError` message for "Functions" methods. */ 80 var FUNC_ERROR_TEXT = 'Expected a function'; 81 82 /* Native method references for those with the same name as other `lodash` methods. */ 83 var nativeMax = Math.max; 84 85 /** 86 * Creates a debounced function that delays invoking `func` until after `wait` 87 * milliseconds have elapsed since the last time the debounced function was 88 * invoked. The debounced function comes with a `cancel` method to cancel 89 * delayed invocations. Provide an options object to indicate that `func` 90 * should be invoked on the leading and/or trailing edge of the `wait` timeout. 91 * Subsequent calls to the debounced function return the result of the last 92 * `func` invocation. 93 * 94 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked 95 * on the trailing edge of the timeout only if the the debounced function is 96 * invoked more than once during the `wait` timeout. 97 * 98 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) 99 * for details over the differences between `_.debounce` and `_.throttle`. 100 * 101 * @static 102 * @memberOf _ 103 * @category Function 104 * @param {Function} func The function to debounce. 105 * @param {number} [wait=0] The number of milliseconds to delay. 106 * @param {Object} [options] The options object. 107 * @param {boolean} [options.leading=false] Specify invoking on the leading 108 * edge of the timeout. 109 * @param {number} [options.maxWait] The maximum time `func` is allowed to be 110 * delayed before it's invoked. 111 * @param {boolean} [options.trailing=true] Specify invoking on the trailing 112 * edge of the timeout. 113 * @returns {Function} Returns the new debounced function. 114 * @example 115 * 116 * // avoid costly calculations while the window size is in flux 117 * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); 118 * 119 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls 120 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { 121 * 'leading': true, 122 * 'trailing': false 123 * })); 124 * 125 * // ensure `batchLog` is invoked once after 1 second of debounced calls 126 * var source = new EventSource('/stream'); 127 * jQuery(source).on('message', _.debounce(batchLog, 250, { 128 * 'maxWait': 1000 129 * })); 130 * 131 * // cancel a debounced call 132 * var todoChanges = _.debounce(batchLog, 1000); 133 * Object.observe(models.todo, todoChanges); 134 * 135 * Object.observe(models, function(changes) { 136 * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { 137 * todoChanges.cancel(); 138 * } 139 * }, ['delete']); 140 * 141 * // ...at some point `models.todo` is changed 142 * models.todo.completed = true; 143 * 144 * // ...before 1 second has passed `models.todo` is deleted 145 * // which cancels the debounced `todoChanges` call 146 * delete models.todo; 147 */ 148 function debounce(func, wait, options) { 149 var args, 150 maxTimeoutId, 151 result, 152 stamp, 153 thisArg, 154 timeoutId, 155 trailingCall, 156 lastCalled = 0, 157 maxWait = false, 158 trailing = true; 159 160 if (typeof func != 'function') { 161 throw new TypeError(FUNC_ERROR_TEXT); 162 } 163 wait = wait < 0 ? 0 : (+wait || 0); 164 if (options === true) { 165 var leading = true; 166 trailing = false; 167 } else if (isObject(options)) { 168 leading = !!options.leading; 169 maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); 170 trailing = 'trailing' in options ? !!options.trailing : trailing; 171 } 172 173 function cancel() { 174 if (timeoutId) { 175 clearTimeout(timeoutId); 176 } 177 if (maxTimeoutId) { 178 clearTimeout(maxTimeoutId); 179 } 180 lastCalled = 0; 181 maxTimeoutId = timeoutId = trailingCall = undefined; 182 } 183 184 function complete(isCalled, id) { 185 if (id) { 186 clearTimeout(id); 187 } 188 maxTimeoutId = timeoutId = trailingCall = undefined; 189 if (isCalled) { 190 lastCalled = now(); 191 result = func.apply(thisArg, args); 192 if (!timeoutId && !maxTimeoutId) { 193 args = thisArg = undefined; 194 } 195 } 196 } 197 198 function delayed() { 199 var remaining = wait - (now() - stamp); 200 if (remaining <= 0 || remaining > wait) { 201 complete(trailingCall, maxTimeoutId); 202 } else { 203 timeoutId = setTimeout(delayed, remaining); 204 } 205 } 206 207 function maxDelayed() { 208 complete(trailing, timeoutId); 209 } 210 211 function debounced() { 212 args = arguments; 213 stamp = now(); 214 thisArg = this; 215 trailingCall = trailing && (timeoutId || !leading); 216 217 if (maxWait === false) { 218 var leadingCall = leading && !timeoutId; 219 } else { 220 if (!maxTimeoutId && !leading) { 221 lastCalled = stamp; 222 } 223 var remaining = maxWait - (stamp - lastCalled), 224 isCalled = remaining <= 0 || remaining > maxWait; 225 226 if (isCalled) { 227 if (maxTimeoutId) { 228 maxTimeoutId = clearTimeout(maxTimeoutId); 229 } 230 lastCalled = stamp; 231 result = func.apply(thisArg, args); 232 } 233 else if (!maxTimeoutId) { 234 maxTimeoutId = setTimeout(maxDelayed, remaining); 235 } 236 } 237 if (isCalled && timeoutId) { 238 timeoutId = clearTimeout(timeoutId); 239 } 240 else if (!timeoutId && wait !== maxWait) { 241 timeoutId = setTimeout(delayed, wait); 242 } 243 if (leadingCall) { 244 isCalled = true; 245 result = func.apply(thisArg, args); 246 } 247 if (isCalled && !timeoutId && !maxTimeoutId) { 248 args = thisArg = undefined; 249 } 250 return result; 251 } 252 debounced.cancel = cancel; 253 return debounced; 254 } 255 256 module.exports = debounce; 257 258 },{"../date/now":4,"../lang/isObject":33}],6:[function(_dereq_,module,exports){ 259 /** Used as the `TypeError` message for "Functions" methods. */ 260 var FUNC_ERROR_TEXT = 'Expected a function'; 261 262 /* Native method references for those with the same name as other `lodash` methods. */ 263 var nativeMax = Math.max; 264 265 /** 266 * Creates a function that invokes `func` with the `this` binding of the 267 * created function and arguments from `start` and beyond provided as an array. 268 * 269 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters). 270 * 271 * @static 272 * @memberOf _ 273 * @category Function 274 * @param {Function} func The function to apply a rest parameter to. 275 * @param {number} [start=func.length-1] The start position of the rest parameter. 276 * @returns {Function} Returns the new function. 277 * @example 278 * 279 * var say = _.restParam(function(what, names) { 280 * return what + ' ' + _.initial(names).join(', ') + 281 * (_.size(names) > 1 ? ', & ' : '') + _.last(names); 282 * }); 283 * 284 * say('hello', 'fred', 'barney', 'pebbles'); 285 * // => 'hello fred, barney, & pebbles' 286 */ 287 function restParam(func, start) { 288 if (typeof func != 'function') { 289 throw new TypeError(FUNC_ERROR_TEXT); 290 } 291 start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); 292 return function() { 293 var args = arguments, 294 index = -1, 295 length = nativeMax(args.length - start, 0), 296 rest = Array(length); 297 298 while (++index < length) { 299 rest[index] = args[start + index]; 300 } 301 switch (start) { 302 case 0: return func.call(this, rest); 303 case 1: return func.call(this, args[0], rest); 304 case 2: return func.call(this, args[0], args[1], rest); 305 } 306 var otherArgs = Array(start + 1); 307 index = -1; 308 while (++index < start) { 309 otherArgs[index] = args[index]; 310 } 311 otherArgs[start] = rest; 312 return func.apply(this, otherArgs); 313 }; 314 } 315 316 module.exports = restParam; 317 318 },{}],7:[function(_dereq_,module,exports){ 319 var debounce = _dereq_('./debounce'), 320 isObject = _dereq_('../lang/isObject'); 321 322 /** Used as the `TypeError` message for "Functions" methods. */ 323 var FUNC_ERROR_TEXT = 'Expected a function'; 324 325 /** 326 * Creates a throttled function that only invokes `func` at most once per 327 * every `wait` milliseconds. The throttled function comes with a `cancel` 328 * method to cancel delayed invocations. Provide an options object to indicate 329 * that `func` should be invoked on the leading and/or trailing edge of the 330 * `wait` timeout. Subsequent calls to the throttled function return the 331 * result of the last `func` call. 332 * 333 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked 334 * on the trailing edge of the timeout only if the the throttled function is 335 * invoked more than once during the `wait` timeout. 336 * 337 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) 338 * for details over the differences between `_.throttle` and `_.debounce`. 339 * 340 * @static 341 * @memberOf _ 342 * @category Function 343 * @param {Function} func The function to throttle. 344 * @param {number} [wait=0] The number of milliseconds to throttle invocations to. 345 * @param {Object} [options] The options object. 346 * @param {boolean} [options.leading=true] Specify invoking on the leading 347 * edge of the timeout. 348 * @param {boolean} [options.trailing=true] Specify invoking on the trailing 349 * edge of the timeout. 350 * @returns {Function} Returns the new throttled function. 351 * @example 352 * 353 * // avoid excessively updating the position while scrolling 354 * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); 355 * 356 * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes 357 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { 358 * 'trailing': false 359 * })); 360 * 361 * // cancel a trailing throttled call 362 * jQuery(window).on('popstate', throttled.cancel); 363 */ 364 function throttle(func, wait, options) { 365 var leading = true, 366 trailing = true; 367 368 if (typeof func != 'function') { 369 throw new TypeError(FUNC_ERROR_TEXT); 370 } 371 if (options === false) { 372 leading = false; 373 } else if (isObject(options)) { 374 leading = 'leading' in options ? !!options.leading : leading; 375 trailing = 'trailing' in options ? !!options.trailing : trailing; 376 } 377 return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); 378 } 379 380 module.exports = throttle; 381 382 },{"../lang/isObject":33,"./debounce":5}],8:[function(_dereq_,module,exports){ 383 /** 384 * Copies the values of `source` to `array`. 385 * 386 * @private 387 * @param {Array} source The array to copy values from. 388 * @param {Array} [array=[]] The array to copy values to. 389 * @returns {Array} Returns `array`. 390 */ 391 function arrayCopy(source, array) { 392 var index = -1, 393 length = source.length; 394 395 array || (array = Array(length)); 396 while (++index < length) { 397 array[index] = source[index]; 398 } 399 return array; 400 } 401 402 module.exports = arrayCopy; 403 404 },{}],9:[function(_dereq_,module,exports){ 405 /** 406 * A specialized version of `_.forEach` for arrays without support for callback 407 * shorthands and `this` binding. 408 * 409 * @private 410 * @param {Array} array The array to iterate over. 411 * @param {Function} iteratee The function invoked per iteration. 412 * @returns {Array} Returns `array`. 413 */ 414 function arrayEach(array, iteratee) { 415 var index = -1, 416 length = array.length; 417 418 while (++index < length) { 419 if (iteratee(array[index], index, array) === false) { 420 break; 421 } 422 } 423 return array; 424 } 425 426 module.exports = arrayEach; 427 428 },{}],10:[function(_dereq_,module,exports){ 429 /** 430 * Copies properties of `source` to `object`. 431 * 432 * @private 433 * @param {Object} source The object to copy properties from. 434 * @param {Array} props The property names to copy. 435 * @param {Object} [object={}] The object to copy properties to. 436 * @returns {Object} Returns `object`. 437 */ 438 function baseCopy(source, props, object) { 439 object || (object = {}); 440 441 var index = -1, 442 length = props.length; 443 444 while (++index < length) { 445 var key = props[index]; 446 object[key] = source[key]; 447 } 448 return object; 449 } 450 451 module.exports = baseCopy; 452 453 },{}],11:[function(_dereq_,module,exports){ 454 var createBaseFor = _dereq_('./createBaseFor'); 455 456 /** 457 * The base implementation of `baseForIn` and `baseForOwn` which iterates 458 * over `object` properties returned by `keysFunc` invoking `iteratee` for 459 * each property. Iteratee functions may exit iteration early by explicitly 460 * returning `false`. 461 * 462 * @private 463 * @param {Object} object The object to iterate over. 464 * @param {Function} iteratee The function invoked per iteration. 465 * @param {Function} keysFunc The function to get the keys of `object`. 466 * @returns {Object} Returns `object`. 467 */ 468 var baseFor = createBaseFor(); 469 470 module.exports = baseFor; 471 472 },{"./createBaseFor":18}],12:[function(_dereq_,module,exports){ 473 var baseFor = _dereq_('./baseFor'), 474 keysIn = _dereq_('../object/keysIn'); 475 476 /** 477 * The base implementation of `_.forIn` without support for callback 478 * shorthands and `this` binding. 479 * 480 * @private 481 * @param {Object} object The object to iterate over. 482 * @param {Function} iteratee The function invoked per iteration. 483 * @returns {Object} Returns `object`. 484 */ 485 function baseForIn(object, iteratee) { 486 return baseFor(object, iteratee, keysIn); 487 } 488 489 module.exports = baseForIn; 490 491 },{"../object/keysIn":39,"./baseFor":11}],13:[function(_dereq_,module,exports){ 492 var arrayEach = _dereq_('./arrayEach'), 493 baseMergeDeep = _dereq_('./baseMergeDeep'), 494 isArray = _dereq_('../lang/isArray'), 495 isArrayLike = _dereq_('./isArrayLike'), 496 isObject = _dereq_('../lang/isObject'), 497 isObjectLike = _dereq_('./isObjectLike'), 498 isTypedArray = _dereq_('../lang/isTypedArray'), 499 keys = _dereq_('../object/keys'); 500 501 /** 502 * The base implementation of `_.merge` without support for argument juggling, 503 * multiple sources, and `this` binding `customizer` functions. 504 * 505 * @private 506 * @param {Object} object The destination object. 507 * @param {Object} source The source object. 508 * @param {Function} [customizer] The function to customize merged values. 509 * @param {Array} [stackA=[]] Tracks traversed source objects. 510 * @param {Array} [stackB=[]] Associates values with source counterparts. 511 * @returns {Object} Returns `object`. 512 */ 513 function baseMerge(object, source, customizer, stackA, stackB) { 514 if (!isObject(object)) { 515 return object; 516 } 517 var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), 518 props = isSrcArr ? undefined : keys(source); 519 520 arrayEach(props || source, function(srcValue, key) { 521 if (props) { 522 key = srcValue; 523 srcValue = source[key]; 524 } 525 if (isObjectLike(srcValue)) { 526 stackA || (stackA = []); 527 stackB || (stackB = []); 528 baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); 529 } 530 else { 531 var value = object[key], 532 result = customizer ? customizer(value, srcValue, key, object, source) : undefined, 533 isCommon = result === undefined; 534 535 if (isCommon) { 536 result = srcValue; 537 } 538 if ((result !== undefined || (isSrcArr && !(key in object))) && 539 (isCommon || (result === result ? (result !== value) : (value === value)))) { 540 object[key] = result; 541 } 542 } 543 }); 544 return object; 545 } 546 547 module.exports = baseMerge; 548 549 },{"../lang/isArray":30,"../lang/isObject":33,"../lang/isTypedArray":36,"../object/keys":38,"./arrayEach":9,"./baseMergeDeep":14,"./isArrayLike":21,"./isObjectLike":26}],14:[function(_dereq_,module,exports){ 550 var arrayCopy = _dereq_('./arrayCopy'), 551 isArguments = _dereq_('../lang/isArguments'), 552 isArray = _dereq_('../lang/isArray'), 553 isArrayLike = _dereq_('./isArrayLike'), 554 isPlainObject = _dereq_('../lang/isPlainObject'), 555 isTypedArray = _dereq_('../lang/isTypedArray'), 556 toPlainObject = _dereq_('../lang/toPlainObject'); 557 558 /** 559 * A specialized version of `baseMerge` for arrays and objects which performs 560 * deep merges and tracks traversed objects enabling objects with circular 561 * references to be merged. 562 * 563 * @private 564 * @param {Object} object The destination object. 565 * @param {Object} source The source object. 566 * @param {string} key The key of the value to merge. 567 * @param {Function} mergeFunc The function to merge values. 568 * @param {Function} [customizer] The function to customize merged values. 569 * @param {Array} [stackA=[]] Tracks traversed source objects. 570 * @param {Array} [stackB=[]] Associates values with source counterparts. 571 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. 572 */ 573 function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { 574 var length = stackA.length, 575 srcValue = source[key]; 576 577 while (length--) { 578 if (stackA[length] == srcValue) { 579 object[key] = stackB[length]; 580 return; 581 } 582 } 583 var value = object[key], 584 result = customizer ? customizer(value, srcValue, key, object, source) : undefined, 585 isCommon = result === undefined; 586 587 if (isCommon) { 588 result = srcValue; 589 if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { 590 result = isArray(value) 591 ? value 592 : (isArrayLike(value) ? arrayCopy(value) : []); 593 } 594 else if (isPlainObject(srcValue) || isArguments(srcValue)) { 595 result = isArguments(value) 596 ? toPlainObject(value) 597 : (isPlainObject(value) ? value : {}); 598 } 599 else { 600 isCommon = false; 601 } 602 } 603 // Add the source value to the stack of traversed objects and associate 604 // it with its merged value. 605 stackA.push(srcValue); 606 stackB.push(result); 607 608 if (isCommon) { 609 // Recursively merge objects and arrays (susceptible to call stack limits). 610 object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); 611 } else if (result === result ? (result !== value) : (value === value)) { 612 object[key] = result; 613 } 614 } 615 616 module.exports = baseMergeDeep; 617 618 },{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isPlainObject":34,"../lang/isTypedArray":36,"../lang/toPlainObject":37,"./arrayCopy":8,"./isArrayLike":21}],15:[function(_dereq_,module,exports){ 619 var toObject = _dereq_('./toObject'); 620 621 /** 622 * The base implementation of `_.property` without support for deep paths. 623 * 624 * @private 625 * @param {string} key The key of the property to get. 626 * @returns {Function} Returns the new function. 627 */ 628 function baseProperty(key) { 629 return function(object) { 630 return object == null ? undefined : toObject(object)[key]; 631 }; 632 } 633 634 module.exports = baseProperty; 635 636 },{"./toObject":28}],16:[function(_dereq_,module,exports){ 637 var identity = _dereq_('../utility/identity'); 638 639 /** 640 * A specialized version of `baseCallback` which only supports `this` binding 641 * and specifying the number of arguments to provide to `func`. 642 * 643 * @private 644 * @param {Function} func The function to bind. 645 * @param {*} thisArg The `this` binding of `func`. 646 * @param {number} [argCount] The number of arguments to provide to `func`. 647 * @returns {Function} Returns the callback. 648 */ 649 function bindCallback(func, thisArg, argCount) { 650 if (typeof func != 'function') { 651 return identity; 652 } 653 if (thisArg === undefined) { 654 return func; 655 } 656 switch (argCount) { 657 case 1: return function(value) { 658 return func.call(thisArg, value); 659 }; 660 case 3: return function(value, index, collection) { 661 return func.call(thisArg, value, index, collection); 662 }; 663 case 4: return function(accumulator, value, index, collection) { 664 return func.call(thisArg, accumulator, value, index, collection); 665 }; 666 case 5: return function(value, other, key, object, source) { 667 return func.call(thisArg, value, other, key, object, source); 668 }; 669 } 670 return function() { 671 return func.apply(thisArg, arguments); 672 }; 673 } 674 675 module.exports = bindCallback; 676 677 },{"../utility/identity":42}],17:[function(_dereq_,module,exports){ 678 var bindCallback = _dereq_('./bindCallback'), 679 isIterateeCall = _dereq_('./isIterateeCall'), 680 restParam = _dereq_('../function/restParam'); 681 682 /** 683 * Creates a `_.assign`, `_.defaults`, or `_.merge` function. 684 * 685 * @private 686 * @param {Function} assigner The function to assign values. 687 * @returns {Function} Returns the new assigner function. 688 */ 689 function createAssigner(assigner) { 690 return restParam(function(object, sources) { 691 var index = -1, 692 length = object == null ? 0 : sources.length, 693 customizer = length > 2 ? sources[length - 2] : undefined, 694 guard = length > 2 ? sources[2] : undefined, 695 thisArg = length > 1 ? sources[length - 1] : undefined; 696 697 if (typeof customizer == 'function') { 698 customizer = bindCallback(customizer, thisArg, 5); 699 length -= 2; 700 } else { 701 customizer = typeof thisArg == 'function' ? thisArg : undefined; 702 length -= (customizer ? 1 : 0); 703 } 704 if (guard && isIterateeCall(sources[0], sources[1], guard)) { 705 customizer = length < 3 ? undefined : customizer; 706 length = 1; 707 } 708 while (++index < length) { 709 var source = sources[index]; 710 if (source) { 711 assigner(object, source, customizer); 712 } 713 } 714 return object; 715 }); 716 } 717 718 module.exports = createAssigner; 719 720 },{"../function/restParam":6,"./bindCallback":16,"./isIterateeCall":24}],18:[function(_dereq_,module,exports){ 721 var toObject = _dereq_('./toObject'); 722 723 /** 724 * Creates a base function for `_.forIn` or `_.forInRight`. 725 * 726 * @private 727 * @param {boolean} [fromRight] Specify iterating from right to left. 728 * @returns {Function} Returns the new base function. 729 */ 730 function createBaseFor(fromRight) { 731 return function(object, iteratee, keysFunc) { 732 var iterable = toObject(object), 733 props = keysFunc(object), 734 length = props.length, 735 index = fromRight ? length : -1; 736 737 while ((fromRight ? index-- : ++index < length)) { 738 var key = props[index]; 739 if (iteratee(iterable[key], key, iterable) === false) { 740 break; 741 } 742 } 743 return object; 744 }; 745 } 746 747 module.exports = createBaseFor; 748 749 },{"./toObject":28}],19:[function(_dereq_,module,exports){ 750 var baseProperty = _dereq_('./baseProperty'); 751 752 /** 753 * Gets the "length" property value of `object`. 754 * 755 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) 756 * that affects Safari on at least iOS 8.1-8.3 ARM64. 757 * 758 * @private 759 * @param {Object} object The object to query. 760 * @returns {*} Returns the "length" value. 761 */ 762 var getLength = baseProperty('length'); 763 764 module.exports = getLength; 765 766 },{"./baseProperty":15}],20:[function(_dereq_,module,exports){ 767 var isNative = _dereq_('../lang/isNative'); 768 769 /** 770 * Gets the native function at `key` of `object`. 771 * 772 * @private 773 * @param {Object} object The object to query. 774 * @param {string} key The key of the method to get. 775 * @returns {*} Returns the function if it's native, else `undefined`. 776 */ 777 function getNative(object, key) { 778 var value = object == null ? undefined : object[key]; 779 return isNative(value) ? value : undefined; 780 } 781 782 module.exports = getNative; 783 784 },{"../lang/isNative":32}],21:[function(_dereq_,module,exports){ 785 var getLength = _dereq_('./getLength'), 786 isLength = _dereq_('./isLength'); 787 788 /** 789 * Checks if `value` is array-like. 790 * 791 * @private 792 * @param {*} value The value to check. 793 * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 794 */ 795 function isArrayLike(value) { 796 return value != null && isLength(getLength(value)); 797 } 798 799 module.exports = isArrayLike; 800 801 },{"./getLength":19,"./isLength":25}],22:[function(_dereq_,module,exports){ 802 /** 803 * Checks if `value` is a host object in IE < 9. 804 * 805 * @private 806 * @param {*} value The value to check. 807 * @returns {boolean} Returns `true` if `value` is a host object, else `false`. 808 */ 809 var isHostObject = (function() { 810 try { 811 Object({ 'toString': 0 } + ''); 812 } catch(e) { 813 return function() { return false; }; 814 } 815 return function(value) { 816 // IE < 9 presents many host objects as `Object` objects that can coerce 817 // to strings despite having improperly defined `toString` methods. 818 return typeof value.toString != 'function' && typeof (value + '') == 'string'; 819 }; 820 }()); 821 822 module.exports = isHostObject; 823 824 },{}],23:[function(_dereq_,module,exports){ 825 /** Used to detect unsigned integer values. */ 826 var reIsUint = /^\d+$/; 827 828 /** 829 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) 830 * of an array-like value. 831 */ 832 var MAX_SAFE_INTEGER = 9007199254740991; 833 834 /** 835 * Checks if `value` is a valid array-like index. 836 * 837 * @private 838 * @param {*} value The value to check. 839 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 840 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 841 */ 842 function isIndex(value, length) { 843 value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; 844 length = length == null ? MAX_SAFE_INTEGER : length; 845 return value > -1 && value % 1 == 0 && value < length; 846 } 847 848 module.exports = isIndex; 849 850 },{}],24:[function(_dereq_,module,exports){ 851 var isArrayLike = _dereq_('./isArrayLike'), 852 isIndex = _dereq_('./isIndex'), 853 isObject = _dereq_('../lang/isObject'); 854 855 /** 856 * Checks if the provided arguments are from an iteratee call. 857 * 858 * @private 859 * @param {*} value The potential iteratee value argument. 860 * @param {*} index The potential iteratee index or key argument. 861 * @param {*} object The potential iteratee object argument. 862 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. 863 */ 864 function isIterateeCall(value, index, object) { 865 if (!isObject(object)) { 866 return false; 867 } 868 var type = typeof index; 869 if (type == 'number' 870 ? (isArrayLike(object) && isIndex(index, object.length)) 871 : (type == 'string' && index in object)) { 872 var other = object[index]; 873 return value === value ? (value === other) : (other !== other); 874 } 875 return false; 876 } 877 878 module.exports = isIterateeCall; 879 880 },{"../lang/isObject":33,"./isArrayLike":21,"./isIndex":23}],25:[function(_dereq_,module,exports){ 881 /** 882 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) 883 * of an array-like value. 884 */ 885 var MAX_SAFE_INTEGER = 9007199254740991; 886 887 /** 888 * Checks if `value` is a valid array-like length. 889 * 890 * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). 891 * 892 * @private 893 * @param {*} value The value to check. 894 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 895 */ 896 function isLength(value) { 897 return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 898 } 899 900 module.exports = isLength; 901 902 },{}],26:[function(_dereq_,module,exports){ 903 /** 904 * Checks if `value` is object-like. 905 * 906 * @private 907 * @param {*} value The value to check. 908 * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 909 */ 910 function isObjectLike(value) { 911 return !!value && typeof value == 'object'; 912 } 913 914 module.exports = isObjectLike; 915 916 },{}],27:[function(_dereq_,module,exports){ 917 var isArguments = _dereq_('../lang/isArguments'), 918 isArray = _dereq_('../lang/isArray'), 919 isIndex = _dereq_('./isIndex'), 920 isLength = _dereq_('./isLength'), 921 isString = _dereq_('../lang/isString'), 922 keysIn = _dereq_('../object/keysIn'); 923 924 /** Used for native method references. */ 925 var objectProto = Object.prototype; 926 927 /** Used to check objects for own properties. */ 928 var hasOwnProperty = objectProto.hasOwnProperty; 929 930 /** 931 * A fallback implementation of `Object.keys` which creates an array of the 932 * own enumerable property names of `object`. 933 * 934 * @private 935 * @param {Object} object The object to query. 936 * @returns {Array} Returns the array of property names. 937 */ 938 function shimKeys(object) { 939 var props = keysIn(object), 940 propsLength = props.length, 941 length = propsLength && object.length; 942 943 var allowIndexes = !!length && isLength(length) && 944 (isArray(object) || isArguments(object) || isString(object)); 945 946 var index = -1, 947 result = []; 948 949 while (++index < propsLength) { 950 var key = props[index]; 951 if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { 952 result.push(key); 953 } 954 } 955 return result; 956 } 957 958 module.exports = shimKeys; 959 960 },{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isString":35,"../object/keysIn":39,"./isIndex":23,"./isLength":25}],28:[function(_dereq_,module,exports){ 961 var isObject = _dereq_('../lang/isObject'), 962 isString = _dereq_('../lang/isString'), 963 support = _dereq_('../support'); 964 965 /** 966 * Converts `value` to an object if it's not one. 967 * 968 * @private 969 * @param {*} value The value to process. 970 * @returns {Object} Returns the object. 971 */ 972 function toObject(value) { 973 if (support.unindexedChars && isString(value)) { 974 var index = -1, 975 length = value.length, 976 result = Object(value); 977 978 while (++index < length) { 979 result[index] = value.charAt(index); 980 } 981 return result; 982 } 983 return isObject(value) ? value : Object(value); 984 } 985 986 module.exports = toObject; 987 988 },{"../lang/isObject":33,"../lang/isString":35,"../support":41}],29:[function(_dereq_,module,exports){ 989 var isArrayLike = _dereq_('../internal/isArrayLike'), 990 isObjectLike = _dereq_('../internal/isObjectLike'); 991 992 /** Used for native method references. */ 993 var objectProto = Object.prototype; 994 995 /** Used to check objects for own properties. */ 996 var hasOwnProperty = objectProto.hasOwnProperty; 997 998 /** Native method references. */ 999 var propertyIsEnumerable = objectProto.propertyIsEnumerable; 1000 1001 /** 1002 * Checks if `value` is classified as an `arguments` object. 1003 * 1004 * @static 1005 * @memberOf _ 1006 * @category Lang 1007 * @param {*} value The value to check. 1008 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 1009 * @example 1010 * 1011 * _.isArguments(function() { return arguments; }()); 1012 * // => true 1013 * 1014 * _.isArguments([1, 2, 3]); 1015 * // => false 1016 */ 1017 function isArguments(value) { 1018 return isObjectLike(value) && isArrayLike(value) && 1019 hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); 1020 } 1021 1022 module.exports = isArguments; 1023 1024 },{"../internal/isArrayLike":21,"../internal/isObjectLike":26}],30:[function(_dereq_,module,exports){ 1025 var getNative = _dereq_('../internal/getNative'), 1026 isLength = _dereq_('../internal/isLength'), 1027 isObjectLike = _dereq_('../internal/isObjectLike'); 1028 1029 /** `Object#toString` result references. */ 1030 var arrayTag = '[object Array]'; 1031 1032 /** Used for native method references. */ 1033 var objectProto = Object.prototype; 1034 1035 /** 1036 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1037 * of values. 1038 */ 1039 var objToString = objectProto.toString; 1040 1041 /* Native method references for those with the same name as other `lodash` methods. */ 1042 var nativeIsArray = getNative(Array, 'isArray'); 1043 1044 /** 1045 * Checks if `value` is classified as an `Array` object. 1046 * 1047 * @static 1048 * @memberOf _ 1049 * @category Lang 1050 * @param {*} value The value to check. 1051 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 1052 * @example 1053 * 1054 * _.isArray([1, 2, 3]); 1055 * // => true 1056 * 1057 * _.isArray(function() { return arguments; }()); 1058 * // => false 1059 */ 1060 var isArray = nativeIsArray || function(value) { 1061 return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; 1062 }; 1063 1064 module.exports = isArray; 1065 1066 },{"../internal/getNative":20,"../internal/isLength":25,"../internal/isObjectLike":26}],31:[function(_dereq_,module,exports){ 1067 var isObject = _dereq_('./isObject'); 1068 1069 /** `Object#toString` result references. */ 1070 var funcTag = '[object Function]'; 1071 1072 /** Used for native method references. */ 1073 var objectProto = Object.prototype; 1074 1075 /** 1076 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1077 * of values. 1078 */ 1079 var objToString = objectProto.toString; 1080 1081 /** 1082 * Checks if `value` is classified as a `Function` object. 1083 * 1084 * @static 1085 * @memberOf _ 1086 * @category Lang 1087 * @param {*} value The value to check. 1088 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 1089 * @example 1090 * 1091 * _.isFunction(_); 1092 * // => true 1093 * 1094 * _.isFunction(/abc/); 1095 * // => false 1096 */ 1097 function isFunction(value) { 1098 // The use of `Object#toString` avoids issues with the `typeof` operator 1099 // in older versions of Chrome and Safari which return 'function' for regexes 1100 // and Safari 8 which returns 'object' for typed array constructors. 1101 return isObject(value) && objToString.call(value) == funcTag; 1102 } 1103 1104 module.exports = isFunction; 1105 1106 },{"./isObject":33}],32:[function(_dereq_,module,exports){ 1107 var isFunction = _dereq_('./isFunction'), 1108 isHostObject = _dereq_('../internal/isHostObject'), 1109 isObjectLike = _dereq_('../internal/isObjectLike'); 1110 1111 /** Used to detect host constructors (Safari > 5). */ 1112 var reIsHostCtor = /^\[object .+?Constructor\]$/; 1113 1114 /** Used for native method references. */ 1115 var objectProto = Object.prototype; 1116 1117 /** Used to resolve the decompiled source of functions. */ 1118 var fnToString = Function.prototype.toString; 1119 1120 /** Used to check objects for own properties. */ 1121 var hasOwnProperty = objectProto.hasOwnProperty; 1122 1123 /** Used to detect if a method is native. */ 1124 var reIsNative = RegExp('^' + 1125 fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') 1126 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 1127 ); 1128 1129 /** 1130 * Checks if `value` is a native function. 1131 * 1132 * @static 1133 * @memberOf _ 1134 * @category Lang 1135 * @param {*} value The value to check. 1136 * @returns {boolean} Returns `true` if `value` is a native function, else `false`. 1137 * @example 1138 * 1139 * _.isNative(Array.prototype.push); 1140 * // => true 1141 * 1142 * _.isNative(_); 1143 * // => false 1144 */ 1145 function isNative(value) { 1146 if (value == null) { 1147 return false; 1148 } 1149 if (isFunction(value)) { 1150 return reIsNative.test(fnToString.call(value)); 1151 } 1152 return isObjectLike(value) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value); 1153 } 1154 1155 module.exports = isNative; 1156 1157 },{"../internal/isHostObject":22,"../internal/isObjectLike":26,"./isFunction":31}],33:[function(_dereq_,module,exports){ 1158 /** 1159 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. 1160 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 1161 * 1162 * @static 1163 * @memberOf _ 1164 * @category Lang 1165 * @param {*} value The value to check. 1166 * @returns {boolean} Returns `true` if `value` is an object, else `false`. 1167 * @example 1168 * 1169 * _.isObject({}); 1170 * // => true 1171 * 1172 * _.isObject([1, 2, 3]); 1173 * // => true 1174 * 1175 * _.isObject(1); 1176 * // => false 1177 */ 1178 function isObject(value) { 1179 // Avoid a V8 JIT bug in Chrome 19-20. 1180 // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. 1181 var type = typeof value; 1182 return !!value && (type == 'object' || type == 'function'); 1183 } 1184 1185 module.exports = isObject; 1186 1187 },{}],34:[function(_dereq_,module,exports){ 1188 var baseForIn = _dereq_('../internal/baseForIn'), 1189 isArguments = _dereq_('./isArguments'), 1190 isHostObject = _dereq_('../internal/isHostObject'), 1191 isObjectLike = _dereq_('../internal/isObjectLike'), 1192 support = _dereq_('../support'); 1193 1194 /** `Object#toString` result references. */ 1195 var objectTag = '[object Object]'; 1196 1197 /** Used for native method references. */ 1198 var objectProto = Object.prototype; 1199 1200 /** Used to check objects for own properties. */ 1201 var hasOwnProperty = objectProto.hasOwnProperty; 1202 1203 /** 1204 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1205 * of values. 1206 */ 1207 var objToString = objectProto.toString; 1208 1209 /** 1210 * Checks if `value` is a plain object, that is, an object created by the 1211 * `Object` constructor or one with a `[[Prototype]]` of `null`. 1212 * 1213 * **Note:** This method assumes objects created by the `Object` constructor 1214 * have no inherited enumerable properties. 1215 * 1216 * @static 1217 * @memberOf _ 1218 * @category Lang 1219 * @param {*} value The value to check. 1220 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. 1221 * @example 1222 * 1223 * function Foo() { 1224 * this.a = 1; 1225 * } 1226 * 1227 * _.isPlainObject(new Foo); 1228 * // => false 1229 * 1230 * _.isPlainObject([1, 2, 3]); 1231 * // => false 1232 * 1233 * _.isPlainObject({ 'x': 0, 'y': 0 }); 1234 * // => true 1235 * 1236 * _.isPlainObject(Object.create(null)); 1237 * // => true 1238 */ 1239 function isPlainObject(value) { 1240 var Ctor; 1241 1242 // Exit early for non `Object` objects. 1243 if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value) && !isArguments(value)) || 1244 (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { 1245 return false; 1246 } 1247 // IE < 9 iterates inherited properties before own properties. If the first 1248 // iterated property is an object's own property then there are no inherited 1249 // enumerable properties. 1250 var result; 1251 if (support.ownLast) { 1252 baseForIn(value, function(subValue, key, object) { 1253 result = hasOwnProperty.call(object, key); 1254 return false; 1255 }); 1256 return result !== false; 1257 } 1258 // In most environments an object's own properties are iterated before 1259 // its inherited properties. If the last iterated property is an object's 1260 // own property then there are no inherited enumerable properties. 1261 baseForIn(value, function(subValue, key) { 1262 result = key; 1263 }); 1264 return result === undefined || hasOwnProperty.call(value, result); 1265 } 1266 1267 module.exports = isPlainObject; 1268 1269 },{"../internal/baseForIn":12,"../internal/isHostObject":22,"../internal/isObjectLike":26,"../support":41,"./isArguments":29}],35:[function(_dereq_,module,exports){ 1270 var isObjectLike = _dereq_('../internal/isObjectLike'); 1271 1272 /** `Object#toString` result references. */ 1273 var stringTag = '[object String]'; 1274 1275 /** Used for native method references. */ 1276 var objectProto = Object.prototype; 1277 1278 /** 1279 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1280 * of values. 1281 */ 1282 var objToString = objectProto.toString; 1283 1284 /** 1285 * Checks if `value` is classified as a `String` primitive or object. 1286 * 1287 * @static 1288 * @memberOf _ 1289 * @category Lang 1290 * @param {*} value The value to check. 1291 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 1292 * @example 1293 * 1294 * _.isString('abc'); 1295 * // => true 1296 * 1297 * _.isString(1); 1298 * // => false 1299 */ 1300 function isString(value) { 1301 return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); 1302 } 1303 1304 module.exports = isString; 1305 1306 },{"../internal/isObjectLike":26}],36:[function(_dereq_,module,exports){ 1307 var isLength = _dereq_('../internal/isLength'), 1308 isObjectLike = _dereq_('../internal/isObjectLike'); 1309 1310 /** `Object#toString` result references. */ 1311 var argsTag = '[object Arguments]', 1312 arrayTag = '[object Array]', 1313 boolTag = '[object Boolean]', 1314 dateTag = '[object Date]', 1315 errorTag = '[object Error]', 1316 funcTag = '[object Function]', 1317 mapTag = '[object Map]', 1318 numberTag = '[object Number]', 1319 objectTag = '[object Object]', 1320 regexpTag = '[object RegExp]', 1321 setTag = '[object Set]', 1322 stringTag = '[object String]', 1323 weakMapTag = '[object WeakMap]'; 1324 1325 var arrayBufferTag = '[object ArrayBuffer]', 1326 float32Tag = '[object Float32Array]', 1327 float64Tag = '[object Float64Array]', 1328 int8Tag = '[object Int8Array]', 1329 int16Tag = '[object Int16Array]', 1330 int32Tag = '[object Int32Array]', 1331 uint8Tag = '[object Uint8Array]', 1332 uint8ClampedTag = '[object Uint8ClampedArray]', 1333 uint16Tag = '[object Uint16Array]', 1334 uint32Tag = '[object Uint32Array]'; 1335 1336 /** Used to identify `toStringTag` values of typed arrays. */ 1337 var typedArrayTags = {}; 1338 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = 1339 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = 1340 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = 1341 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = 1342 typedArrayTags[uint32Tag] = true; 1343 typedArrayTags[argsTag] = typedArrayTags[arrayTag] = 1344 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = 1345 typedArrayTags[dateTag] = typedArrayTags[errorTag] = 1346 typedArrayTags[funcTag] = typedArrayTags[mapTag] = 1347 typedArrayTags[numberTag] = typedArrayTags[objectTag] = 1348 typedArrayTags[regexpTag] = typedArrayTags[setTag] = 1349 typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; 1350 1351 /** Used for native method references. */ 1352 var objectProto = Object.prototype; 1353 1354 /** 1355 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1356 * of values. 1357 */ 1358 var objToString = objectProto.toString; 1359 1360 /** 1361 * Checks if `value` is classified as a typed array. 1362 * 1363 * @static 1364 * @memberOf _ 1365 * @category Lang 1366 * @param {*} value The value to check. 1367 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. 1368 * @example 1369 * 1370 * _.isTypedArray(new Uint8Array); 1371 * // => true 1372 * 1373 * _.isTypedArray([]); 1374 * // => false 1375 */ 1376 function isTypedArray(value) { 1377 return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; 1378 } 1379 1380 module.exports = isTypedArray; 1381 1382 },{"../internal/isLength":25,"../internal/isObjectLike":26}],37:[function(_dereq_,module,exports){ 1383 var baseCopy = _dereq_('../internal/baseCopy'), 1384 keysIn = _dereq_('../object/keysIn'); 1385 1386 /** 1387 * Converts `value` to a plain object flattening inherited enumerable 1388 * properties of `value` to own properties of the plain object. 1389 * 1390 * @static 1391 * @memberOf _ 1392 * @category Lang 1393 * @param {*} value The value to convert. 1394 * @returns {Object} Returns the converted plain object. 1395 * @example 1396 * 1397 * function Foo() { 1398 * this.b = 2; 1399 * } 1400 * 1401 * Foo.prototype.c = 3; 1402 * 1403 * _.assign({ 'a': 1 }, new Foo); 1404 * // => { 'a': 1, 'b': 2 } 1405 * 1406 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); 1407 * // => { 'a': 1, 'b': 2, 'c': 3 } 1408 */ 1409 function toPlainObject(value) { 1410 return baseCopy(value, keysIn(value)); 1411 } 1412 1413 module.exports = toPlainObject; 1414 1415 },{"../internal/baseCopy":10,"../object/keysIn":39}],38:[function(_dereq_,module,exports){ 1416 var getNative = _dereq_('../internal/getNative'), 1417 isArrayLike = _dereq_('../internal/isArrayLike'), 1418 isObject = _dereq_('../lang/isObject'), 1419 shimKeys = _dereq_('../internal/shimKeys'), 1420 support = _dereq_('../support'); 1421 1422 /* Native method references for those with the same name as other `lodash` methods. */ 1423 var nativeKeys = getNative(Object, 'keys'); 1424 1425 /** 1426 * Creates an array of the own enumerable property names of `object`. 1427 * 1428 * **Note:** Non-object values are coerced to objects. See the 1429 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) 1430 * for more details. 1431 * 1432 * @static 1433 * @memberOf _ 1434 * @category Object 1435 * @param {Object} object The object to query. 1436 * @returns {Array} Returns the array of property names. 1437 * @example 1438 * 1439 * function Foo() { 1440 * this.a = 1; 1441 * this.b = 2; 1442 * } 1443 * 1444 * Foo.prototype.c = 3; 1445 * 1446 * _.keys(new Foo); 1447 * // => ['a', 'b'] (iteration order is not guaranteed) 1448 * 1449 * _.keys('hi'); 1450 * // => ['0', '1'] 1451 */ 1452 var keys = !nativeKeys ? shimKeys : function(object) { 1453 var Ctor = object == null ? undefined : object.constructor; 1454 if ((typeof Ctor == 'function' && Ctor.prototype === object) || 1455 (typeof object == 'function' ? support.enumPrototypes : isArrayLike(object))) { 1456 return shimKeys(object); 1457 } 1458 return isObject(object) ? nativeKeys(object) : []; 1459 }; 1460 1461 module.exports = keys; 1462 1463 },{"../internal/getNative":20,"../internal/isArrayLike":21,"../internal/shimKeys":27,"../lang/isObject":33,"../support":41}],39:[function(_dereq_,module,exports){ 1464 var arrayEach = _dereq_('../internal/arrayEach'), 1465 isArguments = _dereq_('../lang/isArguments'), 1466 isArray = _dereq_('../lang/isArray'), 1467 isFunction = _dereq_('../lang/isFunction'), 1468 isIndex = _dereq_('../internal/isIndex'), 1469 isLength = _dereq_('../internal/isLength'), 1470 isObject = _dereq_('../lang/isObject'), 1471 isString = _dereq_('../lang/isString'), 1472 support = _dereq_('../support'); 1473 1474 /** `Object#toString` result references. */ 1475 var arrayTag = '[object Array]', 1476 boolTag = '[object Boolean]', 1477 dateTag = '[object Date]', 1478 errorTag = '[object Error]', 1479 funcTag = '[object Function]', 1480 numberTag = '[object Number]', 1481 objectTag = '[object Object]', 1482 regexpTag = '[object RegExp]', 1483 stringTag = '[object String]'; 1484 1485 /** Used to fix the JScript `[[DontEnum]]` bug. */ 1486 var shadowProps = [ 1487 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 1488 'toLocaleString', 'toString', 'valueOf' 1489 ]; 1490 1491 /** Used for native method references. */ 1492 var errorProto = Error.prototype, 1493 objectProto = Object.prototype, 1494 stringProto = String.prototype; 1495 1496 /** Used to check objects for own properties. */ 1497 var hasOwnProperty = objectProto.hasOwnProperty; 1498 1499 /** 1500 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 1501 * of values. 1502 */ 1503 var objToString = objectProto.toString; 1504 1505 /** Used to avoid iterating over non-enumerable properties in IE < 9. */ 1506 var nonEnumProps = {}; 1507 nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; 1508 nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true }; 1509 nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true }; 1510 nonEnumProps[objectTag] = { 'constructor': true }; 1511 1512 arrayEach(shadowProps, function(key) { 1513 for (var tag in nonEnumProps) { 1514 if (hasOwnProperty.call(nonEnumProps, tag)) { 1515 var props = nonEnumProps[tag]; 1516 props[key] = hasOwnProperty.call(props, key); 1517 } 1518 } 1519 }); 1520 1521 /** 1522 * Creates an array of the own and inherited enumerable property names of `object`. 1523 * 1524 * **Note:** Non-object values are coerced to objects. 1525 * 1526 * @static 1527 * @memberOf _ 1528 * @category Object 1529 * @param {Object} object The object to query. 1530 * @returns {Array} Returns the array of property names. 1531 * @example 1532 * 1533 * function Foo() { 1534 * this.a = 1; 1535 * this.b = 2; 1536 * } 1537 * 1538 * Foo.prototype.c = 3; 1539 * 1540 * _.keysIn(new Foo); 1541 * // => ['a', 'b', 'c'] (iteration order is not guaranteed) 1542 */ 1543 function keysIn(object) { 1544 if (object == null) { 1545 return []; 1546 } 1547 if (!isObject(object)) { 1548 object = Object(object); 1549 } 1550 var length = object.length; 1551 1552 length = (length && isLength(length) && 1553 (isArray(object) || isArguments(object) || isString(object)) && length) || 0; 1554 1555 var Ctor = object.constructor, 1556 index = -1, 1557 proto = (isFunction(Ctor) && Ctor.prototype) || objectProto, 1558 isProto = proto === object, 1559 result = Array(length), 1560 skipIndexes = length > 0, 1561 skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error), 1562 skipProto = support.enumPrototypes && isFunction(object); 1563 1564 while (++index < length) { 1565 result[index] = (index + ''); 1566 } 1567 // lodash skips the `constructor` property when it infers it's iterating 1568 // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]` 1569 // attribute of an existing property and the `constructor` property of a 1570 // prototype defaults to non-enumerable. 1571 for (var key in object) { 1572 if (!(skipProto && key == 'prototype') && 1573 !(skipErrorProps && (key == 'message' || key == 'name')) && 1574 !(skipIndexes && isIndex(key, length)) && 1575 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { 1576 result.push(key); 1577 } 1578 } 1579 if (support.nonEnumShadows && object !== objectProto) { 1580 var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)), 1581 nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag]; 1582 1583 if (tag == objectTag) { 1584 proto = objectProto; 1585 } 1586 length = shadowProps.length; 1587 while (length--) { 1588 key = shadowProps[length]; 1589 var nonEnum = nonEnums[key]; 1590 if (!(isProto && nonEnum) && 1591 (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) { 1592 result.push(key); 1593 } 1594 } 1595 } 1596 return result; 1597 } 1598 1599 module.exports = keysIn; 1600 1601 },{"../internal/arrayEach":9,"../internal/isIndex":23,"../internal/isLength":25,"../lang/isArguments":29,"../lang/isArray":30,"../lang/isFunction":31,"../lang/isObject":33,"../lang/isString":35,"../support":41}],40:[function(_dereq_,module,exports){ 1602 var baseMerge = _dereq_('../internal/baseMerge'), 1603 createAssigner = _dereq_('../internal/createAssigner'); 1604 1605 /** 1606 * Recursively merges own enumerable properties of the source object(s), that 1607 * don't resolve to `undefined` into the destination object. Subsequent sources 1608 * overwrite property assignments of previous sources. If `customizer` is 1609 * provided it's invoked to produce the merged values of the destination and 1610 * source properties. If `customizer` returns `undefined` merging is handled 1611 * by the method instead. The `customizer` is bound to `thisArg` and invoked 1612 * with five arguments: (objectValue, sourceValue, key, object, source). 1613 * 1614 * @static 1615 * @memberOf _ 1616 * @category Object 1617 * @param {Object} object The destination object. 1618 * @param {...Object} [sources] The source objects. 1619 * @param {Function} [customizer] The function to customize assigned values. 1620 * @param {*} [thisArg] The `this` binding of `customizer`. 1621 * @returns {Object} Returns `object`. 1622 * @example 1623 * 1624 * var users = { 1625 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] 1626 * }; 1627 * 1628 * var ages = { 1629 * 'data': [{ 'age': 36 }, { 'age': 40 }] 1630 * }; 1631 * 1632 * _.merge(users, ages); 1633 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } 1634 * 1635 * // using a customizer callback 1636 * var object = { 1637 * 'fruits': ['apple'], 1638 * 'vegetables': ['beet'] 1639 * }; 1640 * 1641 * var other = { 1642 * 'fruits': ['banana'], 1643 * 'vegetables': ['carrot'] 1644 * }; 1645 * 1646 * _.merge(object, other, function(a, b) { 1647 * if (_.isArray(a)) { 1648 * return a.concat(b); 1649 * } 1650 * }); 1651 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } 1652 */ 1653 var merge = createAssigner(baseMerge); 1654 1655 module.exports = merge; 1656 1657 },{"../internal/baseMerge":13,"../internal/createAssigner":17}],41:[function(_dereq_,module,exports){ 1658 /** Used for native method references. */ 1659 var arrayProto = Array.prototype, 1660 errorProto = Error.prototype, 1661 objectProto = Object.prototype; 1662 1663 /** Native method references. */ 1664 var propertyIsEnumerable = objectProto.propertyIsEnumerable, 1665 splice = arrayProto.splice; 1666 1667 /** 1668 * An object environment feature flags. 1669 * 1670 * @static 1671 * @memberOf _ 1672 * @type Object 1673 */ 1674 var support = {}; 1675 1676 (function(x) { 1677 var Ctor = function() { this.x = x; }, 1678 object = { '0': x, 'length': x }, 1679 props = []; 1680 1681 Ctor.prototype = { 'valueOf': x, 'y': x }; 1682 for (var key in new Ctor) { props.push(key); } 1683 1684 /** 1685 * Detect if `name` or `message` properties of `Error.prototype` are 1686 * enumerable by default (IE < 9, Safari < 5.1). 1687 * 1688 * @memberOf _.support 1689 * @type boolean 1690 */ 1691 support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || 1692 propertyIsEnumerable.call(errorProto, 'name'); 1693 1694 /** 1695 * Detect if `prototype` properties are enumerable by default. 1696 * 1697 * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 1698 * (if the prototype or a property on the prototype has been set) 1699 * incorrectly set the `[[Enumerable]]` value of a function's `prototype` 1700 * property to `true`. 1701 * 1702 * @memberOf _.support 1703 * @type boolean 1704 */ 1705 support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype'); 1706 1707 /** 1708 * Detect if properties shadowing those on `Object.prototype` are non-enumerable. 1709 * 1710 * In IE < 9 an object's own properties, shadowing non-enumerable ones, 1711 * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug). 1712 * 1713 * @memberOf _.support 1714 * @type boolean 1715 */ 1716 support.nonEnumShadows = !/valueOf/.test(props); 1717 1718 /** 1719 * Detect if own properties are iterated after inherited properties (IE < 9). 1720 * 1721 * @memberOf _.support 1722 * @type boolean 1723 */ 1724 support.ownLast = props[0] != 'x'; 1725 1726 /** 1727 * Detect if `Array#shift` and `Array#splice` augment array-like objects 1728 * correctly. 1729 * 1730 * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array 1731 * `shift()` and `splice()` functions that fail to remove the last element, 1732 * `value[0]`, of array-like objects even though the "length" property is 1733 * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8, 1734 * while `splice()` is buggy regardless of mode in IE < 9. 1735 * 1736 * @memberOf _.support 1737 * @type boolean 1738 */ 1739 support.spliceObjects = (splice.call(object, 0, 1), !object[0]); 1740 1741 /** 1742 * Detect lack of support for accessing string characters by index. 1743 * 1744 * IE < 8 can't access characters by index. IE 8 can only access characters 1745 * by index on string literals, not string objects. 1746 * 1747 * @memberOf _.support 1748 * @type boolean 1749 */ 1750 support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx'; 1751 }(1, 0)); 1752 1753 module.exports = support; 1754 1755 },{}],42:[function(_dereq_,module,exports){ 1756 /** 1757 * This method returns the first argument provided to it. 1758 * 1759 * @static 1760 * @memberOf _ 1761 * @category Utility 1762 * @param {*} value Any value. 1763 * @returns {*} Returns `value`. 1764 * @example 1765 * 1766 * var object = { 'user': 'fred' }; 1767 * 1768 * _.identity(object) === object; 1769 * // => true 1770 */ 1771 function identity(value) { 1772 return value; 1773 } 1774 1775 module.exports = identity; 1776 1777 },{}],43:[function(_dereq_,module,exports){ 1778 'use strict'; 1779 1780 var keys = _dereq_('object-keys'); 1781 1782 module.exports = function hasSymbols() { 1783 if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } 1784 if (typeof Symbol.iterator === 'symbol') { return true; } 1785 1786 var obj = {}; 1787 var sym = Symbol('test'); 1788 if (typeof sym === 'string') { return false; } 1789 1790 // temp disabled per https://github.com/ljharb/object.assign/issues/17 1791 // if (sym instanceof Symbol) { return false; } 1792 // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 1793 // if (!(Object(sym) instanceof Symbol)) { return false; } 1794 1795 var symVal = 42; 1796 obj[sym] = symVal; 1797 for (sym in obj) { return false; } 1798 if (keys(obj).length !== 0) { return false; } 1799 if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } 1800 1801 if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } 1802 1803 var syms = Object.getOwnPropertySymbols(obj); 1804 if (syms.length !== 1 || syms[0] !== sym) { return false; } 1805 1806 if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } 1807 1808 if (typeof Object.getOwnPropertyDescriptor === 'function') { 1809 var descriptor = Object.getOwnPropertyDescriptor(obj, sym); 1810 if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } 1811 } 1812 1813 return true; 1814 }; 1815 1816 },{"object-keys":50}],44:[function(_dereq_,module,exports){ 1817 'use strict'; 1818 1819 // modified from https://github.com/es-shims/es6-shim 1820 var keys = _dereq_('object-keys'); 1821 var bind = _dereq_('function-bind'); 1822 var canBeObject = function (obj) { 1823 return typeof obj !== 'undefined' && obj !== null; 1824 }; 1825 var hasSymbols = _dereq_('./hasSymbols')(); 1826 var toObject = Object; 1827 var push = bind.call(Function.call, Array.prototype.push); 1828 var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable); 1829 1830 module.exports = function assign(target, source1) { 1831 if (!canBeObject(target)) { throw new TypeError('target must be an object'); } 1832 var objTarget = toObject(target); 1833 var s, source, i, props, syms, value, key; 1834 for (s = 1; s < arguments.length; ++s) { 1835 source = toObject(arguments[s]); 1836 props = keys(source); 1837 if (hasSymbols && Object.getOwnPropertySymbols) { 1838 syms = Object.getOwnPropertySymbols(source); 1839 for (i = 0; i < syms.length; ++i) { 1840 key = syms[i]; 1841 if (propIsEnumerable(source, key)) { 1842 push(props, key); 1843 } 1844 } 1845 } 1846 for (i = 0; i < props.length; ++i) { 1847 key = props[i]; 1848 value = source[key]; 1849 if (propIsEnumerable(source, key)) { 1850 objTarget[key] = value; 1851 } 1852 } 1853 } 1854 return objTarget; 1855 }; 1856 1857 },{"./hasSymbols":43,"function-bind":49,"object-keys":50}],45:[function(_dereq_,module,exports){ 1858 'use strict'; 1859 1860 var defineProperties = _dereq_('define-properties'); 1861 1862 var implementation = _dereq_('./implementation'); 1863 var getPolyfill = _dereq_('./polyfill'); 1864 var shim = _dereq_('./shim'); 1865 1866 defineProperties(implementation, { 1867 implementation: implementation, 1868 getPolyfill: getPolyfill, 1869 shim: shim 1870 }); 1871 1872 module.exports = implementation; 1873 1874 },{"./implementation":44,"./polyfill":52,"./shim":53,"define-properties":46}],46:[function(_dereq_,module,exports){ 1875 'use strict'; 1876 1877 var keys = _dereq_('object-keys'); 1878 var foreach = _dereq_('foreach'); 1879 var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; 1880 1881 var toStr = Object.prototype.toString; 1882 1883 var isFunction = function (fn) { 1884 return typeof fn === 'function' && toStr.call(fn) === '[object Function]'; 1885 }; 1886 1887 var arePropertyDescriptorsSupported = function () { 1888 var obj = {}; 1889 try { 1890 Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); 1891 /* eslint-disable no-unused-vars, no-restricted-syntax */ 1892 for (var _ in obj) { return false; } 1893 /* eslint-enable no-unused-vars, no-restricted-syntax */ 1894 return obj.x === obj; 1895 } catch (e) { /* this is IE 8. */ 1896 return false; 1897 } 1898 }; 1899 var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported(); 1900 1901 var defineProperty = function (object, name, value, predicate) { 1902 if (name in object && (!isFunction(predicate) || !predicate())) { 1903 return; 1904 } 1905 if (supportsDescriptors) { 1906 Object.defineProperty(object, name, { 1907 configurable: true, 1908 enumerable: false, 1909 value: value, 1910 writable: true 1911 }); 1912 } else { 1913 object[name] = value; 1914 } 1915 }; 1916 1917 var defineProperties = function (object, map) { 1918 var predicates = arguments.length > 2 ? arguments[2] : {}; 1919 var props = keys(map); 1920 if (hasSymbols) { 1921 props = props.concat(Object.getOwnPropertySymbols(map)); 1922 } 1923 foreach(props, function (name) { 1924 defineProperty(object, name, map[name], predicates[name]); 1925 }); 1926 }; 1927 1928 defineProperties.supportsDescriptors = !!supportsDescriptors; 1929 1930 module.exports = defineProperties; 1931 1932 },{"foreach":47,"object-keys":50}],47:[function(_dereq_,module,exports){ 1933 1934 var hasOwn = Object.prototype.hasOwnProperty; 1935 var toString = Object.prototype.toString; 1936 1937 module.exports = function forEach (obj, fn, ctx) { 1938 if (toString.call(fn) !== '[object Function]') { 1939 throw new TypeError('iterator must be a function'); 1940 } 1941 var l = obj.length; 1942 if (l === +l) { 1943 for (var i = 0; i < l; i++) { 1944 fn.call(ctx, obj[i], i, obj); 1945 } 1946 } else { 1947 for (var k in obj) { 1948 if (hasOwn.call(obj, k)) { 1949 fn.call(ctx, obj[k], k, obj); 1950 } 1951 } 1952 } 1953 }; 1954 1955 1956 },{}],48:[function(_dereq_,module,exports){ 1957 var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; 1958 var slice = Array.prototype.slice; 1959 var toStr = Object.prototype.toString; 1960 var funcType = '[object Function]'; 1961 1962 module.exports = function bind(that) { 1963 var target = this; 1964 if (typeof target !== 'function' || toStr.call(target) !== funcType) { 1965 throw new TypeError(ERROR_MESSAGE + target); 1966 } 1967 var args = slice.call(arguments, 1); 1968 1969 var bound; 1970 var binder = function () { 1971 if (this instanceof bound) { 1972 var result = target.apply( 1973 this, 1974 args.concat(slice.call(arguments)) 1975 ); 1976 if (Object(result) === result) { 1977 return result; 1978 } 1979 return this; 1980 } else { 1981 return target.apply( 1982 that, 1983 args.concat(slice.call(arguments)) 1984 ); 1985 } 1986 }; 1987 1988 var boundLength = Math.max(0, target.length - args.length); 1989 var boundArgs = []; 1990 for (var i = 0; i < boundLength; i++) { 1991 boundArgs.push('$' + i); 1992 } 1993 1994 bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); 1995 1996 if (target.prototype) { 1997 var Empty = function Empty() {}; 1998 Empty.prototype = target.prototype; 1999 bound.prototype = new Empty(); 2000 Empty.prototype = null; 2001 } 2002 2003 return bound; 2004 }; 2005 2006 },{}],49:[function(_dereq_,module,exports){ 2007 var implementation = _dereq_('./implementation'); 2008 2009 module.exports = Function.prototype.bind || implementation; 2010 2011 },{"./implementation":48}],50:[function(_dereq_,module,exports){ 2012 'use strict'; 2013 2014 // modified from https://github.com/es-shims/es5-shim 2015 var has = Object.prototype.hasOwnProperty; 2016 var toStr = Object.prototype.toString; 2017 var slice = Array.prototype.slice; 2018 var isArgs = _dereq_('./isArguments'); 2019 var hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'); 2020 var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); 2021 var dontEnums = [ 2022 'toString', 2023 'toLocaleString', 2024 'valueOf', 2025 'hasOwnProperty', 2026 'isPrototypeOf', 2027 'propertyIsEnumerable', 2028 'constructor' 2029 ]; 2030 var equalsConstructorPrototype = function (o) { 2031 var ctor = o.constructor; 2032 return ctor && ctor.prototype === o; 2033 }; 2034 var blacklistedKeys = { 2035 $console: true, 2036 $frame: true, 2037 $frameElement: true, 2038 $frames: true, 2039 $parent: true, 2040 $self: true, 2041 $webkitIndexedDB: true, 2042 $webkitStorageInfo: true, 2043 $window: true 2044 }; 2045 var hasAutomationEqualityBug = (function () { 2046 /* global window */ 2047 if (typeof window === 'undefined') { return false; } 2048 for (var k in window) { 2049 try { 2050 if (!blacklistedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { 2051 try { 2052 equalsConstructorPrototype(window[k]); 2053 } catch (e) { 2054 return true; 2055 } 2056 } 2057 } catch (e) { 2058 return true; 2059 } 2060 } 2061 return false; 2062 }()); 2063 var equalsConstructorPrototypeIfNotBuggy = function (o) { 2064 /* global window */ 2065 if (typeof window === 'undefined' || !hasAutomationEqualityBug) { 2066 return equalsConstructorPrototype(o); 2067 } 2068 try { 2069 return equalsConstructorPrototype(o); 2070 } catch (e) { 2071 return false; 2072 } 2073 }; 2074 2075 var keysShim = function keys(object) { 2076 var isObject = object !== null && typeof object === 'object'; 2077 var isFunction = toStr.call(object) === '[object Function]'; 2078 var isArguments = isArgs(object); 2079 var isString = isObject && toStr.call(object) === '[object String]'; 2080 var theKeys = []; 2081 2082 if (!isObject && !isFunction && !isArguments) { 2083 throw new TypeError('Object.keys called on a non-object'); 2084 } 2085 2086 var skipProto = hasProtoEnumBug && isFunction; 2087 if (isString && object.length > 0 && !has.call(object, 0)) { 2088 for (var i = 0; i < object.length; ++i) { 2089 theKeys.push(String(i)); 2090 } 2091 } 2092 2093 if (isArguments && object.length > 0) { 2094 for (var j = 0; j < object.length; ++j) { 2095 theKeys.push(String(j)); 2096 } 2097 } else { 2098 for (var name in object) { 2099 if (!(skipProto && name === 'prototype') && has.call(object, name)) { 2100 theKeys.push(String(name)); 2101 } 2102 } 2103 } 2104 2105 if (hasDontEnumBug) { 2106 var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); 2107 2108 for (var k = 0; k < dontEnums.length; ++k) { 2109 if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { 2110 theKeys.push(dontEnums[k]); 2111 } 2112 } 2113 } 2114 return theKeys; 2115 }; 2116 2117 keysShim.shim = function shimObjectKeys() { 2118 if (Object.keys) { 2119 var keysWorksWithArguments = (function () { 2120 // Safari 5.0 bug 2121 return (Object.keys(arguments) || '').length === 2; 2122 }(1, 2)); 2123 if (!keysWorksWithArguments) { 2124 var originalKeys = Object.keys; 2125 Object.keys = function keys(object) { 2126 if (isArgs(object)) { 2127 return originalKeys(slice.call(object)); 2128 } else { 2129 return originalKeys(object); 2130 } 2131 }; 2132 } 2133 } else { 2134 Object.keys = keysShim; 2135 } 2136 return Object.keys || keysShim; 2137 }; 2138 2139 module.exports = keysShim; 2140 2141 },{"./isArguments":51}],51:[function(_dereq_,module,exports){ 2142 'use strict'; 2143 2144 var toStr = Object.prototype.toString; 2145 2146 module.exports = function isArguments(value) { 2147 var str = toStr.call(value); 2148 var isArgs = str === '[object Arguments]'; 2149 if (!isArgs) { 2150 isArgs = str !== '[object Array]' && 2151 value !== null && 2152 typeof value === 'object' && 2153 typeof value.length === 'number' && 2154 value.length >= 0 && 2155 toStr.call(value.callee) === '[object Function]'; 2156 } 2157 return isArgs; 2158 }; 2159 2160 },{}],52:[function(_dereq_,module,exports){ 2161 'use strict'; 2162 2163 var implementation = _dereq_('./implementation'); 2164 2165 var lacksProperEnumerationOrder = function () { 2166 if (!Object.assign) { 2167 return false; 2168 } 2169 // v8, specifically in node 4.x, has a bug with incorrect property enumeration order 2170 // note: this does not detect the bug unless there's 20 characters 2171 var str = 'abcdefghijklmnopqrst'; 2172 var letters = str.split(''); 2173 var map = {}; 2174 for (var i = 0; i < letters.length; ++i) { 2175 map[letters[i]] = letters[i]; 2176 } 2177 var obj = Object.assign({}, map); 2178 var actual = ''; 2179 for (var k in obj) { 2180 actual += k; 2181 } 2182 return str !== actual; 2183 }; 2184 2185 var assignHasPendingExceptions = function () { 2186 if (!Object.assign || !Object.preventExtensions) { 2187 return false; 2188 } 2189 // Firefox 37 still has "pending exception" logic in its Object.assign implementation, 2190 // which is 72% slower than our shim, and Firefox 40's native implementation. 2191 var thrower = Object.preventExtensions({ 1: 2 }); 2192 try { 2193 Object.assign(thrower, 'xy'); 2194 } catch (e) { 2195 return thrower[1] === 'y'; 2196 } 2197 }; 2198 2199 module.exports = function getPolyfill() { 2200 if (!Object.assign) { 2201 return implementation; 2202 } 2203 if (lacksProperEnumerationOrder()) { 2204 return implementation; 2205 } 2206 if (assignHasPendingExceptions()) { 2207 return implementation; 2208 } 2209 return Object.assign; 2210 }; 2211 2212 },{"./implementation":44}],53:[function(_dereq_,module,exports){ 2213 'use strict'; 2214 2215 var define = _dereq_('define-properties'); 2216 var getPolyfill = _dereq_('./polyfill'); 2217 2218 module.exports = function shimAssign() { 2219 var polyfill = getPolyfill(); 2220 define( 2221 Object, 2222 { assign: polyfill }, 2223 { assign: function () { return Object.assign !== polyfill; } } 2224 ); 2225 return polyfill; 2226 }; 2227 2228 },{"./polyfill":52,"define-properties":46}],54:[function(_dereq_,module,exports){ 2229 module.exports = SafeParseTuple 2230 2231 function SafeParseTuple(obj, reviver) { 2232 var json 2233 var error = null 2234 2235 try { 2236 json = JSON.parse(obj, reviver) 2237 } catch (err) { 2238 error = err 2239 } 2240 2241 return [error, json] 2242 } 2243 2244 },{}],55:[function(_dereq_,module,exports){ 2245 function clean (s) { 2246 return s.replace(/\n\r?\s*/g, '') 2247 } 2248 2249 2250 module.exports = function tsml (sa) { 2251 var s = '' 2252 , i = 0 2253 2254 for (; i < arguments.length; i++) 2255 s += clean(sa[i]) + (arguments[i + 1] || '') 2256 2257 return s 2258 } 2259 },{}],56:[function(_dereq_,module,exports){ 2260 "use strict"; 2261 var window = _dereq_("global/window") 2262 var once = _dereq_("once") 2263 var isFunction = _dereq_("is-function") 2264 var parseHeaders = _dereq_("parse-headers") 2265 var xtend = _dereq_("xtend") 2266 2267 module.exports = createXHR 2268 createXHR.XMLHttpRequest = window.XMLHttpRequest || noop 2269 createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest 2270 2271 forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) { 2272 createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) { 2273 options = initParams(uri, options, callback) 2274 options.method = method.toUpperCase() 2275 return _createXHR(options) 2276 } 2277 }) 2278 2279 function forEachArray(array, iterator) { 2280 for (var i = 0; i < array.length; i++) { 2281 iterator(array[i]) 2282 } 2283 } 2284 2285 function isEmpty(obj){ 2286 for(var i in obj){ 2287 if(obj.hasOwnProperty(i)) return false 2288 } 2289 return true 2290 } 2291 2292 function initParams(uri, options, callback) { 2293 var params = uri 2294 2295 if (isFunction(options)) { 2296 callback = options 2297 if (typeof uri === "string") { 2298 params = {uri:uri} 2299 } 2300 } else { 2301 params = xtend(options, {uri: uri}) 2302 } 2303 2304 params.callback = callback 2305 return params 2306 } 2307 2308 function createXHR(uri, options, callback) { 2309 options = initParams(uri, options, callback) 2310 return _createXHR(options) 2311 } 2312 2313 function _createXHR(options) { 2314 var callback = options.callback 2315 if(typeof callback === "undefined"){ 2316 throw new Error("callback argument missing") 2317 } 2318 callback = once(callback) 2319 2320 function readystatechange() { 2321 if (xhr.readyState === 4) { 2322 loadFunc() 2323 } 2324 } 2325 2326 function getBody() { 2327 // Chrome with requestType=blob throws errors arround when even testing access to responseText 2328 var body = undefined 2329 2330 if (xhr.response) { 2331 body = xhr.response 2332 } else if (xhr.responseType === "text" || !xhr.responseType) { 2333 body = xhr.responseText || xhr.responseXML 2334 } 2335 2336 if (isJson) { 2337 try { 2338 body = JSON.parse(body) 2339 } catch (e) {} 2340 } 2341 2342 return body 2343 } 2344 2345 var failureResponse = { 2346 body: undefined, 2347 headers: {}, 2348 statusCode: 0, 2349 method: method, 2350 url: uri, 2351 rawRequest: xhr 2352 } 2353 2354 function errorFunc(evt) { 2355 clearTimeout(timeoutTimer) 2356 if(!(evt instanceof Error)){ 2357 evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") ) 2358 } 2359 evt.statusCode = 0 2360 callback(evt, failureResponse) 2361 } 2362 2363 // will load the data & process the response in a special response object 2364 function loadFunc() { 2365 if (aborted) return 2366 var status 2367 clearTimeout(timeoutTimer) 2368 if(options.useXDR && xhr.status===undefined) { 2369 //IE8 CORS GET successful response doesn't have a status field, but body is fine 2370 status = 200 2371 } else { 2372 status = (xhr.status === 1223 ? 204 : xhr.status) 2373 } 2374 var response = failureResponse 2375 var err = null 2376 2377 if (status !== 0){ 2378 response = { 2379 body: getBody(), 2380 statusCode: status, 2381 method: method, 2382 headers: {}, 2383 url: uri, 2384 rawRequest: xhr 2385 } 2386 if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE 2387 response.headers = parseHeaders(xhr.getAllResponseHeaders()) 2388 } 2389 } else { 2390 err = new Error("Internal XMLHttpRequest Error") 2391 } 2392 callback(err, response, response.body) 2393 2394 } 2395 2396 var xhr = options.xhr || null 2397 2398 if (!xhr) { 2399 if (options.cors || options.useXDR) { 2400 xhr = new createXHR.XDomainRequest() 2401 }else{ 2402 xhr = new createXHR.XMLHttpRequest() 2403 } 2404 } 2405 2406 var key 2407 var aborted 2408 var uri = xhr.url = options.uri || options.url 2409 var method = xhr.method = options.method || "GET" 2410 var body = options.body || options.data || null 2411 var headers = xhr.headers = options.headers || {} 2412 var sync = !!options.sync 2413 var isJson = false 2414 var timeoutTimer 2415 2416 if ("json" in options) { 2417 isJson = true 2418 headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user 2419 if (method !== "GET" && method !== "HEAD") { 2420 headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user 2421 body = JSON.stringify(options.json) 2422 } 2423 } 2424 2425 xhr.onreadystatechange = readystatechange 2426 xhr.onload = loadFunc 2427 xhr.onerror = errorFunc 2428 // IE9 must have onprogress be set to a unique function. 2429 xhr.onprogress = function () { 2430 // IE must die 2431 } 2432 xhr.ontimeout = errorFunc 2433 xhr.open(method, uri, !sync, options.username, options.password) 2434 //has to be after open 2435 if(!sync) { 2436 xhr.withCredentials = !!options.withCredentials 2437 } 2438 // Cannot set timeout with sync request 2439 // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly 2440 // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent 2441 if (!sync && options.timeout > 0 ) { 2442 timeoutTimer = setTimeout(function(){ 2443 aborted=true//IE9 may still call readystatechange 2444 xhr.abort("timeout") 2445 var e = new Error("XMLHttpRequest timeout") 2446 e.code = "ETIMEDOUT" 2447 errorFunc(e) 2448 }, options.timeout ) 2449 } 2450 2451 if (xhr.setRequestHeader) { 2452 for(key in headers){ 2453 if(headers.hasOwnProperty(key)){ 2454 xhr.setRequestHeader(key, headers[key]) 2455 } 2456 } 2457 } else if (options.headers && !isEmpty(options.headers)) { 2458 throw new Error("Headers cannot be set on an XDomainRequest object") 2459 } 2460 2461 if ("responseType" in options) { 2462 xhr.responseType = options.responseType 2463 } 2464 2465 if ("beforeSend" in options && 2466 typeof options.beforeSend === "function" 2467 ) { 2468 options.beforeSend(xhr) 2469 } 2470 2471 xhr.send(body) 2472 2473 return xhr 2474 2475 2476 } 2477 2478 function noop() {} 2479 2480 },{"global/window":2,"is-function":57,"once":58,"parse-headers":61,"xtend":62}],57:[function(_dereq_,module,exports){ 2481 module.exports = isFunction 2482 2483 var toString = Object.prototype.toString 2484 2485 function isFunction (fn) { 2486 var string = toString.call(fn) 2487 return string === '[object Function]' || 2488 (typeof fn === 'function' && string !== '[object RegExp]') || 2489 (typeof window !== 'undefined' && 2490 // IE8 and below 2491 (fn === window.setTimeout || 2492 fn === window.alert || 2493 fn === window.confirm || 2494 fn === window.prompt)) 2495 }; 2496 2497 },{}],58:[function(_dereq_,module,exports){ 2498 module.exports = once 2499 2500 once.proto = once(function () { 2501 Object.defineProperty(Function.prototype, 'once', { 2502 value: function () { 2503 return once(this) 2504 }, 2505 configurable: true 2506 }) 2507 }) 2508 2509 function once (fn) { 2510 var called = false 2511 return function () { 2512 if (called) return 2513 called = true 2514 return fn.apply(this, arguments) 2515 } 2516 } 2517 2518 },{}],59:[function(_dereq_,module,exports){ 2519 var isFunction = _dereq_('is-function') 2520 2521 module.exports = forEach 2522 2523 var toString = Object.prototype.toString 2524 var hasOwnProperty = Object.prototype.hasOwnProperty 2525 2526 function forEach(list, iterator, context) { 2527 if (!isFunction(iterator)) { 2528 throw new TypeError('iterator must be a function') 2529 } 2530 2531 if (arguments.length < 3) { 2532 context = this 2533 } 2534 2535 if (toString.call(list) === '[object Array]') 2536 forEachArray(list, iterator, context) 2537 else if (typeof list === 'string') 2538 forEachString(list, iterator, context) 2539 else 2540 forEachObject(list, iterator, context) 2541 } 2542 2543 function forEachArray(array, iterator, context) { 2544 for (var i = 0, len = array.length; i < len; i++) { 2545 if (hasOwnProperty.call(array, i)) { 2546 iterator.call(context, array[i], i, array) 2547 } 2548 } 2549 } 2550 2551 function forEachString(string, iterator, context) { 2552 for (var i = 0, len = string.length; i < len; i++) { 2553 // no such thing as a sparse string. 2554 iterator.call(context, string.charAt(i), i, string) 2555 } 2556 } 2557 2558 function forEachObject(object, iterator, context) { 2559 for (var k in object) { 2560 if (hasOwnProperty.call(object, k)) { 2561 iterator.call(context, object[k], k, object) 2562 } 2563 } 2564 } 2565 2566 },{"is-function":57}],60:[function(_dereq_,module,exports){ 2567 2568 exports = module.exports = trim; 2569 2570 function trim(str){ 2571 return str.replace(/^\s*|\s*$/g, ''); 2572 } 2573 2574 exports.left = function(str){ 2575 return str.replace(/^\s*/, ''); 2576 }; 2577 2578 exports.right = function(str){ 2579 return str.replace(/\s*$/, ''); 2580 }; 2581 2582 },{}],61:[function(_dereq_,module,exports){ 2583 var trim = _dereq_('trim') 2584 , forEach = _dereq_('for-each') 2585 , isArray = function(arg) { 2586 return Object.prototype.toString.call(arg) === '[object Array]'; 2587 } 2588 2589 module.exports = function (headers) { 2590 if (!headers) 2591 return {} 2592 2593 var result = {} 2594 2595 forEach( 2596 trim(headers).split('\n') 2597 , function (row) { 2598 var index = row.indexOf(':') 2599 , key = trim(row.slice(0, index)).toLowerCase() 2600 , value = trim(row.slice(index + 1)) 2601 2602 if (typeof(result[key]) === 'undefined') { 2603 result[key] = value 2604 } else if (isArray(result[key])) { 2605 result[key].push(value) 2606 } else { 2607 result[key] = [ result[key], value ] 2608 } 2609 } 2610 ) 2611 2612 return result 2613 } 2614 },{"for-each":59,"trim":60}],62:[function(_dereq_,module,exports){ 2615 module.exports = extend 2616 2617 var hasOwnProperty = Object.prototype.hasOwnProperty; 2618 2619 function extend() { 2620 var target = {} 2621 2622 for (var i = 0; i < arguments.length; i++) { 2623 var source = arguments[i] 2624 2625 for (var key in source) { 2626 if (hasOwnProperty.call(source, key)) { 2627 target[key] = source[key] 2628 } 2629 } 2630 } 2631 2632 return target 2633 } 2634 2635 },{}],63:[function(_dereq_,module,exports){ 2636 /** 2637 * @file big-play-button.js 2638 */ 2639 'use strict'; 2640 2641 exports.__esModule = true; 2642 2643 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 2644 2645 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 2646 2647 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2648 2649 var _buttonJs = _dereq_('./button.js'); 2650 2651 var _buttonJs2 = _interopRequireDefault(_buttonJs); 2652 2653 var _componentJs = _dereq_('./component.js'); 2654 2655 var _componentJs2 = _interopRequireDefault(_componentJs); 2656 2657 /** 2658 * Initial play button. Shows before the video has played. The hiding of the 2659 * big play button is done via CSS and player states. 2660 * 2661 * @param {Object} player Main Player 2662 * @param {Object=} options Object of option names and values 2663 * @extends Button 2664 * @class BigPlayButton 2665 */ 2666 2667 var BigPlayButton = (function (_Button) { 2668 _inherits(BigPlayButton, _Button); 2669 2670 function BigPlayButton(player, options) { 2671 _classCallCheck(this, BigPlayButton); 2672 2673 _Button.call(this, player, options); 2674 } 2675 2676 /** 2677 * Allow sub components to stack CSS class names 2678 * 2679 * @return {String} The constructed class name 2680 * @method buildCSSClass 2681 */ 2682 2683 BigPlayButton.prototype.buildCSSClass = function buildCSSClass() { 2684 return 'vjs-big-play-button'; 2685 }; 2686 2687 /** 2688 * Handles click for play 2689 * 2690 * @method handleClick 2691 */ 2692 2693 BigPlayButton.prototype.handleClick = function handleClick() { 2694 this.player_.play(); 2695 }; 2696 2697 return BigPlayButton; 2698 })(_buttonJs2['default']); 2699 2700 BigPlayButton.prototype.controlText_ = 'Play Video'; 2701 2702 _componentJs2['default'].registerComponent('BigPlayButton', BigPlayButton); 2703 exports['default'] = BigPlayButton; 2704 module.exports = exports['default']; 2705 2706 },{"./button.js":64,"./component.js":67}],64:[function(_dereq_,module,exports){ 2707 /** 2708 * @file button.js 2709 */ 2710 'use strict'; 2711 2712 exports.__esModule = true; 2713 2714 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 2715 2716 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 2717 2718 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 2719 2720 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2721 2722 var _clickableComponentJs = _dereq_('./clickable-component.js'); 2723 2724 var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); 2725 2726 var _component = _dereq_('./component'); 2727 2728 var _component2 = _interopRequireDefault(_component); 2729 2730 var _utilsEventsJs = _dereq_('./utils/events.js'); 2731 2732 var Events = _interopRequireWildcard(_utilsEventsJs); 2733 2734 var _utilsFnJs = _dereq_('./utils/fn.js'); 2735 2736 var Fn = _interopRequireWildcard(_utilsFnJs); 2737 2738 var _utilsLogJs = _dereq_('./utils/log.js'); 2739 2740 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 2741 2742 var _globalDocument = _dereq_('global/document'); 2743 2744 var _globalDocument2 = _interopRequireDefault(_globalDocument); 2745 2746 var _objectAssign = _dereq_('object.assign'); 2747 2748 var _objectAssign2 = _interopRequireDefault(_objectAssign); 2749 2750 /** 2751 * Base class for all buttons 2752 * 2753 * @param {Object} player Main Player 2754 * @param {Object=} options Object of option names and values 2755 * @extends ClickableComponent 2756 * @class Button 2757 */ 2758 2759 var Button = (function (_ClickableComponent) { 2760 _inherits(Button, _ClickableComponent); 2761 2762 function Button(player, options) { 2763 _classCallCheck(this, Button); 2764 2765 _ClickableComponent.call(this, player, options); 2766 } 2767 2768 /** 2769 * Create the component's DOM element 2770 * 2771 * @param {String=} type Element's node type. e.g. 'div' 2772 * @param {Object=} props An object of properties that should be set on the element 2773 * @param {Object=} attributes An object of attributes that should be set on the element 2774 * @return {Element} 2775 * @method createEl 2776 */ 2777 2778 Button.prototype.createEl = function createEl() { 2779 var tag = arguments.length <= 0 || arguments[0] === undefined ? 'button' : arguments[0]; 2780 var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 2781 var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 2782 2783 props = _objectAssign2['default']({ 2784 className: this.buildCSSClass() 2785 }, props); 2786 2787 if (tag !== 'button') { 2788 _utilsLogJs2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.'); 2789 2790 // Add properties for clickable element which is not a native HTML button 2791 props = _objectAssign2['default']({ 2792 tabIndex: 0 2793 }, props); 2794 2795 // Add ARIA attributes for clickable element which is not a native HTML button 2796 attributes = _objectAssign2['default']({ 2797 role: 'button' 2798 }, attributes); 2799 } 2800 2801 // Add attributes for button element 2802 attributes = _objectAssign2['default']({ 2803 type: 'button', // Necessary since the default button type is "submit" 2804 'aria-live': 'polite' // let the screen reader user know that the text of the button may change 2805 }, attributes); 2806 2807 var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes); 2808 2809 this.createControlTextEl(el); 2810 2811 return el; 2812 }; 2813 2814 /** 2815 * Adds a child component inside this button 2816 * 2817 * @param {String|Component} child The class name or instance of a child to add 2818 * @param {Object=} options Options, including options to be passed to children of the child. 2819 * @return {Component} The child component (created by this process if a string was used) 2820 * @deprecated 2821 * @method addChild 2822 */ 2823 2824 Button.prototype.addChild = function addChild(child) { 2825 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 2826 2827 var className = this.constructor.name; 2828 _utilsLogJs2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.'); 2829 2830 // Avoid the error message generated by ClickableComponent's addChild method 2831 return _component2['default'].prototype.addChild.call(this, child, options); 2832 }; 2833 2834 /** 2835 * Handle KeyPress (document level) - Extend with specific functionality for button 2836 * 2837 * @method handleKeyPress 2838 */ 2839 2840 Button.prototype.handleKeyPress = function handleKeyPress(event) { 2841 // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button. 2842 if (event.which === 32 || event.which === 13) {} else { 2843 _ClickableComponent.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys 2844 } 2845 }; 2846 2847 return Button; 2848 })(_clickableComponentJs2['default']); 2849 2850 _component2['default'].registerComponent('Button', Button); 2851 exports['default'] = Button; 2852 module.exports = exports['default']; 2853 2854 },{"./clickable-component.js":65,"./component":67,"./utils/events.js":135,"./utils/fn.js":136,"./utils/log.js":139,"global/document":1,"object.assign":45}],65:[function(_dereq_,module,exports){ 2855 /** 2856 * @file button.js 2857 */ 2858 'use strict'; 2859 2860 exports.__esModule = true; 2861 2862 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 2863 2864 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 2865 2866 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 2867 2868 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2869 2870 var _component = _dereq_('./component'); 2871 2872 var _component2 = _interopRequireDefault(_component); 2873 2874 var _utilsDomJs = _dereq_('./utils/dom.js'); 2875 2876 var Dom = _interopRequireWildcard(_utilsDomJs); 2877 2878 var _utilsEventsJs = _dereq_('./utils/events.js'); 2879 2880 var Events = _interopRequireWildcard(_utilsEventsJs); 2881 2882 var _utilsFnJs = _dereq_('./utils/fn.js'); 2883 2884 var Fn = _interopRequireWildcard(_utilsFnJs); 2885 2886 var _utilsLogJs = _dereq_('./utils/log.js'); 2887 2888 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 2889 2890 var _globalDocument = _dereq_('global/document'); 2891 2892 var _globalDocument2 = _interopRequireDefault(_globalDocument); 2893 2894 var _objectAssign = _dereq_('object.assign'); 2895 2896 var _objectAssign2 = _interopRequireDefault(_objectAssign); 2897 2898 /** 2899 * Clickable Component which is clickable or keyboard actionable, but is not a native HTML button 2900 * 2901 * @param {Object} player Main Player 2902 * @param {Object=} options Object of option names and values 2903 * @extends Component 2904 * @class ClickableComponent 2905 */ 2906 2907 var ClickableComponent = (function (_Component) { 2908 _inherits(ClickableComponent, _Component); 2909 2910 function ClickableComponent(player, options) { 2911 _classCallCheck(this, ClickableComponent); 2912 2913 _Component.call(this, player, options); 2914 2915 this.emitTapEvents(); 2916 2917 this.on('tap', this.handleClick); 2918 this.on('click', this.handleClick); 2919 this.on('focus', this.handleFocus); 2920 this.on('blur', this.handleBlur); 2921 } 2922 2923 /** 2924 * Create the component's DOM element 2925 * 2926 * @param {String=} type Element's node type. e.g. 'div' 2927 * @param {Object=} props An object of properties that should be set on the element 2928 * @param {Object=} attributes An object of attributes that should be set on the element 2929 * @return {Element} 2930 * @method createEl 2931 */ 2932 2933 ClickableComponent.prototype.createEl = function createEl() { 2934 var tag = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; 2935 var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 2936 var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 2937 2938 props = _objectAssign2['default']({ 2939 className: this.buildCSSClass(), 2940 tabIndex: 0 2941 }, props); 2942 2943 if (tag === 'button') { 2944 _utilsLogJs2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.'); 2945 } 2946 2947 // Add ARIA attributes for clickable element which is not a native HTML button 2948 attributes = _objectAssign2['default']({ 2949 role: 'button', 2950 'aria-live': 'polite' // let the screen reader user know that the text of the element may change 2951 }, attributes); 2952 2953 var el = _Component.prototype.createEl.call(this, tag, props, attributes); 2954 2955 this.createControlTextEl(el); 2956 2957 return el; 2958 }; 2959 2960 /** 2961 * create control text 2962 * 2963 * @param {Element} el Parent element for the control text 2964 * @return {Element} 2965 * @method controlText 2966 */ 2967 2968 ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) { 2969 this.controlTextEl_ = Dom.createEl('span', { 2970 className: 'vjs-control-text' 2971 }); 2972 2973 if (el) { 2974 el.appendChild(this.controlTextEl_); 2975 } 2976 2977 this.controlText(this.controlText_); 2978 2979 return this.controlTextEl_; 2980 }; 2981 2982 /** 2983 * Controls text - both request and localize 2984 * 2985 * @param {String} text Text for element 2986 * @return {String} 2987 * @method controlText 2988 */ 2989 2990 ClickableComponent.prototype.controlText = function controlText(text) { 2991 if (!text) return this.controlText_ || 'Need Text'; 2992 2993 this.controlText_ = text; 2994 this.controlTextEl_.innerHTML = this.localize(this.controlText_); 2995 2996 return this; 2997 }; 2998 2999 /** 3000 * Allows sub components to stack CSS class names 3001 * 3002 * @return {String} 3003 * @method buildCSSClass 3004 */ 3005 3006 ClickableComponent.prototype.buildCSSClass = function buildCSSClass() { 3007 return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this); 3008 }; 3009 3010 /** 3011 * Adds a child component inside this clickable-component 3012 * 3013 * @param {String|Component} child The class name or instance of a child to add 3014 * @param {Object=} options Options, including options to be passed to children of the child. 3015 * @return {Component} The child component (created by this process if a string was used) 3016 * @method addChild 3017 */ 3018 3019 ClickableComponent.prototype.addChild = function addChild(child) { 3020 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 3021 3022 // TODO: Fix adding an actionable child to a ClickableComponent; currently 3023 // it will cause issues with assistive technology (e.g. screen readers) 3024 // which support ARIA, since an element with role="button" cannot have 3025 // actionable child elements. 3026 3027 //let className = this.constructor.name; 3028 //log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`); 3029 3030 return _Component.prototype.addChild.call(this, child, options); 3031 }; 3032 3033 /** 3034 * Enable the component element 3035 * 3036 * @return {Component} 3037 * @method enable 3038 */ 3039 3040 ClickableComponent.prototype.enable = function enable() { 3041 this.removeClass('vjs-disabled'); 3042 this.el_.setAttribute('aria-disabled', 'false'); 3043 return this; 3044 }; 3045 3046 /** 3047 * Disable the component element 3048 * 3049 * @return {Component} 3050 * @method disable 3051 */ 3052 3053 ClickableComponent.prototype.disable = function disable() { 3054 this.addClass('vjs-disabled'); 3055 this.el_.setAttribute('aria-disabled', 'true'); 3056 return this; 3057 }; 3058 3059 /** 3060 * Handle Click - Override with specific functionality for component 3061 * 3062 * @method handleClick 3063 */ 3064 3065 ClickableComponent.prototype.handleClick = function handleClick() {}; 3066 3067 /** 3068 * Handle Focus - Add keyboard functionality to element 3069 * 3070 * @method handleFocus 3071 */ 3072 3073 ClickableComponent.prototype.handleFocus = function handleFocus() { 3074 Events.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); 3075 }; 3076 3077 /** 3078 * Handle KeyPress (document level) - Trigger click when Space or Enter key is pressed 3079 * 3080 * @method handleKeyPress 3081 */ 3082 3083 ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) { 3084 // Support Space (32) or Enter (13) key operation to fire a click event 3085 if (event.which === 32 || event.which === 13) { 3086 event.preventDefault(); 3087 this.handleClick(event); 3088 } else if (_Component.prototype.handleKeyPress) { 3089 _Component.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys 3090 } 3091 }; 3092 3093 /** 3094 * Handle Blur - Remove keyboard triggers 3095 * 3096 * @method handleBlur 3097 */ 3098 3099 ClickableComponent.prototype.handleBlur = function handleBlur() { 3100 Events.off(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); 3101 }; 3102 3103 return ClickableComponent; 3104 })(_component2['default']); 3105 3106 _component2['default'].registerComponent('ClickableComponent', ClickableComponent); 3107 exports['default'] = ClickableComponent; 3108 module.exports = exports['default']; 3109 3110 },{"./component":67,"./utils/dom.js":134,"./utils/events.js":135,"./utils/fn.js":136,"./utils/log.js":139,"global/document":1,"object.assign":45}],66:[function(_dereq_,module,exports){ 3111 'use strict'; 3112 3113 exports.__esModule = true; 3114 3115 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 3116 3117 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 3118 3119 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 3120 3121 var _button = _dereq_('./button'); 3122 3123 var _button2 = _interopRequireDefault(_button); 3124 3125 var _component = _dereq_('./component'); 3126 3127 var _component2 = _interopRequireDefault(_component); 3128 3129 /** 3130 * The `CloseButton` component is a button which fires a "close" event 3131 * when it is activated. 3132 * 3133 * @extends Button 3134 * @class CloseButton 3135 */ 3136 3137 var CloseButton = (function (_Button) { 3138 _inherits(CloseButton, _Button); 3139 3140 function CloseButton(player, options) { 3141 _classCallCheck(this, CloseButton); 3142 3143 _Button.call(this, player, options); 3144 this.controlText(options && options.controlText || this.localize('Close')); 3145 } 3146 3147 CloseButton.prototype.buildCSSClass = function buildCSSClass() { 3148 return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this); 3149 }; 3150 3151 CloseButton.prototype.handleClick = function handleClick() { 3152 this.trigger({ type: 'close', bubbles: false }); 3153 }; 3154 3155 return CloseButton; 3156 })(_button2['default']); 3157 3158 _component2['default'].registerComponent('CloseButton', CloseButton); 3159 exports['default'] = CloseButton; 3160 module.exports = exports['default']; 3161 3162 },{"./button":64,"./component":67}],67:[function(_dereq_,module,exports){ 3163 /** 3164 * @file component.js 3165 * 3166 * Player Component - Base class for all UI objects 3167 */ 3168 3169 'use strict'; 3170 3171 exports.__esModule = true; 3172 3173 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 3174 3175 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 3176 3177 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 3178 3179 var _globalWindow = _dereq_('global/window'); 3180 3181 var _globalWindow2 = _interopRequireDefault(_globalWindow); 3182 3183 var _utilsDomJs = _dereq_('./utils/dom.js'); 3184 3185 var Dom = _interopRequireWildcard(_utilsDomJs); 3186 3187 var _utilsFnJs = _dereq_('./utils/fn.js'); 3188 3189 var Fn = _interopRequireWildcard(_utilsFnJs); 3190 3191 var _utilsGuidJs = _dereq_('./utils/guid.js'); 3192 3193 var Guid = _interopRequireWildcard(_utilsGuidJs); 3194 3195 var _utilsEventsJs = _dereq_('./utils/events.js'); 3196 3197 var Events = _interopRequireWildcard(_utilsEventsJs); 3198 3199 var _utilsLogJs = _dereq_('./utils/log.js'); 3200 3201 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 3202 3203 var _utilsToTitleCaseJs = _dereq_('./utils/to-title-case.js'); 3204 3205 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 3206 3207 var _objectAssign = _dereq_('object.assign'); 3208 3209 var _objectAssign2 = _interopRequireDefault(_objectAssign); 3210 3211 var _utilsMergeOptionsJs = _dereq_('./utils/merge-options.js'); 3212 3213 var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); 3214 3215 /** 3216 * Base UI Component class 3217 * Components are embeddable UI objects that are represented by both a 3218 * javascript object and an element in the DOM. They can be children of other 3219 * components, and can have many children themselves. 3220 * ```js 3221 * // adding a button to the player 3222 * var button = player.addChild('button'); 3223 * button.el(); // -> button element 3224 * ``` 3225 * ```html 3226 * <div class="video-js"> 3227 * <div class="vjs-button">Button</div> 3228 * </div> 3229 * ``` 3230 * Components are also event targets. 3231 * ```js 3232 * button.on('click', function(){ 3233 * console.log('Button Clicked!'); 3234 * }); 3235 * button.trigger('customevent'); 3236 * ``` 3237 * 3238 * @param {Object} player Main Player 3239 * @param {Object=} options Object of option names and values 3240 * @param {Function=} ready Ready callback function 3241 * @class Component 3242 */ 3243 3244 var Component = (function () { 3245 function Component(player, options, ready) { 3246 _classCallCheck(this, Component); 3247 3248 // The component might be the player itself and we can't pass `this` to super 3249 if (!player && this.play) { 3250 this.player_ = player = this; // eslint-disable-line 3251 } else { 3252 this.player_ = player; 3253 } 3254 3255 // Make a copy of prototype.options_ to protect against overriding defaults 3256 this.options_ = _utilsMergeOptionsJs2['default']({}, this.options_); 3257 3258 // Updated options with supplied options 3259 options = this.options_ = _utilsMergeOptionsJs2['default'](this.options_, options); 3260 3261 // Get ID from options or options element if one is supplied 3262 this.id_ = options.id || options.el && options.el.id; 3263 3264 // If there was no ID from the options, generate one 3265 if (!this.id_) { 3266 // Don't require the player ID function in the case of mock players 3267 var id = player && player.id && player.id() || 'no_player'; 3268 3269 this.id_ = id + '_component_' + Guid.newGUID(); 3270 } 3271 3272 this.name_ = options.name || null; 3273 3274 // Create element if one wasn't provided in options 3275 if (options.el) { 3276 this.el_ = options.el; 3277 } else if (options.createEl !== false) { 3278 this.el_ = this.createEl(); 3279 } 3280 3281 this.children_ = []; 3282 this.childIndex_ = {}; 3283 this.childNameIndex_ = {}; 3284 3285 // Add any child components in options 3286 if (options.initChildren !== false) { 3287 this.initChildren(); 3288 } 3289 3290 this.ready(ready); 3291 // Don't want to trigger ready here or it will before init is actually 3292 // finished for all children that run this constructor 3293 3294 if (options.reportTouchActivity !== false) { 3295 this.enableTouchActivity(); 3296 } 3297 } 3298 3299 /** 3300 * Dispose of the component and all child components 3301 * 3302 * @method dispose 3303 */ 3304 3305 Component.prototype.dispose = function dispose() { 3306 this.trigger({ type: 'dispose', bubbles: false }); 3307 3308 // Dispose all children. 3309 if (this.children_) { 3310 for (var i = this.children_.length - 1; i >= 0; i--) { 3311 if (this.children_[i].dispose) { 3312 this.children_[i].dispose(); 3313 } 3314 } 3315 } 3316 3317 // Delete child references 3318 this.children_ = null; 3319 this.childIndex_ = null; 3320 this.childNameIndex_ = null; 3321 3322 // Remove all event listeners. 3323 this.off(); 3324 3325 // Remove element from DOM 3326 if (this.el_.parentNode) { 3327 this.el_.parentNode.removeChild(this.el_); 3328 } 3329 3330 Dom.removeElData(this.el_); 3331 this.el_ = null; 3332 }; 3333 3334 /** 3335 * Return the component's player 3336 * 3337 * @return {Player} 3338 * @method player 3339 */ 3340 3341 Component.prototype.player = function player() { 3342 return this.player_; 3343 }; 3344 3345 /** 3346 * Deep merge of options objects 3347 * Whenever a property is an object on both options objects 3348 * the two properties will be merged using mergeOptions. 3349 * 3350 * ```js 3351 * Parent.prototype.options_ = { 3352 * optionSet: { 3353 * 'childOne': { 'foo': 'bar', 'asdf': 'fdsa' }, 3354 * 'childTwo': {}, 3355 * 'childThree': {} 3356 * } 3357 * } 3358 * newOptions = { 3359 * optionSet: { 3360 * 'childOne': { 'foo': 'baz', 'abc': '123' } 3361 * 'childTwo': null, 3362 * 'childFour': {} 3363 * } 3364 * } 3365 * 3366 * this.options(newOptions); 3367 * ``` 3368 * RESULT 3369 * ```js 3370 * { 3371 * optionSet: { 3372 * 'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' }, 3373 * 'childTwo': null, // Disabled. Won't be initialized. 3374 * 'childThree': {}, 3375 * 'childFour': {} 3376 * } 3377 * } 3378 * ``` 3379 * 3380 * @param {Object} obj Object of new option values 3381 * @return {Object} A NEW object of this.options_ and obj merged 3382 * @method options 3383 */ 3384 3385 Component.prototype.options = function options(obj) { 3386 _utilsLogJs2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); 3387 3388 if (!obj) { 3389 return this.options_; 3390 } 3391 3392 this.options_ = _utilsMergeOptionsJs2['default'](this.options_, obj); 3393 return this.options_; 3394 }; 3395 3396 /** 3397 * Get the component's DOM element 3398 * ```js 3399 * var domEl = myComponent.el(); 3400 * ``` 3401 * 3402 * @return {Element} 3403 * @method el 3404 */ 3405 3406 Component.prototype.el = function el() { 3407 return this.el_; 3408 }; 3409 3410 /** 3411 * Create the component's DOM element 3412 * 3413 * @param {String=} tagName Element's node type. e.g. 'div' 3414 * @param {Object=} properties An object of properties that should be set 3415 * @param {Object=} attributes An object of attributes that should be set 3416 * @return {Element} 3417 * @method createEl 3418 */ 3419 3420 Component.prototype.createEl = function createEl(tagName, properties, attributes) { 3421 return Dom.createEl(tagName, properties, attributes); 3422 }; 3423 3424 Component.prototype.localize = function localize(string) { 3425 var code = this.player_.language && this.player_.language(); 3426 var languages = this.player_.languages && this.player_.languages(); 3427 3428 if (!code || !languages) { 3429 return string; 3430 } 3431 3432 var language = languages[code]; 3433 3434 if (language && language[string]) { 3435 return language[string]; 3436 } 3437 3438 var primaryCode = code.split('-')[0]; 3439 var primaryLang = languages[primaryCode]; 3440 3441 if (primaryLang && primaryLang[string]) { 3442 return primaryLang[string]; 3443 } 3444 3445 return string; 3446 }; 3447 3448 /** 3449 * Return the component's DOM element where children are inserted. 3450 * Will either be the same as el() or a new element defined in createEl(). 3451 * 3452 * @return {Element} 3453 * @method contentEl 3454 */ 3455 3456 Component.prototype.contentEl = function contentEl() { 3457 return this.contentEl_ || this.el_; 3458 }; 3459 3460 /** 3461 * Get the component's ID 3462 * ```js 3463 * var id = myComponent.id(); 3464 * ``` 3465 * 3466 * @return {String} 3467 * @method id 3468 */ 3469 3470 Component.prototype.id = function id() { 3471 return this.id_; 3472 }; 3473 3474 /** 3475 * Get the component's name. The name is often used to reference the component. 3476 * ```js 3477 * var name = myComponent.name(); 3478 * ``` 3479 * 3480 * @return {String} 3481 * @method name 3482 */ 3483 3484 Component.prototype.name = function name() { 3485 return this.name_; 3486 }; 3487 3488 /** 3489 * Get an array of all child components 3490 * ```js 3491 * var kids = myComponent.children(); 3492 * ``` 3493 * 3494 * @return {Array} The children 3495 * @method children 3496 */ 3497 3498 Component.prototype.children = function children() { 3499 return this.children_; 3500 }; 3501 3502 /** 3503 * Returns a child component with the provided ID 3504 * 3505 * @return {Component} 3506 * @method getChildById 3507 */ 3508 3509 Component.prototype.getChildById = function getChildById(id) { 3510 return this.childIndex_[id]; 3511 }; 3512 3513 /** 3514 * Returns a child component with the provided name 3515 * 3516 * @return {Component} 3517 * @method getChild 3518 */ 3519 3520 Component.prototype.getChild = function getChild(name) { 3521 return this.childNameIndex_[name]; 3522 }; 3523 3524 /** 3525 * Adds a child component inside this component 3526 * ```js 3527 * myComponent.el(); 3528 * // -> <div class='my-component'></div> 3529 * myComponent.children(); 3530 * // [empty array] 3531 * 3532 * var myButton = myComponent.addChild('MyButton'); 3533 * // -> <div class='my-component'><div class="my-button">myButton<div></div> 3534 * // -> myButton === myComponent.children()[0]; 3535 * ``` 3536 * Pass in options for child constructors and options for children of the child 3537 * ```js 3538 * var myButton = myComponent.addChild('MyButton', { 3539 * text: 'Press Me', 3540 * buttonChildExample: { 3541 * buttonChildOption: true 3542 * } 3543 * }); 3544 * ``` 3545 * 3546 * @param {String|Component} child The class name or instance of a child to add 3547 * @param {Object=} options Options, including options to be passed to children of the child. 3548 * @param {Number} index into our children array to attempt to add the child 3549 * @return {Component} The child component (created by this process if a string was used) 3550 * @method addChild 3551 */ 3552 3553 Component.prototype.addChild = function addChild(child) { 3554 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 3555 var index = arguments.length <= 2 || arguments[2] === undefined ? this.children_.length : arguments[2]; 3556 3557 var component = undefined; 3558 var componentName = undefined; 3559 3560 // If child is a string, create nt with options 3561 if (typeof child === 'string') { 3562 componentName = child; 3563 3564 // Options can also be specified as a boolean, so convert to an empty object if false. 3565 if (!options) { 3566 options = {}; 3567 } 3568 3569 // Same as above, but true is deprecated so show a warning. 3570 if (options === true) { 3571 _utilsLogJs2['default'].warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.'); 3572 options = {}; 3573 } 3574 3575 // If no componentClass in options, assume componentClass is the name lowercased 3576 // (e.g. playButton) 3577 var componentClassName = options.componentClass || _utilsToTitleCaseJs2['default'](componentName); 3578 3579 // Set name through options 3580 options.name = componentName; 3581 3582 // Create a new object & element for this controls set 3583 // If there's no .player_, this is a player 3584 var ComponentClass = Component.getComponent(componentClassName); 3585 3586 if (!ComponentClass) { 3587 throw new Error('Component ' + componentClassName + ' does not exist'); 3588 } 3589 3590 // data stored directly on the videojs object may be 3591 // misidentified as a component to retain 3592 // backwards-compatibility with 4.x. check to make sure the 3593 // component class can be instantiated. 3594 if (typeof ComponentClass !== 'function') { 3595 return null; 3596 } 3597 3598 component = new ComponentClass(this.player_ || this, options); 3599 3600 // child is a component instance 3601 } else { 3602 component = child; 3603 } 3604 3605 this.children_.splice(index, 0, component); 3606 3607 if (typeof component.id === 'function') { 3608 this.childIndex_[component.id()] = component; 3609 } 3610 3611 // If a name wasn't used to create the component, check if we can use the 3612 // name function of the component 3613 componentName = componentName || component.name && component.name(); 3614 3615 if (componentName) { 3616 this.childNameIndex_[componentName] = component; 3617 } 3618 3619 // Add the UI object's element to the container div (box) 3620 // Having an element is not required 3621 if (typeof component.el === 'function' && component.el()) { 3622 var childNodes = this.contentEl().children; 3623 var refNode = childNodes[index] || null; 3624 this.contentEl().insertBefore(component.el(), refNode); 3625 } 3626 3627 // Return so it can stored on parent object if desired. 3628 return component; 3629 }; 3630 3631 /** 3632 * Remove a child component from this component's list of children, and the 3633 * child component's element from this component's element 3634 * 3635 * @param {Component} component Component to remove 3636 * @method removeChild 3637 */ 3638 3639 Component.prototype.removeChild = function removeChild(component) { 3640 if (typeof component === 'string') { 3641 component = this.getChild(component); 3642 } 3643 3644 if (!component || !this.children_) { 3645 return; 3646 } 3647 3648 var childFound = false; 3649 3650 for (var i = this.children_.length - 1; i >= 0; i--) { 3651 if (this.children_[i] === component) { 3652 childFound = true; 3653 this.children_.splice(i, 1); 3654 break; 3655 } 3656 } 3657 3658 if (!childFound) { 3659 return; 3660 } 3661 3662 this.childIndex_[component.id()] = null; 3663 this.childNameIndex_[component.name()] = null; 3664 3665 var compEl = component.el(); 3666 3667 if (compEl && compEl.parentNode === this.contentEl()) { 3668 this.contentEl().removeChild(component.el()); 3669 } 3670 }; 3671 3672 /** 3673 * Add and initialize default child components from options 3674 * ```js 3675 * // when an instance of MyComponent is created, all children in options 3676 * // will be added to the instance by their name strings and options 3677 * MyComponent.prototype.options_ = { 3678 * children: [ 3679 * 'myChildComponent' 3680 * ], 3681 * myChildComponent: { 3682 * myChildOption: true 3683 * } 3684 * }; 3685 * 3686 * // Or when creating the component 3687 * var myComp = new MyComponent(player, { 3688 * children: [ 3689 * 'myChildComponent' 3690 * ], 3691 * myChildComponent: { 3692 * myChildOption: true 3693 * } 3694 * }); 3695 * ``` 3696 * The children option can also be an array of 3697 * child options objects (that also include a 'name' key). 3698 * This can be used if you have two child components of the 3699 * same type that need different options. 3700 * ```js 3701 * var myComp = new MyComponent(player, { 3702 * children: [ 3703 * 'button', 3704 * { 3705 * name: 'button', 3706 * someOtherOption: true 3707 * }, 3708 * { 3709 * name: 'button', 3710 * someOtherOption: false 3711 * } 3712 * ] 3713 * }); 3714 * ``` 3715 * 3716 * @method initChildren 3717 */ 3718 3719 Component.prototype.initChildren = function initChildren() { 3720 var _this = this; 3721 3722 var children = this.options_.children; 3723 3724 if (children) { 3725 (function () { 3726 // `this` is `parent` 3727 var parentOptions = _this.options_; 3728 3729 var handleAdd = function handleAdd(child) { 3730 var name = child.name; 3731 var opts = child.opts; 3732 3733 // Allow options for children to be set at the parent options 3734 // e.g. videojs(id, { controlBar: false }); 3735 // instead of videojs(id, { children: { controlBar: false }); 3736 if (parentOptions[name] !== undefined) { 3737 opts = parentOptions[name]; 3738 } 3739 3740 // Allow for disabling default components 3741 // e.g. options['children']['posterImage'] = false 3742 if (opts === false) { 3743 return; 3744 } 3745 3746 // Allow options to be passed as a simple boolean if no configuration 3747 // is necessary. 3748 if (opts === true) { 3749 opts = {}; 3750 } 3751 3752 // We also want to pass the original player options to each component as well so they don't need to 3753 // reach back into the player for options later. 3754 opts.playerOptions = _this.options_.playerOptions; 3755 3756 // Create and add the child component. 3757 // Add a direct reference to the child by name on the parent instance. 3758 // If two of the same component are used, different names should be supplied 3759 // for each 3760 var newChild = _this.addChild(name, opts); 3761 if (newChild) { 3762 _this[name] = newChild; 3763 } 3764 }; 3765 3766 // Allow for an array of children details to passed in the options 3767 var workingChildren = undefined; 3768 var Tech = Component.getComponent('Tech'); 3769 3770 if (Array.isArray(children)) { 3771 workingChildren = children; 3772 } else { 3773 workingChildren = Object.keys(children); 3774 } 3775 3776 workingChildren 3777 // children that are in this.options_ but also in workingChildren would 3778 // give us extra children we do not want. So, we want to filter them out. 3779 .concat(Object.keys(_this.options_).filter(function (child) { 3780 return !workingChildren.some(function (wchild) { 3781 if (typeof wchild === 'string') { 3782 return child === wchild; 3783 } else { 3784 return child === wchild.name; 3785 } 3786 }); 3787 })).map(function (child) { 3788 var name = undefined, 3789 opts = undefined; 3790 3791 if (typeof child === 'string') { 3792 name = child; 3793 opts = children[name] || _this.options_[name] || {}; 3794 } else { 3795 name = child.name; 3796 opts = child; 3797 } 3798 3799 return { name: name, opts: opts }; 3800 }).filter(function (child) { 3801 // we have to make sure that child.name isn't in the techOrder since 3802 // techs are registerd as Components but can't aren't compatible 3803 // See https://github.com/videojs/video.js/issues/2772 3804 var c = Component.getComponent(child.opts.componentClass || _utilsToTitleCaseJs2['default'](child.name)); 3805 return c && !Tech.isTech(c); 3806 }).forEach(handleAdd); 3807 })(); 3808 } 3809 }; 3810 3811 /** 3812 * Allows sub components to stack CSS class names 3813 * 3814 * @return {String} The constructed class name 3815 * @method buildCSSClass 3816 */ 3817 3818 Component.prototype.buildCSSClass = function buildCSSClass() { 3819 // Child classes can include a function that does: 3820 // return 'CLASS NAME' + this._super(); 3821 return ''; 3822 }; 3823 3824 /** 3825 * Add an event listener to this component's element 3826 * ```js 3827 * var myFunc = function(){ 3828 * var myComponent = this; 3829 * // Do something when the event is fired 3830 * }; 3831 * 3832 * myComponent.on('eventType', myFunc); 3833 * ``` 3834 * The context of myFunc will be myComponent unless previously bound. 3835 * Alternatively, you can add a listener to another element or component. 3836 * ```js 3837 * myComponent.on(otherElement, 'eventName', myFunc); 3838 * myComponent.on(otherComponent, 'eventName', myFunc); 3839 * ``` 3840 * The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)` 3841 * and `otherComponent.on('eventName', myFunc)` is that this way the listeners 3842 * will be automatically cleaned up when either component is disposed. 3843 * It will also bind myComponent as the context of myFunc. 3844 * **NOTE**: When using this on elements in the page other than window 3845 * and document (both permanent), if you remove the element from the DOM 3846 * you need to call `myComponent.trigger(el, 'dispose')` on it to clean up 3847 * references to it and allow the browser to garbage collect it. 3848 * 3849 * @param {String|Component} first The event type or other component 3850 * @param {Function|String} second The event handler or event type 3851 * @param {Function} third The event handler 3852 * @return {Component} 3853 * @method on 3854 */ 3855 3856 Component.prototype.on = function on(first, second, third) { 3857 var _this2 = this; 3858 3859 if (typeof first === 'string' || Array.isArray(first)) { 3860 Events.on(this.el_, first, Fn.bind(this, second)); 3861 3862 // Targeting another component or element 3863 } else { 3864 (function () { 3865 var target = first; 3866 var type = second; 3867 var fn = Fn.bind(_this2, third); 3868 3869 // When this component is disposed, remove the listener from the other component 3870 var removeOnDispose = function removeOnDispose() { 3871 return _this2.off(target, type, fn); 3872 }; 3873 3874 // Use the same function ID so we can remove it later it using the ID 3875 // of the original listener 3876 removeOnDispose.guid = fn.guid; 3877 _this2.on('dispose', removeOnDispose); 3878 3879 // If the other component is disposed first we need to clean the reference 3880 // to the other component in this component's removeOnDispose listener 3881 // Otherwise we create a memory leak. 3882 var cleanRemover = function cleanRemover() { 3883 return _this2.off('dispose', removeOnDispose); 3884 }; 3885 3886 // Add the same function ID so we can easily remove it later 3887 cleanRemover.guid = fn.guid; 3888 3889 // Check if this is a DOM node 3890 if (first.nodeName) { 3891 // Add the listener to the other element 3892 Events.on(target, type, fn); 3893 Events.on(target, 'dispose', cleanRemover); 3894 3895 // Should be a component 3896 // Not using `instanceof Component` because it makes mock players difficult 3897 } else if (typeof first.on === 'function') { 3898 // Add the listener to the other component 3899 target.on(type, fn); 3900 target.on('dispose', cleanRemover); 3901 } 3902 })(); 3903 } 3904 3905 return this; 3906 }; 3907 3908 /** 3909 * Remove an event listener from this component's element 3910 * ```js 3911 * myComponent.off('eventType', myFunc); 3912 * ``` 3913 * If myFunc is excluded, ALL listeners for the event type will be removed. 3914 * If eventType is excluded, ALL listeners will be removed from the component. 3915 * Alternatively you can use `off` to remove listeners that were added to other 3916 * elements or components using `myComponent.on(otherComponent...`. 3917 * In this case both the event type and listener function are REQUIRED. 3918 * ```js 3919 * myComponent.off(otherElement, 'eventType', myFunc); 3920 * myComponent.off(otherComponent, 'eventType', myFunc); 3921 * ``` 3922 * 3923 * @param {String=|Component} first The event type or other component 3924 * @param {Function=|String} second The listener function or event type 3925 * @param {Function=} third The listener for other component 3926 * @return {Component} 3927 * @method off 3928 */ 3929 3930 Component.prototype.off = function off(first, second, third) { 3931 if (!first || typeof first === 'string' || Array.isArray(first)) { 3932 Events.off(this.el_, first, second); 3933 } else { 3934 var target = first; 3935 var type = second; 3936 // Ensure there's at least a guid, even if the function hasn't been used 3937 var fn = Fn.bind(this, third); 3938 3939 // Remove the dispose listener on this component, 3940 // which was given the same guid as the event listener 3941 this.off('dispose', fn); 3942 3943 if (first.nodeName) { 3944 // Remove the listener 3945 Events.off(target, type, fn); 3946 // Remove the listener for cleaning the dispose listener 3947 Events.off(target, 'dispose', fn); 3948 } else { 3949 target.off(type, fn); 3950 target.off('dispose', fn); 3951 } 3952 } 3953 3954 return this; 3955 }; 3956 3957 /** 3958 * Add an event listener to be triggered only once and then removed 3959 * ```js 3960 * myComponent.one('eventName', myFunc); 3961 * ``` 3962 * Alternatively you can add a listener to another element or component 3963 * that will be triggered only once. 3964 * ```js 3965 * myComponent.one(otherElement, 'eventName', myFunc); 3966 * myComponent.one(otherComponent, 'eventName', myFunc); 3967 * ``` 3968 * 3969 * @param {String|Component} first The event type or other component 3970 * @param {Function|String} second The listener function or event type 3971 * @param {Function=} third The listener function for other component 3972 * @return {Component} 3973 * @method one 3974 */ 3975 3976 Component.prototype.one = function one(first, second, third) { 3977 var _this3 = this, 3978 _arguments = arguments; 3979 3980 if (typeof first === 'string' || Array.isArray(first)) { 3981 Events.one(this.el_, first, Fn.bind(this, second)); 3982 } else { 3983 (function () { 3984 var target = first; 3985 var type = second; 3986 var fn = Fn.bind(_this3, third); 3987 3988 var newFunc = function newFunc() { 3989 _this3.off(target, type, newFunc); 3990 fn.apply(null, _arguments); 3991 }; 3992 3993 // Keep the same function ID so we can remove it later 3994 newFunc.guid = fn.guid; 3995 3996 _this3.on(target, type, newFunc); 3997 })(); 3998 } 3999 4000 return this; 4001 }; 4002 4003 /** 4004 * Trigger an event on an element 4005 * ```js 4006 * myComponent.trigger('eventName'); 4007 * myComponent.trigger({'type':'eventName'}); 4008 * myComponent.trigger('eventName', {data: 'some data'}); 4009 * myComponent.trigger({'type':'eventName'}, {data: 'some data'}); 4010 * ``` 4011 * 4012 * @param {Event|Object|String} event A string (the type) or an event object with a type attribute 4013 * @param {Object} [hash] data hash to pass along with the event 4014 * @return {Component} self 4015 * @method trigger 4016 */ 4017 4018 Component.prototype.trigger = function trigger(event, hash) { 4019 Events.trigger(this.el_, event, hash); 4020 return this; 4021 }; 4022 4023 /** 4024 * Bind a listener to the component's ready state. 4025 * Different from event listeners in that if the ready event has already happened 4026 * it will trigger the function immediately. 4027 * 4028 * @param {Function} fn Ready listener 4029 * @param {Boolean} sync Exec the listener synchronously if component is ready 4030 * @return {Component} 4031 * @method ready 4032 */ 4033 4034 Component.prototype.ready = function ready(fn) { 4035 var sync = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 4036 4037 if (fn) { 4038 if (this.isReady_) { 4039 if (sync) { 4040 fn.call(this); 4041 } else { 4042 // Call the function asynchronously by default for consistency 4043 this.setTimeout(fn, 1); 4044 } 4045 } else { 4046 this.readyQueue_ = this.readyQueue_ || []; 4047 this.readyQueue_.push(fn); 4048 } 4049 } 4050 return this; 4051 }; 4052 4053 /** 4054 * Trigger the ready listeners 4055 * 4056 * @return {Component} 4057 * @method triggerReady 4058 */ 4059 4060 Component.prototype.triggerReady = function triggerReady() { 4061 this.isReady_ = true; 4062 4063 // Ensure ready is triggerd asynchronously 4064 this.setTimeout(function () { 4065 var readyQueue = this.readyQueue_; 4066 4067 // Reset Ready Queue 4068 this.readyQueue_ = []; 4069 4070 if (readyQueue && readyQueue.length > 0) { 4071 readyQueue.forEach(function (fn) { 4072 fn.call(this); 4073 }, this); 4074 } 4075 4076 // Allow for using event listeners also 4077 this.trigger('ready'); 4078 }, 1); 4079 }; 4080 4081 /** 4082 * Finds a single DOM element matching `selector` within the component's 4083 * `contentEl` or another custom context. 4084 * 4085 * @method $ 4086 * @param {String} selector 4087 * A valid CSS selector, which will be passed to `querySelector`. 4088 * 4089 * @param {Element|String} [context=document] 4090 * A DOM element within which to query. Can also be a selector 4091 * string in which case the first matching element will be used 4092 * as context. If missing (or no element matches selector), falls 4093 * back to `document`. 4094 * 4095 * @return {Element|null} 4096 */ 4097 4098 Component.prototype.$ = function $(selector, context) { 4099 return Dom.$(selector, context || this.contentEl()); 4100 }; 4101 4102 /** 4103 * Finds a all DOM elements matching `selector` within the component's 4104 * `contentEl` or another custom context. 4105 * 4106 * @method $$ 4107 * @param {String} selector 4108 * A valid CSS selector, which will be passed to `querySelectorAll`. 4109 * 4110 * @param {Element|String} [context=document] 4111 * A DOM element within which to query. Can also be a selector 4112 * string in which case the first matching element will be used 4113 * as context. If missing (or no element matches selector), falls 4114 * back to `document`. 4115 * 4116 * @return {NodeList} 4117 */ 4118 4119 Component.prototype.$$ = function $$(selector, context) { 4120 return Dom.$$(selector, context || this.contentEl()); 4121 }; 4122 4123 /** 4124 * Check if a component's element has a CSS class name 4125 * 4126 * @param {String} classToCheck Classname to check 4127 * @return {Component} 4128 * @method hasClass 4129 */ 4130 4131 Component.prototype.hasClass = function hasClass(classToCheck) { 4132 return Dom.hasElClass(this.el_, classToCheck); 4133 }; 4134 4135 /** 4136 * Add a CSS class name to the component's element 4137 * 4138 * @param {String} classToAdd Classname to add 4139 * @return {Component} 4140 * @method addClass 4141 */ 4142 4143 Component.prototype.addClass = function addClass(classToAdd) { 4144 Dom.addElClass(this.el_, classToAdd); 4145 return this; 4146 }; 4147 4148 /** 4149 * Remove a CSS class name from the component's element 4150 * 4151 * @param {String} classToRemove Classname to remove 4152 * @return {Component} 4153 * @method removeClass 4154 */ 4155 4156 Component.prototype.removeClass = function removeClass(classToRemove) { 4157 Dom.removeElClass(this.el_, classToRemove); 4158 return this; 4159 }; 4160 4161 /** 4162 * Add or remove a CSS class name from the component's element 4163 * 4164 * @param {String} classToToggle 4165 * @param {Boolean|Function} [predicate] 4166 * Can be a function that returns a Boolean. If `true`, the class 4167 * will be added; if `false`, the class will be removed. If not 4168 * given, the class will be added if not present and vice versa. 4169 * 4170 * @return {Component} 4171 * @method toggleClass 4172 */ 4173 4174 Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) { 4175 Dom.toggleElClass(this.el_, classToToggle, predicate); 4176 return this; 4177 }; 4178 4179 /** 4180 * Show the component element if hidden 4181 * 4182 * @return {Component} 4183 * @method show 4184 */ 4185 4186 Component.prototype.show = function show() { 4187 this.removeClass('vjs-hidden'); 4188 return this; 4189 }; 4190 4191 /** 4192 * Hide the component element if currently showing 4193 * 4194 * @return {Component} 4195 * @method hide 4196 */ 4197 4198 Component.prototype.hide = function hide() { 4199 this.addClass('vjs-hidden'); 4200 return this; 4201 }; 4202 4203 /** 4204 * Lock an item in its visible state 4205 * To be used with fadeIn/fadeOut. 4206 * 4207 * @return {Component} 4208 * @private 4209 * @method lockShowing 4210 */ 4211 4212 Component.prototype.lockShowing = function lockShowing() { 4213 this.addClass('vjs-lock-showing'); 4214 return this; 4215 }; 4216 4217 /** 4218 * Unlock an item to be hidden 4219 * To be used with fadeIn/fadeOut. 4220 * 4221 * @return {Component} 4222 * @private 4223 * @method unlockShowing 4224 */ 4225 4226 Component.prototype.unlockShowing = function unlockShowing() { 4227 this.removeClass('vjs-lock-showing'); 4228 return this; 4229 }; 4230 4231 /** 4232 * Set or get the width of the component (CSS values) 4233 * Setting the video tag dimension values only works with values in pixels. 4234 * Percent values will not work. 4235 * Some percents can be used, but width()/height() will return the number + %, 4236 * not the actual computed width/height. 4237 * 4238 * @param {Number|String=} num Optional width number 4239 * @param {Boolean} skipListeners Skip the 'resize' event trigger 4240 * @return {Component} This component, when setting the width 4241 * @return {Number|String} The width, when getting 4242 * @method width 4243 */ 4244 4245 Component.prototype.width = function width(num, skipListeners) { 4246 return this.dimension('width', num, skipListeners); 4247 }; 4248 4249 /** 4250 * Get or set the height of the component (CSS values) 4251 * Setting the video tag dimension values only works with values in pixels. 4252 * Percent values will not work. 4253 * Some percents can be used, but width()/height() will return the number + %, 4254 * not the actual computed width/height. 4255 * 4256 * @param {Number|String=} num New component height 4257 * @param {Boolean=} skipListeners Skip the resize event trigger 4258 * @return {Component} This component, when setting the height 4259 * @return {Number|String} The height, when getting 4260 * @method height 4261 */ 4262 4263 Component.prototype.height = function height(num, skipListeners) { 4264 return this.dimension('height', num, skipListeners); 4265 }; 4266 4267 /** 4268 * Set both width and height at the same time 4269 * 4270 * @param {Number|String} width Width of player 4271 * @param {Number|String} height Height of player 4272 * @return {Component} The component 4273 * @method dimensions 4274 */ 4275 4276 Component.prototype.dimensions = function dimensions(width, height) { 4277 // Skip resize listeners on width for optimization 4278 return this.width(width, true).height(height); 4279 }; 4280 4281 /** 4282 * Get or set width or height 4283 * This is the shared code for the width() and height() methods. 4284 * All for an integer, integer + 'px' or integer + '%'; 4285 * Known issue: Hidden elements officially have a width of 0. We're defaulting 4286 * to the style.width value and falling back to computedStyle which has the 4287 * hidden element issue. Info, but probably not an efficient fix: 4288 * http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/ 4289 * 4290 * @param {String} widthOrHeight 'width' or 'height' 4291 * @param {Number|String=} num New dimension 4292 * @param {Boolean=} skipListeners Skip resize event trigger 4293 * @return {Component} The component if a dimension was set 4294 * @return {Number|String} The dimension if nothing was set 4295 * @private 4296 * @method dimension 4297 */ 4298 4299 Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) { 4300 if (num !== undefined) { 4301 // Set to zero if null or literally NaN (NaN !== NaN) 4302 if (num === null || num !== num) { 4303 num = 0; 4304 } 4305 4306 // Check if using css width/height (% or px) and adjust 4307 if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) { 4308 this.el_.style[widthOrHeight] = num; 4309 } else if (num === 'auto') { 4310 this.el_.style[widthOrHeight] = ''; 4311 } else { 4312 this.el_.style[widthOrHeight] = num + 'px'; 4313 } 4314 4315 // skipListeners allows us to avoid triggering the resize event when setting both width and height 4316 if (!skipListeners) { 4317 this.trigger('resize'); 4318 } 4319 4320 // Return component 4321 return this; 4322 } 4323 4324 // Not setting a value, so getting it 4325 // Make sure element exists 4326 if (!this.el_) { 4327 return 0; 4328 } 4329 4330 // Get dimension value from style 4331 var val = this.el_.style[widthOrHeight]; 4332 var pxIndex = val.indexOf('px'); 4333 4334 if (pxIndex !== -1) { 4335 // Return the pixel value with no 'px' 4336 return parseInt(val.slice(0, pxIndex), 10); 4337 } 4338 4339 // No px so using % or no style was set, so falling back to offsetWidth/height 4340 // If component has display:none, offset will return 0 4341 // TODO: handle display:none and no dimension style using px 4342 return parseInt(this.el_['offset' + _utilsToTitleCaseJs2['default'](widthOrHeight)], 10); 4343 }; 4344 4345 /** 4346 * Get width or height of computed style 4347 * @param {String} widthOrHeight 'width' or 'height' 4348 * @return {Number|Boolean} The bolean false if nothing was set 4349 * @method currentDimension 4350 */ 4351 4352 Component.prototype.currentDimension = function currentDimension(widthOrHeight) { 4353 var computedWidthOrHeight = 0; 4354 4355 if (widthOrHeight !== 'width' && widthOrHeight !== 'height') { 4356 throw new Error('currentDimension only accepts width or height value'); 4357 } 4358 4359 if (typeof _globalWindow2['default'].getComputedStyle === 'function') { 4360 var computedStyle = _globalWindow2['default'].getComputedStyle(this.el_); 4361 computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight]; 4362 } else if (this.el_.currentStyle) { 4363 // ie 8 doesn't support computed style, shim it 4364 // return clientWidth or clientHeight instead for better accuracy 4365 var rule = 'offset' + _utilsToTitleCaseJs2['default'](widthOrHeight); 4366 computedWidthOrHeight = this.el_[rule]; 4367 } 4368 4369 // remove 'px' from variable and parse as integer 4370 computedWidthOrHeight = parseFloat(computedWidthOrHeight); 4371 return computedWidthOrHeight; 4372 }; 4373 4374 /** 4375 * Get an object which contains width and height values of computed style 4376 * @return {Object} The dimensions of element 4377 * @method currentDimensions 4378 */ 4379 4380 Component.prototype.currentDimensions = function currentDimensions() { 4381 return { 4382 width: this.currentDimension('width'), 4383 height: this.currentDimension('height') 4384 }; 4385 }; 4386 4387 /** 4388 * Get width of computed style 4389 * @return {Integer} 4390 * @method currentWidth 4391 */ 4392 4393 Component.prototype.currentWidth = function currentWidth() { 4394 return this.currentDimension('width'); 4395 }; 4396 4397 /** 4398 * Get height of computed style 4399 * @return {Integer} 4400 * @method currentHeight 4401 */ 4402 4403 Component.prototype.currentHeight = function currentHeight() { 4404 return this.currentDimension('height'); 4405 }; 4406 4407 /** 4408 * Emit 'tap' events when touch events are supported 4409 * This is used to support toggling the controls through a tap on the video. 4410 * We're requiring them to be enabled because otherwise every component would 4411 * have this extra overhead unnecessarily, on mobile devices where extra 4412 * overhead is especially bad. 4413 * 4414 * @private 4415 * @method emitTapEvents 4416 */ 4417 4418 Component.prototype.emitTapEvents = function emitTapEvents() { 4419 // Track the start time so we can determine how long the touch lasted 4420 var touchStart = 0; 4421 var firstTouch = null; 4422 4423 // Maximum movement allowed during a touch event to still be considered a tap 4424 // Other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number. 4425 var tapMovementThreshold = 10; 4426 4427 // The maximum length a touch can be while still being considered a tap 4428 var touchTimeThreshold = 200; 4429 4430 var couldBeTap = undefined; 4431 4432 this.on('touchstart', function (event) { 4433 // If more than one finger, don't consider treating this as a click 4434 if (event.touches.length === 1) { 4435 // Copy the touches object to prevent modifying the original 4436 firstTouch = _objectAssign2['default']({}, event.touches[0]); 4437 // Record start time so we can detect a tap vs. "touch and hold" 4438 touchStart = new Date().getTime(); 4439 // Reset couldBeTap tracking 4440 couldBeTap = true; 4441 } 4442 }); 4443 4444 this.on('touchmove', function (event) { 4445 // If more than one finger, don't consider treating this as a click 4446 if (event.touches.length > 1) { 4447 couldBeTap = false; 4448 } else if (firstTouch) { 4449 // Some devices will throw touchmoves for all but the slightest of taps. 4450 // So, if we moved only a small distance, this could still be a tap 4451 var xdiff = event.touches[0].pageX - firstTouch.pageX; 4452 var ydiff = event.touches[0].pageY - firstTouch.pageY; 4453 var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); 4454 4455 if (touchDistance > tapMovementThreshold) { 4456 couldBeTap = false; 4457 } 4458 } 4459 }); 4460 4461 var noTap = function noTap() { 4462 couldBeTap = false; 4463 }; 4464 4465 // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s 4466 this.on('touchleave', noTap); 4467 this.on('touchcancel', noTap); 4468 4469 // When the touch ends, measure how long it took and trigger the appropriate 4470 // event 4471 this.on('touchend', function (event) { 4472 firstTouch = null; 4473 // Proceed only if the touchmove/leave/cancel event didn't happen 4474 if (couldBeTap === true) { 4475 // Measure how long the touch lasted 4476 var touchTime = new Date().getTime() - touchStart; 4477 4478 // Make sure the touch was less than the threshold to be considered a tap 4479 if (touchTime < touchTimeThreshold) { 4480 // Don't let browser turn this into a click 4481 event.preventDefault(); 4482 this.trigger('tap'); 4483 // It may be good to copy the touchend event object and change the 4484 // type to tap, if the other event properties aren't exact after 4485 // Events.fixEvent runs (e.g. event.target) 4486 } 4487 } 4488 }); 4489 }; 4490 4491 /** 4492 * Report user touch activity when touch events occur 4493 * User activity is used to determine when controls should show/hide. It's 4494 * relatively simple when it comes to mouse events, because any mouse event 4495 * should show the controls. So we capture mouse events that bubble up to the 4496 * player and report activity when that happens. 4497 * With touch events it isn't as easy. We can't rely on touch events at the 4498 * player level, because a tap (touchstart + touchend) on the video itself on 4499 * mobile devices is meant to turn controls off (and on). User activity is 4500 * checked asynchronously, so what could happen is a tap event on the video 4501 * turns the controls off, then the touchend event bubbles up to the player, 4502 * which if it reported user activity, would turn the controls right back on. 4503 * (We also don't want to completely block touch events from bubbling up) 4504 * Also a touchmove, touch+hold, and anything other than a tap is not supposed 4505 * to turn the controls back on on a mobile device. 4506 * Here we're setting the default component behavior to report user activity 4507 * whenever touch events happen, and this can be turned off by components that 4508 * want touch events to act differently. 4509 * 4510 * @method enableTouchActivity 4511 */ 4512 4513 Component.prototype.enableTouchActivity = function enableTouchActivity() { 4514 // Don't continue if the root player doesn't support reporting user activity 4515 if (!this.player() || !this.player().reportUserActivity) { 4516 return; 4517 } 4518 4519 // listener for reporting that the user is active 4520 var report = Fn.bind(this.player(), this.player().reportUserActivity); 4521 4522 var touchHolding = undefined; 4523 4524 this.on('touchstart', function () { 4525 report(); 4526 // For as long as the they are touching the device or have their mouse down, 4527 // we consider them active even if they're not moving their finger or mouse. 4528 // So we want to continue to update that they are active 4529 this.clearInterval(touchHolding); 4530 // report at the same interval as activityCheck 4531 touchHolding = this.setInterval(report, 250); 4532 }); 4533 4534 var touchEnd = function touchEnd(event) { 4535 report(); 4536 // stop the interval that maintains activity if the touch is holding 4537 this.clearInterval(touchHolding); 4538 }; 4539 4540 this.on('touchmove', report); 4541 this.on('touchend', touchEnd); 4542 this.on('touchcancel', touchEnd); 4543 }; 4544 4545 /** 4546 * Creates timeout and sets up disposal automatically. 4547 * 4548 * @param {Function} fn The function to run after the timeout. 4549 * @param {Number} timeout Number of ms to delay before executing specified function. 4550 * @return {Number} Returns the timeout ID 4551 * @method setTimeout 4552 */ 4553 4554 Component.prototype.setTimeout = function setTimeout(fn, timeout) { 4555 fn = Fn.bind(this, fn); 4556 4557 // window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't. 4558 var timeoutId = _globalWindow2['default'].setTimeout(fn, timeout); 4559 4560 var disposeFn = function disposeFn() { 4561 this.clearTimeout(timeoutId); 4562 }; 4563 4564 disposeFn.guid = 'vjs-timeout-' + timeoutId; 4565 4566 this.on('dispose', disposeFn); 4567 4568 return timeoutId; 4569 }; 4570 4571 /** 4572 * Clears a timeout and removes the associated dispose listener 4573 * 4574 * @param {Number} timeoutId The id of the timeout to clear 4575 * @return {Number} Returns the timeout ID 4576 * @method clearTimeout 4577 */ 4578 4579 Component.prototype.clearTimeout = function clearTimeout(timeoutId) { 4580 _globalWindow2['default'].clearTimeout(timeoutId); 4581 4582 var disposeFn = function disposeFn() {}; 4583 4584 disposeFn.guid = 'vjs-timeout-' + timeoutId; 4585 4586 this.off('dispose', disposeFn); 4587 4588 return timeoutId; 4589 }; 4590 4591 /** 4592 * Creates an interval and sets up disposal automatically. 4593 * 4594 * @param {Function} fn The function to run every N seconds. 4595 * @param {Number} interval Number of ms to delay before executing specified function. 4596 * @return {Number} Returns the interval ID 4597 * @method setInterval 4598 */ 4599 4600 Component.prototype.setInterval = function setInterval(fn, interval) { 4601 fn = Fn.bind(this, fn); 4602 4603 var intervalId = _globalWindow2['default'].setInterval(fn, interval); 4604 4605 var disposeFn = function disposeFn() { 4606 this.clearInterval(intervalId); 4607 }; 4608 4609 disposeFn.guid = 'vjs-interval-' + intervalId; 4610 4611 this.on('dispose', disposeFn); 4612 4613 return intervalId; 4614 }; 4615 4616 /** 4617 * Clears an interval and removes the associated dispose listener 4618 * 4619 * @param {Number} intervalId The id of the interval to clear 4620 * @return {Number} Returns the interval ID 4621 * @method clearInterval 4622 */ 4623 4624 Component.prototype.clearInterval = function clearInterval(intervalId) { 4625 _globalWindow2['default'].clearInterval(intervalId); 4626 4627 var disposeFn = function disposeFn() {}; 4628 4629 disposeFn.guid = 'vjs-interval-' + intervalId; 4630 4631 this.off('dispose', disposeFn); 4632 4633 return intervalId; 4634 }; 4635 4636 /** 4637 * Registers a component 4638 * 4639 * @param {String} name Name of the component to register 4640 * @param {Object} comp The component to register 4641 * @static 4642 * @method registerComponent 4643 */ 4644 4645 Component.registerComponent = function registerComponent(name, comp) { 4646 if (!Component.components_) { 4647 Component.components_ = {}; 4648 } 4649 4650 Component.components_[name] = comp; 4651 return comp; 4652 }; 4653 4654 /** 4655 * Gets a component by name 4656 * 4657 * @param {String} name Name of the component to get 4658 * @return {Component} 4659 * @static 4660 * @method getComponent 4661 */ 4662 4663 Component.getComponent = function getComponent(name) { 4664 if (Component.components_ && Component.components_[name]) { 4665 return Component.components_[name]; 4666 } 4667 4668 if (_globalWindow2['default'] && _globalWindow2['default'].videojs && _globalWindow2['default'].videojs[name]) { 4669 _utilsLogJs2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)'); 4670 return _globalWindow2['default'].videojs[name]; 4671 } 4672 }; 4673 4674 /** 4675 * Sets up the constructor using the supplied init method 4676 * or uses the init of the parent object 4677 * 4678 * @param {Object} props An object of properties 4679 * @static 4680 * @deprecated 4681 * @method extend 4682 */ 4683 4684 Component.extend = function extend(props) { 4685 props = props || {}; 4686 4687 _utilsLogJs2['default'].warn('Component.extend({}) has been deprecated, use videojs.extend(Component, {}) instead'); 4688 4689 // Set up the constructor using the supplied init method 4690 // or using the init of the parent object 4691 // Make sure to check the unobfuscated version for external libs 4692 var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {}; 4693 // In Resig's simple class inheritance (previously used) the constructor 4694 // is a function that calls `this.init.apply(arguments)` 4695 // However that would prevent us from using `ParentObject.call(this);` 4696 // in a Child constructor because the `this` in `this.init` 4697 // would still refer to the Child and cause an infinite loop. 4698 // We would instead have to do 4699 // `ParentObject.prototype.init.apply(this, arguments);` 4700 // Bleh. We're not creating a _super() function, so it's good to keep 4701 // the parent constructor reference simple. 4702 var subObj = function subObj() { 4703 init.apply(this, arguments); 4704 }; 4705 4706 // Inherit from this object's prototype 4707 subObj.prototype = Object.create(this.prototype); 4708 // Reset the constructor property for subObj otherwise 4709 // instances of subObj would have the constructor of the parent Object 4710 subObj.prototype.constructor = subObj; 4711 4712 // Make the class extendable 4713 subObj.extend = Component.extend; 4714 4715 // Extend subObj's prototype with functions and other properties from props 4716 for (var _name in props) { 4717 if (props.hasOwnProperty(_name)) { 4718 subObj.prototype[_name] = props[_name]; 4719 } 4720 } 4721 4722 return subObj; 4723 }; 4724 4725 return Component; 4726 })(); 4727 4728 Component.registerComponent('Component', Component); 4729 exports['default'] = Component; 4730 module.exports = exports['default']; 4731 4732 },{"./utils/dom.js":134,"./utils/events.js":135,"./utils/fn.js":136,"./utils/guid.js":138,"./utils/log.js":139,"./utils/merge-options.js":140,"./utils/to-title-case.js":143,"global/window":2,"object.assign":45}],68:[function(_dereq_,module,exports){ 4733 /** 4734 * @file control-bar.js 4735 */ 4736 'use strict'; 4737 4738 exports.__esModule = true; 4739 4740 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4741 4742 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 4743 4744 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 4745 4746 var _componentJs = _dereq_('../component.js'); 4747 4748 var _componentJs2 = _interopRequireDefault(_componentJs); 4749 4750 // Required children 4751 4752 var _playToggleJs = _dereq_('./play-toggle.js'); 4753 4754 var _playToggleJs2 = _interopRequireDefault(_playToggleJs); 4755 4756 var _timeControlsCurrentTimeDisplayJs = _dereq_('./time-controls/current-time-display.js'); 4757 4758 var _timeControlsCurrentTimeDisplayJs2 = _interopRequireDefault(_timeControlsCurrentTimeDisplayJs); 4759 4760 var _timeControlsDurationDisplayJs = _dereq_('./time-controls/duration-display.js'); 4761 4762 var _timeControlsDurationDisplayJs2 = _interopRequireDefault(_timeControlsDurationDisplayJs); 4763 4764 var _timeControlsTimeDividerJs = _dereq_('./time-controls/time-divider.js'); 4765 4766 var _timeControlsTimeDividerJs2 = _interopRequireDefault(_timeControlsTimeDividerJs); 4767 4768 var _timeControlsRemainingTimeDisplayJs = _dereq_('./time-controls/remaining-time-display.js'); 4769 4770 var _timeControlsRemainingTimeDisplayJs2 = _interopRequireDefault(_timeControlsRemainingTimeDisplayJs); 4771 4772 var _liveDisplayJs = _dereq_('./live-display.js'); 4773 4774 var _liveDisplayJs2 = _interopRequireDefault(_liveDisplayJs); 4775 4776 var _progressControlProgressControlJs = _dereq_('./progress-control/progress-control.js'); 4777 4778 var _progressControlProgressControlJs2 = _interopRequireDefault(_progressControlProgressControlJs); 4779 4780 var _fullscreenToggleJs = _dereq_('./fullscreen-toggle.js'); 4781 4782 var _fullscreenToggleJs2 = _interopRequireDefault(_fullscreenToggleJs); 4783 4784 var _volumeControlVolumeControlJs = _dereq_('./volume-control/volume-control.js'); 4785 4786 var _volumeControlVolumeControlJs2 = _interopRequireDefault(_volumeControlVolumeControlJs); 4787 4788 var _volumeMenuButtonJs = _dereq_('./volume-menu-button.js'); 4789 4790 var _volumeMenuButtonJs2 = _interopRequireDefault(_volumeMenuButtonJs); 4791 4792 var _muteToggleJs = _dereq_('./mute-toggle.js'); 4793 4794 var _muteToggleJs2 = _interopRequireDefault(_muteToggleJs); 4795 4796 var _textTrackControlsChaptersButtonJs = _dereq_('./text-track-controls/chapters-button.js'); 4797 4798 var _textTrackControlsChaptersButtonJs2 = _interopRequireDefault(_textTrackControlsChaptersButtonJs); 4799 4800 var _textTrackControlsDescriptionsButtonJs = _dereq_('./text-track-controls/descriptions-button.js'); 4801 4802 var _textTrackControlsDescriptionsButtonJs2 = _interopRequireDefault(_textTrackControlsDescriptionsButtonJs); 4803 4804 var _textTrackControlsSubtitlesButtonJs = _dereq_('./text-track-controls/subtitles-button.js'); 4805 4806 var _textTrackControlsSubtitlesButtonJs2 = _interopRequireDefault(_textTrackControlsSubtitlesButtonJs); 4807 4808 var _textTrackControlsCaptionsButtonJs = _dereq_('./text-track-controls/captions-button.js'); 4809 4810 var _textTrackControlsCaptionsButtonJs2 = _interopRequireDefault(_textTrackControlsCaptionsButtonJs); 4811 4812 var _playbackRateMenuPlaybackRateMenuButtonJs = _dereq_('./playback-rate-menu/playback-rate-menu-button.js'); 4813 4814 var _playbackRateMenuPlaybackRateMenuButtonJs2 = _interopRequireDefault(_playbackRateMenuPlaybackRateMenuButtonJs); 4815 4816 var _spacerControlsCustomControlSpacerJs = _dereq_('./spacer-controls/custom-control-spacer.js'); 4817 4818 var _spacerControlsCustomControlSpacerJs2 = _interopRequireDefault(_spacerControlsCustomControlSpacerJs); 4819 4820 /** 4821 * Container of main controls 4822 * 4823 * @extends Component 4824 * @class ControlBar 4825 */ 4826 4827 var ControlBar = (function (_Component) { 4828 _inherits(ControlBar, _Component); 4829 4830 function ControlBar() { 4831 _classCallCheck(this, ControlBar); 4832 4833 _Component.apply(this, arguments); 4834 } 4835 4836 /** 4837 * Create the component's DOM element 4838 * 4839 * @return {Element} 4840 * @method createEl 4841 */ 4842 4843 ControlBar.prototype.createEl = function createEl() { 4844 return _Component.prototype.createEl.call(this, 'div', { 4845 className: 'vjs-control-bar', 4846 dir: 'ltr' 4847 }, { 4848 'role': 'group' // The control bar is a group, so it can contain menuitems 4849 }); 4850 }; 4851 4852 return ControlBar; 4853 })(_componentJs2['default']); 4854 4855 ControlBar.prototype.options_ = { 4856 loadEvent: 'play', 4857 children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'fullscreenToggle'] 4858 }; 4859 4860 _componentJs2['default'].registerComponent('ControlBar', ControlBar); 4861 exports['default'] = ControlBar; 4862 module.exports = exports['default']; 4863 4864 },{"../component.js":67,"./fullscreen-toggle.js":69,"./live-display.js":70,"./mute-toggle.js":71,"./play-toggle.js":72,"./playback-rate-menu/playback-rate-menu-button.js":73,"./progress-control/progress-control.js":78,"./spacer-controls/custom-control-spacer.js":81,"./text-track-controls/captions-button.js":84,"./text-track-controls/chapters-button.js":85,"./text-track-controls/descriptions-button.js":87,"./text-track-controls/subtitles-button.js":89,"./time-controls/current-time-display.js":92,"./time-controls/duration-display.js":93,"./time-controls/remaining-time-display.js":94,"./time-controls/time-divider.js":95,"./volume-control/volume-control.js":97,"./volume-menu-button.js":99}],69:[function(_dereq_,module,exports){ 4865 /** 4866 * @file fullscreen-toggle.js 4867 */ 4868 'use strict'; 4869 4870 exports.__esModule = true; 4871 4872 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4873 4874 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 4875 4876 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 4877 4878 var _buttonJs = _dereq_('../button.js'); 4879 4880 var _buttonJs2 = _interopRequireDefault(_buttonJs); 4881 4882 var _componentJs = _dereq_('../component.js'); 4883 4884 var _componentJs2 = _interopRequireDefault(_componentJs); 4885 4886 /** 4887 * Toggle fullscreen video 4888 * 4889 * @extends Button 4890 * @class FullscreenToggle 4891 */ 4892 4893 var FullscreenToggle = (function (_Button) { 4894 _inherits(FullscreenToggle, _Button); 4895 4896 function FullscreenToggle() { 4897 _classCallCheck(this, FullscreenToggle); 4898 4899 _Button.apply(this, arguments); 4900 } 4901 4902 /** 4903 * Allow sub components to stack CSS class names 4904 * 4905 * @return {String} The constructed class name 4906 * @method buildCSSClass 4907 */ 4908 4909 FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() { 4910 return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this); 4911 }; 4912 4913 /** 4914 * Handles click for full screen 4915 * 4916 * @method handleClick 4917 */ 4918 4919 FullscreenToggle.prototype.handleClick = function handleClick() { 4920 if (!this.player_.isFullscreen()) { 4921 this.player_.requestFullscreen(); 4922 this.controlText('Non-Fullscreen'); 4923 } else { 4924 this.player_.exitFullscreen(); 4925 this.controlText('Fullscreen'); 4926 } 4927 }; 4928 4929 return FullscreenToggle; 4930 })(_buttonJs2['default']); 4931 4932 FullscreenToggle.prototype.controlText_ = 'Fullscreen'; 4933 4934 _componentJs2['default'].registerComponent('FullscreenToggle', FullscreenToggle); 4935 exports['default'] = FullscreenToggle; 4936 module.exports = exports['default']; 4937 4938 },{"../button.js":64,"../component.js":67}],70:[function(_dereq_,module,exports){ 4939 /** 4940 * @file live-display.js 4941 */ 4942 'use strict'; 4943 4944 exports.__esModule = true; 4945 4946 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 4947 4948 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4949 4950 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 4951 4952 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 4953 4954 var _component = _dereq_('../component'); 4955 4956 var _component2 = _interopRequireDefault(_component); 4957 4958 var _utilsDomJs = _dereq_('../utils/dom.js'); 4959 4960 var Dom = _interopRequireWildcard(_utilsDomJs); 4961 4962 /** 4963 * Displays the live indicator 4964 * TODO - Future make it click to snap to live 4965 * 4966 * @extends Component 4967 * @class LiveDisplay 4968 */ 4969 4970 var LiveDisplay = (function (_Component) { 4971 _inherits(LiveDisplay, _Component); 4972 4973 function LiveDisplay(player, options) { 4974 _classCallCheck(this, LiveDisplay); 4975 4976 _Component.call(this, player, options); 4977 4978 this.updateShowing(); 4979 this.on(this.player(), 'durationchange', this.updateShowing); 4980 } 4981 4982 /** 4983 * Create the component's DOM element 4984 * 4985 * @return {Element} 4986 * @method createEl 4987 */ 4988 4989 LiveDisplay.prototype.createEl = function createEl() { 4990 var el = _Component.prototype.createEl.call(this, 'div', { 4991 className: 'vjs-live-control vjs-control' 4992 }); 4993 4994 this.contentEl_ = Dom.createEl('div', { 4995 className: 'vjs-live-display', 4996 innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE') 4997 }, { 4998 'aria-live': 'off' 4999 }); 5000 5001 el.appendChild(this.contentEl_); 5002 return el; 5003 }; 5004 5005 LiveDisplay.prototype.updateShowing = function updateShowing() { 5006 if (this.player().duration() === Infinity) { 5007 this.show(); 5008 } else { 5009 this.hide(); 5010 } 5011 }; 5012 5013 return LiveDisplay; 5014 })(_component2['default']); 5015 5016 _component2['default'].registerComponent('LiveDisplay', LiveDisplay); 5017 exports['default'] = LiveDisplay; 5018 module.exports = exports['default']; 5019 5020 },{"../component":67,"../utils/dom.js":134}],71:[function(_dereq_,module,exports){ 5021 /** 5022 * @file mute-toggle.js 5023 */ 5024 'use strict'; 5025 5026 exports.__esModule = true; 5027 5028 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5029 5030 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5031 5032 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5033 5034 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5035 5036 var _button = _dereq_('../button'); 5037 5038 var _button2 = _interopRequireDefault(_button); 5039 5040 var _component = _dereq_('../component'); 5041 5042 var _component2 = _interopRequireDefault(_component); 5043 5044 var _utilsDomJs = _dereq_('../utils/dom.js'); 5045 5046 var Dom = _interopRequireWildcard(_utilsDomJs); 5047 5048 /** 5049 * A button component for muting the audio 5050 * 5051 * @param {Player|Object} player 5052 * @param {Object=} options 5053 * @extends Button 5054 * @class MuteToggle 5055 */ 5056 5057 var MuteToggle = (function (_Button) { 5058 _inherits(MuteToggle, _Button); 5059 5060 function MuteToggle(player, options) { 5061 _classCallCheck(this, MuteToggle); 5062 5063 _Button.call(this, player, options); 5064 5065 this.on(player, 'volumechange', this.update); 5066 5067 // hide mute toggle if the current tech doesn't support volume control 5068 if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { 5069 this.addClass('vjs-hidden'); 5070 } 5071 5072 this.on(player, 'loadstart', function () { 5073 this.update(); // We need to update the button to account for a default muted state. 5074 5075 if (player.tech_['featuresVolumeControl'] === false) { 5076 this.addClass('vjs-hidden'); 5077 } else { 5078 this.removeClass('vjs-hidden'); 5079 } 5080 }); 5081 } 5082 5083 /** 5084 * Allow sub components to stack CSS class names 5085 * 5086 * @return {String} The constructed class name 5087 * @method buildCSSClass 5088 */ 5089 5090 MuteToggle.prototype.buildCSSClass = function buildCSSClass() { 5091 return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this); 5092 }; 5093 5094 /** 5095 * Handle click on mute 5096 * 5097 * @method handleClick 5098 */ 5099 5100 MuteToggle.prototype.handleClick = function handleClick() { 5101 this.player_.muted(this.player_.muted() ? false : true); 5102 }; 5103 5104 /** 5105 * Update volume 5106 * 5107 * @method update 5108 */ 5109 5110 MuteToggle.prototype.update = function update() { 5111 var vol = this.player_.volume(), 5112 level = 3; 5113 5114 if (vol === 0 || this.player_.muted()) { 5115 level = 0; 5116 } else if (vol < 0.33) { 5117 level = 1; 5118 } else if (vol < 0.67) { 5119 level = 2; 5120 } 5121 5122 // Don't rewrite the button text if the actual text doesn't change. 5123 // This causes unnecessary and confusing information for screen reader users. 5124 // This check is needed because this function gets called every time the volume level is changed. 5125 var toMute = this.player_.muted() ? 'Unmute' : 'Mute'; 5126 if (this.controlText() !== toMute) { 5127 this.controlText(toMute); 5128 } 5129 5130 /* TODO improve muted icon classes */ 5131 for (var i = 0; i < 4; i++) { 5132 Dom.removeElClass(this.el_, 'vjs-vol-' + i); 5133 } 5134 Dom.addElClass(this.el_, 'vjs-vol-' + level); 5135 }; 5136 5137 return MuteToggle; 5138 })(_button2['default']); 5139 5140 MuteToggle.prototype.controlText_ = 'Mute'; 5141 5142 _component2['default'].registerComponent('MuteToggle', MuteToggle); 5143 exports['default'] = MuteToggle; 5144 module.exports = exports['default']; 5145 5146 },{"../button":64,"../component":67,"../utils/dom.js":134}],72:[function(_dereq_,module,exports){ 5147 /** 5148 * @file play-toggle.js 5149 */ 5150 'use strict'; 5151 5152 exports.__esModule = true; 5153 5154 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5155 5156 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5157 5158 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5159 5160 var _buttonJs = _dereq_('../button.js'); 5161 5162 var _buttonJs2 = _interopRequireDefault(_buttonJs); 5163 5164 var _componentJs = _dereq_('../component.js'); 5165 5166 var _componentJs2 = _interopRequireDefault(_componentJs); 5167 5168 /** 5169 * Button to toggle between play and pause 5170 * 5171 * @param {Player|Object} player 5172 * @param {Object=} options 5173 * @extends Button 5174 * @class PlayToggle 5175 */ 5176 5177 var PlayToggle = (function (_Button) { 5178 _inherits(PlayToggle, _Button); 5179 5180 function PlayToggle(player, options) { 5181 _classCallCheck(this, PlayToggle); 5182 5183 _Button.call(this, player, options); 5184 5185 this.on(player, 'play', this.handlePlay); 5186 this.on(player, 'pause', this.handlePause); 5187 } 5188 5189 /** 5190 * Allow sub components to stack CSS class names 5191 * 5192 * @return {String} The constructed class name 5193 * @method buildCSSClass 5194 */ 5195 5196 PlayToggle.prototype.buildCSSClass = function buildCSSClass() { 5197 return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this); 5198 }; 5199 5200 /** 5201 * Handle click to toggle between play and pause 5202 * 5203 * @method handleClick 5204 */ 5205 5206 PlayToggle.prototype.handleClick = function handleClick() { 5207 if (this.player_.paused()) { 5208 this.player_.play(); 5209 } else { 5210 this.player_.pause(); 5211 } 5212 }; 5213 5214 /** 5215 * Add the vjs-playing class to the element so it can change appearance 5216 * 5217 * @method handlePlay 5218 */ 5219 5220 PlayToggle.prototype.handlePlay = function handlePlay() { 5221 this.removeClass('vjs-paused'); 5222 this.addClass('vjs-playing'); 5223 this.controlText('Pause'); // change the button text to "Pause" 5224 }; 5225 5226 /** 5227 * Add the vjs-paused class to the element so it can change appearance 5228 * 5229 * @method handlePause 5230 */ 5231 5232 PlayToggle.prototype.handlePause = function handlePause() { 5233 this.removeClass('vjs-playing'); 5234 this.addClass('vjs-paused'); 5235 this.controlText('Play'); // change the button text to "Play" 5236 }; 5237 5238 return PlayToggle; 5239 })(_buttonJs2['default']); 5240 5241 PlayToggle.prototype.controlText_ = 'Play'; 5242 5243 _componentJs2['default'].registerComponent('PlayToggle', PlayToggle); 5244 exports['default'] = PlayToggle; 5245 module.exports = exports['default']; 5246 5247 },{"../button.js":64,"../component.js":67}],73:[function(_dereq_,module,exports){ 5248 /** 5249 * @file playback-rate-menu-button.js 5250 */ 5251 'use strict'; 5252 5253 exports.__esModule = true; 5254 5255 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5256 5257 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5258 5259 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5260 5261 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5262 5263 var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js'); 5264 5265 var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); 5266 5267 var _menuMenuJs = _dereq_('../../menu/menu.js'); 5268 5269 var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); 5270 5271 var _playbackRateMenuItemJs = _dereq_('./playback-rate-menu-item.js'); 5272 5273 var _playbackRateMenuItemJs2 = _interopRequireDefault(_playbackRateMenuItemJs); 5274 5275 var _componentJs = _dereq_('../../component.js'); 5276 5277 var _componentJs2 = _interopRequireDefault(_componentJs); 5278 5279 var _utilsDomJs = _dereq_('../../utils/dom.js'); 5280 5281 var Dom = _interopRequireWildcard(_utilsDomJs); 5282 5283 /** 5284 * The component for controlling the playback rate 5285 * 5286 * @param {Player|Object} player 5287 * @param {Object=} options 5288 * @extends MenuButton 5289 * @class PlaybackRateMenuButton 5290 */ 5291 5292 var PlaybackRateMenuButton = (function (_MenuButton) { 5293 _inherits(PlaybackRateMenuButton, _MenuButton); 5294 5295 function PlaybackRateMenuButton(player, options) { 5296 _classCallCheck(this, PlaybackRateMenuButton); 5297 5298 _MenuButton.call(this, player, options); 5299 5300 this.updateVisibility(); 5301 this.updateLabel(); 5302 5303 this.on(player, 'loadstart', this.updateVisibility); 5304 this.on(player, 'ratechange', this.updateLabel); 5305 } 5306 5307 /** 5308 * Create the component's DOM element 5309 * 5310 * @return {Element} 5311 * @method createEl 5312 */ 5313 5314 PlaybackRateMenuButton.prototype.createEl = function createEl() { 5315 var el = _MenuButton.prototype.createEl.call(this); 5316 5317 this.labelEl_ = Dom.createEl('div', { 5318 className: 'vjs-playback-rate-value', 5319 innerHTML: 1.0 5320 }); 5321 5322 el.appendChild(this.labelEl_); 5323 5324 return el; 5325 }; 5326 5327 /** 5328 * Allow sub components to stack CSS class names 5329 * 5330 * @return {String} The constructed class name 5331 * @method buildCSSClass 5332 */ 5333 5334 PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() { 5335 return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this); 5336 }; 5337 5338 /** 5339 * Create the playback rate menu 5340 * 5341 * @return {Menu} Menu object populated with items 5342 * @method createMenu 5343 */ 5344 5345 PlaybackRateMenuButton.prototype.createMenu = function createMenu() { 5346 var menu = new _menuMenuJs2['default'](this.player()); 5347 var rates = this.playbackRates(); 5348 5349 if (rates) { 5350 for (var i = rates.length - 1; i >= 0; i--) { 5351 menu.addChild(new _playbackRateMenuItemJs2['default'](this.player(), { 'rate': rates[i] + 'x' })); 5352 } 5353 } 5354 5355 return menu; 5356 }; 5357 5358 /** 5359 * Updates ARIA accessibility attributes 5360 * 5361 * @method updateARIAAttributes 5362 */ 5363 5364 PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() { 5365 // Current playback rate 5366 this.el().setAttribute('aria-valuenow', this.player().playbackRate()); 5367 }; 5368 5369 /** 5370 * Handle menu item click 5371 * 5372 * @method handleClick 5373 */ 5374 5375 PlaybackRateMenuButton.prototype.handleClick = function handleClick() { 5376 // select next rate option 5377 var currentRate = this.player().playbackRate(); 5378 var rates = this.playbackRates(); 5379 5380 // this will select first one if the last one currently selected 5381 var newRate = rates[0]; 5382 for (var i = 0; i < rates.length; i++) { 5383 if (rates[i] > currentRate) { 5384 newRate = rates[i]; 5385 break; 5386 } 5387 } 5388 this.player().playbackRate(newRate); 5389 }; 5390 5391 /** 5392 * Get possible playback rates 5393 * 5394 * @return {Array} Possible playback rates 5395 * @method playbackRates 5396 */ 5397 5398 PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() { 5399 return this.options_['playbackRates'] || this.options_.playerOptions && this.options_.playerOptions['playbackRates']; 5400 }; 5401 5402 /** 5403 * Get supported playback rates 5404 * 5405 * @return {Array} Supported playback rates 5406 * @method playbackRateSupported 5407 */ 5408 5409 PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() { 5410 return this.player().tech_ && this.player().tech_['featuresPlaybackRate'] && this.playbackRates() && this.playbackRates().length > 0; 5411 }; 5412 5413 /** 5414 * Hide playback rate controls when they're no playback rate options to select 5415 * 5416 * @method updateVisibility 5417 */ 5418 5419 PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility() { 5420 if (this.playbackRateSupported()) { 5421 this.removeClass('vjs-hidden'); 5422 } else { 5423 this.addClass('vjs-hidden'); 5424 } 5425 }; 5426 5427 /** 5428 * Update button label when rate changed 5429 * 5430 * @method updateLabel 5431 */ 5432 5433 PlaybackRateMenuButton.prototype.updateLabel = function updateLabel() { 5434 if (this.playbackRateSupported()) { 5435 this.labelEl_.innerHTML = this.player().playbackRate() + 'x'; 5436 } 5437 }; 5438 5439 return PlaybackRateMenuButton; 5440 })(_menuMenuButtonJs2['default']); 5441 5442 PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate'; 5443 5444 _componentJs2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton); 5445 exports['default'] = PlaybackRateMenuButton; 5446 module.exports = exports['default']; 5447 5448 },{"../../component.js":67,"../../menu/menu-button.js":106,"../../menu/menu.js":108,"../../utils/dom.js":134,"./playback-rate-menu-item.js":74}],74:[function(_dereq_,module,exports){ 5449 /** 5450 * @file playback-rate-menu-item.js 5451 */ 5452 'use strict'; 5453 5454 exports.__esModule = true; 5455 5456 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5457 5458 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5459 5460 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5461 5462 var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); 5463 5464 var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); 5465 5466 var _componentJs = _dereq_('../../component.js'); 5467 5468 var _componentJs2 = _interopRequireDefault(_componentJs); 5469 5470 /** 5471 * The specific menu item type for selecting a playback rate 5472 * 5473 * @param {Player|Object} player 5474 * @param {Object=} options 5475 * @extends MenuItem 5476 * @class PlaybackRateMenuItem 5477 */ 5478 5479 var PlaybackRateMenuItem = (function (_MenuItem) { 5480 _inherits(PlaybackRateMenuItem, _MenuItem); 5481 5482 function PlaybackRateMenuItem(player, options) { 5483 _classCallCheck(this, PlaybackRateMenuItem); 5484 5485 var label = options['rate']; 5486 var rate = parseFloat(label, 10); 5487 5488 // Modify options for parent MenuItem class's init. 5489 options['label'] = label; 5490 options['selected'] = rate === 1; 5491 _MenuItem.call(this, player, options); 5492 5493 this.label = label; 5494 this.rate = rate; 5495 5496 this.on(player, 'ratechange', this.update); 5497 } 5498 5499 /** 5500 * Handle click on menu item 5501 * 5502 * @method handleClick 5503 */ 5504 5505 PlaybackRateMenuItem.prototype.handleClick = function handleClick() { 5506 _MenuItem.prototype.handleClick.call(this); 5507 this.player().playbackRate(this.rate); 5508 }; 5509 5510 /** 5511 * Update playback rate with selected rate 5512 * 5513 * @method update 5514 */ 5515 5516 PlaybackRateMenuItem.prototype.update = function update() { 5517 this.selected(this.player().playbackRate() === this.rate); 5518 }; 5519 5520 return PlaybackRateMenuItem; 5521 })(_menuMenuItemJs2['default']); 5522 5523 PlaybackRateMenuItem.prototype.contentElType = 'button'; 5524 5525 _componentJs2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem); 5526 exports['default'] = PlaybackRateMenuItem; 5527 module.exports = exports['default']; 5528 5529 },{"../../component.js":67,"../../menu/menu-item.js":107}],75:[function(_dereq_,module,exports){ 5530 /** 5531 * @file load-progress-bar.js 5532 */ 5533 'use strict'; 5534 5535 exports.__esModule = true; 5536 5537 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5538 5539 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5540 5541 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5542 5543 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5544 5545 var _componentJs = _dereq_('../../component.js'); 5546 5547 var _componentJs2 = _interopRequireDefault(_componentJs); 5548 5549 var _utilsDomJs = _dereq_('../../utils/dom.js'); 5550 5551 var Dom = _interopRequireWildcard(_utilsDomJs); 5552 5553 /** 5554 * Shows load progress 5555 * 5556 * @param {Player|Object} player 5557 * @param {Object=} options 5558 * @extends Component 5559 * @class LoadProgressBar 5560 */ 5561 5562 var LoadProgressBar = (function (_Component) { 5563 _inherits(LoadProgressBar, _Component); 5564 5565 function LoadProgressBar(player, options) { 5566 _classCallCheck(this, LoadProgressBar); 5567 5568 _Component.call(this, player, options); 5569 this.on(player, 'progress', this.update); 5570 } 5571 5572 /** 5573 * Create the component's DOM element 5574 * 5575 * @return {Element} 5576 * @method createEl 5577 */ 5578 5579 LoadProgressBar.prototype.createEl = function createEl() { 5580 return _Component.prototype.createEl.call(this, 'div', { 5581 className: 'vjs-load-progress', 5582 innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>' 5583 }); 5584 }; 5585 5586 /** 5587 * Update progress bar 5588 * 5589 * @method update 5590 */ 5591 5592 LoadProgressBar.prototype.update = function update() { 5593 var buffered = this.player_.buffered(); 5594 var duration = this.player_.duration(); 5595 var bufferedEnd = this.player_.bufferedEnd(); 5596 var children = this.el_.children; 5597 5598 // get the percent width of a time compared to the total end 5599 var percentify = function percentify(time, end) { 5600 var percent = time / end || 0; // no NaN 5601 return (percent >= 1 ? 1 : percent) * 100 + '%'; 5602 }; 5603 5604 // update the width of the progress bar 5605 this.el_.style.width = percentify(bufferedEnd, duration); 5606 5607 // add child elements to represent the individual buffered time ranges 5608 for (var i = 0; i < buffered.length; i++) { 5609 var start = buffered.start(i); 5610 var end = buffered.end(i); 5611 var part = children[i]; 5612 5613 if (!part) { 5614 part = this.el_.appendChild(Dom.createEl()); 5615 } 5616 5617 // set the percent based on the width of the progress bar (bufferedEnd) 5618 part.style.left = percentify(start, bufferedEnd); 5619 part.style.width = percentify(end - start, bufferedEnd); 5620 } 5621 5622 // remove unused buffered range elements 5623 for (var i = children.length; i > buffered.length; i--) { 5624 this.el_.removeChild(children[i - 1]); 5625 } 5626 }; 5627 5628 return LoadProgressBar; 5629 })(_componentJs2['default']); 5630 5631 _componentJs2['default'].registerComponent('LoadProgressBar', LoadProgressBar); 5632 exports['default'] = LoadProgressBar; 5633 module.exports = exports['default']; 5634 5635 },{"../../component.js":67,"../../utils/dom.js":134}],76:[function(_dereq_,module,exports){ 5636 /** 5637 * @file mouse-time-display.js 5638 */ 5639 'use strict'; 5640 5641 exports.__esModule = true; 5642 5643 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5644 5645 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5646 5647 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5648 5649 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5650 5651 var _globalWindow = _dereq_('global/window'); 5652 5653 var _globalWindow2 = _interopRequireDefault(_globalWindow); 5654 5655 var _componentJs = _dereq_('../../component.js'); 5656 5657 var _componentJs2 = _interopRequireDefault(_componentJs); 5658 5659 var _utilsDomJs = _dereq_('../../utils/dom.js'); 5660 5661 var Dom = _interopRequireWildcard(_utilsDomJs); 5662 5663 var _utilsFnJs = _dereq_('../../utils/fn.js'); 5664 5665 var Fn = _interopRequireWildcard(_utilsFnJs); 5666 5667 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 5668 5669 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 5670 5671 var _lodashCompatFunctionThrottle = _dereq_('lodash-compat/function/throttle'); 5672 5673 var _lodashCompatFunctionThrottle2 = _interopRequireDefault(_lodashCompatFunctionThrottle); 5674 5675 /** 5676 * The Mouse Time Display component shows the time you will seek to 5677 * when hovering over the progress bar 5678 * 5679 * @param {Player|Object} player 5680 * @param {Object=} options 5681 * @extends Component 5682 * @class MouseTimeDisplay 5683 */ 5684 5685 var MouseTimeDisplay = (function (_Component) { 5686 _inherits(MouseTimeDisplay, _Component); 5687 5688 function MouseTimeDisplay(player, options) { 5689 var _this = this; 5690 5691 _classCallCheck(this, MouseTimeDisplay); 5692 5693 _Component.call(this, player, options); 5694 5695 if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { 5696 this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; 5697 } 5698 5699 if (this.keepTooltipsInside) { 5700 this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' }); 5701 this.el().appendChild(this.tooltip); 5702 this.addClass('vjs-keep-tooltips-inside'); 5703 } 5704 5705 this.update(0, 0); 5706 5707 player.on('ready', function () { 5708 _this.on(player.controlBar.progressControl.el(), 'mousemove', _lodashCompatFunctionThrottle2['default'](Fn.bind(_this, _this.handleMouseMove), 25)); 5709 }); 5710 } 5711 5712 /** 5713 * Create the component's DOM element 5714 * 5715 * @return {Element} 5716 * @method createEl 5717 */ 5718 5719 MouseTimeDisplay.prototype.createEl = function createEl() { 5720 return _Component.prototype.createEl.call(this, 'div', { 5721 className: 'vjs-mouse-display' 5722 }); 5723 }; 5724 5725 MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) { 5726 var duration = this.player_.duration(); 5727 var newTime = this.calculateDistance(event) * duration; 5728 var position = event.pageX - Dom.findElPosition(this.el().parentNode).left; 5729 5730 this.update(newTime, position); 5731 }; 5732 5733 MouseTimeDisplay.prototype.update = function update(newTime, position) { 5734 var time = _utilsFormatTimeJs2['default'](newTime, this.player_.duration()); 5735 5736 this.el().style.left = position + 'px'; 5737 this.el().setAttribute('data-current-time', time); 5738 5739 if (this.keepTooltipsInside) { 5740 var clampedPosition = this.clampPosition_(position); 5741 var difference = position - clampedPosition + 1; 5742 var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltip).width); 5743 var tooltipWidthHalf = tooltipWidth / 2; 5744 5745 this.tooltip.innerHTML = time; 5746 this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px'; 5747 } 5748 }; 5749 5750 MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) { 5751 return Dom.getPointerPosition(this.el().parentNode, event).x; 5752 }; 5753 5754 /** 5755 * This takes in a horizontal position for the bar and returns a clamped position. 5756 * Clamped position means that it will keep the position greater than half the width 5757 * of the tooltip and smaller than the player width minus half the width o the tooltip. 5758 * It will only clamp the position if `keepTooltipsInside` option is set. 5759 * 5760 * @param {Number} position the position the bar wants to be 5761 * @return {Number} newPosition the (potentially) clamped position 5762 * @method clampPosition_ 5763 */ 5764 5765 MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) { 5766 if (!this.keepTooltipsInside) { 5767 return position; 5768 } 5769 5770 var playerWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.player().el()).width); 5771 var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltip).width); 5772 var tooltipWidthHalf = tooltipWidth / 2; 5773 var actualPosition = position; 5774 5775 if (position < tooltipWidthHalf) { 5776 actualPosition = Math.ceil(tooltipWidthHalf); 5777 } else if (position > playerWidth - tooltipWidthHalf) { 5778 actualPosition = Math.floor(playerWidth - tooltipWidthHalf); 5779 } 5780 5781 return actualPosition; 5782 }; 5783 5784 return MouseTimeDisplay; 5785 })(_componentJs2['default']); 5786 5787 _componentJs2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay); 5788 exports['default'] = MouseTimeDisplay; 5789 module.exports = exports['default']; 5790 5791 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/format-time.js":137,"global/window":2,"lodash-compat/function/throttle":7}],77:[function(_dereq_,module,exports){ 5792 /** 5793 * @file play-progress-bar.js 5794 */ 5795 'use strict'; 5796 5797 exports.__esModule = true; 5798 5799 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5800 5801 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5802 5803 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5804 5805 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5806 5807 var _componentJs = _dereq_('../../component.js'); 5808 5809 var _componentJs2 = _interopRequireDefault(_componentJs); 5810 5811 var _utilsFnJs = _dereq_('../../utils/fn.js'); 5812 5813 var Fn = _interopRequireWildcard(_utilsFnJs); 5814 5815 var _utilsDomJs = _dereq_('../../utils/dom.js'); 5816 5817 var Dom = _interopRequireWildcard(_utilsDomJs); 5818 5819 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 5820 5821 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 5822 5823 /** 5824 * Shows play progress 5825 * 5826 * @param {Player|Object} player 5827 * @param {Object=} options 5828 * @extends Component 5829 * @class PlayProgressBar 5830 */ 5831 5832 var PlayProgressBar = (function (_Component) { 5833 _inherits(PlayProgressBar, _Component); 5834 5835 function PlayProgressBar(player, options) { 5836 _classCallCheck(this, PlayProgressBar); 5837 5838 _Component.call(this, player, options); 5839 this.updateDataAttr(); 5840 this.on(player, 'timeupdate', this.updateDataAttr); 5841 player.ready(Fn.bind(this, this.updateDataAttr)); 5842 5843 if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { 5844 this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; 5845 } 5846 5847 if (this.keepTooltipsInside) { 5848 this.addClass('vjs-keep-tooltips-inside'); 5849 } 5850 } 5851 5852 /** 5853 * Create the component's DOM element 5854 * 5855 * @return {Element} 5856 * @method createEl 5857 */ 5858 5859 PlayProgressBar.prototype.createEl = function createEl() { 5860 return _Component.prototype.createEl.call(this, 'div', { 5861 className: 'vjs-play-progress vjs-slider-bar', 5862 innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>' 5863 }); 5864 }; 5865 5866 PlayProgressBar.prototype.updateDataAttr = function updateDataAttr() { 5867 var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); 5868 this.el_.setAttribute('data-current-time', _utilsFormatTimeJs2['default'](time, this.player_.duration())); 5869 }; 5870 5871 return PlayProgressBar; 5872 })(_componentJs2['default']); 5873 5874 _componentJs2['default'].registerComponent('PlayProgressBar', PlayProgressBar); 5875 exports['default'] = PlayProgressBar; 5876 module.exports = exports['default']; 5877 5878 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/format-time.js":137}],78:[function(_dereq_,module,exports){ 5879 /** 5880 * @file progress-control.js 5881 */ 5882 'use strict'; 5883 5884 exports.__esModule = true; 5885 5886 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5887 5888 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5889 5890 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5891 5892 var _componentJs = _dereq_('../../component.js'); 5893 5894 var _componentJs2 = _interopRequireDefault(_componentJs); 5895 5896 var _seekBarJs = _dereq_('./seek-bar.js'); 5897 5898 var _seekBarJs2 = _interopRequireDefault(_seekBarJs); 5899 5900 var _mouseTimeDisplayJs = _dereq_('./mouse-time-display.js'); 5901 5902 var _mouseTimeDisplayJs2 = _interopRequireDefault(_mouseTimeDisplayJs); 5903 5904 /** 5905 * The Progress Control component contains the seek bar, load progress, 5906 * and play progress 5907 * 5908 * @param {Player|Object} player 5909 * @param {Object=} options 5910 * @extends Component 5911 * @class ProgressControl 5912 */ 5913 5914 var ProgressControl = (function (_Component) { 5915 _inherits(ProgressControl, _Component); 5916 5917 function ProgressControl() { 5918 _classCallCheck(this, ProgressControl); 5919 5920 _Component.apply(this, arguments); 5921 } 5922 5923 /** 5924 * Create the component's DOM element 5925 * 5926 * @return {Element} 5927 * @method createEl 5928 */ 5929 5930 ProgressControl.prototype.createEl = function createEl() { 5931 return _Component.prototype.createEl.call(this, 'div', { 5932 className: 'vjs-progress-control vjs-control' 5933 }); 5934 }; 5935 5936 return ProgressControl; 5937 })(_componentJs2['default']); 5938 5939 ProgressControl.prototype.options_ = { 5940 children: ['seekBar'] 5941 }; 5942 5943 _componentJs2['default'].registerComponent('ProgressControl', ProgressControl); 5944 exports['default'] = ProgressControl; 5945 module.exports = exports['default']; 5946 5947 },{"../../component.js":67,"./mouse-time-display.js":76,"./seek-bar.js":79}],79:[function(_dereq_,module,exports){ 5948 /** 5949 * @file seek-bar.js 5950 */ 5951 'use strict'; 5952 5953 exports.__esModule = true; 5954 5955 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 5956 5957 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 5958 5959 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 5960 5961 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 5962 5963 var _globalWindow = _dereq_('global/window'); 5964 5965 var _globalWindow2 = _interopRequireDefault(_globalWindow); 5966 5967 var _sliderSliderJs = _dereq_('../../slider/slider.js'); 5968 5969 var _sliderSliderJs2 = _interopRequireDefault(_sliderSliderJs); 5970 5971 var _componentJs = _dereq_('../../component.js'); 5972 5973 var _componentJs2 = _interopRequireDefault(_componentJs); 5974 5975 var _loadProgressBarJs = _dereq_('./load-progress-bar.js'); 5976 5977 var _loadProgressBarJs2 = _interopRequireDefault(_loadProgressBarJs); 5978 5979 var _playProgressBarJs = _dereq_('./play-progress-bar.js'); 5980 5981 var _playProgressBarJs2 = _interopRequireDefault(_playProgressBarJs); 5982 5983 var _tooltipProgressBarJs = _dereq_('./tooltip-progress-bar.js'); 5984 5985 var _tooltipProgressBarJs2 = _interopRequireDefault(_tooltipProgressBarJs); 5986 5987 var _utilsFnJs = _dereq_('../../utils/fn.js'); 5988 5989 var Fn = _interopRequireWildcard(_utilsFnJs); 5990 5991 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 5992 5993 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 5994 5995 var _objectAssign = _dereq_('object.assign'); 5996 5997 var _objectAssign2 = _interopRequireDefault(_objectAssign); 5998 5999 /** 6000 * Seek Bar and holder for the progress bars 6001 * 6002 * @param {Player|Object} player 6003 * @param {Object=} options 6004 * @extends Slider 6005 * @class SeekBar 6006 */ 6007 6008 var SeekBar = (function (_Slider) { 6009 _inherits(SeekBar, _Slider); 6010 6011 function SeekBar(player, options) { 6012 _classCallCheck(this, SeekBar); 6013 6014 _Slider.call(this, player, options); 6015 this.on(player, 'timeupdate', this.updateProgress); 6016 this.on(player, 'ended', this.updateProgress); 6017 player.ready(Fn.bind(this, this.updateProgress)); 6018 6019 if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { 6020 this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; 6021 } 6022 6023 if (this.keepTooltipsInside) { 6024 this.tooltipProgressBar = this.addChild('TooltipProgressBar'); 6025 } 6026 } 6027 6028 /** 6029 * Create the component's DOM element 6030 * 6031 * @return {Element} 6032 * @method createEl 6033 */ 6034 6035 SeekBar.prototype.createEl = function createEl() { 6036 return _Slider.prototype.createEl.call(this, 'div', { 6037 className: 'vjs-progress-holder' 6038 }, { 6039 'aria-label': 'progress bar' 6040 }); 6041 }; 6042 6043 /** 6044 * Update ARIA accessibility attributes 6045 * 6046 * @method updateARIAAttributes 6047 */ 6048 6049 SeekBar.prototype.updateProgress = function updateProgress() { 6050 this.updateAriaAttributes(this.el_); 6051 6052 if (this.keepTooltipsInside) { 6053 this.updateAriaAttributes(this.tooltipProgressBar.el_); 6054 this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width; 6055 6056 var playerWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.player().el()).width); 6057 var tooltipWidth = parseFloat(_globalWindow2['default'].getComputedStyle(this.tooltipProgressBar.tooltip).width); 6058 var tooltipStyle = this.tooltipProgressBar.el().style; 6059 tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px'; 6060 tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px'; 6061 tooltipStyle.right = '-' + tooltipWidth / 2 + 'px'; 6062 } 6063 }; 6064 6065 SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) { 6066 // Allows for smooth scrubbing, when player can't keep up. 6067 var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); 6068 el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); // machine readable value of progress bar (percentage complete) 6069 el.setAttribute('aria-valuetext', _utilsFormatTimeJs2['default'](time, this.player_.duration())); // human readable value of progress bar (time complete) 6070 }; 6071 6072 /** 6073 * Get percentage of video played 6074 * 6075 * @return {Number} Percentage played 6076 * @method getPercent 6077 */ 6078 6079 SeekBar.prototype.getPercent = function getPercent() { 6080 var percent = this.player_.currentTime() / this.player_.duration(); 6081 return percent >= 1 ? 1 : percent; 6082 }; 6083 6084 /** 6085 * Handle mouse down on seek bar 6086 * 6087 * @method handleMouseDown 6088 */ 6089 6090 SeekBar.prototype.handleMouseDown = function handleMouseDown(event) { 6091 _Slider.prototype.handleMouseDown.call(this, event); 6092 6093 this.player_.scrubbing(true); 6094 6095 this.videoWasPlaying = !this.player_.paused(); 6096 this.player_.pause(); 6097 }; 6098 6099 /** 6100 * Handle mouse move on seek bar 6101 * 6102 * @method handleMouseMove 6103 */ 6104 6105 SeekBar.prototype.handleMouseMove = function handleMouseMove(event) { 6106 var newTime = this.calculateDistance(event) * this.player_.duration(); 6107 6108 // Don't let video end while scrubbing. 6109 if (newTime === this.player_.duration()) { 6110 newTime = newTime - 0.1; 6111 } 6112 6113 // Set new time (tell player to seek to new time) 6114 this.player_.currentTime(newTime); 6115 }; 6116 6117 /** 6118 * Handle mouse up on seek bar 6119 * 6120 * @method handleMouseUp 6121 */ 6122 6123 SeekBar.prototype.handleMouseUp = function handleMouseUp(event) { 6124 _Slider.prototype.handleMouseUp.call(this, event); 6125 6126 this.player_.scrubbing(false); 6127 if (this.videoWasPlaying) { 6128 this.player_.play(); 6129 } 6130 }; 6131 6132 /** 6133 * Move more quickly fast forward for keyboard-only users 6134 * 6135 * @method stepForward 6136 */ 6137 6138 SeekBar.prototype.stepForward = function stepForward() { 6139 this.player_.currentTime(this.player_.currentTime() + 5); // more quickly fast forward for keyboard-only users 6140 }; 6141 6142 /** 6143 * Move more quickly rewind for keyboard-only users 6144 * 6145 * @method stepBack 6146 */ 6147 6148 SeekBar.prototype.stepBack = function stepBack() { 6149 this.player_.currentTime(this.player_.currentTime() - 5); // more quickly rewind for keyboard-only users 6150 }; 6151 6152 return SeekBar; 6153 })(_sliderSliderJs2['default']); 6154 6155 SeekBar.prototype.options_ = { 6156 children: ['loadProgressBar', 'mouseTimeDisplay', 'playProgressBar'], 6157 'barName': 'playProgressBar' 6158 }; 6159 6160 SeekBar.prototype.playerEvent = 'timeupdate'; 6161 6162 _componentJs2['default'].registerComponent('SeekBar', SeekBar); 6163 exports['default'] = SeekBar; 6164 module.exports = exports['default']; 6165 6166 },{"../../component.js":67,"../../slider/slider.js":116,"../../utils/fn.js":136,"../../utils/format-time.js":137,"./load-progress-bar.js":75,"./play-progress-bar.js":77,"./tooltip-progress-bar.js":80,"global/window":2,"object.assign":45}],80:[function(_dereq_,module,exports){ 6167 /** 6168 * @file play-progress-bar.js 6169 */ 6170 'use strict'; 6171 6172 exports.__esModule = true; 6173 6174 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 6175 6176 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6177 6178 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6179 6180 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6181 6182 var _componentJs = _dereq_('../../component.js'); 6183 6184 var _componentJs2 = _interopRequireDefault(_componentJs); 6185 6186 var _utilsFnJs = _dereq_('../../utils/fn.js'); 6187 6188 var Fn = _interopRequireWildcard(_utilsFnJs); 6189 6190 var _utilsDomJs = _dereq_('../../utils/dom.js'); 6191 6192 var Dom = _interopRequireWildcard(_utilsDomJs); 6193 6194 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 6195 6196 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 6197 6198 /** 6199 * Shows play progress 6200 * 6201 * @param {Player|Object} player 6202 * @param {Object=} options 6203 * @extends Component 6204 * @class PlayProgressBar 6205 */ 6206 6207 var TooltipProgressBar = (function (_Component) { 6208 _inherits(TooltipProgressBar, _Component); 6209 6210 function TooltipProgressBar(player, options) { 6211 _classCallCheck(this, TooltipProgressBar); 6212 6213 _Component.call(this, player, options); 6214 this.updateDataAttr(); 6215 this.on(player, 'timeupdate', this.updateDataAttr); 6216 player.ready(Fn.bind(this, this.updateDataAttr)); 6217 } 6218 6219 /** 6220 * Create the component's DOM element 6221 * 6222 * @return {Element} 6223 * @method createEl 6224 */ 6225 6226 TooltipProgressBar.prototype.createEl = function createEl() { 6227 var el = _Component.prototype.createEl.call(this, 'div', { 6228 className: 'vjs-tooltip-progress-bar vjs-slider-bar', 6229 innerHTML: '<div class="vjs-time-tooltip"></div>\n <span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>' 6230 }); 6231 6232 this.tooltip = el.querySelector('.vjs-time-tooltip'); 6233 6234 return el; 6235 }; 6236 6237 TooltipProgressBar.prototype.updateDataAttr = function updateDataAttr() { 6238 var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); 6239 var formattedTime = _utilsFormatTimeJs2['default'](time, this.player_.duration()); 6240 this.el_.setAttribute('data-current-time', formattedTime); 6241 this.tooltip.innerHTML = formattedTime; 6242 }; 6243 6244 return TooltipProgressBar; 6245 })(_componentJs2['default']); 6246 6247 _componentJs2['default'].registerComponent('TooltipProgressBar', TooltipProgressBar); 6248 exports['default'] = TooltipProgressBar; 6249 module.exports = exports['default']; 6250 6251 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/format-time.js":137}],81:[function(_dereq_,module,exports){ 6252 /** 6253 * @file custom-control-spacer.js 6254 */ 6255 'use strict'; 6256 6257 exports.__esModule = true; 6258 6259 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6260 6261 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6262 6263 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6264 6265 var _spacerJs = _dereq_('./spacer.js'); 6266 6267 var _spacerJs2 = _interopRequireDefault(_spacerJs); 6268 6269 var _componentJs = _dereq_('../../component.js'); 6270 6271 var _componentJs2 = _interopRequireDefault(_componentJs); 6272 6273 /** 6274 * Spacer specifically meant to be used as an insertion point for new plugins, etc. 6275 * 6276 * @extends Spacer 6277 * @class CustomControlSpacer 6278 */ 6279 6280 var CustomControlSpacer = (function (_Spacer) { 6281 _inherits(CustomControlSpacer, _Spacer); 6282 6283 function CustomControlSpacer() { 6284 _classCallCheck(this, CustomControlSpacer); 6285 6286 _Spacer.apply(this, arguments); 6287 } 6288 6289 /** 6290 * Allow sub components to stack CSS class names 6291 * 6292 * @return {String} The constructed class name 6293 * @method buildCSSClass 6294 */ 6295 6296 CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() { 6297 return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this); 6298 }; 6299 6300 /** 6301 * Create the component's DOM element 6302 * 6303 * @return {Element} 6304 * @method createEl 6305 */ 6306 6307 CustomControlSpacer.prototype.createEl = function createEl() { 6308 var el = _Spacer.prototype.createEl.call(this, { 6309 className: this.buildCSSClass() 6310 }); 6311 6312 // No-flex/table-cell mode requires there be some content 6313 // in the cell to fill the remaining space of the table. 6314 el.innerHTML = ' '; 6315 return el; 6316 }; 6317 6318 return CustomControlSpacer; 6319 })(_spacerJs2['default']); 6320 6321 _componentJs2['default'].registerComponent('CustomControlSpacer', CustomControlSpacer); 6322 exports['default'] = CustomControlSpacer; 6323 module.exports = exports['default']; 6324 6325 },{"../../component.js":67,"./spacer.js":82}],82:[function(_dereq_,module,exports){ 6326 /** 6327 * @file spacer.js 6328 */ 6329 'use strict'; 6330 6331 exports.__esModule = true; 6332 6333 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6334 6335 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6336 6337 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6338 6339 var _componentJs = _dereq_('../../component.js'); 6340 6341 var _componentJs2 = _interopRequireDefault(_componentJs); 6342 6343 /** 6344 * Just an empty spacer element that can be used as an append point for plugins, etc. 6345 * Also can be used to create space between elements when necessary. 6346 * 6347 * @extends Component 6348 * @class Spacer 6349 */ 6350 6351 var Spacer = (function (_Component) { 6352 _inherits(Spacer, _Component); 6353 6354 function Spacer() { 6355 _classCallCheck(this, Spacer); 6356 6357 _Component.apply(this, arguments); 6358 } 6359 6360 /** 6361 * Allow sub components to stack CSS class names 6362 * 6363 * @return {String} The constructed class name 6364 * @method buildCSSClass 6365 */ 6366 6367 Spacer.prototype.buildCSSClass = function buildCSSClass() { 6368 return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this); 6369 }; 6370 6371 /** 6372 * Create the component's DOM element 6373 * 6374 * @return {Element} 6375 * @method createEl 6376 */ 6377 6378 Spacer.prototype.createEl = function createEl() { 6379 return _Component.prototype.createEl.call(this, 'div', { 6380 className: this.buildCSSClass() 6381 }); 6382 }; 6383 6384 return Spacer; 6385 })(_componentJs2['default']); 6386 6387 _componentJs2['default'].registerComponent('Spacer', Spacer); 6388 6389 exports['default'] = Spacer; 6390 module.exports = exports['default']; 6391 6392 },{"../../component.js":67}],83:[function(_dereq_,module,exports){ 6393 /** 6394 * @file caption-settings-menu-item.js 6395 */ 6396 'use strict'; 6397 6398 exports.__esModule = true; 6399 6400 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6401 6402 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6403 6404 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6405 6406 var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); 6407 6408 var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); 6409 6410 var _componentJs = _dereq_('../../component.js'); 6411 6412 var _componentJs2 = _interopRequireDefault(_componentJs); 6413 6414 /** 6415 * The menu item for caption track settings menu 6416 * 6417 * @param {Player|Object} player 6418 * @param {Object=} options 6419 * @extends TextTrackMenuItem 6420 * @class CaptionSettingsMenuItem 6421 */ 6422 6423 var CaptionSettingsMenuItem = (function (_TextTrackMenuItem) { 6424 _inherits(CaptionSettingsMenuItem, _TextTrackMenuItem); 6425 6426 function CaptionSettingsMenuItem(player, options) { 6427 _classCallCheck(this, CaptionSettingsMenuItem); 6428 6429 options['track'] = { 6430 'kind': options['kind'], 6431 'player': player, 6432 'label': options['kind'] + ' settings', 6433 'selectable': false, 6434 'default': false, 6435 mode: 'disabled' 6436 }; 6437 6438 // CaptionSettingsMenuItem has no concept of 'selected' 6439 options['selectable'] = false; 6440 6441 _TextTrackMenuItem.call(this, player, options); 6442 this.addClass('vjs-texttrack-settings'); 6443 this.controlText(', opens ' + options['kind'] + ' settings dialog'); 6444 } 6445 6446 /** 6447 * Handle click on menu item 6448 * 6449 * @method handleClick 6450 */ 6451 6452 CaptionSettingsMenuItem.prototype.handleClick = function handleClick() { 6453 this.player().getChild('textTrackSettings').show(); 6454 this.player().getChild('textTrackSettings').el_.focus(); 6455 }; 6456 6457 return CaptionSettingsMenuItem; 6458 })(_textTrackMenuItemJs2['default']); 6459 6460 _componentJs2['default'].registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem); 6461 exports['default'] = CaptionSettingsMenuItem; 6462 module.exports = exports['default']; 6463 6464 },{"../../component.js":67,"./text-track-menu-item.js":91}],84:[function(_dereq_,module,exports){ 6465 /** 6466 * @file captions-button.js 6467 */ 6468 'use strict'; 6469 6470 exports.__esModule = true; 6471 6472 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6473 6474 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6475 6476 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6477 6478 var _textTrackButtonJs = _dereq_('./text-track-button.js'); 6479 6480 var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); 6481 6482 var _componentJs = _dereq_('../../component.js'); 6483 6484 var _componentJs2 = _interopRequireDefault(_componentJs); 6485 6486 var _captionSettingsMenuItemJs = _dereq_('./caption-settings-menu-item.js'); 6487 6488 var _captionSettingsMenuItemJs2 = _interopRequireDefault(_captionSettingsMenuItemJs); 6489 6490 /** 6491 * The button component for toggling and selecting captions 6492 * 6493 * @param {Object} player Player object 6494 * @param {Object=} options Object of option names and values 6495 * @param {Function=} ready Ready callback function 6496 * @extends TextTrackButton 6497 * @class CaptionsButton 6498 */ 6499 6500 var CaptionsButton = (function (_TextTrackButton) { 6501 _inherits(CaptionsButton, _TextTrackButton); 6502 6503 function CaptionsButton(player, options, ready) { 6504 _classCallCheck(this, CaptionsButton); 6505 6506 _TextTrackButton.call(this, player, options, ready); 6507 this.el_.setAttribute('aria-label', 'Captions Menu'); 6508 } 6509 6510 /** 6511 * Allow sub components to stack CSS class names 6512 * 6513 * @return {String} The constructed class name 6514 * @method buildCSSClass 6515 */ 6516 6517 CaptionsButton.prototype.buildCSSClass = function buildCSSClass() { 6518 return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); 6519 }; 6520 6521 /** 6522 * Update caption menu items 6523 * 6524 * @method update 6525 */ 6526 6527 CaptionsButton.prototype.update = function update() { 6528 var threshold = 2; 6529 _TextTrackButton.prototype.update.call(this); 6530 6531 // if native, then threshold is 1 because no settings button 6532 if (this.player().tech_ && this.player().tech_['featuresNativeTextTracks']) { 6533 threshold = 1; 6534 } 6535 6536 if (this.items && this.items.length > threshold) { 6537 this.show(); 6538 } else { 6539 this.hide(); 6540 } 6541 }; 6542 6543 /** 6544 * Create caption menu items 6545 * 6546 * @return {Array} Array of menu items 6547 * @method createItems 6548 */ 6549 6550 CaptionsButton.prototype.createItems = function createItems() { 6551 var items = []; 6552 6553 if (!(this.player().tech_ && this.player().tech_['featuresNativeTextTracks'])) { 6554 items.push(new _captionSettingsMenuItemJs2['default'](this.player_, { 'kind': this.kind_ })); 6555 } 6556 6557 return _TextTrackButton.prototype.createItems.call(this, items); 6558 }; 6559 6560 return CaptionsButton; 6561 })(_textTrackButtonJs2['default']); 6562 6563 CaptionsButton.prototype.kind_ = 'captions'; 6564 CaptionsButton.prototype.controlText_ = 'Captions'; 6565 6566 _componentJs2['default'].registerComponent('CaptionsButton', CaptionsButton); 6567 exports['default'] = CaptionsButton; 6568 module.exports = exports['default']; 6569 6570 },{"../../component.js":67,"./caption-settings-menu-item.js":83,"./text-track-button.js":90}],85:[function(_dereq_,module,exports){ 6571 /** 6572 * @file chapters-button.js 6573 */ 6574 'use strict'; 6575 6576 exports.__esModule = true; 6577 6578 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 6579 6580 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6581 6582 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6583 6584 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6585 6586 var _textTrackButtonJs = _dereq_('./text-track-button.js'); 6587 6588 var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); 6589 6590 var _componentJs = _dereq_('../../component.js'); 6591 6592 var _componentJs2 = _interopRequireDefault(_componentJs); 6593 6594 var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); 6595 6596 var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); 6597 6598 var _chaptersTrackMenuItemJs = _dereq_('./chapters-track-menu-item.js'); 6599 6600 var _chaptersTrackMenuItemJs2 = _interopRequireDefault(_chaptersTrackMenuItemJs); 6601 6602 var _menuMenuJs = _dereq_('../../menu/menu.js'); 6603 6604 var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); 6605 6606 var _utilsDomJs = _dereq_('../../utils/dom.js'); 6607 6608 var Dom = _interopRequireWildcard(_utilsDomJs); 6609 6610 var _utilsFnJs = _dereq_('../../utils/fn.js'); 6611 6612 var Fn = _interopRequireWildcard(_utilsFnJs); 6613 6614 var _utilsToTitleCaseJs = _dereq_('../../utils/to-title-case.js'); 6615 6616 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 6617 6618 var _globalWindow = _dereq_('global/window'); 6619 6620 var _globalWindow2 = _interopRequireDefault(_globalWindow); 6621 6622 /** 6623 * The button component for toggling and selecting chapters 6624 * Chapters act much differently than other text tracks 6625 * Cues are navigation vs. other tracks of alternative languages 6626 * 6627 * @param {Object} player Player object 6628 * @param {Object=} options Object of option names and values 6629 * @param {Function=} ready Ready callback function 6630 * @extends TextTrackButton 6631 * @class ChaptersButton 6632 */ 6633 6634 var ChaptersButton = (function (_TextTrackButton) { 6635 _inherits(ChaptersButton, _TextTrackButton); 6636 6637 function ChaptersButton(player, options, ready) { 6638 _classCallCheck(this, ChaptersButton); 6639 6640 _TextTrackButton.call(this, player, options, ready); 6641 this.el_.setAttribute('aria-label', 'Chapters Menu'); 6642 } 6643 6644 /** 6645 * Allow sub components to stack CSS class names 6646 * 6647 * @return {String} The constructed class name 6648 * @method buildCSSClass 6649 */ 6650 6651 ChaptersButton.prototype.buildCSSClass = function buildCSSClass() { 6652 return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); 6653 }; 6654 6655 /** 6656 * Create a menu item for each text track 6657 * 6658 * @return {Array} Array of menu items 6659 * @method createItems 6660 */ 6661 6662 ChaptersButton.prototype.createItems = function createItems() { 6663 var items = []; 6664 6665 var tracks = this.player_.textTracks(); 6666 6667 if (!tracks) { 6668 return items; 6669 } 6670 6671 for (var i = 0; i < tracks.length; i++) { 6672 var track = tracks[i]; 6673 if (track['kind'] === this.kind_) { 6674 items.push(new _textTrackMenuItemJs2['default'](this.player_, { 6675 'track': track 6676 })); 6677 } 6678 } 6679 6680 return items; 6681 }; 6682 6683 /** 6684 * Create menu from chapter buttons 6685 * 6686 * @return {Menu} Menu of chapter buttons 6687 * @method createMenu 6688 */ 6689 6690 ChaptersButton.prototype.createMenu = function createMenu() { 6691 var _this = this; 6692 6693 var tracks = this.player_.textTracks() || []; 6694 var chaptersTrack = undefined; 6695 var items = this.items = []; 6696 6697 for (var i = 0, _length = tracks.length; i < _length; i++) { 6698 var track = tracks[i]; 6699 6700 if (track['kind'] === this.kind_) { 6701 chaptersTrack = track; 6702 6703 break; 6704 } 6705 } 6706 6707 var menu = this.menu; 6708 if (menu === undefined) { 6709 menu = new _menuMenuJs2['default'](this.player_); 6710 var title = Dom.createEl('li', { 6711 className: 'vjs-menu-title', 6712 innerHTML: _utilsToTitleCaseJs2['default'](this.kind_), 6713 tabIndex: -1 6714 }); 6715 menu.children_.unshift(title); 6716 Dom.insertElFirst(title, menu.contentEl()); 6717 } 6718 6719 if (chaptersTrack && chaptersTrack.cues == null) { 6720 chaptersTrack['mode'] = 'hidden'; 6721 6722 var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(chaptersTrack); 6723 6724 if (remoteTextTrackEl) { 6725 remoteTextTrackEl.addEventListener('load', function (event) { 6726 return _this.update(); 6727 }); 6728 } 6729 } 6730 6731 if (chaptersTrack && chaptersTrack.cues && chaptersTrack.cues.length > 0) { 6732 var cues = chaptersTrack['cues'], 6733 cue = undefined; 6734 6735 for (var i = 0, l = cues.length; i < l; i++) { 6736 cue = cues[i]; 6737 6738 var mi = new _chaptersTrackMenuItemJs2['default'](this.player_, { 6739 'track': chaptersTrack, 6740 'cue': cue 6741 }); 6742 6743 items.push(mi); 6744 6745 menu.addChild(mi); 6746 } 6747 6748 this.addChild(menu); 6749 } 6750 6751 if (this.items.length > 0) { 6752 this.show(); 6753 } 6754 6755 return menu; 6756 }; 6757 6758 return ChaptersButton; 6759 })(_textTrackButtonJs2['default']); 6760 6761 ChaptersButton.prototype.kind_ = 'chapters'; 6762 ChaptersButton.prototype.controlText_ = 'Chapters'; 6763 6764 _componentJs2['default'].registerComponent('ChaptersButton', ChaptersButton); 6765 exports['default'] = ChaptersButton; 6766 module.exports = exports['default']; 6767 6768 },{"../../component.js":67,"../../menu/menu.js":108,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/to-title-case.js":143,"./chapters-track-menu-item.js":86,"./text-track-button.js":90,"./text-track-menu-item.js":91,"global/window":2}],86:[function(_dereq_,module,exports){ 6769 /** 6770 * @file chapters-track-menu-item.js 6771 */ 6772 'use strict'; 6773 6774 exports.__esModule = true; 6775 6776 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 6777 6778 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6779 6780 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6781 6782 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6783 6784 var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); 6785 6786 var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); 6787 6788 var _componentJs = _dereq_('../../component.js'); 6789 6790 var _componentJs2 = _interopRequireDefault(_componentJs); 6791 6792 var _utilsFnJs = _dereq_('../../utils/fn.js'); 6793 6794 var Fn = _interopRequireWildcard(_utilsFnJs); 6795 6796 /** 6797 * The chapter track menu item 6798 * 6799 * @param {Player|Object} player 6800 * @param {Object=} options 6801 * @extends MenuItem 6802 * @class ChaptersTrackMenuItem 6803 */ 6804 6805 var ChaptersTrackMenuItem = (function (_MenuItem) { 6806 _inherits(ChaptersTrackMenuItem, _MenuItem); 6807 6808 function ChaptersTrackMenuItem(player, options) { 6809 _classCallCheck(this, ChaptersTrackMenuItem); 6810 6811 var track = options['track']; 6812 var cue = options['cue']; 6813 var currentTime = player.currentTime(); 6814 6815 // Modify options for parent MenuItem class's init. 6816 options['label'] = cue.text; 6817 options['selected'] = cue['startTime'] <= currentTime && currentTime < cue['endTime']; 6818 _MenuItem.call(this, player, options); 6819 6820 this.track = track; 6821 this.cue = cue; 6822 track.addEventListener('cuechange', Fn.bind(this, this.update)); 6823 } 6824 6825 /** 6826 * Handle click on menu item 6827 * 6828 * @method handleClick 6829 */ 6830 6831 ChaptersTrackMenuItem.prototype.handleClick = function handleClick() { 6832 _MenuItem.prototype.handleClick.call(this); 6833 this.player_.currentTime(this.cue.startTime); 6834 this.update(this.cue.startTime); 6835 }; 6836 6837 /** 6838 * Update chapter menu item 6839 * 6840 * @method update 6841 */ 6842 6843 ChaptersTrackMenuItem.prototype.update = function update() { 6844 var cue = this.cue; 6845 var currentTime = this.player_.currentTime(); 6846 6847 // vjs.log(currentTime, cue.startTime); 6848 this.selected(cue['startTime'] <= currentTime && currentTime < cue['endTime']); 6849 }; 6850 6851 return ChaptersTrackMenuItem; 6852 })(_menuMenuItemJs2['default']); 6853 6854 _componentJs2['default'].registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem); 6855 exports['default'] = ChaptersTrackMenuItem; 6856 module.exports = exports['default']; 6857 6858 },{"../../component.js":67,"../../menu/menu-item.js":107,"../../utils/fn.js":136}],87:[function(_dereq_,module,exports){ 6859 /** 6860 * @file descriptions-button.js 6861 */ 6862 'use strict'; 6863 6864 exports.__esModule = true; 6865 6866 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 6867 6868 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6869 6870 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6871 6872 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6873 6874 var _textTrackButtonJs = _dereq_('./text-track-button.js'); 6875 6876 var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); 6877 6878 var _componentJs = _dereq_('../../component.js'); 6879 6880 var _componentJs2 = _interopRequireDefault(_componentJs); 6881 6882 var _utilsFnJs = _dereq_('../../utils/fn.js'); 6883 6884 var Fn = _interopRequireWildcard(_utilsFnJs); 6885 6886 /** 6887 * The button component for toggling and selecting descriptions 6888 * 6889 * @param {Object} player Player object 6890 * @param {Object=} options Object of option names and values 6891 * @param {Function=} ready Ready callback function 6892 * @extends TextTrackButton 6893 * @class DescriptionsButton 6894 */ 6895 6896 var DescriptionsButton = (function (_TextTrackButton) { 6897 _inherits(DescriptionsButton, _TextTrackButton); 6898 6899 function DescriptionsButton(player, options, ready) { 6900 var _this = this; 6901 6902 _classCallCheck(this, DescriptionsButton); 6903 6904 _TextTrackButton.call(this, player, options, ready); 6905 this.el_.setAttribute('aria-label', 'Descriptions Menu'); 6906 6907 var tracks = player.textTracks(); 6908 6909 if (tracks) { 6910 (function () { 6911 var changeHandler = Fn.bind(_this, _this.handleTracksChange); 6912 6913 tracks.addEventListener('change', changeHandler); 6914 _this.on('dispose', function () { 6915 tracks.removeEventListener('change', changeHandler); 6916 }); 6917 })(); 6918 } 6919 } 6920 6921 /** 6922 * Handle text track change 6923 * 6924 * @method handleTracksChange 6925 */ 6926 6927 DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) { 6928 var tracks = this.player().textTracks(); 6929 var disabled = false; 6930 6931 // Check whether a track of a different kind is showing 6932 for (var i = 0, l = tracks.length; i < l; i++) { 6933 var track = tracks[i]; 6934 if (track['kind'] !== this.kind_ && track['mode'] === 'showing') { 6935 disabled = true; 6936 break; 6937 } 6938 } 6939 6940 // If another track is showing, disable this menu button 6941 if (disabled) { 6942 this.disable(); 6943 } else { 6944 this.enable(); 6945 } 6946 }; 6947 6948 /** 6949 * Allow sub components to stack CSS class names 6950 * 6951 * @return {String} The constructed class name 6952 * @method buildCSSClass 6953 */ 6954 6955 DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() { 6956 return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); 6957 }; 6958 6959 return DescriptionsButton; 6960 })(_textTrackButtonJs2['default']); 6961 6962 DescriptionsButton.prototype.kind_ = 'descriptions'; 6963 DescriptionsButton.prototype.controlText_ = 'Descriptions'; 6964 6965 _componentJs2['default'].registerComponent('DescriptionsButton', DescriptionsButton); 6966 exports['default'] = DescriptionsButton; 6967 module.exports = exports['default']; 6968 6969 },{"../../component.js":67,"../../utils/fn.js":136,"./text-track-button.js":90}],88:[function(_dereq_,module,exports){ 6970 /** 6971 * @file off-text-track-menu-item.js 6972 */ 6973 'use strict'; 6974 6975 exports.__esModule = true; 6976 6977 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6978 6979 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6980 6981 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6982 6983 var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); 6984 6985 var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); 6986 6987 var _componentJs = _dereq_('../../component.js'); 6988 6989 var _componentJs2 = _interopRequireDefault(_componentJs); 6990 6991 /** 6992 * A special menu item for turning of a specific type of text track 6993 * 6994 * @param {Player|Object} player 6995 * @param {Object=} options 6996 * @extends TextTrackMenuItem 6997 * @class OffTextTrackMenuItem 6998 */ 6999 7000 var OffTextTrackMenuItem = (function (_TextTrackMenuItem) { 7001 _inherits(OffTextTrackMenuItem, _TextTrackMenuItem); 7002 7003 function OffTextTrackMenuItem(player, options) { 7004 _classCallCheck(this, OffTextTrackMenuItem); 7005 7006 // Create pseudo track info 7007 // Requires options['kind'] 7008 options['track'] = { 7009 'kind': options['kind'], 7010 'player': player, 7011 'label': options['kind'] + ' off', 7012 'default': false, 7013 'mode': 'disabled' 7014 }; 7015 7016 // MenuItem is selectable 7017 options['selectable'] = true; 7018 7019 _TextTrackMenuItem.call(this, player, options); 7020 this.selected(true); 7021 } 7022 7023 /** 7024 * Handle text track change 7025 * 7026 * @param {Object} event Event object 7027 * @method handleTracksChange 7028 */ 7029 7030 OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { 7031 var tracks = this.player().textTracks(); 7032 var selected = true; 7033 7034 for (var i = 0, l = tracks.length; i < l; i++) { 7035 var track = tracks[i]; 7036 if (track['kind'] === this.track['kind'] && track['mode'] === 'showing') { 7037 selected = false; 7038 break; 7039 } 7040 } 7041 7042 this.selected(selected); 7043 }; 7044 7045 return OffTextTrackMenuItem; 7046 })(_textTrackMenuItemJs2['default']); 7047 7048 _componentJs2['default'].registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem); 7049 exports['default'] = OffTextTrackMenuItem; 7050 module.exports = exports['default']; 7051 7052 },{"../../component.js":67,"./text-track-menu-item.js":91}],89:[function(_dereq_,module,exports){ 7053 /** 7054 * @file subtitles-button.js 7055 */ 7056 'use strict'; 7057 7058 exports.__esModule = true; 7059 7060 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7061 7062 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7063 7064 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7065 7066 var _textTrackButtonJs = _dereq_('./text-track-button.js'); 7067 7068 var _textTrackButtonJs2 = _interopRequireDefault(_textTrackButtonJs); 7069 7070 var _componentJs = _dereq_('../../component.js'); 7071 7072 var _componentJs2 = _interopRequireDefault(_componentJs); 7073 7074 /** 7075 * The button component for toggling and selecting subtitles 7076 * 7077 * @param {Object} player Player object 7078 * @param {Object=} options Object of option names and values 7079 * @param {Function=} ready Ready callback function 7080 * @extends TextTrackButton 7081 * @class SubtitlesButton 7082 */ 7083 7084 var SubtitlesButton = (function (_TextTrackButton) { 7085 _inherits(SubtitlesButton, _TextTrackButton); 7086 7087 function SubtitlesButton(player, options, ready) { 7088 _classCallCheck(this, SubtitlesButton); 7089 7090 _TextTrackButton.call(this, player, options, ready); 7091 this.el_.setAttribute('aria-label', 'Subtitles Menu'); 7092 } 7093 7094 /** 7095 * Allow sub components to stack CSS class names 7096 * 7097 * @return {String} The constructed class name 7098 * @method buildCSSClass 7099 */ 7100 7101 SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() { 7102 return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); 7103 }; 7104 7105 return SubtitlesButton; 7106 })(_textTrackButtonJs2['default']); 7107 7108 SubtitlesButton.prototype.kind_ = 'subtitles'; 7109 SubtitlesButton.prototype.controlText_ = 'Subtitles'; 7110 7111 _componentJs2['default'].registerComponent('SubtitlesButton', SubtitlesButton); 7112 exports['default'] = SubtitlesButton; 7113 module.exports = exports['default']; 7114 7115 },{"../../component.js":67,"./text-track-button.js":90}],90:[function(_dereq_,module,exports){ 7116 /** 7117 * @file text-track-button.js 7118 */ 7119 'use strict'; 7120 7121 exports.__esModule = true; 7122 7123 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7124 7125 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7126 7127 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7128 7129 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7130 7131 var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js'); 7132 7133 var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); 7134 7135 var _componentJs = _dereq_('../../component.js'); 7136 7137 var _componentJs2 = _interopRequireDefault(_componentJs); 7138 7139 var _utilsFnJs = _dereq_('../../utils/fn.js'); 7140 7141 var Fn = _interopRequireWildcard(_utilsFnJs); 7142 7143 var _textTrackMenuItemJs = _dereq_('./text-track-menu-item.js'); 7144 7145 var _textTrackMenuItemJs2 = _interopRequireDefault(_textTrackMenuItemJs); 7146 7147 var _offTextTrackMenuItemJs = _dereq_('./off-text-track-menu-item.js'); 7148 7149 var _offTextTrackMenuItemJs2 = _interopRequireDefault(_offTextTrackMenuItemJs); 7150 7151 /** 7152 * The base class for buttons that toggle specific text track types (e.g. subtitles) 7153 * 7154 * @param {Player|Object} player 7155 * @param {Object=} options 7156 * @extends MenuButton 7157 * @class TextTrackButton 7158 */ 7159 7160 var TextTrackButton = (function (_MenuButton) { 7161 _inherits(TextTrackButton, _MenuButton); 7162 7163 function TextTrackButton(player, options) { 7164 _classCallCheck(this, TextTrackButton); 7165 7166 _MenuButton.call(this, player, options); 7167 7168 var tracks = this.player_.textTracks(); 7169 7170 if (this.items.length <= 1) { 7171 this.hide(); 7172 } 7173 7174 if (!tracks) { 7175 return; 7176 } 7177 7178 var updateHandler = Fn.bind(this, this.update); 7179 tracks.addEventListener('removetrack', updateHandler); 7180 tracks.addEventListener('addtrack', updateHandler); 7181 7182 this.player_.on('dispose', function () { 7183 tracks.removeEventListener('removetrack', updateHandler); 7184 tracks.removeEventListener('addtrack', updateHandler); 7185 }); 7186 } 7187 7188 // Create a menu item for each text track 7189 7190 TextTrackButton.prototype.createItems = function createItems() { 7191 var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; 7192 7193 // Add an OFF menu item to turn all tracks off 7194 items.push(new _offTextTrackMenuItemJs2['default'](this.player_, { 'kind': this.kind_ })); 7195 7196 var tracks = this.player_.textTracks(); 7197 7198 if (!tracks) { 7199 return items; 7200 } 7201 7202 for (var i = 0; i < tracks.length; i++) { 7203 var track = tracks[i]; 7204 7205 // only add tracks that are of the appropriate kind and have a label 7206 if (track['kind'] === this.kind_) { 7207 items.push(new _textTrackMenuItemJs2['default'](this.player_, { 7208 // MenuItem is selectable 7209 'selectable': true, 7210 'track': track 7211 })); 7212 } 7213 } 7214 7215 return items; 7216 }; 7217 7218 return TextTrackButton; 7219 })(_menuMenuButtonJs2['default']); 7220 7221 _componentJs2['default'].registerComponent('TextTrackButton', TextTrackButton); 7222 exports['default'] = TextTrackButton; 7223 module.exports = exports['default']; 7224 7225 },{"../../component.js":67,"../../menu/menu-button.js":106,"../../utils/fn.js":136,"./off-text-track-menu-item.js":88,"./text-track-menu-item.js":91}],91:[function(_dereq_,module,exports){ 7226 /** 7227 * @file text-track-menu-item.js 7228 */ 7229 'use strict'; 7230 7231 exports.__esModule = true; 7232 7233 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7234 7235 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7236 7237 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7238 7239 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7240 7241 var _menuMenuItemJs = _dereq_('../../menu/menu-item.js'); 7242 7243 var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); 7244 7245 var _componentJs = _dereq_('../../component.js'); 7246 7247 var _componentJs2 = _interopRequireDefault(_componentJs); 7248 7249 var _utilsFnJs = _dereq_('../../utils/fn.js'); 7250 7251 var Fn = _interopRequireWildcard(_utilsFnJs); 7252 7253 var _globalWindow = _dereq_('global/window'); 7254 7255 var _globalWindow2 = _interopRequireDefault(_globalWindow); 7256 7257 var _globalDocument = _dereq_('global/document'); 7258 7259 var _globalDocument2 = _interopRequireDefault(_globalDocument); 7260 7261 /** 7262 * The specific menu item type for selecting a language within a text track kind 7263 * 7264 * @param {Player|Object} player 7265 * @param {Object=} options 7266 * @extends MenuItem 7267 * @class TextTrackMenuItem 7268 */ 7269 7270 var TextTrackMenuItem = (function (_MenuItem) { 7271 _inherits(TextTrackMenuItem, _MenuItem); 7272 7273 function TextTrackMenuItem(player, options) { 7274 var _this = this; 7275 7276 _classCallCheck(this, TextTrackMenuItem); 7277 7278 var track = options['track']; 7279 var tracks = player.textTracks(); 7280 7281 // Modify options for parent MenuItem class's init. 7282 options['label'] = track['label'] || track['language'] || 'Unknown'; 7283 options['selected'] = track['default'] || track['mode'] === 'showing'; 7284 7285 _MenuItem.call(this, player, options); 7286 7287 this.track = track; 7288 7289 if (tracks) { 7290 (function () { 7291 var changeHandler = Fn.bind(_this, _this.handleTracksChange); 7292 7293 tracks.addEventListener('change', changeHandler); 7294 _this.on('dispose', function () { 7295 tracks.removeEventListener('change', changeHandler); 7296 }); 7297 })(); 7298 } 7299 7300 // iOS7 doesn't dispatch change events to TextTrackLists when an 7301 // associated track's mode changes. Without something like 7302 // Object.observe() (also not present on iOS7), it's not 7303 // possible to detect changes to the mode attribute and polyfill 7304 // the change event. As a poor substitute, we manually dispatch 7305 // change events whenever the controls modify the mode. 7306 if (tracks && tracks.onchange === undefined) { 7307 (function () { 7308 var event = undefined; 7309 7310 _this.on(['tap', 'click'], function () { 7311 if (typeof _globalWindow2['default'].Event !== 'object') { 7312 // Android 2.3 throws an Illegal Constructor error for window.Event 7313 try { 7314 event = new _globalWindow2['default'].Event('change'); 7315 } catch (err) {} 7316 } 7317 7318 if (!event) { 7319 event = _globalDocument2['default'].createEvent('Event'); 7320 event.initEvent('change', true, true); 7321 } 7322 7323 tracks.dispatchEvent(event); 7324 }); 7325 })(); 7326 } 7327 } 7328 7329 /** 7330 * Handle click on text track 7331 * 7332 * @method handleClick 7333 */ 7334 7335 TextTrackMenuItem.prototype.handleClick = function handleClick(event) { 7336 var kind = this.track['kind']; 7337 var tracks = this.player_.textTracks(); 7338 7339 _MenuItem.prototype.handleClick.call(this, event); 7340 7341 if (!tracks) return; 7342 7343 for (var i = 0; i < tracks.length; i++) { 7344 var track = tracks[i]; 7345 7346 if (track['kind'] !== kind) { 7347 continue; 7348 } 7349 7350 if (track === this.track) { 7351 track['mode'] = 'showing'; 7352 } else { 7353 track['mode'] = 'disabled'; 7354 } 7355 } 7356 }; 7357 7358 /** 7359 * Handle text track change 7360 * 7361 * @method handleTracksChange 7362 */ 7363 7364 TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { 7365 this.selected(this.track['mode'] === 'showing'); 7366 }; 7367 7368 return TextTrackMenuItem; 7369 })(_menuMenuItemJs2['default']); 7370 7371 _componentJs2['default'].registerComponent('TextTrackMenuItem', TextTrackMenuItem); 7372 exports['default'] = TextTrackMenuItem; 7373 module.exports = exports['default']; 7374 7375 },{"../../component.js":67,"../../menu/menu-item.js":107,"../../utils/fn.js":136,"global/document":1,"global/window":2}],92:[function(_dereq_,module,exports){ 7376 /** 7377 * @file current-time-display.js 7378 */ 7379 'use strict'; 7380 7381 exports.__esModule = true; 7382 7383 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7384 7385 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7386 7387 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7388 7389 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7390 7391 var _componentJs = _dereq_('../../component.js'); 7392 7393 var _componentJs2 = _interopRequireDefault(_componentJs); 7394 7395 var _utilsDomJs = _dereq_('../../utils/dom.js'); 7396 7397 var Dom = _interopRequireWildcard(_utilsDomJs); 7398 7399 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 7400 7401 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 7402 7403 /** 7404 * Displays the current time 7405 * 7406 * @param {Player|Object} player 7407 * @param {Object=} options 7408 * @extends Component 7409 * @class CurrentTimeDisplay 7410 */ 7411 7412 var CurrentTimeDisplay = (function (_Component) { 7413 _inherits(CurrentTimeDisplay, _Component); 7414 7415 function CurrentTimeDisplay(player, options) { 7416 _classCallCheck(this, CurrentTimeDisplay); 7417 7418 _Component.call(this, player, options); 7419 7420 this.on(player, 'timeupdate', this.updateContent); 7421 } 7422 7423 /** 7424 * Create the component's DOM element 7425 * 7426 * @return {Element} 7427 * @method createEl 7428 */ 7429 7430 CurrentTimeDisplay.prototype.createEl = function createEl() { 7431 var el = _Component.prototype.createEl.call(this, 'div', { 7432 className: 'vjs-current-time vjs-time-control vjs-control' 7433 }); 7434 7435 this.contentEl_ = Dom.createEl('div', { 7436 className: 'vjs-current-time-display', 7437 // label the current time for screen reader users 7438 innerHTML: '<span class="vjs-control-text">Current Time </span>' + '0:00' 7439 }, { 7440 // tell screen readers not to automatically read the time as it changes 7441 'aria-live': 'off' 7442 }); 7443 7444 el.appendChild(this.contentEl_); 7445 return el; 7446 }; 7447 7448 /** 7449 * Update current time display 7450 * 7451 * @method updateContent 7452 */ 7453 7454 CurrentTimeDisplay.prototype.updateContent = function updateContent() { 7455 // Allows for smooth scrubbing, when player can't keep up. 7456 var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); 7457 var localizedText = this.localize('Current Time'); 7458 var formattedTime = _utilsFormatTimeJs2['default'](time, this.player_.duration()); 7459 if (formattedTime !== this.formattedTime_) { 7460 this.formattedTime_ = formattedTime; 7461 this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime; 7462 } 7463 }; 7464 7465 return CurrentTimeDisplay; 7466 })(_componentJs2['default']); 7467 7468 _componentJs2['default'].registerComponent('CurrentTimeDisplay', CurrentTimeDisplay); 7469 exports['default'] = CurrentTimeDisplay; 7470 module.exports = exports['default']; 7471 7472 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],93:[function(_dereq_,module,exports){ 7473 /** 7474 * @file duration-display.js 7475 */ 7476 'use strict'; 7477 7478 exports.__esModule = true; 7479 7480 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7481 7482 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7483 7484 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7485 7486 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7487 7488 var _componentJs = _dereq_('../../component.js'); 7489 7490 var _componentJs2 = _interopRequireDefault(_componentJs); 7491 7492 var _utilsDomJs = _dereq_('../../utils/dom.js'); 7493 7494 var Dom = _interopRequireWildcard(_utilsDomJs); 7495 7496 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 7497 7498 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 7499 7500 /** 7501 * Displays the duration 7502 * 7503 * @param {Player|Object} player 7504 * @param {Object=} options 7505 * @extends Component 7506 * @class DurationDisplay 7507 */ 7508 7509 var DurationDisplay = (function (_Component) { 7510 _inherits(DurationDisplay, _Component); 7511 7512 function DurationDisplay(player, options) { 7513 _classCallCheck(this, DurationDisplay); 7514 7515 _Component.call(this, player, options); 7516 7517 // this might need to be changed to 'durationchange' instead of 'timeupdate' eventually, 7518 // however the durationchange event fires before this.player_.duration() is set, 7519 // so the value cannot be written out using this method. 7520 // Once the order of durationchange and this.player_.duration() being set is figured out, 7521 // this can be updated. 7522 this.on(player, 'timeupdate', this.updateContent); 7523 this.on(player, 'loadedmetadata', this.updateContent); 7524 } 7525 7526 /** 7527 * Create the component's DOM element 7528 * 7529 * @return {Element} 7530 * @method createEl 7531 */ 7532 7533 DurationDisplay.prototype.createEl = function createEl() { 7534 var el = _Component.prototype.createEl.call(this, 'div', { 7535 className: 'vjs-duration vjs-time-control vjs-control' 7536 }); 7537 7538 this.contentEl_ = Dom.createEl('div', { 7539 className: 'vjs-duration-display', 7540 // label the duration time for screen reader users 7541 innerHTML: '<span class="vjs-control-text">' + this.localize('Duration Time') + '</span> 0:00' 7542 }, { 7543 // tell screen readers not to automatically read the time as it changes 7544 'aria-live': 'off' 7545 }); 7546 7547 el.appendChild(this.contentEl_); 7548 return el; 7549 }; 7550 7551 /** 7552 * Update duration time display 7553 * 7554 * @method updateContent 7555 */ 7556 7557 DurationDisplay.prototype.updateContent = function updateContent() { 7558 var duration = this.player_.duration(); 7559 if (duration && this.duration_ !== duration) { 7560 this.duration_ = duration; 7561 var localizedText = this.localize('Duration Time'); 7562 var formattedTime = _utilsFormatTimeJs2['default'](duration); 7563 this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime; // label the duration time for screen reader users 7564 } 7565 }; 7566 7567 return DurationDisplay; 7568 })(_componentJs2['default']); 7569 7570 _componentJs2['default'].registerComponent('DurationDisplay', DurationDisplay); 7571 exports['default'] = DurationDisplay; 7572 module.exports = exports['default']; 7573 7574 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],94:[function(_dereq_,module,exports){ 7575 /** 7576 * @file remaining-time-display.js 7577 */ 7578 'use strict'; 7579 7580 exports.__esModule = true; 7581 7582 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7583 7584 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7585 7586 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7587 7588 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7589 7590 var _componentJs = _dereq_('../../component.js'); 7591 7592 var _componentJs2 = _interopRequireDefault(_componentJs); 7593 7594 var _utilsDomJs = _dereq_('../../utils/dom.js'); 7595 7596 var Dom = _interopRequireWildcard(_utilsDomJs); 7597 7598 var _utilsFormatTimeJs = _dereq_('../../utils/format-time.js'); 7599 7600 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 7601 7602 /** 7603 * Displays the time left in the video 7604 * 7605 * @param {Player|Object} player 7606 * @param {Object=} options 7607 * @extends Component 7608 * @class RemainingTimeDisplay 7609 */ 7610 7611 var RemainingTimeDisplay = (function (_Component) { 7612 _inherits(RemainingTimeDisplay, _Component); 7613 7614 function RemainingTimeDisplay(player, options) { 7615 _classCallCheck(this, RemainingTimeDisplay); 7616 7617 _Component.call(this, player, options); 7618 7619 this.on(player, 'timeupdate', this.updateContent); 7620 } 7621 7622 /** 7623 * Create the component's DOM element 7624 * 7625 * @return {Element} 7626 * @method createEl 7627 */ 7628 7629 RemainingTimeDisplay.prototype.createEl = function createEl() { 7630 var el = _Component.prototype.createEl.call(this, 'div', { 7631 className: 'vjs-remaining-time vjs-time-control vjs-control' 7632 }); 7633 7634 this.contentEl_ = Dom.createEl('div', { 7635 className: 'vjs-remaining-time-display', 7636 // label the remaining time for screen reader users 7637 innerHTML: '<span class="vjs-control-text">' + this.localize('Remaining Time') + '</span> -0:00' 7638 }, { 7639 // tell screen readers not to automatically read the time as it changes 7640 'aria-live': 'off' 7641 }); 7642 7643 el.appendChild(this.contentEl_); 7644 return el; 7645 }; 7646 7647 /** 7648 * Update remaining time display 7649 * 7650 * @method updateContent 7651 */ 7652 7653 RemainingTimeDisplay.prototype.updateContent = function updateContent() { 7654 if (this.player_.duration()) { 7655 var localizedText = this.localize('Remaining Time'); 7656 var formattedTime = _utilsFormatTimeJs2['default'](this.player_.remainingTime()); 7657 if (formattedTime !== this.formattedTime_) { 7658 this.formattedTime_ = formattedTime; 7659 this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> -' + formattedTime; 7660 } 7661 } 7662 7663 // Allows for smooth scrubbing, when player can't keep up. 7664 // var time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime(); 7665 // this.contentEl_.innerHTML = vjs.formatTime(time, this.player_.duration()); 7666 }; 7667 7668 return RemainingTimeDisplay; 7669 })(_componentJs2['default']); 7670 7671 _componentJs2['default'].registerComponent('RemainingTimeDisplay', RemainingTimeDisplay); 7672 exports['default'] = RemainingTimeDisplay; 7673 module.exports = exports['default']; 7674 7675 },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],95:[function(_dereq_,module,exports){ 7676 /** 7677 * @file time-divider.js 7678 */ 7679 'use strict'; 7680 7681 exports.__esModule = true; 7682 7683 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7684 7685 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7686 7687 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7688 7689 var _componentJs = _dereq_('../../component.js'); 7690 7691 var _componentJs2 = _interopRequireDefault(_componentJs); 7692 7693 /** 7694 * The separator between the current time and duration. 7695 * Can be hidden if it's not needed in the design. 7696 * 7697 * @param {Player|Object} player 7698 * @param {Object=} options 7699 * @extends Component 7700 * @class TimeDivider 7701 */ 7702 7703 var TimeDivider = (function (_Component) { 7704 _inherits(TimeDivider, _Component); 7705 7706 function TimeDivider() { 7707 _classCallCheck(this, TimeDivider); 7708 7709 _Component.apply(this, arguments); 7710 } 7711 7712 /** 7713 * Create the component's DOM element 7714 * 7715 * @return {Element} 7716 * @method createEl 7717 */ 7718 7719 TimeDivider.prototype.createEl = function createEl() { 7720 return _Component.prototype.createEl.call(this, 'div', { 7721 className: 'vjs-time-control vjs-time-divider', 7722 innerHTML: '<div><span>/</span></div>' 7723 }); 7724 }; 7725 7726 return TimeDivider; 7727 })(_componentJs2['default']); 7728 7729 _componentJs2['default'].registerComponent('TimeDivider', TimeDivider); 7730 exports['default'] = TimeDivider; 7731 module.exports = exports['default']; 7732 7733 },{"../../component.js":67}],96:[function(_dereq_,module,exports){ 7734 /** 7735 * @file volume-bar.js 7736 */ 7737 'use strict'; 7738 7739 exports.__esModule = true; 7740 7741 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 7742 7743 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7744 7745 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7746 7747 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7748 7749 var _sliderSliderJs = _dereq_('../../slider/slider.js'); 7750 7751 var _sliderSliderJs2 = _interopRequireDefault(_sliderSliderJs); 7752 7753 var _componentJs = _dereq_('../../component.js'); 7754 7755 var _componentJs2 = _interopRequireDefault(_componentJs); 7756 7757 var _utilsFnJs = _dereq_('../../utils/fn.js'); 7758 7759 var Fn = _interopRequireWildcard(_utilsFnJs); 7760 7761 // Required children 7762 7763 var _volumeLevelJs = _dereq_('./volume-level.js'); 7764 7765 var _volumeLevelJs2 = _interopRequireDefault(_volumeLevelJs); 7766 7767 /** 7768 * The bar that contains the volume level and can be clicked on to adjust the level 7769 * 7770 * @param {Player|Object} player 7771 * @param {Object=} options 7772 * @extends Slider 7773 * @class VolumeBar 7774 */ 7775 7776 var VolumeBar = (function (_Slider) { 7777 _inherits(VolumeBar, _Slider); 7778 7779 function VolumeBar(player, options) { 7780 _classCallCheck(this, VolumeBar); 7781 7782 _Slider.call(this, player, options); 7783 this.on(player, 'volumechange', this.updateARIAAttributes); 7784 player.ready(Fn.bind(this, this.updateARIAAttributes)); 7785 } 7786 7787 /** 7788 * Create the component's DOM element 7789 * 7790 * @return {Element} 7791 * @method createEl 7792 */ 7793 7794 VolumeBar.prototype.createEl = function createEl() { 7795 return _Slider.prototype.createEl.call(this, 'div', { 7796 className: 'vjs-volume-bar vjs-slider-bar' 7797 }, { 7798 'aria-label': 'volume level' 7799 }); 7800 }; 7801 7802 /** 7803 * Handle mouse move on volume bar 7804 * 7805 * @method handleMouseMove 7806 */ 7807 7808 VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) { 7809 this.checkMuted(); 7810 this.player_.volume(this.calculateDistance(event)); 7811 }; 7812 7813 VolumeBar.prototype.checkMuted = function checkMuted() { 7814 if (this.player_.muted()) { 7815 this.player_.muted(false); 7816 } 7817 }; 7818 7819 /** 7820 * Get percent of volume level 7821 * 7822 * @retun {Number} Volume level percent 7823 * @method getPercent 7824 */ 7825 7826 VolumeBar.prototype.getPercent = function getPercent() { 7827 if (this.player_.muted()) { 7828 return 0; 7829 } else { 7830 return this.player_.volume(); 7831 } 7832 }; 7833 7834 /** 7835 * Increase volume level for keyboard users 7836 * 7837 * @method stepForward 7838 */ 7839 7840 VolumeBar.prototype.stepForward = function stepForward() { 7841 this.checkMuted(); 7842 this.player_.volume(this.player_.volume() + 0.1); 7843 }; 7844 7845 /** 7846 * Decrease volume level for keyboard users 7847 * 7848 * @method stepBack 7849 */ 7850 7851 VolumeBar.prototype.stepBack = function stepBack() { 7852 this.checkMuted(); 7853 this.player_.volume(this.player_.volume() - 0.1); 7854 }; 7855 7856 /** 7857 * Update ARIA accessibility attributes 7858 * 7859 * @method updateARIAAttributes 7860 */ 7861 7862 VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes() { 7863 // Current value of volume bar as a percentage 7864 var volume = (this.player_.volume() * 100).toFixed(2); 7865 this.el_.setAttribute('aria-valuenow', volume); 7866 this.el_.setAttribute('aria-valuetext', volume + '%'); 7867 }; 7868 7869 return VolumeBar; 7870 })(_sliderSliderJs2['default']); 7871 7872 VolumeBar.prototype.options_ = { 7873 children: ['volumeLevel'], 7874 'barName': 'volumeLevel' 7875 }; 7876 7877 VolumeBar.prototype.playerEvent = 'volumechange'; 7878 7879 _componentJs2['default'].registerComponent('VolumeBar', VolumeBar); 7880 exports['default'] = VolumeBar; 7881 module.exports = exports['default']; 7882 7883 },{"../../component.js":67,"../../slider/slider.js":116,"../../utils/fn.js":136,"./volume-level.js":98}],97:[function(_dereq_,module,exports){ 7884 /** 7885 * @file volume-control.js 7886 */ 7887 'use strict'; 7888 7889 exports.__esModule = true; 7890 7891 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7892 7893 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7894 7895 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7896 7897 var _componentJs = _dereq_('../../component.js'); 7898 7899 var _componentJs2 = _interopRequireDefault(_componentJs); 7900 7901 // Required children 7902 7903 var _volumeBarJs = _dereq_('./volume-bar.js'); 7904 7905 var _volumeBarJs2 = _interopRequireDefault(_volumeBarJs); 7906 7907 /** 7908 * The component for controlling the volume level 7909 * 7910 * @param {Player|Object} player 7911 * @param {Object=} options 7912 * @extends Component 7913 * @class VolumeControl 7914 */ 7915 7916 var VolumeControl = (function (_Component) { 7917 _inherits(VolumeControl, _Component); 7918 7919 function VolumeControl(player, options) { 7920 _classCallCheck(this, VolumeControl); 7921 7922 _Component.call(this, player, options); 7923 7924 // hide volume controls when they're not supported by the current tech 7925 if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { 7926 this.addClass('vjs-hidden'); 7927 } 7928 this.on(player, 'loadstart', function () { 7929 if (player.tech_['featuresVolumeControl'] === false) { 7930 this.addClass('vjs-hidden'); 7931 } else { 7932 this.removeClass('vjs-hidden'); 7933 } 7934 }); 7935 } 7936 7937 /** 7938 * Create the component's DOM element 7939 * 7940 * @return {Element} 7941 * @method createEl 7942 */ 7943 7944 VolumeControl.prototype.createEl = function createEl() { 7945 return _Component.prototype.createEl.call(this, 'div', { 7946 className: 'vjs-volume-control vjs-control' 7947 }); 7948 }; 7949 7950 return VolumeControl; 7951 })(_componentJs2['default']); 7952 7953 VolumeControl.prototype.options_ = { 7954 children: ['volumeBar'] 7955 }; 7956 7957 _componentJs2['default'].registerComponent('VolumeControl', VolumeControl); 7958 exports['default'] = VolumeControl; 7959 module.exports = exports['default']; 7960 7961 },{"../../component.js":67,"./volume-bar.js":96}],98:[function(_dereq_,module,exports){ 7962 /** 7963 * @file volume-level.js 7964 */ 7965 'use strict'; 7966 7967 exports.__esModule = true; 7968 7969 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 7970 7971 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 7972 7973 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 7974 7975 var _componentJs = _dereq_('../../component.js'); 7976 7977 var _componentJs2 = _interopRequireDefault(_componentJs); 7978 7979 /** 7980 * Shows volume level 7981 * 7982 * @param {Player|Object} player 7983 * @param {Object=} options 7984 * @extends Component 7985 * @class VolumeLevel 7986 */ 7987 7988 var VolumeLevel = (function (_Component) { 7989 _inherits(VolumeLevel, _Component); 7990 7991 function VolumeLevel() { 7992 _classCallCheck(this, VolumeLevel); 7993 7994 _Component.apply(this, arguments); 7995 } 7996 7997 /** 7998 * Create the component's DOM element 7999 * 8000 * @return {Element} 8001 * @method createEl 8002 */ 8003 8004 VolumeLevel.prototype.createEl = function createEl() { 8005 return _Component.prototype.createEl.call(this, 'div', { 8006 className: 'vjs-volume-level', 8007 innerHTML: '<span class="vjs-control-text"></span>' 8008 }); 8009 }; 8010 8011 return VolumeLevel; 8012 })(_componentJs2['default']); 8013 8014 _componentJs2['default'].registerComponent('VolumeLevel', VolumeLevel); 8015 exports['default'] = VolumeLevel; 8016 module.exports = exports['default']; 8017 8018 },{"../../component.js":67}],99:[function(_dereq_,module,exports){ 8019 /** 8020 * @file volume-menu-button.js 8021 */ 8022 'use strict'; 8023 8024 exports.__esModule = true; 8025 8026 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8027 8028 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 8029 8030 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8031 8032 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8033 8034 var _utilsFnJs = _dereq_('../utils/fn.js'); 8035 8036 var Fn = _interopRequireWildcard(_utilsFnJs); 8037 8038 var _componentJs = _dereq_('../component.js'); 8039 8040 var _componentJs2 = _interopRequireDefault(_componentJs); 8041 8042 var _popupPopupJs = _dereq_('../popup/popup.js'); 8043 8044 var _popupPopupJs2 = _interopRequireDefault(_popupPopupJs); 8045 8046 var _popupPopupButtonJs = _dereq_('../popup/popup-button.js'); 8047 8048 var _popupPopupButtonJs2 = _interopRequireDefault(_popupPopupButtonJs); 8049 8050 var _muteToggleJs = _dereq_('./mute-toggle.js'); 8051 8052 var _muteToggleJs2 = _interopRequireDefault(_muteToggleJs); 8053 8054 var _volumeControlVolumeBarJs = _dereq_('./volume-control/volume-bar.js'); 8055 8056 var _volumeControlVolumeBarJs2 = _interopRequireDefault(_volumeControlVolumeBarJs); 8057 8058 /** 8059 * Button for volume popup 8060 * 8061 * @param {Player|Object} player 8062 * @param {Object=} options 8063 * @extends PopupButton 8064 * @class VolumeMenuButton 8065 */ 8066 8067 var VolumeMenuButton = (function (_PopupButton) { 8068 _inherits(VolumeMenuButton, _PopupButton); 8069 8070 function VolumeMenuButton(player) { 8071 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 8072 8073 _classCallCheck(this, VolumeMenuButton); 8074 8075 // Default to inline 8076 if (options.inline === undefined) { 8077 options.inline = true; 8078 } 8079 8080 // If the vertical option isn't passed at all, default to true. 8081 if (options.vertical === undefined) { 8082 // If an inline volumeMenuButton is used, we should default to using 8083 // a horizontal slider for obvious reasons. 8084 if (options.inline) { 8085 options.vertical = false; 8086 } else { 8087 options.vertical = true; 8088 } 8089 } 8090 8091 // The vertical option needs to be set on the volumeBar as well, 8092 // since that will need to be passed along to the VolumeBar constructor 8093 options.volumeBar = options.volumeBar || {}; 8094 options.volumeBar.vertical = !!options.vertical; 8095 8096 _PopupButton.call(this, player, options); 8097 8098 // Same listeners as MuteToggle 8099 this.on(player, 'volumechange', this.volumeUpdate); 8100 this.on(player, 'loadstart', this.volumeUpdate); 8101 8102 // hide mute toggle if the current tech doesn't support volume control 8103 function updateVisibility() { 8104 if (player.tech_ && player.tech_['featuresVolumeControl'] === false) { 8105 this.addClass('vjs-hidden'); 8106 } else { 8107 this.removeClass('vjs-hidden'); 8108 } 8109 } 8110 8111 updateVisibility.call(this); 8112 this.on(player, 'loadstart', updateVisibility); 8113 8114 this.on(this.volumeBar, ['slideractive', 'focus'], function () { 8115 this.addClass('vjs-slider-active'); 8116 }); 8117 8118 this.on(this.volumeBar, ['sliderinactive', 'blur'], function () { 8119 this.removeClass('vjs-slider-active'); 8120 }); 8121 8122 this.on(this.volumeBar, ['focus'], function () { 8123 this.addClass('vjs-lock-showing'); 8124 }); 8125 8126 this.on(this.volumeBar, ['blur'], function () { 8127 this.removeClass('vjs-lock-showing'); 8128 }); 8129 } 8130 8131 /** 8132 * Allow sub components to stack CSS class names 8133 * 8134 * @return {String} The constructed class name 8135 * @method buildCSSClass 8136 */ 8137 8138 VolumeMenuButton.prototype.buildCSSClass = function buildCSSClass() { 8139 var orientationClass = ''; 8140 if (!!this.options_.vertical) { 8141 orientationClass = 'vjs-volume-menu-button-vertical'; 8142 } else { 8143 orientationClass = 'vjs-volume-menu-button-horizontal'; 8144 } 8145 8146 return 'vjs-volume-menu-button ' + _PopupButton.prototype.buildCSSClass.call(this) + ' ' + orientationClass; 8147 }; 8148 8149 /** 8150 * Allow sub components to stack CSS class names 8151 * 8152 * @return {Popup} The volume popup button 8153 * @method createPopup 8154 */ 8155 8156 VolumeMenuButton.prototype.createPopup = function createPopup() { 8157 var popup = new _popupPopupJs2['default'](this.player_, { 8158 contentElType: 'div' 8159 }); 8160 8161 var vb = new _volumeControlVolumeBarJs2['default'](this.player_, this.options_.volumeBar); 8162 8163 popup.addChild(vb); 8164 8165 this.menuContent = popup; 8166 this.volumeBar = vb; 8167 8168 this.attachVolumeBarEvents(); 8169 8170 return popup; 8171 }; 8172 8173 /** 8174 * Handle click on volume popup and calls super 8175 * 8176 * @method handleClick 8177 */ 8178 8179 VolumeMenuButton.prototype.handleClick = function handleClick() { 8180 _muteToggleJs2['default'].prototype.handleClick.call(this); 8181 _PopupButton.prototype.handleClick.call(this); 8182 }; 8183 8184 VolumeMenuButton.prototype.attachVolumeBarEvents = function attachVolumeBarEvents() { 8185 this.menuContent.on(['mousedown', 'touchdown'], Fn.bind(this, this.handleMouseDown)); 8186 }; 8187 8188 VolumeMenuButton.prototype.handleMouseDown = function handleMouseDown(event) { 8189 this.on(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); 8190 this.on(this.el_.ownerDocument, ['mouseup', 'touchend'], this.handleMouseUp); 8191 }; 8192 8193 VolumeMenuButton.prototype.handleMouseUp = function handleMouseUp(event) { 8194 this.off(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); 8195 }; 8196 8197 return VolumeMenuButton; 8198 })(_popupPopupButtonJs2['default']); 8199 8200 VolumeMenuButton.prototype.volumeUpdate = _muteToggleJs2['default'].prototype.update; 8201 VolumeMenuButton.prototype.controlText_ = 'Mute'; 8202 8203 _componentJs2['default'].registerComponent('VolumeMenuButton', VolumeMenuButton); 8204 exports['default'] = VolumeMenuButton; 8205 module.exports = exports['default']; 8206 8207 },{"../component.js":67,"../popup/popup-button.js":112,"../popup/popup.js":113,"../utils/fn.js":136,"./mute-toggle.js":71,"./volume-control/volume-bar.js":96}],100:[function(_dereq_,module,exports){ 8208 /** 8209 * @file error-display.js 8210 */ 8211 'use strict'; 8212 8213 exports.__esModule = true; 8214 8215 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 8216 8217 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8218 8219 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8220 8221 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8222 8223 var _component = _dereq_('./component'); 8224 8225 var _component2 = _interopRequireDefault(_component); 8226 8227 var _modalDialog = _dereq_('./modal-dialog'); 8228 8229 var _modalDialog2 = _interopRequireDefault(_modalDialog); 8230 8231 var _utilsDom = _dereq_('./utils/dom'); 8232 8233 var Dom = _interopRequireWildcard(_utilsDom); 8234 8235 var _utilsMergeOptions = _dereq_('./utils/merge-options'); 8236 8237 var _utilsMergeOptions2 = _interopRequireDefault(_utilsMergeOptions); 8238 8239 /** 8240 * Display that an error has occurred making the video unplayable. 8241 * 8242 * @extends ModalDialog 8243 * @class ErrorDisplay 8244 */ 8245 8246 var ErrorDisplay = (function (_ModalDialog) { 8247 _inherits(ErrorDisplay, _ModalDialog); 8248 8249 /** 8250 * Constructor for error display modal. 8251 * 8252 * @param {Player} player 8253 * @param {Object} [options] 8254 */ 8255 8256 function ErrorDisplay(player, options) { 8257 _classCallCheck(this, ErrorDisplay); 8258 8259 _ModalDialog.call(this, player, options); 8260 this.on(player, 'error', this.open); 8261 } 8262 8263 /** 8264 * Include the old class for backward-compatibility. 8265 * 8266 * This can be removed in 6.0. 8267 * 8268 * @method buildCSSClass 8269 * @deprecated 8270 * @return {String} 8271 */ 8272 8273 ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() { 8274 return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this); 8275 }; 8276 8277 /** 8278 * Generates the modal content based on the player error. 8279 * 8280 * @return {String|Null} 8281 */ 8282 8283 ErrorDisplay.prototype.content = function content() { 8284 var error = this.player().error(); 8285 return error ? this.localize(error.message) : ''; 8286 }; 8287 8288 return ErrorDisplay; 8289 })(_modalDialog2['default']); 8290 8291 ErrorDisplay.prototype.options_ = _utilsMergeOptions2['default'](_modalDialog2['default'].prototype.options_, { 8292 fillAlways: true, 8293 temporary: false, 8294 uncloseable: true 8295 }); 8296 8297 _component2['default'].registerComponent('ErrorDisplay', ErrorDisplay); 8298 exports['default'] = ErrorDisplay; 8299 module.exports = exports['default']; 8300 8301 },{"./component":67,"./modal-dialog":109,"./utils/dom":134,"./utils/merge-options":140}],101:[function(_dereq_,module,exports){ 8302 /** 8303 * @file event-target.js 8304 */ 8305 'use strict'; 8306 8307 exports.__esModule = true; 8308 8309 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 8310 8311 var _utilsEventsJs = _dereq_('./utils/events.js'); 8312 8313 var Events = _interopRequireWildcard(_utilsEventsJs); 8314 8315 var EventTarget = function EventTarget() {}; 8316 8317 EventTarget.prototype.allowedEvents_ = {}; 8318 8319 EventTarget.prototype.on = function (type, fn) { 8320 // Remove the addEventListener alias before calling Events.on 8321 // so we don't get into an infinite type loop 8322 var ael = this.addEventListener; 8323 this.addEventListener = Function.prototype; 8324 Events.on(this, type, fn); 8325 this.addEventListener = ael; 8326 }; 8327 EventTarget.prototype.addEventListener = EventTarget.prototype.on; 8328 8329 EventTarget.prototype.off = function (type, fn) { 8330 Events.off(this, type, fn); 8331 }; 8332 EventTarget.prototype.removeEventListener = EventTarget.prototype.off; 8333 8334 EventTarget.prototype.one = function (type, fn) { 8335 Events.one(this, type, fn); 8336 }; 8337 8338 EventTarget.prototype.trigger = function (event) { 8339 var type = event.type || event; 8340 8341 if (typeof event === 'string') { 8342 event = { 8343 type: type 8344 }; 8345 } 8346 event = Events.fixEvent(event); 8347 8348 if (this.allowedEvents_[type] && this['on' + type]) { 8349 this['on' + type](event); 8350 } 8351 8352 Events.trigger(this, event); 8353 }; 8354 // The standard DOM EventTarget.dispatchEvent() is aliased to trigger() 8355 EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger; 8356 8357 exports['default'] = EventTarget; 8358 module.exports = exports['default']; 8359 8360 },{"./utils/events.js":135}],102:[function(_dereq_,module,exports){ 8361 'use strict'; 8362 8363 exports.__esModule = true; 8364 8365 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8366 8367 var _utilsLog = _dereq_('./utils/log'); 8368 8369 var _utilsLog2 = _interopRequireDefault(_utilsLog); 8370 8371 /* 8372 * @file extend.js 8373 * 8374 * A combination of node inherits and babel's inherits (after transpile). 8375 * Both work the same but node adds `super_` to the subClass 8376 * and Bable adds the superClass as __proto__. Both seem useful. 8377 */ 8378 var _inherits = function _inherits(subClass, superClass) { 8379 if (typeof superClass !== 'function' && superClass !== null) { 8380 throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); 8381 } 8382 8383 subClass.prototype = Object.create(superClass && superClass.prototype, { 8384 constructor: { 8385 value: subClass, 8386 enumerable: false, 8387 writable: true, 8388 configurable: true 8389 } 8390 }); 8391 8392 if (superClass) { 8393 // node 8394 subClass.super_ = superClass; 8395 } 8396 }; 8397 8398 /* 8399 * Function for subclassing using the same inheritance that 8400 * videojs uses internally 8401 * ```js 8402 * var Button = videojs.getComponent('Button'); 8403 * ``` 8404 * ```js 8405 * var MyButton = videojs.extend(Button, { 8406 * constructor: function(player, options) { 8407 * Button.call(this, player, options); 8408 * }, 8409 * onClick: function() { 8410 * // doSomething 8411 * } 8412 * }); 8413 * ``` 8414 */ 8415 var extendFn = function extendFn(superClass) { 8416 var subClassMethods = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 8417 8418 var subClass = function subClass() { 8419 superClass.apply(this, arguments); 8420 }; 8421 var methods = {}; 8422 8423 if (typeof subClassMethods === 'object') { 8424 if (typeof subClassMethods.init === 'function') { 8425 _utilsLog2['default'].warn('Constructor logic via init() is deprecated; please use constructor() instead.'); 8426 subClassMethods.constructor = subClassMethods.init; 8427 } 8428 if (subClassMethods.constructor !== Object.prototype.constructor) { 8429 subClass = subClassMethods.constructor; 8430 } 8431 methods = subClassMethods; 8432 } else if (typeof subClassMethods === 'function') { 8433 subClass = subClassMethods; 8434 } 8435 8436 _inherits(subClass, superClass); 8437 8438 // Extend subObj's prototype with functions and other properties from props 8439 for (var name in methods) { 8440 if (methods.hasOwnProperty(name)) { 8441 subClass.prototype[name] = methods[name]; 8442 } 8443 } 8444 8445 return subClass; 8446 }; 8447 8448 exports['default'] = extendFn; 8449 module.exports = exports['default']; 8450 8451 },{"./utils/log":139}],103:[function(_dereq_,module,exports){ 8452 /** 8453 * @file fullscreen-api.js 8454 */ 8455 'use strict'; 8456 8457 exports.__esModule = true; 8458 8459 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8460 8461 var _globalDocument = _dereq_('global/document'); 8462 8463 var _globalDocument2 = _interopRequireDefault(_globalDocument); 8464 8465 /* 8466 * Store the browser-specific methods for the fullscreen API 8467 * @type {Object|undefined} 8468 * @private 8469 */ 8470 var FullscreenApi = {}; 8471 8472 // browser API methods 8473 // map approach from Screenful.js - https://github.com/sindresorhus/screenfull.js 8474 var apiMap = [ 8475 // Spec: https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html 8476 ['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], 8477 // WebKit 8478 ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], 8479 // Old WebKit (Safari 5.1) 8480 ['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], 8481 // Mozilla 8482 ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], 8483 // Microsoft 8484 ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']]; 8485 8486 var specApi = apiMap[0]; 8487 var browserApi = undefined; 8488 8489 // determine the supported set of functions 8490 for (var i = 0; i < apiMap.length; i++) { 8491 // check for exitFullscreen function 8492 if (apiMap[i][1] in _globalDocument2['default']) { 8493 browserApi = apiMap[i]; 8494 break; 8495 } 8496 } 8497 8498 // map the browser API names to the spec API names 8499 if (browserApi) { 8500 for (var i = 0; i < browserApi.length; i++) { 8501 FullscreenApi[specApi[i]] = browserApi[i]; 8502 } 8503 } 8504 8505 exports['default'] = FullscreenApi; 8506 module.exports = exports['default']; 8507 8508 },{"global/document":1}],104:[function(_dereq_,module,exports){ 8509 /** 8510 * @file loading-spinner.js 8511 */ 8512 'use strict'; 8513 8514 exports.__esModule = true; 8515 8516 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8517 8518 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8519 8520 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8521 8522 var _component = _dereq_('./component'); 8523 8524 var _component2 = _interopRequireDefault(_component); 8525 8526 /* Loading Spinner 8527 ================================================================================ */ 8528 /** 8529 * Loading spinner for waiting events 8530 * 8531 * @extends Component 8532 * @class LoadingSpinner 8533 */ 8534 8535 var LoadingSpinner = (function (_Component) { 8536 _inherits(LoadingSpinner, _Component); 8537 8538 function LoadingSpinner() { 8539 _classCallCheck(this, LoadingSpinner); 8540 8541 _Component.apply(this, arguments); 8542 } 8543 8544 /** 8545 * Create the component's DOM element 8546 * 8547 * @method createEl 8548 */ 8549 8550 LoadingSpinner.prototype.createEl = function createEl() { 8551 return _Component.prototype.createEl.call(this, 'div', { 8552 className: 'vjs-loading-spinner', 8553 dir: 'ltr' 8554 }); 8555 }; 8556 8557 return LoadingSpinner; 8558 })(_component2['default']); 8559 8560 _component2['default'].registerComponent('LoadingSpinner', LoadingSpinner); 8561 exports['default'] = LoadingSpinner; 8562 module.exports = exports['default']; 8563 8564 },{"./component":67}],105:[function(_dereq_,module,exports){ 8565 /** 8566 * @file media-error.js 8567 */ 8568 'use strict'; 8569 8570 exports.__esModule = true; 8571 8572 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8573 8574 var _objectAssign = _dereq_('object.assign'); 8575 8576 var _objectAssign2 = _interopRequireDefault(_objectAssign); 8577 8578 /* 8579 * Custom MediaError to mimic the HTML5 MediaError 8580 * 8581 * @param {Number} code The media error code 8582 */ 8583 var MediaError = function MediaError(code) { 8584 if (typeof code === 'number') { 8585 this.code = code; 8586 } else if (typeof code === 'string') { 8587 // default code is zero, so this is a custom error 8588 this.message = code; 8589 } else if (typeof code === 'object') { 8590 // object 8591 _objectAssign2['default'](this, code); 8592 } 8593 8594 if (!this.message) { 8595 this.message = MediaError.defaultMessages[this.code] || ''; 8596 } 8597 }; 8598 8599 /* 8600 * The error code that refers two one of the defined 8601 * MediaError types 8602 * 8603 * @type {Number} 8604 */ 8605 MediaError.prototype.code = 0; 8606 8607 /* 8608 * An optional message to be shown with the error. 8609 * Message is not part of the HTML5 video spec 8610 * but allows for more informative custom errors. 8611 * 8612 * @type {String} 8613 */ 8614 MediaError.prototype.message = ''; 8615 8616 /* 8617 * An optional status code that can be set by plugins 8618 * to allow even more detail about the error. 8619 * For example the HLS plugin might provide the specific 8620 * HTTP status code that was returned when the error 8621 * occurred, then allowing a custom error overlay 8622 * to display more information. 8623 * 8624 * @type {Array} 8625 */ 8626 MediaError.prototype.status = null; 8627 8628 MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', // = 0 8629 'MEDIA_ERR_ABORTED', // = 1 8630 'MEDIA_ERR_NETWORK', // = 2 8631 'MEDIA_ERR_DECODE', // = 3 8632 'MEDIA_ERR_SRC_NOT_SUPPORTED', // = 4 8633 'MEDIA_ERR_ENCRYPTED' // = 5 8634 ]; 8635 8636 MediaError.defaultMessages = { 8637 1: 'You aborted the media playback', 8638 2: 'A network error caused the media download to fail part-way.', 8639 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.', 8640 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.', 8641 5: 'The media is encrypted and we do not have the keys to decrypt it.' 8642 }; 8643 8644 // Add types as properties on MediaError 8645 // e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; 8646 for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { 8647 MediaError[MediaError.errorTypes[errNum]] = errNum; 8648 // values should be accessible on both the class and instance 8649 MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; 8650 } 8651 8652 exports['default'] = MediaError; 8653 module.exports = exports['default']; 8654 8655 },{"object.assign":45}],106:[function(_dereq_,module,exports){ 8656 /** 8657 * @file menu-button.js 8658 */ 8659 'use strict'; 8660 8661 exports.__esModule = true; 8662 8663 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 8664 8665 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8666 8667 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8668 8669 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8670 8671 var _clickableComponentJs = _dereq_('../clickable-component.js'); 8672 8673 var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); 8674 8675 var _componentJs = _dereq_('../component.js'); 8676 8677 var _componentJs2 = _interopRequireDefault(_componentJs); 8678 8679 var _menuJs = _dereq_('./menu.js'); 8680 8681 var _menuJs2 = _interopRequireDefault(_menuJs); 8682 8683 var _utilsDomJs = _dereq_('../utils/dom.js'); 8684 8685 var Dom = _interopRequireWildcard(_utilsDomJs); 8686 8687 var _utilsFnJs = _dereq_('../utils/fn.js'); 8688 8689 var Fn = _interopRequireWildcard(_utilsFnJs); 8690 8691 var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); 8692 8693 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 8694 8695 /** 8696 * A button class with a popup menu 8697 * 8698 * @param {Player|Object} player 8699 * @param {Object=} options 8700 * @extends Button 8701 * @class MenuButton 8702 */ 8703 8704 var MenuButton = (function (_ClickableComponent) { 8705 _inherits(MenuButton, _ClickableComponent); 8706 8707 function MenuButton(player) { 8708 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 8709 8710 _classCallCheck(this, MenuButton); 8711 8712 _ClickableComponent.call(this, player, options); 8713 8714 this.update(); 8715 8716 this.enabled_ = true; 8717 8718 this.el_.setAttribute('aria-haspopup', 'true'); 8719 this.el_.setAttribute('role', 'menuitem'); 8720 this.on('keydown', this.handleSubmenuKeyPress); 8721 } 8722 8723 /** 8724 * Update menu 8725 * 8726 * @method update 8727 */ 8728 8729 MenuButton.prototype.update = function update() { 8730 var menu = this.createMenu(); 8731 8732 if (this.menu) { 8733 this.removeChild(this.menu); 8734 } 8735 8736 this.menu = menu; 8737 this.addChild(menu); 8738 8739 /** 8740 * Track the state of the menu button 8741 * 8742 * @type {Boolean} 8743 * @private 8744 */ 8745 this.buttonPressed_ = false; 8746 this.el_.setAttribute('aria-expanded', 'false'); 8747 8748 if (this.items && this.items.length === 0) { 8749 this.hide(); 8750 } else if (this.items && this.items.length > 1) { 8751 this.show(); 8752 } 8753 }; 8754 8755 /** 8756 * Create menu 8757 * 8758 * @return {Menu} The constructed menu 8759 * @method createMenu 8760 */ 8761 8762 MenuButton.prototype.createMenu = function createMenu() { 8763 var menu = new _menuJs2['default'](this.player_); 8764 8765 // Add a title list item to the top 8766 if (this.options_.title) { 8767 var title = Dom.createEl('li', { 8768 className: 'vjs-menu-title', 8769 innerHTML: _utilsToTitleCaseJs2['default'](this.options_.title), 8770 tabIndex: -1 8771 }); 8772 menu.children_.unshift(title); 8773 Dom.insertElFirst(title, menu.contentEl()); 8774 } 8775 8776 this.items = this['createItems'](); 8777 8778 if (this.items) { 8779 // Add menu items to the menu 8780 for (var i = 0; i < this.items.length; i++) { 8781 menu.addItem(this.items[i]); 8782 } 8783 } 8784 8785 return menu; 8786 }; 8787 8788 /** 8789 * Create the list of menu items. Specific to each subclass. 8790 * 8791 * @method createItems 8792 */ 8793 8794 MenuButton.prototype.createItems = function createItems() {}; 8795 8796 /** 8797 * Create the component's DOM element 8798 * 8799 * @return {Element} 8800 * @method createEl 8801 */ 8802 8803 MenuButton.prototype.createEl = function createEl() { 8804 return _ClickableComponent.prototype.createEl.call(this, 'div', { 8805 className: this.buildCSSClass() 8806 }); 8807 }; 8808 8809 /** 8810 * Allow sub components to stack CSS class names 8811 * 8812 * @return {String} The constructed class name 8813 * @method buildCSSClass 8814 */ 8815 8816 MenuButton.prototype.buildCSSClass = function buildCSSClass() { 8817 var menuButtonClass = 'vjs-menu-button'; 8818 8819 // If the inline option is passed, we want to use different styles altogether. 8820 if (this.options_.inline === true) { 8821 menuButtonClass += '-inline'; 8822 } else { 8823 menuButtonClass += '-popup'; 8824 } 8825 8826 return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); 8827 }; 8828 8829 /** 8830 * When you click the button it adds focus, which 8831 * will show the menu indefinitely. 8832 * So we'll remove focus when the mouse leaves the button. 8833 * Focus is needed for tab navigation. 8834 * Allow sub components to stack CSS class names 8835 * 8836 * @method handleClick 8837 */ 8838 8839 MenuButton.prototype.handleClick = function handleClick() { 8840 this.one('mouseout', Fn.bind(this, function () { 8841 this.menu.unlockShowing(); 8842 this.el_.blur(); 8843 })); 8844 if (this.buttonPressed_) { 8845 this.unpressButton(); 8846 } else { 8847 this.pressButton(); 8848 } 8849 }; 8850 8851 /** 8852 * Handle key press on menu 8853 * 8854 * @param {Object} event Key press event 8855 * @method handleKeyPress 8856 */ 8857 8858 MenuButton.prototype.handleKeyPress = function handleKeyPress(event) { 8859 8860 // Escape (27) key or Tab (9) key unpress the 'button' 8861 if (event.which === 27 || event.which === 9) { 8862 if (this.buttonPressed_) { 8863 this.unpressButton(); 8864 } 8865 // Don't preventDefault for Tab key - we still want to lose focus 8866 if (event.which !== 9) { 8867 event.preventDefault(); 8868 } 8869 // Up (38) key or Down (40) key press the 'button' 8870 } else if (event.which === 38 || event.which === 40) { 8871 if (!this.buttonPressed_) { 8872 this.pressButton(); 8873 event.preventDefault(); 8874 } 8875 } else { 8876 _ClickableComponent.prototype.handleKeyPress.call(this, event); 8877 } 8878 }; 8879 8880 /** 8881 * Handle key press on submenu 8882 * 8883 * @param {Object} event Key press event 8884 * @method handleSubmenuKeyPress 8885 */ 8886 8887 MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) { 8888 8889 // Escape (27) key or Tab (9) key unpress the 'button' 8890 if (event.which === 27 || event.which === 9) { 8891 if (this.buttonPressed_) { 8892 this.unpressButton(); 8893 } 8894 // Don't preventDefault for Tab key - we still want to lose focus 8895 if (event.which !== 9) { 8896 event.preventDefault(); 8897 } 8898 } 8899 }; 8900 8901 /** 8902 * Makes changes based on button pressed 8903 * 8904 * @method pressButton 8905 */ 8906 8907 MenuButton.prototype.pressButton = function pressButton() { 8908 if (this.enabled_) { 8909 this.buttonPressed_ = true; 8910 this.menu.lockShowing(); 8911 this.el_.setAttribute('aria-expanded', 'true'); 8912 this.menu.focus(); // set the focus into the submenu 8913 } 8914 }; 8915 8916 /** 8917 * Makes changes based on button unpressed 8918 * 8919 * @method unpressButton 8920 */ 8921 8922 MenuButton.prototype.unpressButton = function unpressButton() { 8923 if (this.enabled_) { 8924 this.buttonPressed_ = false; 8925 this.menu.unlockShowing(); 8926 this.el_.setAttribute('aria-expanded', 'false'); 8927 this.el_.focus(); // Set focus back to this menu button 8928 } 8929 }; 8930 8931 /** 8932 * Disable the menu button 8933 * 8934 * @return {Component} 8935 * @method disable 8936 */ 8937 8938 MenuButton.prototype.disable = function disable() { 8939 // Unpress, but don't force focus on this button 8940 this.buttonPressed_ = false; 8941 this.menu.unlockShowing(); 8942 this.el_.setAttribute('aria-expanded', 'false'); 8943 8944 this.enabled_ = false; 8945 8946 return _ClickableComponent.prototype.disable.call(this); 8947 }; 8948 8949 /** 8950 * Enable the menu button 8951 * 8952 * @return {Component} 8953 * @method disable 8954 */ 8955 8956 MenuButton.prototype.enable = function enable() { 8957 this.enabled_ = true; 8958 8959 return _ClickableComponent.prototype.enable.call(this); 8960 }; 8961 8962 return MenuButton; 8963 })(_clickableComponentJs2['default']); 8964 8965 _componentJs2['default'].registerComponent('MenuButton', MenuButton); 8966 exports['default'] = MenuButton; 8967 module.exports = exports['default']; 8968 8969 },{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":134,"../utils/fn.js":136,"../utils/to-title-case.js":143,"./menu.js":108}],107:[function(_dereq_,module,exports){ 8970 /** 8971 * @file menu-item.js 8972 */ 8973 'use strict'; 8974 8975 exports.__esModule = true; 8976 8977 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8978 8979 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8980 8981 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8982 8983 var _clickableComponentJs = _dereq_('../clickable-component.js'); 8984 8985 var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); 8986 8987 var _componentJs = _dereq_('../component.js'); 8988 8989 var _componentJs2 = _interopRequireDefault(_componentJs); 8990 8991 var _objectAssign = _dereq_('object.assign'); 8992 8993 var _objectAssign2 = _interopRequireDefault(_objectAssign); 8994 8995 /** 8996 * The component for a menu item. `<li>` 8997 * 8998 * @param {Player|Object} player 8999 * @param {Object=} options 9000 * @extends Button 9001 * @class MenuItem 9002 */ 9003 9004 var MenuItem = (function (_ClickableComponent) { 9005 _inherits(MenuItem, _ClickableComponent); 9006 9007 function MenuItem(player, options) { 9008 _classCallCheck(this, MenuItem); 9009 9010 _ClickableComponent.call(this, player, options); 9011 9012 this.selectable = options['selectable']; 9013 9014 this.selected(options['selected']); 9015 9016 if (this.selectable) { 9017 // TODO: May need to be either menuitemcheckbox or menuitemradio, 9018 // and may need logical grouping of menu items. 9019 this.el_.setAttribute('role', 'menuitemcheckbox'); 9020 } else { 9021 this.el_.setAttribute('role', 'menuitem'); 9022 } 9023 } 9024 9025 /** 9026 * Create the component's DOM element 9027 * 9028 * @param {String=} type Desc 9029 * @param {Object=} props Desc 9030 * @return {Element} 9031 * @method createEl 9032 */ 9033 9034 MenuItem.prototype.createEl = function createEl(type, props, attrs) { 9035 return _ClickableComponent.prototype.createEl.call(this, 'li', _objectAssign2['default']({ 9036 className: 'vjs-menu-item', 9037 innerHTML: this.localize(this.options_['label']), 9038 tabIndex: -1 9039 }, props), attrs); 9040 }; 9041 9042 /** 9043 * Handle a click on the menu item, and set it to selected 9044 * 9045 * @method handleClick 9046 */ 9047 9048 MenuItem.prototype.handleClick = function handleClick() { 9049 this.selected(true); 9050 }; 9051 9052 /** 9053 * Set this menu item as selected or not 9054 * 9055 * @param {Boolean} selected 9056 * @method selected 9057 */ 9058 9059 MenuItem.prototype.selected = function selected(_selected) { 9060 if (this.selectable) { 9061 if (_selected) { 9062 this.addClass('vjs-selected'); 9063 this.el_.setAttribute('aria-checked', 'true'); 9064 // aria-checked isn't fully supported by browsers/screen readers, 9065 // so indicate selected state to screen reader in the control text. 9066 this.controlText(', selected'); 9067 } else { 9068 this.removeClass('vjs-selected'); 9069 this.el_.setAttribute('aria-checked', 'false'); 9070 // Indicate un-selected state to screen reader 9071 // Note that a space clears out the selected state text 9072 this.controlText(' '); 9073 } 9074 } 9075 }; 9076 9077 return MenuItem; 9078 })(_clickableComponentJs2['default']); 9079 9080 _componentJs2['default'].registerComponent('MenuItem', MenuItem); 9081 exports['default'] = MenuItem; 9082 module.exports = exports['default']; 9083 9084 },{"../clickable-component.js":65,"../component.js":67,"object.assign":45}],108:[function(_dereq_,module,exports){ 9085 /** 9086 * @file menu.js 9087 */ 9088 'use strict'; 9089 9090 exports.__esModule = true; 9091 9092 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 9093 9094 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9095 9096 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 9097 9098 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 9099 9100 var _componentJs = _dereq_('../component.js'); 9101 9102 var _componentJs2 = _interopRequireDefault(_componentJs); 9103 9104 var _utilsDomJs = _dereq_('../utils/dom.js'); 9105 9106 var Dom = _interopRequireWildcard(_utilsDomJs); 9107 9108 var _utilsFnJs = _dereq_('../utils/fn.js'); 9109 9110 var Fn = _interopRequireWildcard(_utilsFnJs); 9111 9112 var _utilsEventsJs = _dereq_('../utils/events.js'); 9113 9114 var Events = _interopRequireWildcard(_utilsEventsJs); 9115 9116 /** 9117 * The Menu component is used to build pop up menus, including subtitle and 9118 * captions selection menus. 9119 * 9120 * @extends Component 9121 * @class Menu 9122 */ 9123 9124 var Menu = (function (_Component) { 9125 _inherits(Menu, _Component); 9126 9127 function Menu(player, options) { 9128 _classCallCheck(this, Menu); 9129 9130 _Component.call(this, player, options); 9131 9132 this.focusedChild_ = -1; 9133 9134 this.on('keydown', this.handleKeyPress); 9135 } 9136 9137 /** 9138 * Add a menu item to the menu 9139 * 9140 * @param {Object|String} component Component or component type to add 9141 * @method addItem 9142 */ 9143 9144 Menu.prototype.addItem = function addItem(component) { 9145 this.addChild(component); 9146 component.on('click', Fn.bind(this, function () { 9147 this.unlockShowing(); 9148 //TODO: Need to set keyboard focus back to the menuButton 9149 })); 9150 }; 9151 9152 /** 9153 * Create the component's DOM element 9154 * 9155 * @return {Element} 9156 * @method createEl 9157 */ 9158 9159 Menu.prototype.createEl = function createEl() { 9160 var contentElType = this.options_.contentElType || 'ul'; 9161 this.contentEl_ = Dom.createEl(contentElType, { 9162 className: 'vjs-menu-content' 9163 }); 9164 this.contentEl_.setAttribute('role', 'menu'); 9165 var el = _Component.prototype.createEl.call(this, 'div', { 9166 append: this.contentEl_, 9167 className: 'vjs-menu' 9168 }); 9169 el.setAttribute('role', 'presentation'); 9170 el.appendChild(this.contentEl_); 9171 9172 // Prevent clicks from bubbling up. Needed for Menu Buttons, 9173 // where a click on the parent is significant 9174 Events.on(el, 'click', function (event) { 9175 event.preventDefault(); 9176 event.stopImmediatePropagation(); 9177 }); 9178 9179 return el; 9180 }; 9181 9182 /** 9183 * Handle key press for menu 9184 * 9185 * @param {Object} event Event object 9186 * @method handleKeyPress 9187 */ 9188 9189 Menu.prototype.handleKeyPress = function handleKeyPress(event) { 9190 if (event.which === 37 || event.which === 40) { 9191 // Left and Down Arrows 9192 event.preventDefault(); 9193 this.stepForward(); 9194 } else if (event.which === 38 || event.which === 39) { 9195 // Up and Right Arrows 9196 event.preventDefault(); 9197 this.stepBack(); 9198 } 9199 }; 9200 9201 /** 9202 * Move to next (lower) menu item for keyboard users 9203 * 9204 * @method stepForward 9205 */ 9206 9207 Menu.prototype.stepForward = function stepForward() { 9208 var stepChild = 0; 9209 9210 if (this.focusedChild_ !== undefined) { 9211 stepChild = this.focusedChild_ + 1; 9212 } 9213 this.focus(stepChild); 9214 }; 9215 9216 /** 9217 * Move to previous (higher) menu item for keyboard users 9218 * 9219 * @method stepBack 9220 */ 9221 9222 Menu.prototype.stepBack = function stepBack() { 9223 var stepChild = 0; 9224 9225 if (this.focusedChild_ !== undefined) { 9226 stepChild = this.focusedChild_ - 1; 9227 } 9228 this.focus(stepChild); 9229 }; 9230 9231 /** 9232 * Set focus on a menu item in the menu 9233 * 9234 * @param {Object|String} item Index of child item set focus on 9235 * @method focus 9236 */ 9237 9238 Menu.prototype.focus = function focus() { 9239 var item = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0]; 9240 9241 var children = this.children().slice(); 9242 var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className); 9243 9244 if (haveTitle) { 9245 children.shift(); 9246 } 9247 9248 if (children.length > 0) { 9249 if (item < 0) { 9250 item = 0; 9251 } else if (item >= children.length) { 9252 item = children.length - 1; 9253 } 9254 9255 this.focusedChild_ = item; 9256 9257 children[item].el_.focus(); 9258 } 9259 }; 9260 9261 return Menu; 9262 })(_componentJs2['default']); 9263 9264 _componentJs2['default'].registerComponent('Menu', Menu); 9265 exports['default'] = Menu; 9266 module.exports = exports['default']; 9267 9268 },{"../component.js":67,"../utils/dom.js":134,"../utils/events.js":135,"../utils/fn.js":136}],109:[function(_dereq_,module,exports){ 9269 /** 9270 * @file modal-dialog.js 9271 */ 9272 'use strict'; 9273 9274 exports.__esModule = true; 9275 9276 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9277 9278 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 9279 9280 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 9281 9282 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 9283 9284 var _utilsDom = _dereq_('./utils/dom'); 9285 9286 var Dom = _interopRequireWildcard(_utilsDom); 9287 9288 var _utilsFn = _dereq_('./utils/fn'); 9289 9290 var Fn = _interopRequireWildcard(_utilsFn); 9291 9292 var _utilsLog = _dereq_('./utils/log'); 9293 9294 var _utilsLog2 = _interopRequireDefault(_utilsLog); 9295 9296 var _component = _dereq_('./component'); 9297 9298 var _component2 = _interopRequireDefault(_component); 9299 9300 var _closeButton = _dereq_('./close-button'); 9301 9302 var _closeButton2 = _interopRequireDefault(_closeButton); 9303 9304 var MODAL_CLASS_NAME = 'vjs-modal-dialog'; 9305 var ESC = 27; 9306 9307 /** 9308 * The `ModalDialog` displays over the video and its controls, which blocks 9309 * interaction with the player until it is closed. 9310 * 9311 * Modal dialogs include a "Close" button and will close when that button 9312 * is activated - or when ESC is pressed anywhere. 9313 * 9314 * @extends Component 9315 * @class ModalDialog 9316 */ 9317 9318 var ModalDialog = (function (_Component) { 9319 _inherits(ModalDialog, _Component); 9320 9321 /** 9322 * Constructor for modals. 9323 * 9324 * @param {Player} player 9325 * @param {Object} [options] 9326 * @param {Mixed} [options.content=undefined] 9327 * Provide customized content for this modal. 9328 * 9329 * @param {String} [options.description] 9330 * A text description for the modal, primarily for accessibility. 9331 * 9332 * @param {Boolean} [options.fillAlways=false] 9333 * Normally, modals are automatically filled only the first time 9334 * they open. This tells the modal to refresh its content 9335 * every time it opens. 9336 * 9337 * @param {String} [options.label] 9338 * A text label for the modal, primarily for accessibility. 9339 * 9340 * @param {Boolean} [options.temporary=true] 9341 * If `true`, the modal can only be opened once; it will be 9342 * disposed as soon as it's closed. 9343 * 9344 * @param {Boolean} [options.uncloseable=false] 9345 * If `true`, the user will not be able to close the modal 9346 * through the UI in the normal ways. Programmatic closing is 9347 * still possible. 9348 * 9349 */ 9350 9351 function ModalDialog(player, options) { 9352 _classCallCheck(this, ModalDialog); 9353 9354 _Component.call(this, player, options); 9355 this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = false; 9356 9357 this.closeable(!this.options_.uncloseable); 9358 this.content(this.options_.content); 9359 9360 // Make sure the contentEl is defined AFTER any children are initialized 9361 // because we only want the contents of the modal in the contentEl 9362 // (not the UI elements like the close button). 9363 this.contentEl_ = Dom.createEl('div', { 9364 className: MODAL_CLASS_NAME + '-content' 9365 }, { 9366 role: 'document' 9367 }); 9368 9369 this.descEl_ = Dom.createEl('p', { 9370 className: MODAL_CLASS_NAME + '-description vjs-offscreen', 9371 id: this.el().getAttribute('aria-describedby') 9372 }); 9373 9374 Dom.textContent(this.descEl_, this.description()); 9375 this.el_.appendChild(this.descEl_); 9376 this.el_.appendChild(this.contentEl_); 9377 } 9378 9379 /* 9380 * Modal dialog default options. 9381 * 9382 * @type {Object} 9383 * @private 9384 */ 9385 9386 /** 9387 * Create the modal's DOM element 9388 * 9389 * @method createEl 9390 * @return {Element} 9391 */ 9392 9393 ModalDialog.prototype.createEl = function createEl() { 9394 return _Component.prototype.createEl.call(this, 'div', { 9395 className: this.buildCSSClass(), 9396 tabIndex: -1 9397 }, { 9398 'aria-describedby': this.id() + '_description', 9399 'aria-hidden': 'true', 9400 'aria-label': this.label(), 9401 role: 'dialog' 9402 }); 9403 }; 9404 9405 /** 9406 * Build the modal's CSS class. 9407 * 9408 * @method buildCSSClass 9409 * @return {String} 9410 */ 9411 9412 ModalDialog.prototype.buildCSSClass = function buildCSSClass() { 9413 return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this); 9414 }; 9415 9416 /** 9417 * Handles key presses on the document, looking for ESC, which closes 9418 * the modal. 9419 * 9420 * @method handleKeyPress 9421 * @param {Event} e 9422 */ 9423 9424 ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) { 9425 if (e.which === ESC && this.closeable()) { 9426 this.close(); 9427 } 9428 }; 9429 9430 /** 9431 * Returns the label string for this modal. Primarily used for accessibility. 9432 * 9433 * @return {String} 9434 */ 9435 9436 ModalDialog.prototype.label = function label() { 9437 return this.options_.label || this.localize('Modal Window'); 9438 }; 9439 9440 /** 9441 * Returns the description string for this modal. Primarily used for 9442 * accessibility. 9443 * 9444 * @return {String} 9445 */ 9446 9447 ModalDialog.prototype.description = function description() { 9448 var desc = this.options_.description || this.localize('This is a modal window.'); 9449 9450 // Append a universal closeability message if the modal is closeable. 9451 if (this.closeable()) { 9452 desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.'); 9453 } 9454 9455 return desc; 9456 }; 9457 9458 /** 9459 * Opens the modal. 9460 * 9461 * @method open 9462 * @return {ModalDialog} 9463 */ 9464 9465 ModalDialog.prototype.open = function open() { 9466 if (!this.opened_) { 9467 var player = this.player(); 9468 9469 this.trigger('beforemodalopen'); 9470 this.opened_ = true; 9471 9472 // Fill content if the modal has never opened before and 9473 // never been filled. 9474 if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { 9475 this.fill(); 9476 } 9477 9478 // If the player was playing, pause it and take note of its previously 9479 // playing state. 9480 this.wasPlaying_ = !player.paused(); 9481 9482 if (this.wasPlaying_) { 9483 player.pause(); 9484 } 9485 9486 if (this.closeable()) { 9487 this.on(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); 9488 } 9489 9490 player.controls(false); 9491 this.show(); 9492 this.el().setAttribute('aria-hidden', 'false'); 9493 this.trigger('modalopen'); 9494 this.hasBeenOpened_ = true; 9495 } 9496 return this; 9497 }; 9498 9499 /** 9500 * Whether or not the modal is opened currently. 9501 * 9502 * @method opened 9503 * @param {Boolean} [value] 9504 * If given, it will open (`true`) or close (`false`) the modal. 9505 * 9506 * @return {Boolean} 9507 */ 9508 9509 ModalDialog.prototype.opened = function opened(value) { 9510 if (typeof value === 'boolean') { 9511 this[value ? 'open' : 'close'](); 9512 } 9513 return this.opened_; 9514 }; 9515 9516 /** 9517 * Closes the modal. 9518 * 9519 * @method close 9520 * @return {ModalDialog} 9521 */ 9522 9523 ModalDialog.prototype.close = function close() { 9524 if (this.opened_) { 9525 var player = this.player(); 9526 9527 this.trigger('beforemodalclose'); 9528 this.opened_ = false; 9529 9530 if (this.wasPlaying_) { 9531 player.play(); 9532 } 9533 9534 if (this.closeable()) { 9535 this.off(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); 9536 } 9537 9538 player.controls(true); 9539 this.hide(); 9540 this.el().setAttribute('aria-hidden', 'true'); 9541 this.trigger('modalclose'); 9542 9543 if (this.options_.temporary) { 9544 this.dispose(); 9545 } 9546 } 9547 return this; 9548 }; 9549 9550 /** 9551 * Whether or not the modal is closeable via the UI. 9552 * 9553 * @method closeable 9554 * @param {Boolean} [value] 9555 * If given as a Boolean, it will set the `closeable` option. 9556 * 9557 * @return {Boolean} 9558 */ 9559 9560 ModalDialog.prototype.closeable = function closeable(value) { 9561 if (typeof value === 'boolean') { 9562 var closeable = this.closeable_ = !!value; 9563 var _close = this.getChild('closeButton'); 9564 9565 // If this is being made closeable and has no close button, add one. 9566 if (closeable && !_close) { 9567 9568 // The close button should be a child of the modal - not its 9569 // content element, so temporarily change the content element. 9570 var temp = this.contentEl_; 9571 this.contentEl_ = this.el_; 9572 _close = this.addChild('closeButton'); 9573 this.contentEl_ = temp; 9574 this.on(_close, 'close', this.close); 9575 } 9576 9577 // If this is being made uncloseable and has a close button, remove it. 9578 if (!closeable && _close) { 9579 this.off(_close, 'close', this.close); 9580 this.removeChild(_close); 9581 _close.dispose(); 9582 } 9583 } 9584 return this.closeable_; 9585 }; 9586 9587 /** 9588 * Fill the modal's content element with the modal's "content" option. 9589 * 9590 * The content element will be emptied before this change takes place. 9591 * 9592 * @method fill 9593 * @return {ModalDialog} 9594 */ 9595 9596 ModalDialog.prototype.fill = function fill() { 9597 return this.fillWith(this.content()); 9598 }; 9599 9600 /** 9601 * Fill the modal's content element with arbitrary content. 9602 * 9603 * The content element will be emptied before this change takes place. 9604 * 9605 * @method fillWith 9606 * @param {Mixed} [content] 9607 * The same rules apply to this as apply to the `content` option. 9608 * 9609 * @return {ModalDialog} 9610 */ 9611 9612 ModalDialog.prototype.fillWith = function fillWith(content) { 9613 var contentEl = this.contentEl(); 9614 var parentEl = contentEl.parentNode; 9615 var nextSiblingEl = contentEl.nextSibling; 9616 9617 this.trigger('beforemodalfill'); 9618 this.hasBeenFilled_ = true; 9619 9620 // Detach the content element from the DOM before performing 9621 // manipulation to avoid modifying the live DOM multiple times. 9622 parentEl.removeChild(contentEl); 9623 this.empty(); 9624 Dom.insertContent(contentEl, content); 9625 this.trigger('modalfill'); 9626 9627 // Re-inject the re-filled content element. 9628 if (nextSiblingEl) { 9629 parentEl.insertBefore(contentEl, nextSiblingEl); 9630 } else { 9631 parentEl.appendChild(contentEl); 9632 } 9633 9634 return this; 9635 }; 9636 9637 /** 9638 * Empties the content element. 9639 * 9640 * This happens automatically anytime the modal is filled. 9641 * 9642 * @method empty 9643 * @return {ModalDialog} 9644 */ 9645 9646 ModalDialog.prototype.empty = function empty() { 9647 this.trigger('beforemodalempty'); 9648 Dom.emptyEl(this.contentEl()); 9649 this.trigger('modalempty'); 9650 return this; 9651 }; 9652 9653 /** 9654 * Gets or sets the modal content, which gets normalized before being 9655 * rendered into the DOM. 9656 * 9657 * This does not update the DOM or fill the modal, but it is called during 9658 * that process. 9659 * 9660 * @method content 9661 * @param {Mixed} [value] 9662 * If defined, sets the internal content value to be used on the 9663 * next call(s) to `fill`. This value is normalized before being 9664 * inserted. To "clear" the internal content value, pass `null`. 9665 * 9666 * @return {Mixed} 9667 */ 9668 9669 ModalDialog.prototype.content = function content(value) { 9670 if (typeof value !== 'undefined') { 9671 this.content_ = value; 9672 } 9673 return this.content_; 9674 }; 9675 9676 return ModalDialog; 9677 })(_component2['default']); 9678 9679 ModalDialog.prototype.options_ = { 9680 temporary: true 9681 }; 9682 9683 _component2['default'].registerComponent('ModalDialog', ModalDialog); 9684 exports['default'] = ModalDialog; 9685 module.exports = exports['default']; 9686 9687 },{"./close-button":66,"./component":67,"./utils/dom":134,"./utils/fn":136,"./utils/log":139}],110:[function(_dereq_,module,exports){ 9688 /** 9689 * @file player.js 9690 */ 9691 // Subclasses Component 9692 'use strict'; 9693 9694 exports.__esModule = true; 9695 9696 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 9697 9698 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9699 9700 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 9701 9702 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 9703 9704 var _componentJs = _dereq_('./component.js'); 9705 9706 var _componentJs2 = _interopRequireDefault(_componentJs); 9707 9708 var _globalDocument = _dereq_('global/document'); 9709 9710 var _globalDocument2 = _interopRequireDefault(_globalDocument); 9711 9712 var _globalWindow = _dereq_('global/window'); 9713 9714 var _globalWindow2 = _interopRequireDefault(_globalWindow); 9715 9716 var _utilsEventsJs = _dereq_('./utils/events.js'); 9717 9718 var Events = _interopRequireWildcard(_utilsEventsJs); 9719 9720 var _utilsDomJs = _dereq_('./utils/dom.js'); 9721 9722 var Dom = _interopRequireWildcard(_utilsDomJs); 9723 9724 var _utilsFnJs = _dereq_('./utils/fn.js'); 9725 9726 var Fn = _interopRequireWildcard(_utilsFnJs); 9727 9728 var _utilsGuidJs = _dereq_('./utils/guid.js'); 9729 9730 var Guid = _interopRequireWildcard(_utilsGuidJs); 9731 9732 var _utilsBrowserJs = _dereq_('./utils/browser.js'); 9733 9734 var browser = _interopRequireWildcard(_utilsBrowserJs); 9735 9736 var _utilsLogJs = _dereq_('./utils/log.js'); 9737 9738 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 9739 9740 var _utilsToTitleCaseJs = _dereq_('./utils/to-title-case.js'); 9741 9742 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 9743 9744 var _utilsTimeRangesJs = _dereq_('./utils/time-ranges.js'); 9745 9746 var _utilsBufferJs = _dereq_('./utils/buffer.js'); 9747 9748 var _utilsStylesheetJs = _dereq_('./utils/stylesheet.js'); 9749 9750 var stylesheet = _interopRequireWildcard(_utilsStylesheetJs); 9751 9752 var _fullscreenApiJs = _dereq_('./fullscreen-api.js'); 9753 9754 var _fullscreenApiJs2 = _interopRequireDefault(_fullscreenApiJs); 9755 9756 var _mediaErrorJs = _dereq_('./media-error.js'); 9757 9758 var _mediaErrorJs2 = _interopRequireDefault(_mediaErrorJs); 9759 9760 var _safeJsonParseTuple = _dereq_('safe-json-parse/tuple'); 9761 9762 var _safeJsonParseTuple2 = _interopRequireDefault(_safeJsonParseTuple); 9763 9764 var _objectAssign = _dereq_('object.assign'); 9765 9766 var _objectAssign2 = _interopRequireDefault(_objectAssign); 9767 9768 var _utilsMergeOptionsJs = _dereq_('./utils/merge-options.js'); 9769 9770 var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); 9771 9772 var _tracksTextTrackListConverterJs = _dereq_('./tracks/text-track-list-converter.js'); 9773 9774 var _tracksTextTrackListConverterJs2 = _interopRequireDefault(_tracksTextTrackListConverterJs); 9775 9776 // Include required child components (importing also registers them) 9777 9778 var _techLoaderJs = _dereq_('./tech/loader.js'); 9779 9780 var _techLoaderJs2 = _interopRequireDefault(_techLoaderJs); 9781 9782 var _posterImageJs = _dereq_('./poster-image.js'); 9783 9784 var _posterImageJs2 = _interopRequireDefault(_posterImageJs); 9785 9786 var _tracksTextTrackDisplayJs = _dereq_('./tracks/text-track-display.js'); 9787 9788 var _tracksTextTrackDisplayJs2 = _interopRequireDefault(_tracksTextTrackDisplayJs); 9789 9790 var _loadingSpinnerJs = _dereq_('./loading-spinner.js'); 9791 9792 var _loadingSpinnerJs2 = _interopRequireDefault(_loadingSpinnerJs); 9793 9794 var _bigPlayButtonJs = _dereq_('./big-play-button.js'); 9795 9796 var _bigPlayButtonJs2 = _interopRequireDefault(_bigPlayButtonJs); 9797 9798 var _controlBarControlBarJs = _dereq_('./control-bar/control-bar.js'); 9799 9800 var _controlBarControlBarJs2 = _interopRequireDefault(_controlBarControlBarJs); 9801 9802 var _errorDisplayJs = _dereq_('./error-display.js'); 9803 9804 var _errorDisplayJs2 = _interopRequireDefault(_errorDisplayJs); 9805 9806 var _tracksTextTrackSettingsJs = _dereq_('./tracks/text-track-settings.js'); 9807 9808 var _tracksTextTrackSettingsJs2 = _interopRequireDefault(_tracksTextTrackSettingsJs); 9809 9810 var _modalDialog = _dereq_('./modal-dialog'); 9811 9812 var _modalDialog2 = _interopRequireDefault(_modalDialog); 9813 9814 // Require html5 tech, at least for disposing the original video tag 9815 9816 var _techTechJs = _dereq_('./tech/tech.js'); 9817 9818 var _techTechJs2 = _interopRequireDefault(_techTechJs); 9819 9820 var _techHtml5Js = _dereq_('./tech/html5.js'); 9821 9822 var _techHtml5Js2 = _interopRequireDefault(_techHtml5Js); 9823 9824 /** 9825 * An instance of the `Player` class is created when any of the Video.js setup methods are used to initialize a video. 9826 * ```js 9827 * var myPlayer = videojs('example_video_1'); 9828 * ``` 9829 * In the following example, the `data-setup` attribute tells the Video.js library to create a player instance when the library is ready. 9830 * ```html 9831 * <video id="example_video_1" data-setup='{}' controls> 9832 * <source src="my-source.mp4" type="video/mp4"> 9833 * </video> 9834 * ``` 9835 * After an instance has been created it can be accessed globally using `Video('example_video_1')`. 9836 * 9837 * @param {Element} tag The original video tag used for configuring options 9838 * @param {Object=} options Object of option names and values 9839 * @param {Function=} ready Ready callback function 9840 * @extends Component 9841 * @class Player 9842 */ 9843 9844 var Player = (function (_Component) { 9845 _inherits(Player, _Component); 9846 9847 /** 9848 * player's constructor function 9849 * 9850 * @constructs 9851 * @method init 9852 * @param {Element} tag The original video tag used for configuring options 9853 * @param {Object=} options Player options 9854 * @param {Function=} ready Ready callback function 9855 */ 9856 9857 function Player(tag, options, ready) { 9858 var _this = this; 9859 9860 _classCallCheck(this, Player); 9861 9862 // Make sure tag ID exists 9863 tag.id = tag.id || 'vjs_video_' + Guid.newGUID(); 9864 9865 // Set Options 9866 // The options argument overrides options set in the video tag 9867 // which overrides globally set options. 9868 // This latter part coincides with the load order 9869 // (tag must exist before Player) 9870 options = _objectAssign2['default'](Player.getTagSettings(tag), options); 9871 9872 // Delay the initialization of children because we need to set up 9873 // player properties first, and can't use `this` before `super()` 9874 options.initChildren = false; 9875 9876 // Same with creating the element 9877 options.createEl = false; 9878 9879 // we don't want the player to report touch activity on itself 9880 // see enableTouchActivity in Component 9881 options.reportTouchActivity = false; 9882 9883 // Run base component initializing with new options 9884 _Component.call(this, null, options, ready); 9885 9886 // if the global option object was accidentally blown away by 9887 // someone, bail early with an informative error 9888 if (!this.options_ || !this.options_.techOrder || !this.options_.techOrder.length) { 9889 throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); 9890 } 9891 9892 this.tag = tag; // Store the original tag used to set options 9893 9894 // Store the tag attributes used to restore html5 element 9895 this.tagAttributes = tag && Dom.getElAttributes(tag); 9896 9897 // Update current language 9898 this.language(this.options_.language); 9899 9900 // Update Supported Languages 9901 if (options.languages) { 9902 (function () { 9903 // Normalise player option languages to lowercase 9904 var languagesToLower = {}; 9905 9906 Object.getOwnPropertyNames(options.languages).forEach(function (name) { 9907 languagesToLower[name.toLowerCase()] = options.languages[name]; 9908 }); 9909 _this.languages_ = languagesToLower; 9910 })(); 9911 } else { 9912 this.languages_ = Player.prototype.options_.languages; 9913 } 9914 9915 // Cache for video property values. 9916 this.cache_ = {}; 9917 9918 // Set poster 9919 this.poster_ = options.poster || ''; 9920 9921 // Set controls 9922 this.controls_ = !!options.controls; 9923 9924 // Original tag settings stored in options 9925 // now remove immediately so native controls don't flash. 9926 // May be turned back on by HTML5 tech if nativeControlsForTouch is true 9927 tag.controls = false; 9928 9929 /* 9930 * Store the internal state of scrubbing 9931 * 9932 * @private 9933 * @return {Boolean} True if the user is scrubbing 9934 */ 9935 this.scrubbing_ = false; 9936 9937 this.el_ = this.createEl(); 9938 9939 // We also want to pass the original player options to each component and plugin 9940 // as well so they don't need to reach back into the player for options later. 9941 // We also need to do another copy of this.options_ so we don't end up with 9942 // an infinite loop. 9943 var playerOptionsCopy = _utilsMergeOptionsJs2['default'](this.options_); 9944 9945 // Load plugins 9946 if (options.plugins) { 9947 (function () { 9948 var plugins = options.plugins; 9949 9950 Object.getOwnPropertyNames(plugins).forEach(function (name) { 9951 if (typeof this[name] === 'function') { 9952 this[name](plugins[name]); 9953 } else { 9954 _utilsLogJs2['default'].error('Unable to find plugin:', name); 9955 } 9956 }, _this); 9957 })(); 9958 } 9959 9960 this.options_.playerOptions = playerOptionsCopy; 9961 9962 this.initChildren(); 9963 9964 // Set isAudio based on whether or not an audio tag was used 9965 this.isAudio(tag.nodeName.toLowerCase() === 'audio'); 9966 9967 // Update controls className. Can't do this when the controls are initially 9968 // set because the element doesn't exist yet. 9969 if (this.controls()) { 9970 this.addClass('vjs-controls-enabled'); 9971 } else { 9972 this.addClass('vjs-controls-disabled'); 9973 } 9974 9975 // Set ARIA label and region role depending on player type 9976 this.el_.setAttribute('role', 'region'); 9977 if (this.isAudio()) { 9978 this.el_.setAttribute('aria-label', 'audio player'); 9979 } else { 9980 this.el_.setAttribute('aria-label', 'video player'); 9981 } 9982 9983 if (this.isAudio()) { 9984 this.addClass('vjs-audio'); 9985 } 9986 9987 if (this.flexNotSupported_()) { 9988 this.addClass('vjs-no-flex'); 9989 } 9990 9991 // TODO: Make this smarter. Toggle user state between touching/mousing 9992 // using events, since devices can have both touch and mouse events. 9993 // if (browser.TOUCH_ENABLED) { 9994 // this.addClass('vjs-touch-enabled'); 9995 // } 9996 9997 // iOS Safari has broken hover handling 9998 if (!browser.IS_IOS) { 9999 this.addClass('vjs-workinghover'); 10000 } 10001 10002 // Make player easily findable by ID 10003 Player.players[this.id_] = this; 10004 10005 // When the player is first initialized, trigger activity so components 10006 // like the control bar show themselves if needed 10007 this.userActive(true); 10008 this.reportUserActivity(); 10009 this.listenForUserActivity_(); 10010 10011 this.on('fullscreenchange', this.handleFullscreenChange_); 10012 this.on('stageclick', this.handleStageClick_); 10013 } 10014 10015 /* 10016 * Global player list 10017 * 10018 * @type {Object} 10019 */ 10020 10021 /** 10022 * Destroys the video player and does any necessary cleanup 10023 * ```js 10024 * myPlayer.dispose(); 10025 * ``` 10026 * This is especially helpful if you are dynamically adding and removing videos 10027 * to/from the DOM. 10028 * 10029 * @method dispose 10030 */ 10031 10032 Player.prototype.dispose = function dispose() { 10033 this.trigger('dispose'); 10034 // prevent dispose from being called twice 10035 this.off('dispose'); 10036 10037 if (this.styleEl_ && this.styleEl_.parentNode) { 10038 this.styleEl_.parentNode.removeChild(this.styleEl_); 10039 } 10040 10041 // Kill reference to this player 10042 Player.players[this.id_] = null; 10043 if (this.tag && this.tag.player) { 10044 this.tag.player = null; 10045 } 10046 if (this.el_ && this.el_.player) { 10047 this.el_.player = null; 10048 } 10049 10050 if (this.tech_) { 10051 this.tech_.dispose(); 10052 } 10053 10054 _Component.prototype.dispose.call(this); 10055 }; 10056 10057 /** 10058 * Create the component's DOM element 10059 * 10060 * @return {Element} 10061 * @method createEl 10062 */ 10063 10064 Player.prototype.createEl = function createEl() { 10065 var el = this.el_ = _Component.prototype.createEl.call(this, 'div'); 10066 var tag = this.tag; 10067 10068 // Remove width/height attrs from tag so CSS can make it 100% width/height 10069 tag.removeAttribute('width'); 10070 tag.removeAttribute('height'); 10071 10072 // Copy over all the attributes from the tag, including ID and class 10073 // ID will now reference player box, not the video tag 10074 var attrs = Dom.getElAttributes(tag); 10075 10076 Object.getOwnPropertyNames(attrs).forEach(function (attr) { 10077 // workaround so we don't totally break IE7 10078 // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 10079 if (attr === 'class') { 10080 el.className = attrs[attr]; 10081 } else { 10082 el.setAttribute(attr, attrs[attr]); 10083 } 10084 }); 10085 10086 // Update tag id/class for use as HTML5 playback tech 10087 // Might think we should do this after embedding in container so .vjs-tech class 10088 // doesn't flash 100% width/height, but class only applies with .video-js parent 10089 tag.playerId = tag.id; 10090 tag.id += '_html5_api'; 10091 tag.className = 'vjs-tech'; 10092 10093 // Make player findable on elements 10094 tag.player = el.player = this; 10095 // Default state of video is paused 10096 this.addClass('vjs-paused'); 10097 10098 // Add a style element in the player that we'll use to set the width/height 10099 // of the player in a way that's still overrideable by CSS, just like the 10100 // video element 10101 if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) { 10102 this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions'); 10103 var defaultsStyleEl = Dom.$('.vjs-styles-defaults'); 10104 var head = Dom.$('head'); 10105 head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); 10106 } 10107 10108 // Pass in the width/height/aspectRatio options which will update the style el 10109 this.width(this.options_.width); 10110 this.height(this.options_.height); 10111 this.fluid(this.options_.fluid); 10112 this.aspectRatio(this.options_.aspectRatio); 10113 10114 // Hide any links within the video/audio tag, because IE doesn't hide them completely. 10115 var links = tag.getElementsByTagName('a'); 10116 for (var i = 0; i < links.length; i++) { 10117 var linkEl = links.item(i); 10118 Dom.addElClass(linkEl, 'vjs-hidden'); 10119 linkEl.setAttribute('hidden', 'hidden'); 10120 } 10121 10122 // insertElFirst seems to cause the networkState to flicker from 3 to 2, so 10123 // keep track of the original for later so we can know if the source originally failed 10124 tag.initNetworkState_ = tag.networkState; 10125 10126 // Wrap video tag in div (el/box) container 10127 if (tag.parentNode) { 10128 tag.parentNode.insertBefore(el, tag); 10129 } 10130 10131 // insert the tag as the first child of the player element 10132 // then manually add it to the children array so that this.addChild 10133 // will work properly for other components 10134 Dom.insertElFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup. 10135 this.children_.unshift(tag); 10136 10137 this.el_ = el; 10138 10139 return el; 10140 }; 10141 10142 /** 10143 * Get/set player width 10144 * 10145 * @param {Number=} value Value for width 10146 * @return {Number} Width when getting 10147 * @method width 10148 */ 10149 10150 Player.prototype.width = function width(value) { 10151 return this.dimension('width', value); 10152 }; 10153 10154 /** 10155 * Get/set player height 10156 * 10157 * @param {Number=} value Value for height 10158 * @return {Number} Height when getting 10159 * @method height 10160 */ 10161 10162 Player.prototype.height = function height(value) { 10163 return this.dimension('height', value); 10164 }; 10165 10166 /** 10167 * Get/set dimension for player 10168 * 10169 * @param {String} dimension Either width or height 10170 * @param {Number=} value Value for dimension 10171 * @return {Component} 10172 * @method dimension 10173 */ 10174 10175 Player.prototype.dimension = function dimension(_dimension, value) { 10176 var privDimension = _dimension + '_'; 10177 10178 if (value === undefined) { 10179 return this[privDimension] || 0; 10180 } 10181 10182 if (value === '') { 10183 // If an empty string is given, reset the dimension to be automatic 10184 this[privDimension] = undefined; 10185 } else { 10186 var parsedVal = parseFloat(value); 10187 10188 if (isNaN(parsedVal)) { 10189 _utilsLogJs2['default'].error('Improper value "' + value + '" supplied for for ' + _dimension); 10190 return this; 10191 } 10192 10193 this[privDimension] = parsedVal; 10194 } 10195 10196 this.updateStyleEl_(); 10197 return this; 10198 }; 10199 10200 /** 10201 * Add/remove the vjs-fluid class 10202 * 10203 * @param {Boolean} bool Value of true adds the class, value of false removes the class 10204 * @method fluid 10205 */ 10206 10207 Player.prototype.fluid = function fluid(bool) { 10208 if (bool === undefined) { 10209 return !!this.fluid_; 10210 } 10211 10212 this.fluid_ = !!bool; 10213 10214 if (bool) { 10215 this.addClass('vjs-fluid'); 10216 } else { 10217 this.removeClass('vjs-fluid'); 10218 } 10219 }; 10220 10221 /** 10222 * Get/Set the aspect ratio 10223 * 10224 * @param {String=} ratio Aspect ratio for player 10225 * @return aspectRatio 10226 * @method aspectRatio 10227 */ 10228 10229 Player.prototype.aspectRatio = function aspectRatio(ratio) { 10230 if (ratio === undefined) { 10231 return this.aspectRatio_; 10232 } 10233 10234 // Check for width:height format 10235 if (!/^\d+\:\d+$/.test(ratio)) { 10236 throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.'); 10237 } 10238 this.aspectRatio_ = ratio; 10239 10240 // We're assuming if you set an aspect ratio you want fluid mode, 10241 // because in fixed mode you could calculate width and height yourself. 10242 this.fluid(true); 10243 10244 this.updateStyleEl_(); 10245 }; 10246 10247 /** 10248 * Update styles of the player element (height, width and aspect ratio) 10249 * 10250 * @method updateStyleEl_ 10251 */ 10252 10253 Player.prototype.updateStyleEl_ = function updateStyleEl_() { 10254 if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE === true) { 10255 var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; 10256 var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; 10257 var techEl = this.tech_ && this.tech_.el(); 10258 10259 if (techEl) { 10260 if (_width >= 0) { 10261 techEl.width = _width; 10262 } 10263 if (_height >= 0) { 10264 techEl.height = _height; 10265 } 10266 } 10267 10268 return; 10269 } 10270 10271 var width = undefined; 10272 var height = undefined; 10273 var aspectRatio = undefined; 10274 var idClass = undefined; 10275 10276 // The aspect ratio is either used directly or to calculate width and height. 10277 if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') { 10278 // Use any aspectRatio that's been specifically set 10279 aspectRatio = this.aspectRatio_; 10280 } else if (this.videoWidth()) { 10281 // Otherwise try to get the aspect ratio from the video metadata 10282 aspectRatio = this.videoWidth() + ':' + this.videoHeight(); 10283 } else { 10284 // Or use a default. The video element's is 2:1, but 16:9 is more common. 10285 aspectRatio = '16:9'; 10286 } 10287 10288 // Get the ratio as a decimal we can use to calculate dimensions 10289 var ratioParts = aspectRatio.split(':'); 10290 var ratioMultiplier = ratioParts[1] / ratioParts[0]; 10291 10292 if (this.width_ !== undefined) { 10293 // Use any width that's been specifically set 10294 width = this.width_; 10295 } else if (this.height_ !== undefined) { 10296 // Or calulate the width from the aspect ratio if a height has been set 10297 width = this.height_ / ratioMultiplier; 10298 } else { 10299 // Or use the video's metadata, or use the video el's default of 300 10300 width = this.videoWidth() || 300; 10301 } 10302 10303 if (this.height_ !== undefined) { 10304 // Use any height that's been specifically set 10305 height = this.height_; 10306 } else { 10307 // Otherwise calculate the height from the ratio and the width 10308 height = width * ratioMultiplier; 10309 } 10310 10311 // Ensure the CSS class is valid by starting with an alpha character 10312 if (/^[^a-zA-Z]/.test(this.id())) { 10313 idClass = 'dimensions-' + this.id(); 10314 } else { 10315 idClass = this.id() + '-dimensions'; 10316 } 10317 10318 // Ensure the right class is still on the player for the style element 10319 this.addClass(idClass); 10320 10321 stylesheet.setTextContent(this.styleEl_, '\n .' + idClass + ' {\n width: ' + width + 'px;\n height: ' + height + 'px;\n }\n\n .' + idClass + '.vjs-fluid {\n padding-top: ' + ratioMultiplier * 100 + '%;\n }\n '); 10322 }; 10323 10324 /** 10325 * Load the Media Playback Technology (tech) 10326 * Load/Create an instance of playback technology including element and API methods 10327 * And append playback element in player div. 10328 * 10329 * @param {String} techName Name of the playback technology 10330 * @param {String} source Video source 10331 * @method loadTech_ 10332 * @private 10333 */ 10334 10335 Player.prototype.loadTech_ = function loadTech_(techName, source) { 10336 10337 // Pause and remove current playback technology 10338 if (this.tech_) { 10339 this.unloadTech_(); 10340 } 10341 10342 // get rid of the HTML5 video tag as soon as we are using another tech 10343 if (techName !== 'Html5' && this.tag) { 10344 _techTechJs2['default'].getTech('Html5').disposeMediaElement(this.tag); 10345 this.tag.player = null; 10346 this.tag = null; 10347 } 10348 10349 this.techName_ = techName; 10350 10351 // Turn off API access because we're loading a new tech that might load asynchronously 10352 this.isReady_ = false; 10353 10354 // Grab tech-specific options from player options and add source and parent element to use. 10355 var techOptions = _objectAssign2['default']({ 10356 'nativeControlsForTouch': this.options_.nativeControlsForTouch, 10357 'source': source, 10358 'playerId': this.id(), 10359 'techId': this.id() + '_' + techName + '_api', 10360 'textTracks': this.textTracks_, 10361 'autoplay': this.options_.autoplay, 10362 'preload': this.options_.preload, 10363 'loop': this.options_.loop, 10364 'muted': this.options_.muted, 10365 'poster': this.poster(), 10366 'language': this.language(), 10367 'vtt.js': this.options_['vtt.js'] 10368 }, this.options_[techName.toLowerCase()]); 10369 10370 if (this.tag) { 10371 techOptions.tag = this.tag; 10372 } 10373 10374 if (source) { 10375 this.currentType_ = source.type; 10376 if (source.src === this.cache_.src && this.cache_.currentTime > 0) { 10377 techOptions.startTime = this.cache_.currentTime; 10378 } 10379 10380 this.cache_.src = source.src; 10381 } 10382 10383 // Initialize tech instance 10384 var techComponent = _techTechJs2['default'].getTech(techName); 10385 // Support old behavior of techs being registered as components. 10386 // Remove once that deprecated behavior is removed. 10387 if (!techComponent) { 10388 techComponent = _componentJs2['default'].getComponent(techName); 10389 } 10390 this.tech_ = new techComponent(techOptions); 10391 10392 // player.triggerReady is always async, so don't need this to be async 10393 this.tech_.ready(Fn.bind(this, this.handleTechReady_), true); 10394 10395 _tracksTextTrackListConverterJs2['default'].jsonToTextTracks(this.textTracksJson_ || [], this.tech_); 10396 10397 // Listen to all HTML5-defined events and trigger them on the player 10398 this.on(this.tech_, 'loadstart', this.handleTechLoadStart_); 10399 this.on(this.tech_, 'waiting', this.handleTechWaiting_); 10400 this.on(this.tech_, 'canplay', this.handleTechCanPlay_); 10401 this.on(this.tech_, 'canplaythrough', this.handleTechCanPlayThrough_); 10402 this.on(this.tech_, 'playing', this.handleTechPlaying_); 10403 this.on(this.tech_, 'ended', this.handleTechEnded_); 10404 this.on(this.tech_, 'seeking', this.handleTechSeeking_); 10405 this.on(this.tech_, 'seeked', this.handleTechSeeked_); 10406 this.on(this.tech_, 'play', this.handleTechPlay_); 10407 this.on(this.tech_, 'firstplay', this.handleTechFirstPlay_); 10408 this.on(this.tech_, 'pause', this.handleTechPause_); 10409 this.on(this.tech_, 'progress', this.handleTechProgress_); 10410 this.on(this.tech_, 'durationchange', this.handleTechDurationChange_); 10411 this.on(this.tech_, 'fullscreenchange', this.handleTechFullscreenChange_); 10412 this.on(this.tech_, 'error', this.handleTechError_); 10413 this.on(this.tech_, 'suspend', this.handleTechSuspend_); 10414 this.on(this.tech_, 'abort', this.handleTechAbort_); 10415 this.on(this.tech_, 'emptied', this.handleTechEmptied_); 10416 this.on(this.tech_, 'stalled', this.handleTechStalled_); 10417 this.on(this.tech_, 'loadedmetadata', this.handleTechLoadedMetaData_); 10418 this.on(this.tech_, 'loadeddata', this.handleTechLoadedData_); 10419 this.on(this.tech_, 'timeupdate', this.handleTechTimeUpdate_); 10420 this.on(this.tech_, 'ratechange', this.handleTechRateChange_); 10421 this.on(this.tech_, 'volumechange', this.handleTechVolumeChange_); 10422 this.on(this.tech_, 'texttrackchange', this.handleTechTextTrackChange_); 10423 this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_); 10424 this.on(this.tech_, 'posterchange', this.handleTechPosterChange_); 10425 10426 this.usingNativeControls(this.techGet_('controls')); 10427 10428 if (this.controls() && !this.usingNativeControls()) { 10429 this.addTechControlsListeners_(); 10430 } 10431 10432 // Add the tech element in the DOM if it was not already there 10433 // Make sure to not insert the original video element if using Html5 10434 if (this.tech_.el().parentNode !== this.el() && (techName !== 'Html5' || !this.tag)) { 10435 Dom.insertElFirst(this.tech_.el(), this.el()); 10436 } 10437 10438 // Get rid of the original video tag reference after the first tech is loaded 10439 if (this.tag) { 10440 this.tag.player = null; 10441 this.tag = null; 10442 } 10443 }; 10444 10445 /** 10446 * Unload playback technology 10447 * 10448 * @method unloadTech_ 10449 * @private 10450 */ 10451 10452 Player.prototype.unloadTech_ = function unloadTech_() { 10453 // Save the current text tracks so that we can reuse the same text tracks with the next tech 10454 this.textTracks_ = this.textTracks(); 10455 this.textTracksJson_ = _tracksTextTrackListConverterJs2['default'].textTracksToJson(this.tech_); 10456 10457 this.isReady_ = false; 10458 10459 this.tech_.dispose(); 10460 10461 this.tech_ = false; 10462 }; 10463 10464 /** 10465 * Return a reference to the current tech. 10466 * It will only return a reference to the tech if given an object with the 10467 * `IWillNotUseThisInPlugins` property on it. This is try and prevent misuse 10468 * of techs by plugins. 10469 * 10470 * @param {Object} 10471 * @return {Object} The Tech 10472 * @method tech 10473 */ 10474 10475 Player.prototype.tech = function tech(safety) { 10476 if (safety && safety.IWillNotUseThisInPlugins) { 10477 return this.tech_; 10478 } 10479 var errorText = '\n Please make sure that you are not using this inside of a plugin.\n To disable this alert and error, please pass in an object with\n `IWillNotUseThisInPlugins` to the `tech` method. See\n https://github.com/videojs/video.js/issues/2617 for more info.\n '; 10480 _globalWindow2['default'].alert(errorText); 10481 throw new Error(errorText); 10482 }; 10483 10484 /** 10485 * Set up click and touch listeners for the playback element 10486 * 10487 * On desktops, a click on the video itself will toggle playback, 10488 * on a mobile device a click on the video toggles controls. 10489 * (toggling controls is done by toggling the user state between active and 10490 * inactive) 10491 * A tap can signal that a user has become active, or has become inactive 10492 * e.g. a quick tap on an iPhone movie should reveal the controls. Another 10493 * quick tap should hide them again (signaling the user is in an inactive 10494 * viewing state) 10495 * In addition to this, we still want the user to be considered inactive after 10496 * a few seconds of inactivity. 10497 * Note: the only part of iOS interaction we can't mimic with this setup 10498 * is a touch and hold on the video element counting as activity in order to 10499 * keep the controls showing, but that shouldn't be an issue. A touch and hold 10500 * on any controls will still keep the user active 10501 * 10502 * @private 10503 * @method addTechControlsListeners_ 10504 */ 10505 10506 Player.prototype.addTechControlsListeners_ = function addTechControlsListeners_() { 10507 // Make sure to remove all the previous listeners in case we are called multiple times. 10508 this.removeTechControlsListeners_(); 10509 10510 // Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do 10511 // trigger mousedown/up. 10512 // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object 10513 // Any touch events are set to block the mousedown event from happening 10514 this.on(this.tech_, 'mousedown', this.handleTechClick_); 10515 10516 // If the controls were hidden we don't want that to change without a tap event 10517 // so we'll check if the controls were already showing before reporting user 10518 // activity 10519 this.on(this.tech_, 'touchstart', this.handleTechTouchStart_); 10520 this.on(this.tech_, 'touchmove', this.handleTechTouchMove_); 10521 this.on(this.tech_, 'touchend', this.handleTechTouchEnd_); 10522 10523 // The tap listener needs to come after the touchend listener because the tap 10524 // listener cancels out any reportedUserActivity when setting userActive(false) 10525 this.on(this.tech_, 'tap', this.handleTechTap_); 10526 }; 10527 10528 /** 10529 * Remove the listeners used for click and tap controls. This is needed for 10530 * toggling to controls disabled, where a tap/touch should do nothing. 10531 * 10532 * @method removeTechControlsListeners_ 10533 * @private 10534 */ 10535 10536 Player.prototype.removeTechControlsListeners_ = function removeTechControlsListeners_() { 10537 // We don't want to just use `this.off()` because there might be other needed 10538 // listeners added by techs that extend this. 10539 this.off(this.tech_, 'tap', this.handleTechTap_); 10540 this.off(this.tech_, 'touchstart', this.handleTechTouchStart_); 10541 this.off(this.tech_, 'touchmove', this.handleTechTouchMove_); 10542 this.off(this.tech_, 'touchend', this.handleTechTouchEnd_); 10543 this.off(this.tech_, 'mousedown', this.handleTechClick_); 10544 }; 10545 10546 /** 10547 * Player waits for the tech to be ready 10548 * 10549 * @method handleTechReady_ 10550 * @private 10551 */ 10552 10553 Player.prototype.handleTechReady_ = function handleTechReady_() { 10554 this.triggerReady(); 10555 10556 // Keep the same volume as before 10557 if (this.cache_.volume) { 10558 this.techCall_('setVolume', this.cache_.volume); 10559 } 10560 10561 // Look if the tech found a higher resolution poster while loading 10562 this.handleTechPosterChange_(); 10563 10564 // Update the duration if available 10565 this.handleTechDurationChange_(); 10566 10567 // Chrome and Safari both have issues with autoplay. 10568 // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. 10569 // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) 10570 // This fixes both issues. Need to wait for API, so it updates displays correctly 10571 if (this.src() && this.tag && this.options_.autoplay && this.paused()) { 10572 delete this.tag.poster; // Chrome Fix. Fixed in Chrome v16. 10573 this.play(); 10574 } 10575 }; 10576 10577 /** 10578 * Fired when the user agent begins looking for media data 10579 * 10580 * @private 10581 * @method handleTechLoadStart_ 10582 */ 10583 10584 Player.prototype.handleTechLoadStart_ = function handleTechLoadStart_() { 10585 // TODO: Update to use `emptied` event instead. See #1277. 10586 10587 this.removeClass('vjs-ended'); 10588 10589 // reset the error state 10590 this.error(null); 10591 10592 // If it's already playing we want to trigger a firstplay event now. 10593 // The firstplay event relies on both the play and loadstart events 10594 // which can happen in any order for a new source 10595 if (!this.paused()) { 10596 this.trigger('loadstart'); 10597 this.trigger('firstplay'); 10598 } else { 10599 // reset the hasStarted state 10600 this.hasStarted(false); 10601 this.trigger('loadstart'); 10602 } 10603 }; 10604 10605 /** 10606 * Add/remove the vjs-has-started class 10607 * 10608 * @param {Boolean} hasStarted The value of true adds the class the value of false remove the class 10609 * @return {Boolean} Boolean value if has started 10610 * @private 10611 * @method hasStarted 10612 */ 10613 10614 Player.prototype.hasStarted = function hasStarted(_hasStarted) { 10615 if (_hasStarted !== undefined) { 10616 // only update if this is a new value 10617 if (this.hasStarted_ !== _hasStarted) { 10618 this.hasStarted_ = _hasStarted; 10619 if (_hasStarted) { 10620 this.addClass('vjs-has-started'); 10621 // trigger the firstplay event if this newly has played 10622 this.trigger('firstplay'); 10623 } else { 10624 this.removeClass('vjs-has-started'); 10625 } 10626 } 10627 return this; 10628 } 10629 return !!this.hasStarted_; 10630 }; 10631 10632 /** 10633 * Fired whenever the media begins or resumes playback 10634 * 10635 * @private 10636 * @method handleTechPlay_ 10637 */ 10638 10639 Player.prototype.handleTechPlay_ = function handleTechPlay_() { 10640 this.removeClass('vjs-ended'); 10641 this.removeClass('vjs-paused'); 10642 this.addClass('vjs-playing'); 10643 10644 // hide the poster when the user hits play 10645 // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play 10646 this.hasStarted(true); 10647 10648 this.trigger('play'); 10649 }; 10650 10651 /** 10652 * Fired whenever the media begins waiting 10653 * 10654 * @private 10655 * @method handleTechWaiting_ 10656 */ 10657 10658 Player.prototype.handleTechWaiting_ = function handleTechWaiting_() { 10659 var _this2 = this; 10660 10661 this.addClass('vjs-waiting'); 10662 this.trigger('waiting'); 10663 this.one('timeupdate', function () { 10664 return _this2.removeClass('vjs-waiting'); 10665 }); 10666 }; 10667 10668 /** 10669 * A handler for events that signal that waiting has ended 10670 * which is not consistent between browsers. See #1351 10671 * 10672 * @private 10673 * @method handleTechCanPlay_ 10674 */ 10675 10676 Player.prototype.handleTechCanPlay_ = function handleTechCanPlay_() { 10677 this.removeClass('vjs-waiting'); 10678 this.trigger('canplay'); 10679 }; 10680 10681 /** 10682 * A handler for events that signal that waiting has ended 10683 * which is not consistent between browsers. See #1351 10684 * 10685 * @private 10686 * @method handleTechCanPlayThrough_ 10687 */ 10688 10689 Player.prototype.handleTechCanPlayThrough_ = function handleTechCanPlayThrough_() { 10690 this.removeClass('vjs-waiting'); 10691 this.trigger('canplaythrough'); 10692 }; 10693 10694 /** 10695 * A handler for events that signal that waiting has ended 10696 * which is not consistent between browsers. See #1351 10697 * 10698 * @private 10699 * @method handleTechPlaying_ 10700 */ 10701 10702 Player.prototype.handleTechPlaying_ = function handleTechPlaying_() { 10703 this.removeClass('vjs-waiting'); 10704 this.trigger('playing'); 10705 }; 10706 10707 /** 10708 * Fired whenever the player is jumping to a new time 10709 * 10710 * @private 10711 * @method handleTechSeeking_ 10712 */ 10713 10714 Player.prototype.handleTechSeeking_ = function handleTechSeeking_() { 10715 this.addClass('vjs-seeking'); 10716 this.trigger('seeking'); 10717 }; 10718 10719 /** 10720 * Fired when the player has finished jumping to a new time 10721 * 10722 * @private 10723 * @method handleTechSeeked_ 10724 */ 10725 10726 Player.prototype.handleTechSeeked_ = function handleTechSeeked_() { 10727 this.removeClass('vjs-seeking'); 10728 this.trigger('seeked'); 10729 }; 10730 10731 /** 10732 * Fired the first time a video is played 10733 * Not part of the HLS spec, and we're not sure if this is the best 10734 * implementation yet, so use sparingly. If you don't have a reason to 10735 * prevent playback, use `myPlayer.one('play');` instead. 10736 * 10737 * @private 10738 * @method handleTechFirstPlay_ 10739 */ 10740 10741 Player.prototype.handleTechFirstPlay_ = function handleTechFirstPlay_() { 10742 //If the first starttime attribute is specified 10743 //then we will start at the given offset in seconds 10744 if (this.options_.starttime) { 10745 this.currentTime(this.options_.starttime); 10746 } 10747 10748 this.addClass('vjs-has-started'); 10749 this.trigger('firstplay'); 10750 }; 10751 10752 /** 10753 * Fired whenever the media has been paused 10754 * 10755 * @private 10756 * @method handleTechPause_ 10757 */ 10758 10759 Player.prototype.handleTechPause_ = function handleTechPause_() { 10760 this.removeClass('vjs-playing'); 10761 this.addClass('vjs-paused'); 10762 this.trigger('pause'); 10763 }; 10764 10765 /** 10766 * Fired while the user agent is downloading media data 10767 * 10768 * @private 10769 * @method handleTechProgress_ 10770 */ 10771 10772 Player.prototype.handleTechProgress_ = function handleTechProgress_() { 10773 this.trigger('progress'); 10774 }; 10775 10776 /** 10777 * Fired when the end of the media resource is reached (currentTime == duration) 10778 * 10779 * @private 10780 * @method handleTechEnded_ 10781 */ 10782 10783 Player.prototype.handleTechEnded_ = function handleTechEnded_() { 10784 this.addClass('vjs-ended'); 10785 if (this.options_.loop) { 10786 this.currentTime(0); 10787 this.play(); 10788 } else if (!this.paused()) { 10789 this.pause(); 10790 } 10791 10792 this.trigger('ended'); 10793 }; 10794 10795 /** 10796 * Fired when the duration of the media resource is first known or changed 10797 * 10798 * @private 10799 * @method handleTechDurationChange_ 10800 */ 10801 10802 Player.prototype.handleTechDurationChange_ = function handleTechDurationChange_() { 10803 this.duration(this.techGet_('duration')); 10804 }; 10805 10806 /** 10807 * Handle a click on the media element to play/pause 10808 * 10809 * @param {Object=} event Event object 10810 * @private 10811 * @method handleTechClick_ 10812 */ 10813 10814 Player.prototype.handleTechClick_ = function handleTechClick_(event) { 10815 // We're using mousedown to detect clicks thanks to Flash, but mousedown 10816 // will also be triggered with right-clicks, so we need to prevent that 10817 if (event.button !== 0) return; 10818 10819 // When controls are disabled a click should not toggle playback because 10820 // the click is considered a control 10821 if (this.controls()) { 10822 if (this.paused()) { 10823 this.play(); 10824 } else { 10825 this.pause(); 10826 } 10827 } 10828 }; 10829 10830 /** 10831 * Handle a tap on the media element. It will toggle the user 10832 * activity state, which hides and shows the controls. 10833 * 10834 * @private 10835 * @method handleTechTap_ 10836 */ 10837 10838 Player.prototype.handleTechTap_ = function handleTechTap_() { 10839 this.userActive(!this.userActive()); 10840 }; 10841 10842 /** 10843 * Handle touch to start 10844 * 10845 * @private 10846 * @method handleTechTouchStart_ 10847 */ 10848 10849 Player.prototype.handleTechTouchStart_ = function handleTechTouchStart_() { 10850 this.userWasActive = this.userActive(); 10851 }; 10852 10853 /** 10854 * Handle touch to move 10855 * 10856 * @private 10857 * @method handleTechTouchMove_ 10858 */ 10859 10860 Player.prototype.handleTechTouchMove_ = function handleTechTouchMove_() { 10861 if (this.userWasActive) { 10862 this.reportUserActivity(); 10863 } 10864 }; 10865 10866 /** 10867 * Handle touch to end 10868 * 10869 * @private 10870 * @method handleTechTouchEnd_ 10871 */ 10872 10873 Player.prototype.handleTechTouchEnd_ = function handleTechTouchEnd_(event) { 10874 // Stop the mouse events from also happening 10875 event.preventDefault(); 10876 }; 10877 10878 /** 10879 * Fired when the player switches in or out of fullscreen mode 10880 * 10881 * @private 10882 * @method handleFullscreenChange_ 10883 */ 10884 10885 Player.prototype.handleFullscreenChange_ = function handleFullscreenChange_() { 10886 if (this.isFullscreen()) { 10887 this.addClass('vjs-fullscreen'); 10888 } else { 10889 this.removeClass('vjs-fullscreen'); 10890 } 10891 }; 10892 10893 /** 10894 * native click events on the SWF aren't triggered on IE11, Win8.1RT 10895 * use stageclick events triggered from inside the SWF instead 10896 * 10897 * @private 10898 * @method handleStageClick_ 10899 */ 10900 10901 Player.prototype.handleStageClick_ = function handleStageClick_() { 10902 this.reportUserActivity(); 10903 }; 10904 10905 /** 10906 * Handle Tech Fullscreen Change 10907 * 10908 * @private 10909 * @method handleTechFullscreenChange_ 10910 */ 10911 10912 Player.prototype.handleTechFullscreenChange_ = function handleTechFullscreenChange_(event, data) { 10913 if (data) { 10914 this.isFullscreen(data.isFullscreen); 10915 } 10916 this.trigger('fullscreenchange'); 10917 }; 10918 10919 /** 10920 * Fires when an error occurred during the loading of an audio/video 10921 * 10922 * @private 10923 * @method handleTechError_ 10924 */ 10925 10926 Player.prototype.handleTechError_ = function handleTechError_() { 10927 var error = this.tech_.error(); 10928 this.error(error && error.code); 10929 }; 10930 10931 /** 10932 * Fires when the browser is intentionally not getting media data 10933 * 10934 * @private 10935 * @method handleTechSuspend_ 10936 */ 10937 10938 Player.prototype.handleTechSuspend_ = function handleTechSuspend_() { 10939 this.trigger('suspend'); 10940 }; 10941 10942 /** 10943 * Fires when the loading of an audio/video is aborted 10944 * 10945 * @private 10946 * @method handleTechAbort_ 10947 */ 10948 10949 Player.prototype.handleTechAbort_ = function handleTechAbort_() { 10950 this.trigger('abort'); 10951 }; 10952 10953 /** 10954 * Fires when the current playlist is empty 10955 * 10956 * @private 10957 * @method handleTechEmptied_ 10958 */ 10959 10960 Player.prototype.handleTechEmptied_ = function handleTechEmptied_() { 10961 this.trigger('emptied'); 10962 }; 10963 10964 /** 10965 * Fires when the browser is trying to get media data, but data is not available 10966 * 10967 * @private 10968 * @method handleTechStalled_ 10969 */ 10970 10971 Player.prototype.handleTechStalled_ = function handleTechStalled_() { 10972 this.trigger('stalled'); 10973 }; 10974 10975 /** 10976 * Fires when the browser has loaded meta data for the audio/video 10977 * 10978 * @private 10979 * @method handleTechLoadedMetaData_ 10980 */ 10981 10982 Player.prototype.handleTechLoadedMetaData_ = function handleTechLoadedMetaData_() { 10983 this.trigger('loadedmetadata'); 10984 }; 10985 10986 /** 10987 * Fires when the browser has loaded the current frame of the audio/video 10988 * 10989 * @private 10990 * @method handleTechLoadedData_ 10991 */ 10992 10993 Player.prototype.handleTechLoadedData_ = function handleTechLoadedData_() { 10994 this.trigger('loadeddata'); 10995 }; 10996 10997 /** 10998 * Fires when the current playback position has changed 10999 * 11000 * @private 11001 * @method handleTechTimeUpdate_ 11002 */ 11003 11004 Player.prototype.handleTechTimeUpdate_ = function handleTechTimeUpdate_() { 11005 this.trigger('timeupdate'); 11006 }; 11007 11008 /** 11009 * Fires when the playing speed of the audio/video is changed 11010 * 11011 * @private 11012 * @method handleTechRateChange_ 11013 */ 11014 11015 Player.prototype.handleTechRateChange_ = function handleTechRateChange_() { 11016 this.trigger('ratechange'); 11017 }; 11018 11019 /** 11020 * Fires when the volume has been changed 11021 * 11022 * @private 11023 * @method handleTechVolumeChange_ 11024 */ 11025 11026 Player.prototype.handleTechVolumeChange_ = function handleTechVolumeChange_() { 11027 this.trigger('volumechange'); 11028 }; 11029 11030 /** 11031 * Fires when the text track has been changed 11032 * 11033 * @private 11034 * @method handleTechTextTrackChange_ 11035 */ 11036 11037 Player.prototype.handleTechTextTrackChange_ = function handleTechTextTrackChange_() { 11038 this.trigger('texttrackchange'); 11039 }; 11040 11041 /** 11042 * Get object for cached values. 11043 * 11044 * @return {Object} 11045 * @method getCache 11046 */ 11047 11048 Player.prototype.getCache = function getCache() { 11049 return this.cache_; 11050 }; 11051 11052 /** 11053 * Pass values to the playback tech 11054 * 11055 * @param {String=} method Method 11056 * @param {Object=} arg Argument 11057 * @private 11058 * @method techCall_ 11059 */ 11060 11061 Player.prototype.techCall_ = function techCall_(method, arg) { 11062 // If it's not ready yet, call method when it is 11063 if (this.tech_ && !this.tech_.isReady_) { 11064 this.tech_.ready(function () { 11065 this[method](arg); 11066 }, true); 11067 11068 // Otherwise call method now 11069 } else { 11070 try { 11071 this.tech_[method](arg); 11072 } catch (e) { 11073 _utilsLogJs2['default'](e); 11074 throw e; 11075 } 11076 } 11077 }; 11078 11079 /** 11080 * Get calls can't wait for the tech, and sometimes don't need to. 11081 * 11082 * @param {String} method Tech method 11083 * @return {Method} 11084 * @private 11085 * @method techGet_ 11086 */ 11087 11088 Player.prototype.techGet_ = function techGet_(method) { 11089 if (this.tech_ && this.tech_.isReady_) { 11090 11091 // Flash likes to die and reload when you hide or reposition it. 11092 // In these cases the object methods go away and we get errors. 11093 // When that happens we'll catch the errors and inform tech that it's not ready any more. 11094 try { 11095 return this.tech_[method](); 11096 } catch (e) { 11097 // When building additional tech libs, an expected method may not be defined yet 11098 if (this.tech_[method] === undefined) { 11099 _utilsLogJs2['default']('Video.js: ' + method + ' method not defined for ' + this.techName_ + ' playback technology.', e); 11100 } else { 11101 // When a method isn't available on the object it throws a TypeError 11102 if (e.name === 'TypeError') { 11103 _utilsLogJs2['default']('Video.js: ' + method + ' unavailable on ' + this.techName_ + ' playback technology element.', e); 11104 this.tech_.isReady_ = false; 11105 } else { 11106 _utilsLogJs2['default'](e); 11107 } 11108 } 11109 throw e; 11110 } 11111 } 11112 11113 return; 11114 }; 11115 11116 /** 11117 * start media playback 11118 * ```js 11119 * myPlayer.play(); 11120 * ``` 11121 * 11122 * @return {Player} self 11123 * @method play 11124 */ 11125 11126 Player.prototype.play = function play() { 11127 this.techCall_('play'); 11128 return this; 11129 }; 11130 11131 /** 11132 * Pause the video playback 11133 * ```js 11134 * myPlayer.pause(); 11135 * ``` 11136 * 11137 * @return {Player} self 11138 * @method pause 11139 */ 11140 11141 Player.prototype.pause = function pause() { 11142 this.techCall_('pause'); 11143 return this; 11144 }; 11145 11146 /** 11147 * Check if the player is paused 11148 * ```js 11149 * var isPaused = myPlayer.paused(); 11150 * var isPlaying = !myPlayer.paused(); 11151 * ``` 11152 * 11153 * @return {Boolean} false if the media is currently playing, or true otherwise 11154 * @method paused 11155 */ 11156 11157 Player.prototype.paused = function paused() { 11158 // The initial state of paused should be true (in Safari it's actually false) 11159 return this.techGet_('paused') === false ? false : true; 11160 }; 11161 11162 /** 11163 * Returns whether or not the user is "scrubbing". Scrubbing is when the user 11164 * has clicked the progress bar handle and is dragging it along the progress bar. 11165 * 11166 * @param {Boolean} isScrubbing True/false the user is scrubbing 11167 * @return {Boolean} The scrubbing status when getting 11168 * @return {Object} The player when setting 11169 * @method scrubbing 11170 */ 11171 11172 Player.prototype.scrubbing = function scrubbing(isScrubbing) { 11173 if (isScrubbing !== undefined) { 11174 this.scrubbing_ = !!isScrubbing; 11175 11176 if (isScrubbing) { 11177 this.addClass('vjs-scrubbing'); 11178 } else { 11179 this.removeClass('vjs-scrubbing'); 11180 } 11181 11182 return this; 11183 } 11184 11185 return this.scrubbing_; 11186 }; 11187 11188 /** 11189 * Get or set the current time (in seconds) 11190 * ```js 11191 * // get 11192 * var whereYouAt = myPlayer.currentTime(); 11193 * // set 11194 * myPlayer.currentTime(120); // 2 minutes into the video 11195 * ``` 11196 * 11197 * @param {Number|String=} seconds The time to seek to 11198 * @return {Number} The time in seconds, when not setting 11199 * @return {Player} self, when the current time is set 11200 * @method currentTime 11201 */ 11202 11203 Player.prototype.currentTime = function currentTime(seconds) { 11204 if (seconds !== undefined) { 11205 11206 this.techCall_('setCurrentTime', seconds); 11207 11208 return this; 11209 } 11210 11211 // cache last currentTime and return. default to 0 seconds 11212 // 11213 // Caching the currentTime is meant to prevent a massive amount of reads on the tech's 11214 // currentTime when scrubbing, but may not provide much performance benefit afterall. 11215 // Should be tested. Also something has to read the actual current time or the cache will 11216 // never get updated. 11217 return this.cache_.currentTime = this.techGet_('currentTime') || 0; 11218 }; 11219 11220 /** 11221 * Get the length in time of the video in seconds 11222 * ```js 11223 * var lengthOfVideo = myPlayer.duration(); 11224 * ``` 11225 * **NOTE**: The video must have started loading before the duration can be 11226 * known, and in the case of Flash, may not be known until the video starts 11227 * playing. 11228 * 11229 * @param {Number} seconds Duration when setting 11230 * @return {Number} The duration of the video in seconds when getting 11231 * @method duration 11232 */ 11233 11234 Player.prototype.duration = function duration(seconds) { 11235 if (seconds === undefined) { 11236 return this.cache_.duration || 0; 11237 } 11238 11239 seconds = parseFloat(seconds) || 0; 11240 11241 // Standardize on Inifity for signaling video is live 11242 if (seconds < 0) { 11243 seconds = Infinity; 11244 } 11245 11246 if (seconds !== this.cache_.duration) { 11247 // Cache the last set value for optimized scrubbing (esp. Flash) 11248 this.cache_.duration = seconds; 11249 11250 if (seconds === Infinity) { 11251 this.addClass('vjs-live'); 11252 } else { 11253 this.removeClass('vjs-live'); 11254 } 11255 11256 this.trigger('durationchange'); 11257 } 11258 11259 return this; 11260 }; 11261 11262 /** 11263 * Calculates how much time is left. 11264 * ```js 11265 * var timeLeft = myPlayer.remainingTime(); 11266 * ``` 11267 * Not a native video element function, but useful 11268 * 11269 * @return {Number} The time remaining in seconds 11270 * @method remainingTime 11271 */ 11272 11273 Player.prototype.remainingTime = function remainingTime() { 11274 return this.duration() - this.currentTime(); 11275 }; 11276 11277 // http://dev.w3.org/html5/spec/video.html#dom-media-buffered 11278 // Buffered returns a timerange object. 11279 // Kind of like an array of portions of the video that have been downloaded. 11280 11281 /** 11282 * Get a TimeRange object with the times of the video that have been downloaded 11283 * If you just want the percent of the video that's been downloaded, 11284 * use bufferedPercent. 11285 * ```js 11286 * // Number of different ranges of time have been buffered. Usually 1. 11287 * numberOfRanges = bufferedTimeRange.length, 11288 * // Time in seconds when the first range starts. Usually 0. 11289 * firstRangeStart = bufferedTimeRange.start(0), 11290 * // Time in seconds when the first range ends 11291 * firstRangeEnd = bufferedTimeRange.end(0), 11292 * // Length in seconds of the first time range 11293 * firstRangeLength = firstRangeEnd - firstRangeStart; 11294 * ``` 11295 * 11296 * @return {Object} A mock TimeRange object (following HTML spec) 11297 * @method buffered 11298 */ 11299 11300 Player.prototype.buffered = function buffered() { 11301 var buffered = this.techGet_('buffered'); 11302 11303 if (!buffered || !buffered.length) { 11304 buffered = _utilsTimeRangesJs.createTimeRange(0, 0); 11305 } 11306 11307 return buffered; 11308 }; 11309 11310 /** 11311 * Get the percent (as a decimal) of the video that's been downloaded 11312 * ```js 11313 * var howMuchIsDownloaded = myPlayer.bufferedPercent(); 11314 * ``` 11315 * 0 means none, 1 means all. 11316 * (This method isn't in the HTML5 spec, but it's very convenient) 11317 * 11318 * @return {Number} A decimal between 0 and 1 representing the percent 11319 * @method bufferedPercent 11320 */ 11321 11322 Player.prototype.bufferedPercent = function bufferedPercent() { 11323 return _utilsBufferJs.bufferedPercent(this.buffered(), this.duration()); 11324 }; 11325 11326 /** 11327 * Get the ending time of the last buffered time range 11328 * This is used in the progress bar to encapsulate all time ranges. 11329 * 11330 * @return {Number} The end of the last buffered time range 11331 * @method bufferedEnd 11332 */ 11333 11334 Player.prototype.bufferedEnd = function bufferedEnd() { 11335 var buffered = this.buffered(), 11336 duration = this.duration(), 11337 end = buffered.end(buffered.length - 1); 11338 11339 if (end > duration) { 11340 end = duration; 11341 } 11342 11343 return end; 11344 }; 11345 11346 /** 11347 * Get or set the current volume of the media 11348 * ```js 11349 * // get 11350 * var howLoudIsIt = myPlayer.volume(); 11351 * // set 11352 * myPlayer.volume(0.5); // Set volume to half 11353 * ``` 11354 * 0 is off (muted), 1.0 is all the way up, 0.5 is half way. 11355 * 11356 * @param {Number} percentAsDecimal The new volume as a decimal percent 11357 * @return {Number} The current volume when getting 11358 * @return {Player} self when setting 11359 * @method volume 11360 */ 11361 11362 Player.prototype.volume = function volume(percentAsDecimal) { 11363 var vol = undefined; 11364 11365 if (percentAsDecimal !== undefined) { 11366 vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1 11367 this.cache_.volume = vol; 11368 this.techCall_('setVolume', vol); 11369 11370 return this; 11371 } 11372 11373 // Default to 1 when returning current volume. 11374 vol = parseFloat(this.techGet_('volume')); 11375 return isNaN(vol) ? 1 : vol; 11376 }; 11377 11378 /** 11379 * Get the current muted state, or turn mute on or off 11380 * ```js 11381 * // get 11382 * var isVolumeMuted = myPlayer.muted(); 11383 * // set 11384 * myPlayer.muted(true); // mute the volume 11385 * ``` 11386 * 11387 * @param {Boolean=} muted True to mute, false to unmute 11388 * @return {Boolean} True if mute is on, false if not when getting 11389 * @return {Player} self when setting mute 11390 * @method muted 11391 */ 11392 11393 Player.prototype.muted = function muted(_muted) { 11394 if (_muted !== undefined) { 11395 this.techCall_('setMuted', _muted); 11396 return this; 11397 } 11398 return this.techGet_('muted') || false; // Default to false 11399 }; 11400 11401 // Check if current tech can support native fullscreen 11402 // (e.g. with built in controls like iOS, so not our flash swf) 11403 /** 11404 * Check to see if fullscreen is supported 11405 * 11406 * @return {Boolean} 11407 * @method supportsFullScreen 11408 */ 11409 11410 Player.prototype.supportsFullScreen = function supportsFullScreen() { 11411 return this.techGet_('supportsFullScreen') || false; 11412 }; 11413 11414 /** 11415 * Check if the player is in fullscreen mode 11416 * ```js 11417 * // get 11418 * var fullscreenOrNot = myPlayer.isFullscreen(); 11419 * // set 11420 * myPlayer.isFullscreen(true); // tell the player it's in fullscreen 11421 * ``` 11422 * NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official 11423 * property and instead document.fullscreenElement is used. But isFullscreen is 11424 * still a valuable property for internal player workings. 11425 * 11426 * @param {Boolean=} isFS Update the player's fullscreen state 11427 * @return {Boolean} true if fullscreen false if not when getting 11428 * @return {Player} self when setting 11429 * @method isFullscreen 11430 */ 11431 11432 Player.prototype.isFullscreen = function isFullscreen(isFS) { 11433 if (isFS !== undefined) { 11434 this.isFullscreen_ = !!isFS; 11435 return this; 11436 } 11437 return !!this.isFullscreen_; 11438 }; 11439 11440 /** 11441 * Increase the size of the video to full screen 11442 * ```js 11443 * myPlayer.requestFullscreen(); 11444 * ``` 11445 * In some browsers, full screen is not supported natively, so it enters 11446 * "full window mode", where the video fills the browser window. 11447 * In browsers and devices that support native full screen, sometimes the 11448 * browser's default controls will be shown, and not the Video.js custom skin. 11449 * This includes most mobile devices (iOS, Android) and older versions of 11450 * Safari. 11451 * 11452 * @return {Player} self 11453 * @method requestFullscreen 11454 */ 11455 11456 Player.prototype.requestFullscreen = function requestFullscreen() { 11457 var fsApi = _fullscreenApiJs2['default']; 11458 11459 this.isFullscreen(true); 11460 11461 if (fsApi.requestFullscreen) { 11462 // the browser supports going fullscreen at the element level so we can 11463 // take the controls fullscreen as well as the video 11464 11465 // Trigger fullscreenchange event after change 11466 // We have to specifically add this each time, and remove 11467 // when canceling fullscreen. Otherwise if there's multiple 11468 // players on a page, they would all be reacting to the same fullscreen 11469 // events 11470 Events.on(_globalDocument2['default'], fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) { 11471 this.isFullscreen(_globalDocument2['default'][fsApi.fullscreenElement]); 11472 11473 // If cancelling fullscreen, remove event listener. 11474 if (this.isFullscreen() === false) { 11475 Events.off(_globalDocument2['default'], fsApi.fullscreenchange, documentFullscreenChange); 11476 } 11477 11478 this.trigger('fullscreenchange'); 11479 })); 11480 11481 this.el_[fsApi.requestFullscreen](); 11482 } else if (this.tech_.supportsFullScreen()) { 11483 // we can't take the video.js controls fullscreen but we can go fullscreen 11484 // with native controls 11485 this.techCall_('enterFullScreen'); 11486 } else { 11487 // fullscreen isn't supported so we'll just stretch the video element to 11488 // fill the viewport 11489 this.enterFullWindow(); 11490 this.trigger('fullscreenchange'); 11491 } 11492 11493 return this; 11494 }; 11495 11496 /** 11497 * Return the video to its normal size after having been in full screen mode 11498 * ```js 11499 * myPlayer.exitFullscreen(); 11500 * ``` 11501 * 11502 * @return {Player} self 11503 * @method exitFullscreen 11504 */ 11505 11506 Player.prototype.exitFullscreen = function exitFullscreen() { 11507 var fsApi = _fullscreenApiJs2['default']; 11508 this.isFullscreen(false); 11509 11510 // Check for browser element fullscreen support 11511 if (fsApi.requestFullscreen) { 11512 _globalDocument2['default'][fsApi.exitFullscreen](); 11513 } else if (this.tech_.supportsFullScreen()) { 11514 this.techCall_('exitFullScreen'); 11515 } else { 11516 this.exitFullWindow(); 11517 this.trigger('fullscreenchange'); 11518 } 11519 11520 return this; 11521 }; 11522 11523 /** 11524 * When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us. 11525 * 11526 * @method enterFullWindow 11527 */ 11528 11529 Player.prototype.enterFullWindow = function enterFullWindow() { 11530 this.isFullWindow = true; 11531 11532 // Storing original doc overflow value to return to when fullscreen is off 11533 this.docOrigOverflow = _globalDocument2['default'].documentElement.style.overflow; 11534 11535 // Add listener for esc key to exit fullscreen 11536 Events.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.fullWindowOnEscKey)); 11537 11538 // Hide any scroll bars 11539 _globalDocument2['default'].documentElement.style.overflow = 'hidden'; 11540 11541 // Apply fullscreen styles 11542 Dom.addElClass(_globalDocument2['default'].body, 'vjs-full-window'); 11543 11544 this.trigger('enterFullWindow'); 11545 }; 11546 11547 /** 11548 * Check for call to either exit full window or full screen on ESC key 11549 * 11550 * @param {String} event Event to check for key press 11551 * @method fullWindowOnEscKey 11552 */ 11553 11554 Player.prototype.fullWindowOnEscKey = function fullWindowOnEscKey(event) { 11555 if (event.keyCode === 27) { 11556 if (this.isFullscreen() === true) { 11557 this.exitFullscreen(); 11558 } else { 11559 this.exitFullWindow(); 11560 } 11561 } 11562 }; 11563 11564 /** 11565 * Exit full window 11566 * 11567 * @method exitFullWindow 11568 */ 11569 11570 Player.prototype.exitFullWindow = function exitFullWindow() { 11571 this.isFullWindow = false; 11572 Events.off(_globalDocument2['default'], 'keydown', this.fullWindowOnEscKey); 11573 11574 // Unhide scroll bars. 11575 _globalDocument2['default'].documentElement.style.overflow = this.docOrigOverflow; 11576 11577 // Remove fullscreen styles 11578 Dom.removeElClass(_globalDocument2['default'].body, 'vjs-full-window'); 11579 11580 // Resize the box, controller, and poster to original sizes 11581 // this.positionAll(); 11582 this.trigger('exitFullWindow'); 11583 }; 11584 11585 /** 11586 * Check whether the player can play a given mimetype 11587 * 11588 * @param {String} type The mimetype to check 11589 * @return {String} 'probably', 'maybe', or '' (empty string) 11590 * @method canPlayType 11591 */ 11592 11593 Player.prototype.canPlayType = function canPlayType(type) { 11594 var can = undefined; 11595 11596 // Loop through each playback technology in the options order 11597 for (var i = 0, j = this.options_.techOrder; i < j.length; i++) { 11598 var techName = _utilsToTitleCaseJs2['default'](j[i]); 11599 var tech = _techTechJs2['default'].getTech(techName); 11600 11601 // Support old behavior of techs being registered as components. 11602 // Remove once that deprecated behavior is removed. 11603 if (!tech) { 11604 tech = _componentJs2['default'].getComponent(techName); 11605 } 11606 11607 // Check if the current tech is defined before continuing 11608 if (!tech) { 11609 _utilsLogJs2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); 11610 continue; 11611 } 11612 11613 // Check if the browser supports this technology 11614 if (tech.isSupported()) { 11615 can = tech.canPlayType(type); 11616 11617 if (can) { 11618 return can; 11619 } 11620 } 11621 } 11622 11623 return ''; 11624 }; 11625 11626 /** 11627 * Select source based on tech-order or source-order 11628 * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise, 11629 * defaults to tech-order selection 11630 * 11631 * @param {Array} sources The sources for a media asset 11632 * @return {Object|Boolean} Object of source and tech order, otherwise false 11633 * @method selectSource 11634 */ 11635 11636 Player.prototype.selectSource = function selectSource(sources) { 11637 // Get only the techs specified in `techOrder` that exist and are supported by the 11638 // current platform 11639 var techs = this.options_.techOrder.map(_utilsToTitleCaseJs2['default']).map(function (techName) { 11640 // `Component.getComponent(...)` is for support of old behavior of techs 11641 // being registered as components. 11642 // Remove once that deprecated behavior is removed. 11643 return [techName, _techTechJs2['default'].getTech(techName) || _componentJs2['default'].getComponent(techName)]; 11644 }).filter(function (_ref) { 11645 var techName = _ref[0]; 11646 var tech = _ref[1]; 11647 11648 // Check if the current tech is defined before continuing 11649 if (tech) { 11650 // Check if the browser supports this technology 11651 return tech.isSupported(); 11652 } 11653 11654 _utilsLogJs2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); 11655 return false; 11656 }); 11657 11658 // Iterate over each `innerArray` element once per `outerArray` element and execute 11659 // `tester` with both. If `tester` returns a non-falsy value, exit early and return 11660 // that value. 11661 var findFirstPassingTechSourcePair = function findFirstPassingTechSourcePair(outerArray, innerArray, tester) { 11662 var found = undefined; 11663 11664 outerArray.some(function (outerChoice) { 11665 return innerArray.some(function (innerChoice) { 11666 found = tester(outerChoice, innerChoice); 11667 11668 if (found) { 11669 return true; 11670 } 11671 }); 11672 }); 11673 11674 return found; 11675 }; 11676 11677 var foundSourceAndTech = undefined; 11678 var flip = function flip(fn) { 11679 return function (a, b) { 11680 return fn(b, a); 11681 }; 11682 }; 11683 var finder = function finder(_ref2, source) { 11684 var techName = _ref2[0]; 11685 var tech = _ref2[1]; 11686 11687 if (tech.canPlaySource(source)) { 11688 return { source: source, tech: techName }; 11689 } 11690 }; 11691 11692 // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources 11693 // to select from them based on their priority. 11694 if (this.options_.sourceOrder) { 11695 // Source-first ordering 11696 foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder)); 11697 } else { 11698 // Tech-first ordering 11699 foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder); 11700 } 11701 11702 return foundSourceAndTech || false; 11703 }; 11704 11705 /** 11706 * The source function updates the video source 11707 * There are three types of variables you can pass as the argument. 11708 * **URL String**: A URL to the the video file. Use this method if you are sure 11709 * the current playback technology (HTML5/Flash) can support the source you 11710 * provide. Currently only MP4 files can be used in both HTML5 and Flash. 11711 * ```js 11712 * myPlayer.src("http://www.example.com/path/to/video.mp4"); 11713 * ``` 11714 * **Source Object (or element):* * A javascript object containing information 11715 * about the source file. Use this method if you want the player to determine if 11716 * it can support the file using the type information. 11717 * ```js 11718 * myPlayer.src({ type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }); 11719 * ``` 11720 * **Array of Source Objects:* * To provide multiple versions of the source so 11721 * that it can be played using HTML5 across browsers you can use an array of 11722 * source objects. Video.js will detect which version is supported and load that 11723 * file. 11724 * ```js 11725 * myPlayer.src([ 11726 * { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }, 11727 * { type: "video/webm", src: "http://www.example.com/path/to/video.webm" }, 11728 * { type: "video/ogg", src: "http://www.example.com/path/to/video.ogv" } 11729 * ]); 11730 * ``` 11731 * 11732 * @param {String|Object|Array=} source The source URL, object, or array of sources 11733 * @return {String} The current video source when getting 11734 * @return {String} The player when setting 11735 * @method src 11736 */ 11737 11738 Player.prototype.src = function src(source) { 11739 if (source === undefined) { 11740 return this.techGet_('src'); 11741 } 11742 11743 var currentTech = _techTechJs2['default'].getTech(this.techName_); 11744 // Support old behavior of techs being registered as components. 11745 // Remove once that deprecated behavior is removed. 11746 if (!currentTech) { 11747 currentTech = _componentJs2['default'].getComponent(this.techName_); 11748 } 11749 11750 // case: Array of source objects to choose from and pick the best to play 11751 if (Array.isArray(source)) { 11752 this.sourceList_(source); 11753 11754 // case: URL String (http://myvideo...) 11755 } else if (typeof source === 'string') { 11756 // create a source object from the string 11757 this.src({ src: source }); 11758 11759 // case: Source object { src: '', type: '' ... } 11760 } else if (source instanceof Object) { 11761 // check if the source has a type and the loaded tech cannot play the source 11762 // if there's no type we'll just try the current tech 11763 if (source.type && !currentTech.canPlaySource(source)) { 11764 // create a source list with the current source and send through 11765 // the tech loop to check for a compatible technology 11766 this.sourceList_([source]); 11767 } else { 11768 this.cache_.src = source.src; 11769 this.currentType_ = source.type || ''; 11770 11771 // wait until the tech is ready to set the source 11772 this.ready(function () { 11773 11774 // The setSource tech method was added with source handlers 11775 // so older techs won't support it 11776 // We need to check the direct prototype for the case where subclasses 11777 // of the tech do not support source handlers 11778 if (currentTech.prototype.hasOwnProperty('setSource')) { 11779 this.techCall_('setSource', source); 11780 } else { 11781 this.techCall_('src', source.src); 11782 } 11783 11784 if (this.options_.preload === 'auto') { 11785 this.load(); 11786 } 11787 11788 if (this.options_.autoplay) { 11789 this.play(); 11790 } 11791 11792 // Set the source synchronously if possible (#2326) 11793 }, true); 11794 } 11795 } 11796 11797 return this; 11798 }; 11799 11800 /** 11801 * Handle an array of source objects 11802 * 11803 * @param {Array} sources Array of source objects 11804 * @private 11805 * @method sourceList_ 11806 */ 11807 11808 Player.prototype.sourceList_ = function sourceList_(sources) { 11809 var sourceTech = this.selectSource(sources); 11810 11811 if (sourceTech) { 11812 if (sourceTech.tech === this.techName_) { 11813 // if this technology is already loaded, set the source 11814 this.src(sourceTech.source); 11815 } else { 11816 // load this technology with the chosen source 11817 this.loadTech_(sourceTech.tech, sourceTech.source); 11818 } 11819 } else { 11820 // We need to wrap this in a timeout to give folks a chance to add error event handlers 11821 this.setTimeout(function () { 11822 this.error({ code: 4, message: this.localize(this.options_.notSupportedMessage) }); 11823 }, 0); 11824 11825 // we could not find an appropriate tech, but let's still notify the delegate that this is it 11826 // this needs a better comment about why this is needed 11827 this.triggerReady(); 11828 } 11829 }; 11830 11831 /** 11832 * Begin loading the src data. 11833 * 11834 * @return {Player} Returns the player 11835 * @method load 11836 */ 11837 11838 Player.prototype.load = function load() { 11839 this.techCall_('load'); 11840 return this; 11841 }; 11842 11843 /** 11844 * Reset the player. Loads the first tech in the techOrder, 11845 * and calls `reset` on the tech`. 11846 * 11847 * @return {Player} Returns the player 11848 * @method reset 11849 */ 11850 11851 Player.prototype.reset = function reset() { 11852 this.loadTech_(_utilsToTitleCaseJs2['default'](this.options_.techOrder[0]), null); 11853 this.techCall_('reset'); 11854 return this; 11855 }; 11856 11857 /** 11858 * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4 11859 * Can be used in conjuction with `currentType` to assist in rebuilding the current source object. 11860 * 11861 * @return {String} The current source 11862 * @method currentSrc 11863 */ 11864 11865 Player.prototype.currentSrc = function currentSrc() { 11866 return this.techGet_('currentSrc') || this.cache_.src || ''; 11867 }; 11868 11869 /** 11870 * Get the current source type e.g. video/mp4 11871 * This can allow you rebuild the current source object so that you could load the same 11872 * source and tech later 11873 * 11874 * @return {String} The source MIME type 11875 * @method currentType 11876 */ 11877 11878 Player.prototype.currentType = function currentType() { 11879 return this.currentType_ || ''; 11880 }; 11881 11882 /** 11883 * Get or set the preload attribute 11884 * 11885 * @param {Boolean} value Boolean to determine if preload should be used 11886 * @return {String} The preload attribute value when getting 11887 * @return {Player} Returns the player when setting 11888 * @method preload 11889 */ 11890 11891 Player.prototype.preload = function preload(value) { 11892 if (value !== undefined) { 11893 this.techCall_('setPreload', value); 11894 this.options_.preload = value; 11895 return this; 11896 } 11897 return this.techGet_('preload'); 11898 }; 11899 11900 /** 11901 * Get or set the autoplay attribute. 11902 * 11903 * @param {Boolean} value Boolean to determine if video should autoplay 11904 * @return {String} The autoplay attribute value when getting 11905 * @return {Player} Returns the player when setting 11906 * @method autoplay 11907 */ 11908 11909 Player.prototype.autoplay = function autoplay(value) { 11910 if (value !== undefined) { 11911 this.techCall_('setAutoplay', value); 11912 this.options_.autoplay = value; 11913 return this; 11914 } 11915 return this.techGet_('autoplay', value); 11916 }; 11917 11918 /** 11919 * Get or set the loop attribute on the video element. 11920 * 11921 * @param {Boolean} value Boolean to determine if video should loop 11922 * @return {String} The loop attribute value when getting 11923 * @return {Player} Returns the player when setting 11924 * @method loop 11925 */ 11926 11927 Player.prototype.loop = function loop(value) { 11928 if (value !== undefined) { 11929 this.techCall_('setLoop', value); 11930 this.options_['loop'] = value; 11931 return this; 11932 } 11933 return this.techGet_('loop'); 11934 }; 11935 11936 /** 11937 * Get or set the poster image source url 11938 * 11939 * ##### EXAMPLE: 11940 * ```js 11941 * // get 11942 * var currentPoster = myPlayer.poster(); 11943 * // set 11944 * myPlayer.poster('http://example.com/myImage.jpg'); 11945 * ``` 11946 * 11947 * @param {String=} src Poster image source URL 11948 * @return {String} poster URL when getting 11949 * @return {Player} self when setting 11950 * @method poster 11951 */ 11952 11953 Player.prototype.poster = function poster(src) { 11954 if (src === undefined) { 11955 return this.poster_; 11956 } 11957 11958 // The correct way to remove a poster is to set as an empty string 11959 // other falsey values will throw errors 11960 if (!src) { 11961 src = ''; 11962 } 11963 11964 // update the internal poster variable 11965 this.poster_ = src; 11966 11967 // update the tech's poster 11968 this.techCall_('setPoster', src); 11969 11970 // alert components that the poster has been set 11971 this.trigger('posterchange'); 11972 11973 return this; 11974 }; 11975 11976 /** 11977 * Some techs (e.g. YouTube) can provide a poster source in an 11978 * asynchronous way. We want the poster component to use this 11979 * poster source so that it covers up the tech's controls. 11980 * (YouTube's play button). However we only want to use this 11981 * soruce if the player user hasn't set a poster through 11982 * the normal APIs. 11983 * 11984 * @private 11985 * @method handleTechPosterChange_ 11986 */ 11987 11988 Player.prototype.handleTechPosterChange_ = function handleTechPosterChange_() { 11989 if (!this.poster_ && this.tech_ && this.tech_.poster) { 11990 this.poster_ = this.tech_.poster() || ''; 11991 11992 // Let components know the poster has changed 11993 this.trigger('posterchange'); 11994 } 11995 }; 11996 11997 /** 11998 * Get or set whether or not the controls are showing. 11999 * 12000 * @param {Boolean} bool Set controls to showing or not 12001 * @return {Boolean} Controls are showing 12002 * @method controls 12003 */ 12004 12005 Player.prototype.controls = function controls(bool) { 12006 if (bool !== undefined) { 12007 bool = !!bool; // force boolean 12008 // Don't trigger a change event unless it actually changed 12009 if (this.controls_ !== bool) { 12010 this.controls_ = bool; 12011 12012 if (this.usingNativeControls()) { 12013 this.techCall_('setControls', bool); 12014 } 12015 12016 if (bool) { 12017 this.removeClass('vjs-controls-disabled'); 12018 this.addClass('vjs-controls-enabled'); 12019 this.trigger('controlsenabled'); 12020 12021 if (!this.usingNativeControls()) { 12022 this.addTechControlsListeners_(); 12023 } 12024 } else { 12025 this.removeClass('vjs-controls-enabled'); 12026 this.addClass('vjs-controls-disabled'); 12027 this.trigger('controlsdisabled'); 12028 12029 if (!this.usingNativeControls()) { 12030 this.removeTechControlsListeners_(); 12031 } 12032 } 12033 } 12034 return this; 12035 } 12036 return !!this.controls_; 12037 }; 12038 12039 /** 12040 * Toggle native controls on/off. Native controls are the controls built into 12041 * devices (e.g. default iPhone controls), Flash, or other techs 12042 * (e.g. Vimeo Controls) 12043 * **This should only be set by the current tech, because only the tech knows 12044 * if it can support native controls** 12045 * 12046 * @param {Boolean} bool True signals that native controls are on 12047 * @return {Player} Returns the player 12048 * @private 12049 * @method usingNativeControls 12050 */ 12051 12052 Player.prototype.usingNativeControls = function usingNativeControls(bool) { 12053 if (bool !== undefined) { 12054 bool = !!bool; // force boolean 12055 // Don't trigger a change event unless it actually changed 12056 if (this.usingNativeControls_ !== bool) { 12057 this.usingNativeControls_ = bool; 12058 if (bool) { 12059 this.addClass('vjs-using-native-controls'); 12060 12061 /** 12062 * player is using the native device controls 12063 * 12064 * @event usingnativecontrols 12065 * @memberof Player 12066 * @instance 12067 * @private 12068 */ 12069 this.trigger('usingnativecontrols'); 12070 } else { 12071 this.removeClass('vjs-using-native-controls'); 12072 12073 /** 12074 * player is using the custom HTML controls 12075 * 12076 * @event usingcustomcontrols 12077 * @memberof Player 12078 * @instance 12079 * @private 12080 */ 12081 this.trigger('usingcustomcontrols'); 12082 } 12083 } 12084 return this; 12085 } 12086 return !!this.usingNativeControls_; 12087 }; 12088 12089 /** 12090 * Set or get the current MediaError 12091 * 12092 * @param {*} err A MediaError or a String/Number to be turned into a MediaError 12093 * @return {MediaError|null} when getting 12094 * @return {Player} when setting 12095 * @method error 12096 */ 12097 12098 Player.prototype.error = function error(err) { 12099 if (err === undefined) { 12100 return this.error_ || null; 12101 } 12102 12103 // restoring to default 12104 if (err === null) { 12105 this.error_ = err; 12106 this.removeClass('vjs-error'); 12107 this.errorDisplay.close(); 12108 return this; 12109 } 12110 12111 // error instance 12112 if (err instanceof _mediaErrorJs2['default']) { 12113 this.error_ = err; 12114 } else { 12115 this.error_ = new _mediaErrorJs2['default'](err); 12116 } 12117 12118 // add the vjs-error classname to the player 12119 this.addClass('vjs-error'); 12120 12121 // log the name of the error type and any message 12122 // ie8 just logs "[object object]" if you just log the error object 12123 _utilsLogJs2['default'].error('(CODE:' + this.error_.code + ' ' + _mediaErrorJs2['default'].errorTypes[this.error_.code] + ')', this.error_.message, this.error_); 12124 12125 // fire an error event on the player 12126 this.trigger('error'); 12127 12128 return this; 12129 }; 12130 12131 /** 12132 * Returns whether or not the player is in the "ended" state. 12133 * 12134 * @return {Boolean} True if the player is in the ended state, false if not. 12135 * @method ended 12136 */ 12137 12138 Player.prototype.ended = function ended() { 12139 return this.techGet_('ended'); 12140 }; 12141 12142 /** 12143 * Returns whether or not the player is in the "seeking" state. 12144 * 12145 * @return {Boolean} True if the player is in the seeking state, false if not. 12146 * @method seeking 12147 */ 12148 12149 Player.prototype.seeking = function seeking() { 12150 return this.techGet_('seeking'); 12151 }; 12152 12153 /** 12154 * Returns the TimeRanges of the media that are currently available 12155 * for seeking to. 12156 * 12157 * @return {TimeRanges} the seekable intervals of the media timeline 12158 * @method seekable 12159 */ 12160 12161 Player.prototype.seekable = function seekable() { 12162 return this.techGet_('seekable'); 12163 }; 12164 12165 /** 12166 * Report user activity 12167 * 12168 * @param {Object} event Event object 12169 * @method reportUserActivity 12170 */ 12171 12172 Player.prototype.reportUserActivity = function reportUserActivity(event) { 12173 this.userActivity_ = true; 12174 }; 12175 12176 /** 12177 * Get/set if user is active 12178 * 12179 * @param {Boolean} bool Value when setting 12180 * @return {Boolean} Value if user is active user when getting 12181 * @method userActive 12182 */ 12183 12184 Player.prototype.userActive = function userActive(bool) { 12185 if (bool !== undefined) { 12186 bool = !!bool; 12187 if (bool !== this.userActive_) { 12188 this.userActive_ = bool; 12189 if (bool) { 12190 // If the user was inactive and is now active we want to reset the 12191 // inactivity timer 12192 this.userActivity_ = true; 12193 this.removeClass('vjs-user-inactive'); 12194 this.addClass('vjs-user-active'); 12195 this.trigger('useractive'); 12196 } else { 12197 // We're switching the state to inactive manually, so erase any other 12198 // activity 12199 this.userActivity_ = false; 12200 12201 // Chrome/Safari/IE have bugs where when you change the cursor it can 12202 // trigger a mousemove event. This causes an issue when you're hiding 12203 // the cursor when the user is inactive, and a mousemove signals user 12204 // activity. Making it impossible to go into inactive mode. Specifically 12205 // this happens in fullscreen when we really need to hide the cursor. 12206 // 12207 // When this gets resolved in ALL browsers it can be removed 12208 // https://code.google.com/p/chromium/issues/detail?id=103041 12209 if (this.tech_) { 12210 this.tech_.one('mousemove', function (e) { 12211 e.stopPropagation(); 12212 e.preventDefault(); 12213 }); 12214 } 12215 12216 this.removeClass('vjs-user-active'); 12217 this.addClass('vjs-user-inactive'); 12218 this.trigger('userinactive'); 12219 } 12220 } 12221 return this; 12222 } 12223 return this.userActive_; 12224 }; 12225 12226 /** 12227 * Listen for user activity based on timeout value 12228 * 12229 * @private 12230 * @method listenForUserActivity_ 12231 */ 12232 12233 Player.prototype.listenForUserActivity_ = function listenForUserActivity_() { 12234 var mouseInProgress = undefined, 12235 lastMoveX = undefined, 12236 lastMoveY = undefined; 12237 12238 var handleActivity = Fn.bind(this, this.reportUserActivity); 12239 12240 var handleMouseMove = function handleMouseMove(e) { 12241 // #1068 - Prevent mousemove spamming 12242 // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970 12243 if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) { 12244 lastMoveX = e.screenX; 12245 lastMoveY = e.screenY; 12246 handleActivity(); 12247 } 12248 }; 12249 12250 var handleMouseDown = function handleMouseDown() { 12251 handleActivity(); 12252 // For as long as the they are touching the device or have their mouse down, 12253 // we consider them active even if they're not moving their finger or mouse. 12254 // So we want to continue to update that they are active 12255 this.clearInterval(mouseInProgress); 12256 // Setting userActivity=true now and setting the interval to the same time 12257 // as the activityCheck interval (250) should ensure we never miss the 12258 // next activityCheck 12259 mouseInProgress = this.setInterval(handleActivity, 250); 12260 }; 12261 12262 var handleMouseUp = function handleMouseUp(event) { 12263 handleActivity(); 12264 // Stop the interval that maintains activity if the mouse/touch is down 12265 this.clearInterval(mouseInProgress); 12266 }; 12267 12268 // Any mouse movement will be considered user activity 12269 this.on('mousedown', handleMouseDown); 12270 this.on('mousemove', handleMouseMove); 12271 this.on('mouseup', handleMouseUp); 12272 12273 // Listen for keyboard navigation 12274 // Shouldn't need to use inProgress interval because of key repeat 12275 this.on('keydown', handleActivity); 12276 this.on('keyup', handleActivity); 12277 12278 // Run an interval every 250 milliseconds instead of stuffing everything into 12279 // the mousemove/touchmove function itself, to prevent performance degradation. 12280 // `this.reportUserActivity` simply sets this.userActivity_ to true, which 12281 // then gets picked up by this loop 12282 // http://ejohn.org/blog/learning-from-twitter/ 12283 var inactivityTimeout = undefined; 12284 var activityCheck = this.setInterval(function () { 12285 // Check to see if mouse/touch activity has happened 12286 if (this.userActivity_) { 12287 // Reset the activity tracker 12288 this.userActivity_ = false; 12289 12290 // If the user state was inactive, set the state to active 12291 this.userActive(true); 12292 12293 // Clear any existing inactivity timeout to start the timer over 12294 this.clearTimeout(inactivityTimeout); 12295 12296 var timeout = this.options_['inactivityTimeout']; 12297 if (timeout > 0) { 12298 // In <timeout> milliseconds, if no more activity has occurred the 12299 // user will be considered inactive 12300 inactivityTimeout = this.setTimeout(function () { 12301 // Protect against the case where the inactivityTimeout can trigger just 12302 // before the next user activity is picked up by the activityCheck loop 12303 // causing a flicker 12304 if (!this.userActivity_) { 12305 this.userActive(false); 12306 } 12307 }, timeout); 12308 } 12309 } 12310 }, 250); 12311 }; 12312 12313 /** 12314 * Gets or sets the current playback rate. A playback rate of 12315 * 1.0 represents normal speed and 0.5 would indicate half-speed 12316 * playback, for instance. 12317 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate 12318 * 12319 * @param {Number} rate New playback rate to set. 12320 * @return {Number} Returns the new playback rate when setting 12321 * @return {Number} Returns the current playback rate when getting 12322 * @method playbackRate 12323 */ 12324 12325 Player.prototype.playbackRate = function playbackRate(rate) { 12326 if (rate !== undefined) { 12327 this.techCall_('setPlaybackRate', rate); 12328 return this; 12329 } 12330 12331 if (this.tech_ && this.tech_['featuresPlaybackRate']) { 12332 return this.techGet_('playbackRate'); 12333 } else { 12334 return 1.0; 12335 } 12336 }; 12337 12338 /** 12339 * Gets or sets the audio flag 12340 * 12341 * @param {Boolean} bool True signals that this is an audio player. 12342 * @return {Boolean} Returns true if player is audio, false if not when getting 12343 * @return {Player} Returns the player if setting 12344 * @private 12345 * @method isAudio 12346 */ 12347 12348 Player.prototype.isAudio = function isAudio(bool) { 12349 if (bool !== undefined) { 12350 this.isAudio_ = !!bool; 12351 return this; 12352 } 12353 12354 return !!this.isAudio_; 12355 }; 12356 12357 /** 12358 * Returns the current state of network activity for the element, from 12359 * the codes in the list below. 12360 * - NETWORK_EMPTY (numeric value 0) 12361 * The element has not yet been initialised. All attributes are in 12362 * their initial states. 12363 * - NETWORK_IDLE (numeric value 1) 12364 * The element's resource selection algorithm is active and has 12365 * selected a resource, but it is not actually using the network at 12366 * this time. 12367 * - NETWORK_LOADING (numeric value 2) 12368 * The user agent is actively trying to download data. 12369 * - NETWORK_NO_SOURCE (numeric value 3) 12370 * The element's resource selection algorithm is active, but it has 12371 * not yet found a resource to use. 12372 * 12373 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states 12374 * @return {Number} the current network activity state 12375 * @method networkState 12376 */ 12377 12378 Player.prototype.networkState = function networkState() { 12379 return this.techGet_('networkState'); 12380 }; 12381 12382 /** 12383 * Returns a value that expresses the current state of the element 12384 * with respect to rendering the current playback position, from the 12385 * codes in the list below. 12386 * - HAVE_NOTHING (numeric value 0) 12387 * No information regarding the media resource is available. 12388 * - HAVE_METADATA (numeric value 1) 12389 * Enough of the resource has been obtained that the duration of the 12390 * resource is available. 12391 * - HAVE_CURRENT_DATA (numeric value 2) 12392 * Data for the immediate current playback position is available. 12393 * - HAVE_FUTURE_DATA (numeric value 3) 12394 * Data for the immediate current playback position is available, as 12395 * well as enough data for the user agent to advance the current 12396 * playback position in the direction of playback. 12397 * - HAVE_ENOUGH_DATA (numeric value 4) 12398 * The user agent estimates that enough data is available for 12399 * playback to proceed uninterrupted. 12400 * 12401 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate 12402 * @return {Number} the current playback rendering state 12403 * @method readyState 12404 */ 12405 12406 Player.prototype.readyState = function readyState() { 12407 return this.techGet_('readyState'); 12408 }; 12409 12410 /** 12411 * Text tracks are tracks of timed text events. 12412 * Captions - text displayed over the video for the hearing impaired 12413 * Subtitles - text displayed over the video for those who don't understand language in the video 12414 * Chapters - text displayed in a menu allowing the user to jump to particular points (chapters) in the video 12415 * Descriptions - audio descriptions that are read back to the user by a screen reading device 12416 */ 12417 12418 /** 12419 * Get an array of associated text tracks. captions, subtitles, chapters, descriptions 12420 * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks 12421 * 12422 * @return {Array} Array of track objects 12423 * @method textTracks 12424 */ 12425 12426 Player.prototype.textTracks = function textTracks() { 12427 // cannot use techGet_ directly because it checks to see whether the tech is ready. 12428 // Flash is unlikely to be ready in time but textTracks should still work. 12429 return this.tech_ && this.tech_['textTracks'](); 12430 }; 12431 12432 /** 12433 * Get an array of remote text tracks 12434 * 12435 * @return {Array} 12436 * @method remoteTextTracks 12437 */ 12438 12439 Player.prototype.remoteTextTracks = function remoteTextTracks() { 12440 return this.tech_ && this.tech_['remoteTextTracks'](); 12441 }; 12442 12443 /** 12444 * Get an array of remote html track elements 12445 * 12446 * @return {HTMLTrackElement[]} 12447 * @method remoteTextTrackEls 12448 */ 12449 12450 Player.prototype.remoteTextTrackEls = function remoteTextTrackEls() { 12451 return this.tech_ && this.tech_['remoteTextTrackEls'](); 12452 }; 12453 12454 /** 12455 * Add a text track 12456 * In addition to the W3C settings we allow adding additional info through options. 12457 * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack 12458 * 12459 * @param {String} kind Captions, subtitles, chapters, descriptions, or metadata 12460 * @param {String=} label Optional label 12461 * @param {String=} language Optional language 12462 * @method addTextTrack 12463 */ 12464 12465 Player.prototype.addTextTrack = function addTextTrack(kind, label, language) { 12466 return this.tech_ && this.tech_['addTextTrack'](kind, label, language); 12467 }; 12468 12469 /** 12470 * Add a remote text track 12471 * 12472 * @param {Object} options Options for remote text track 12473 * @method addRemoteTextTrack 12474 */ 12475 12476 Player.prototype.addRemoteTextTrack = function addRemoteTextTrack(options) { 12477 return this.tech_ && this.tech_['addRemoteTextTrack'](options); 12478 }; 12479 12480 /** 12481 * Remove a remote text track 12482 * 12483 * @param {Object} track Remote text track to remove 12484 * @method removeRemoteTextTrack 12485 */ 12486 12487 Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { 12488 this.tech_ && this.tech_['removeRemoteTextTrack'](track); 12489 }; 12490 12491 /** 12492 * Get video width 12493 * 12494 * @return {Number} Video width 12495 * @method videoWidth 12496 */ 12497 12498 Player.prototype.videoWidth = function videoWidth() { 12499 return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0; 12500 }; 12501 12502 /** 12503 * Get video height 12504 * 12505 * @return {Number} Video height 12506 * @method videoHeight 12507 */ 12508 12509 Player.prototype.videoHeight = function videoHeight() { 12510 return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0; 12511 }; 12512 12513 // Methods to add support for 12514 // initialTime: function(){ return this.techCall_('initialTime'); }, 12515 // startOffsetTime: function(){ return this.techCall_('startOffsetTime'); }, 12516 // played: function(){ return this.techCall_('played'); }, 12517 // videoTracks: function(){ return this.techCall_('videoTracks'); }, 12518 // audioTracks: function(){ return this.techCall_('audioTracks'); }, 12519 // defaultPlaybackRate: function(){ return this.techCall_('defaultPlaybackRate'); }, 12520 // defaultMuted: function(){ return this.techCall_('defaultMuted'); } 12521 12522 /** 12523 * The player's language code 12524 * NOTE: The language should be set in the player options if you want the 12525 * the controls to be built with a specific language. Changing the lanugage 12526 * later will not update controls text. 12527 * 12528 * @param {String} code The locale string 12529 * @return {String} The locale string when getting 12530 * @return {Player} self when setting 12531 * @method language 12532 */ 12533 12534 Player.prototype.language = function language(code) { 12535 if (code === undefined) { 12536 return this.language_; 12537 } 12538 12539 this.language_ = ('' + code).toLowerCase(); 12540 return this; 12541 }; 12542 12543 /** 12544 * Get the player's language dictionary 12545 * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time 12546 * Languages specified directly in the player options have precedence 12547 * 12548 * @return {Array} Array of languages 12549 * @method languages 12550 */ 12551 12552 Player.prototype.languages = function languages() { 12553 return _utilsMergeOptionsJs2['default'](Player.prototype.options_.languages, this.languages_); 12554 }; 12555 12556 /** 12557 * Converts track info to JSON 12558 * 12559 * @return {Object} JSON object of options 12560 * @method toJSON 12561 */ 12562 12563 Player.prototype.toJSON = function toJSON() { 12564 var options = _utilsMergeOptionsJs2['default'](this.options_); 12565 var tracks = options.tracks; 12566 12567 options.tracks = []; 12568 12569 for (var i = 0; i < tracks.length; i++) { 12570 var track = tracks[i]; 12571 12572 // deep merge tracks and null out player so no circular references 12573 track = _utilsMergeOptionsJs2['default'](track); 12574 track.player = undefined; 12575 options.tracks[i] = track; 12576 } 12577 12578 return options; 12579 }; 12580 12581 /** 12582 * Creates a simple modal dialog (an instance of the `ModalDialog` 12583 * component) that immediately overlays the player with arbitrary 12584 * content and removes itself when closed. 12585 * 12586 * @param {String|Function|Element|Array|Null} content 12587 * Same as `ModalDialog#content`'s param of the same name. 12588 * 12589 * The most straight-forward usage is to provide a string or DOM 12590 * element. 12591 * 12592 * @param {Object} [options] 12593 * Extra options which will be passed on to the `ModalDialog`. 12594 * 12595 * @return {ModalDialog} 12596 */ 12597 12598 Player.prototype.createModal = function createModal(content, options) { 12599 var player = this; 12600 12601 options = options || {}; 12602 options.content = content || ''; 12603 12604 var modal = new _modalDialog2['default'](player, options); 12605 12606 player.addChild(modal); 12607 modal.on('dispose', function () { 12608 player.removeChild(modal); 12609 }); 12610 12611 return modal.open(); 12612 }; 12613 12614 /** 12615 * Gets tag settings 12616 * 12617 * @param {Element} tag The player tag 12618 * @return {Array} An array of sources and track objects 12619 * @static 12620 * @method getTagSettings 12621 */ 12622 12623 Player.getTagSettings = function getTagSettings(tag) { 12624 var baseOptions = { 12625 'sources': [], 12626 'tracks': [] 12627 }; 12628 12629 var tagOptions = Dom.getElAttributes(tag); 12630 var dataSetup = tagOptions['data-setup']; 12631 12632 // Check if data-setup attr exists. 12633 if (dataSetup !== null) { 12634 // Parse options JSON 12635 12636 var _safeParseTuple = _safeJsonParseTuple2['default'](dataSetup || '{}'); 12637 12638 var err = _safeParseTuple[0]; 12639 var data = _safeParseTuple[1]; 12640 12641 if (err) { 12642 _utilsLogJs2['default'].error(err); 12643 } 12644 _objectAssign2['default'](tagOptions, data); 12645 } 12646 12647 _objectAssign2['default'](baseOptions, tagOptions); 12648 12649 // Get tag children settings 12650 if (tag.hasChildNodes()) { 12651 var children = tag.childNodes; 12652 12653 for (var i = 0, j = children.length; i < j; i++) { 12654 var child = children[i]; 12655 // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ 12656 var childName = child.nodeName.toLowerCase(); 12657 if (childName === 'source') { 12658 baseOptions.sources.push(Dom.getElAttributes(child)); 12659 } else if (childName === 'track') { 12660 baseOptions.tracks.push(Dom.getElAttributes(child)); 12661 } 12662 } 12663 } 12664 12665 return baseOptions; 12666 }; 12667 12668 return Player; 12669 })(_componentJs2['default']); 12670 12671 Player.players = {}; 12672 12673 var navigator = _globalWindow2['default'].navigator; 12674 /* 12675 * Player instance options, surfaced using options 12676 * options = Player.prototype.options_ 12677 * Make changes in options, not here. 12678 * 12679 * @type {Object} 12680 * @private 12681 */ 12682 Player.prototype.options_ = { 12683 // Default order of fallback technology 12684 techOrder: ['html5', 'flash'], 12685 // techOrder: ['flash','html5'], 12686 12687 html5: {}, 12688 flash: {}, 12689 12690 // defaultVolume: 0.85, 12691 defaultVolume: 0.00, // The freakin seaguls are driving me crazy! 12692 12693 // default inactivity timeout 12694 inactivityTimeout: 2000, 12695 12696 // default playback rates 12697 playbackRates: [], 12698 // Add playback rate selection by adding rates 12699 // 'playbackRates': [0.5, 1, 1.5, 2], 12700 12701 // Included control sets 12702 children: ['mediaLoader', 'posterImage', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'controlBar', 'errorDisplay', 'textTrackSettings'], 12703 12704 language: _globalDocument2['default'].getElementsByTagName('html')[0].getAttribute('lang') || navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language || 'en', 12705 12706 // locales and their language translations 12707 languages: {}, 12708 12709 // Default message to show when a video cannot be played. 12710 notSupportedMessage: 'No compatible source was found for this media.' 12711 }; 12712 12713 /** 12714 * Fired when the player has initial duration and dimension information 12715 * 12716 * @event loadedmetadata 12717 */ 12718 Player.prototype.handleLoadedMetaData_; 12719 12720 /** 12721 * Fired when the player has downloaded data at the current playback position 12722 * 12723 * @event loadeddata 12724 */ 12725 Player.prototype.handleLoadedData_; 12726 12727 /** 12728 * Fired when the user is active, e.g. moves the mouse over the player 12729 * 12730 * @event useractive 12731 */ 12732 Player.prototype.handleUserActive_; 12733 12734 /** 12735 * Fired when the user is inactive, e.g. a short delay after the last mouse move or control interaction 12736 * 12737 * @event userinactive 12738 */ 12739 Player.prototype.handleUserInactive_; 12740 12741 /** 12742 * Fired when the current playback position has changed * 12743 * During playback this is fired every 15-250 milliseconds, depending on the 12744 * playback technology in use. 12745 * 12746 * @event timeupdate 12747 */ 12748 Player.prototype.handleTimeUpdate_; 12749 12750 /** 12751 * Fired when video playback ends 12752 * 12753 * @event ended 12754 */ 12755 Player.prototype.handleTechEnded_; 12756 12757 /** 12758 * Fired when the volume changes 12759 * 12760 * @event volumechange 12761 */ 12762 Player.prototype.handleVolumeChange_; 12763 12764 /** 12765 * Fired when an error occurs 12766 * 12767 * @event error 12768 */ 12769 Player.prototype.handleError_; 12770 12771 Player.prototype.flexNotSupported_ = function () { 12772 var elem = _globalDocument2['default'].createElement('i'); 12773 12774 // Note: We don't actually use flexBasis (or flexOrder), but it's one of the more 12775 // common flex features that we can rely on when checking for flex support. 12776 return !('flexBasis' in elem.style || 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style || 'msFlexOrder' in elem.style) /* IE10-specific (2012 flex spec) */; 12777 }; 12778 12779 _componentJs2['default'].registerComponent('Player', Player); 12780 exports['default'] = Player; 12781 module.exports = exports['default']; 12782 // If empty string, make it a parsable json object. 12783 12784 },{"./big-play-button.js":63,"./component.js":67,"./control-bar/control-bar.js":68,"./error-display.js":100,"./fullscreen-api.js":103,"./loading-spinner.js":104,"./media-error.js":105,"./modal-dialog":109,"./poster-image.js":114,"./tech/html5.js":119,"./tech/loader.js":120,"./tech/tech.js":121,"./tracks/text-track-display.js":125,"./tracks/text-track-list-converter.js":127,"./tracks/text-track-settings.js":129,"./utils/browser.js":131,"./utils/buffer.js":132,"./utils/dom.js":134,"./utils/events.js":135,"./utils/fn.js":136,"./utils/guid.js":138,"./utils/log.js":139,"./utils/merge-options.js":140,"./utils/stylesheet.js":141,"./utils/time-ranges.js":142,"./utils/to-title-case.js":143,"global/document":1,"global/window":2,"object.assign":45,"safe-json-parse/tuple":54}],111:[function(_dereq_,module,exports){ 12785 /** 12786 * @file plugins.js 12787 */ 12788 'use strict'; 12789 12790 exports.__esModule = true; 12791 12792 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12793 12794 var _playerJs = _dereq_('./player.js'); 12795 12796 var _playerJs2 = _interopRequireDefault(_playerJs); 12797 12798 /** 12799 * The method for registering a video.js plugin 12800 * 12801 * @param {String} name The name of the plugin 12802 * @param {Function} init The function that is run when the player inits 12803 * @method plugin 12804 */ 12805 var plugin = function plugin(name, init) { 12806 _playerJs2['default'].prototype[name] = init; 12807 }; 12808 12809 exports['default'] = plugin; 12810 module.exports = exports['default']; 12811 12812 },{"./player.js":110}],112:[function(_dereq_,module,exports){ 12813 /** 12814 * @file popup-button.js 12815 */ 12816 'use strict'; 12817 12818 exports.__esModule = true; 12819 12820 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 12821 12822 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12823 12824 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12825 12826 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 12827 12828 var _clickableComponentJs = _dereq_('../clickable-component.js'); 12829 12830 var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); 12831 12832 var _componentJs = _dereq_('../component.js'); 12833 12834 var _componentJs2 = _interopRequireDefault(_componentJs); 12835 12836 var _popupJs = _dereq_('./popup.js'); 12837 12838 var _popupJs2 = _interopRequireDefault(_popupJs); 12839 12840 var _utilsDomJs = _dereq_('../utils/dom.js'); 12841 12842 var Dom = _interopRequireWildcard(_utilsDomJs); 12843 12844 var _utilsFnJs = _dereq_('../utils/fn.js'); 12845 12846 var Fn = _interopRequireWildcard(_utilsFnJs); 12847 12848 var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); 12849 12850 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 12851 12852 /** 12853 * A button class with a popup control 12854 * 12855 * @param {Player|Object} player 12856 * @param {Object=} options 12857 * @extends ClickableComponent 12858 * @class PopupButton 12859 */ 12860 12861 var PopupButton = (function (_ClickableComponent) { 12862 _inherits(PopupButton, _ClickableComponent); 12863 12864 function PopupButton(player) { 12865 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 12866 12867 _classCallCheck(this, PopupButton); 12868 12869 _ClickableComponent.call(this, player, options); 12870 12871 this.update(); 12872 } 12873 12874 /** 12875 * Update popup 12876 * 12877 * @method update 12878 */ 12879 12880 PopupButton.prototype.update = function update() { 12881 var popup = this.createPopup(); 12882 12883 if (this.popup) { 12884 this.removeChild(this.popup); 12885 } 12886 12887 this.popup = popup; 12888 this.addChild(popup); 12889 12890 if (this.items && this.items.length === 0) { 12891 this.hide(); 12892 } else if (this.items && this.items.length > 1) { 12893 this.show(); 12894 } 12895 }; 12896 12897 /** 12898 * Create popup - Override with specific functionality for component 12899 * 12900 * @return {Popup} The constructed popup 12901 * @method createPopup 12902 */ 12903 12904 PopupButton.prototype.createPopup = function createPopup() {}; 12905 12906 /** 12907 * Create the component's DOM element 12908 * 12909 * @return {Element} 12910 * @method createEl 12911 */ 12912 12913 PopupButton.prototype.createEl = function createEl() { 12914 return _ClickableComponent.prototype.createEl.call(this, 'div', { 12915 className: this.buildCSSClass() 12916 }); 12917 }; 12918 12919 /** 12920 * Allow sub components to stack CSS class names 12921 * 12922 * @return {String} The constructed class name 12923 * @method buildCSSClass 12924 */ 12925 12926 PopupButton.prototype.buildCSSClass = function buildCSSClass() { 12927 var menuButtonClass = 'vjs-menu-button'; 12928 12929 // If the inline option is passed, we want to use different styles altogether. 12930 if (this.options_.inline === true) { 12931 menuButtonClass += '-inline'; 12932 } else { 12933 menuButtonClass += '-popup'; 12934 } 12935 12936 return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); 12937 }; 12938 12939 return PopupButton; 12940 })(_clickableComponentJs2['default']); 12941 12942 _componentJs2['default'].registerComponent('PopupButton', PopupButton); 12943 exports['default'] = PopupButton; 12944 module.exports = exports['default']; 12945 12946 },{"../clickable-component.js":65,"../component.js":67,"../utils/dom.js":134,"../utils/fn.js":136,"../utils/to-title-case.js":143,"./popup.js":113}],113:[function(_dereq_,module,exports){ 12947 /** 12948 * @file popup.js 12949 */ 12950 'use strict'; 12951 12952 exports.__esModule = true; 12953 12954 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 12955 12956 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 12957 12958 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 12959 12960 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 12961 12962 var _componentJs = _dereq_('../component.js'); 12963 12964 var _componentJs2 = _interopRequireDefault(_componentJs); 12965 12966 var _utilsDomJs = _dereq_('../utils/dom.js'); 12967 12968 var Dom = _interopRequireWildcard(_utilsDomJs); 12969 12970 var _utilsFnJs = _dereq_('../utils/fn.js'); 12971 12972 var Fn = _interopRequireWildcard(_utilsFnJs); 12973 12974 var _utilsEventsJs = _dereq_('../utils/events.js'); 12975 12976 var Events = _interopRequireWildcard(_utilsEventsJs); 12977 12978 /** 12979 * The Popup component is used to build pop up controls. 12980 * 12981 * @extends Component 12982 * @class Popup 12983 */ 12984 12985 var Popup = (function (_Component) { 12986 _inherits(Popup, _Component); 12987 12988 function Popup() { 12989 _classCallCheck(this, Popup); 12990 12991 _Component.apply(this, arguments); 12992 } 12993 12994 /** 12995 * Add a popup item to the popup 12996 * 12997 * @param {Object|String} component Component or component type to add 12998 * @method addItem 12999 */ 13000 13001 Popup.prototype.addItem = function addItem(component) { 13002 this.addChild(component); 13003 component.on('click', Fn.bind(this, function () { 13004 this.unlockShowing(); 13005 })); 13006 }; 13007 13008 /** 13009 * Create the component's DOM element 13010 * 13011 * @return {Element} 13012 * @method createEl 13013 */ 13014 13015 Popup.prototype.createEl = function createEl() { 13016 var contentElType = this.options_.contentElType || 'ul'; 13017 this.contentEl_ = Dom.createEl(contentElType, { 13018 className: 'vjs-menu-content' 13019 }); 13020 var el = _Component.prototype.createEl.call(this, 'div', { 13021 append: this.contentEl_, 13022 className: 'vjs-menu' 13023 }); 13024 el.appendChild(this.contentEl_); 13025 13026 // Prevent clicks from bubbling up. Needed for Popup Buttons, 13027 // where a click on the parent is significant 13028 Events.on(el, 'click', function (event) { 13029 event.preventDefault(); 13030 event.stopImmediatePropagation(); 13031 }); 13032 13033 return el; 13034 }; 13035 13036 return Popup; 13037 })(_componentJs2['default']); 13038 13039 _componentJs2['default'].registerComponent('Popup', Popup); 13040 exports['default'] = Popup; 13041 module.exports = exports['default']; 13042 13043 },{"../component.js":67,"../utils/dom.js":134,"../utils/events.js":135,"../utils/fn.js":136}],114:[function(_dereq_,module,exports){ 13044 /** 13045 * @file poster-image.js 13046 */ 13047 'use strict'; 13048 13049 exports.__esModule = true; 13050 13051 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 13052 13053 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 13054 13055 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 13056 13057 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 13058 13059 var _clickableComponentJs = _dereq_('./clickable-component.js'); 13060 13061 var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs); 13062 13063 var _componentJs = _dereq_('./component.js'); 13064 13065 var _componentJs2 = _interopRequireDefault(_componentJs); 13066 13067 var _utilsFnJs = _dereq_('./utils/fn.js'); 13068 13069 var Fn = _interopRequireWildcard(_utilsFnJs); 13070 13071 var _utilsDomJs = _dereq_('./utils/dom.js'); 13072 13073 var Dom = _interopRequireWildcard(_utilsDomJs); 13074 13075 var _utilsBrowserJs = _dereq_('./utils/browser.js'); 13076 13077 var browser = _interopRequireWildcard(_utilsBrowserJs); 13078 13079 /** 13080 * The component that handles showing the poster image. 13081 * 13082 * @param {Player|Object} player 13083 * @param {Object=} options 13084 * @extends Button 13085 * @class PosterImage 13086 */ 13087 13088 var PosterImage = (function (_ClickableComponent) { 13089 _inherits(PosterImage, _ClickableComponent); 13090 13091 function PosterImage(player, options) { 13092 _classCallCheck(this, PosterImage); 13093 13094 _ClickableComponent.call(this, player, options); 13095 13096 this.update(); 13097 player.on('posterchange', Fn.bind(this, this.update)); 13098 } 13099 13100 /** 13101 * Clean up the poster image 13102 * 13103 * @method dispose 13104 */ 13105 13106 PosterImage.prototype.dispose = function dispose() { 13107 this.player().off('posterchange', this.update); 13108 _ClickableComponent.prototype.dispose.call(this); 13109 }; 13110 13111 /** 13112 * Create the poster's image element 13113 * 13114 * @return {Element} 13115 * @method createEl 13116 */ 13117 13118 PosterImage.prototype.createEl = function createEl() { 13119 var el = Dom.createEl('div', { 13120 className: 'vjs-poster', 13121 13122 // Don't want poster to be tabbable. 13123 tabIndex: -1 13124 }); 13125 13126 // To ensure the poster image resizes while maintaining its original aspect 13127 // ratio, use a div with `background-size` when available. For browsers that 13128 // do not support `background-size` (e.g. IE8), fall back on using a regular 13129 // img element. 13130 if (!browser.BACKGROUND_SIZE_SUPPORTED) { 13131 this.fallbackImg_ = Dom.createEl('img'); 13132 el.appendChild(this.fallbackImg_); 13133 } 13134 13135 return el; 13136 }; 13137 13138 /** 13139 * Event handler for updates to the player's poster source 13140 * 13141 * @method update 13142 */ 13143 13144 PosterImage.prototype.update = function update() { 13145 var url = this.player().poster(); 13146 13147 this.setSrc(url); 13148 13149 // If there's no poster source we should display:none on this component 13150 // so it's not still clickable or right-clickable 13151 if (url) { 13152 this.show(); 13153 } else { 13154 this.hide(); 13155 } 13156 }; 13157 13158 /** 13159 * Set the poster source depending on the display method 13160 * 13161 * @param {String} url The URL to the poster source 13162 * @method setSrc 13163 */ 13164 13165 PosterImage.prototype.setSrc = function setSrc(url) { 13166 if (this.fallbackImg_) { 13167 this.fallbackImg_.src = url; 13168 } else { 13169 var backgroundImage = ''; 13170 // Any falsey values should stay as an empty string, otherwise 13171 // this will throw an extra error 13172 if (url) { 13173 backgroundImage = 'url("' + url + '")'; 13174 } 13175 13176 this.el_.style.backgroundImage = backgroundImage; 13177 } 13178 }; 13179 13180 /** 13181 * Event handler for clicks on the poster image 13182 * 13183 * @method handleClick 13184 */ 13185 13186 PosterImage.prototype.handleClick = function handleClick() { 13187 // We don't want a click to trigger playback when controls are disabled 13188 // but CSS should be hiding the poster to prevent that from happening 13189 if (this.player_.paused()) { 13190 this.player_.play(); 13191 } else { 13192 this.player_.pause(); 13193 } 13194 }; 13195 13196 return PosterImage; 13197 })(_clickableComponentJs2['default']); 13198 13199 _componentJs2['default'].registerComponent('PosterImage', PosterImage); 13200 exports['default'] = PosterImage; 13201 module.exports = exports['default']; 13202 13203 },{"./clickable-component.js":65,"./component.js":67,"./utils/browser.js":131,"./utils/dom.js":134,"./utils/fn.js":136}],115:[function(_dereq_,module,exports){ 13204 /** 13205 * @file setup.js 13206 * 13207 * Functions for automatically setting up a player 13208 * based on the data-setup attribute of the video tag 13209 */ 13210 'use strict'; 13211 13212 exports.__esModule = true; 13213 13214 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 13215 13216 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 13217 13218 var _utilsEventsJs = _dereq_('./utils/events.js'); 13219 13220 var Events = _interopRequireWildcard(_utilsEventsJs); 13221 13222 var _globalDocument = _dereq_('global/document'); 13223 13224 var _globalDocument2 = _interopRequireDefault(_globalDocument); 13225 13226 var _globalWindow = _dereq_('global/window'); 13227 13228 var _globalWindow2 = _interopRequireDefault(_globalWindow); 13229 13230 var _windowLoaded = false; 13231 var videojs = undefined; 13232 13233 // Automatically set up any tags that have a data-setup attribute 13234 var autoSetup = function autoSetup() { 13235 // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack* 13236 // var vids = Array.prototype.slice.call(document.getElementsByTagName('video')); 13237 // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); 13238 // var mediaEls = vids.concat(audios); 13239 13240 // Because IE8 doesn't support calling slice on a node list, we need to loop through each list of elements 13241 // to build up a new, combined list of elements. 13242 var vids = _globalDocument2['default'].getElementsByTagName('video'); 13243 var audios = _globalDocument2['default'].getElementsByTagName('audio'); 13244 var mediaEls = []; 13245 if (vids && vids.length > 0) { 13246 for (var i = 0, e = vids.length; i < e; i++) { 13247 mediaEls.push(vids[i]); 13248 } 13249 } 13250 if (audios && audios.length > 0) { 13251 for (var i = 0, e = audios.length; i < e; i++) { 13252 mediaEls.push(audios[i]); 13253 } 13254 } 13255 13256 // Check if any media elements exist 13257 if (mediaEls && mediaEls.length > 0) { 13258 13259 for (var i = 0, e = mediaEls.length; i < e; i++) { 13260 var mediaEl = mediaEls[i]; 13261 13262 // Check if element exists, has getAttribute func. 13263 // IE seems to consider typeof el.getAttribute == 'object' instead of 'function' like expected, at least when loading the player immediately. 13264 if (mediaEl && mediaEl.getAttribute) { 13265 13266 // Make sure this player hasn't already been set up. 13267 if (mediaEl['player'] === undefined) { 13268 var options = mediaEl.getAttribute('data-setup'); 13269 13270 // Check if data-setup attr exists. 13271 // We only auto-setup if they've added the data-setup attr. 13272 if (options !== null) { 13273 // Create new video.js instance. 13274 var player = videojs(mediaEl); 13275 } 13276 } 13277 13278 // If getAttribute isn't defined, we need to wait for the DOM. 13279 } else { 13280 autoSetupTimeout(1); 13281 break; 13282 } 13283 } 13284 13285 // No videos were found, so keep looping unless page is finished loading. 13286 } else if (!_windowLoaded) { 13287 autoSetupTimeout(1); 13288 } 13289 }; 13290 13291 // Pause to let the DOM keep processing 13292 var autoSetupTimeout = function autoSetupTimeout(wait, vjs) { 13293 if (vjs) { 13294 videojs = vjs; 13295 } 13296 13297 setTimeout(autoSetup, wait); 13298 }; 13299 13300 if (_globalDocument2['default'].readyState === 'complete') { 13301 _windowLoaded = true; 13302 } else { 13303 Events.one(_globalWindow2['default'], 'load', function () { 13304 _windowLoaded = true; 13305 }); 13306 } 13307 13308 var hasLoaded = function hasLoaded() { 13309 return _windowLoaded; 13310 }; 13311 13312 exports.autoSetup = autoSetup; 13313 exports.autoSetupTimeout = autoSetupTimeout; 13314 exports.hasLoaded = hasLoaded; 13315 13316 },{"./utils/events.js":135,"global/document":1,"global/window":2}],116:[function(_dereq_,module,exports){ 13317 /** 13318 * @file slider.js 13319 */ 13320 'use strict'; 13321 13322 exports.__esModule = true; 13323 13324 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 13325 13326 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 13327 13328 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 13329 13330 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 13331 13332 var _componentJs = _dereq_('../component.js'); 13333 13334 var _componentJs2 = _interopRequireDefault(_componentJs); 13335 13336 var _utilsDomJs = _dereq_('../utils/dom.js'); 13337 13338 var Dom = _interopRequireWildcard(_utilsDomJs); 13339 13340 var _objectAssign = _dereq_('object.assign'); 13341 13342 var _objectAssign2 = _interopRequireDefault(_objectAssign); 13343 13344 /** 13345 * The base functionality for sliders like the volume bar and seek bar 13346 * 13347 * @param {Player|Object} player 13348 * @param {Object=} options 13349 * @extends Component 13350 * @class Slider 13351 */ 13352 13353 var Slider = (function (_Component) { 13354 _inherits(Slider, _Component); 13355 13356 function Slider(player, options) { 13357 _classCallCheck(this, Slider); 13358 13359 _Component.call(this, player, options); 13360 13361 // Set property names to bar to match with the child Slider class is looking for 13362 this.bar = this.getChild(this.options_.barName); 13363 13364 // Set a horizontal or vertical class on the slider depending on the slider type 13365 this.vertical(!!this.options_.vertical); 13366 13367 this.on('mousedown', this.handleMouseDown); 13368 this.on('touchstart', this.handleMouseDown); 13369 this.on('focus', this.handleFocus); 13370 this.on('blur', this.handleBlur); 13371 this.on('click', this.handleClick); 13372 13373 this.on(player, 'controlsvisible', this.update); 13374 this.on(player, this.playerEvent, this.update); 13375 } 13376 13377 /** 13378 * Create the component's DOM element 13379 * 13380 * @param {String} type Type of element to create 13381 * @param {Object=} props List of properties in Object form 13382 * @return {Element} 13383 * @method createEl 13384 */ 13385 13386 Slider.prototype.createEl = function createEl(type) { 13387 var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 13388 var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 13389 13390 // Add the slider element class to all sub classes 13391 props.className = props.className + ' vjs-slider'; 13392 props = _objectAssign2['default']({ 13393 tabIndex: 0 13394 }, props); 13395 13396 attributes = _objectAssign2['default']({ 13397 'role': 'slider', 13398 'aria-valuenow': 0, 13399 'aria-valuemin': 0, 13400 'aria-valuemax': 100, 13401 tabIndex: 0 13402 }, attributes); 13403 13404 return _Component.prototype.createEl.call(this, type, props, attributes); 13405 }; 13406 13407 /** 13408 * Handle mouse down on slider 13409 * 13410 * @param {Object} event Mouse down event object 13411 * @method handleMouseDown 13412 */ 13413 13414 Slider.prototype.handleMouseDown = function handleMouseDown(event) { 13415 var doc = this.bar.el_.ownerDocument; 13416 13417 event.preventDefault(); 13418 Dom.blockTextSelection(); 13419 13420 this.addClass('vjs-sliding'); 13421 this.trigger('slideractive'); 13422 13423 this.on(doc, 'mousemove', this.handleMouseMove); 13424 this.on(doc, 'mouseup', this.handleMouseUp); 13425 this.on(doc, 'touchmove', this.handleMouseMove); 13426 this.on(doc, 'touchend', this.handleMouseUp); 13427 13428 this.handleMouseMove(event); 13429 }; 13430 13431 /** 13432 * To be overridden by a subclass 13433 * 13434 * @method handleMouseMove 13435 */ 13436 13437 Slider.prototype.handleMouseMove = function handleMouseMove() {}; 13438 13439 /** 13440 * Handle mouse up on Slider 13441 * 13442 * @method handleMouseUp 13443 */ 13444 13445 Slider.prototype.handleMouseUp = function handleMouseUp() { 13446 var doc = this.bar.el_.ownerDocument; 13447 13448 Dom.unblockTextSelection(); 13449 13450 this.removeClass('vjs-sliding'); 13451 this.trigger('sliderinactive'); 13452 13453 this.off(doc, 'mousemove', this.handleMouseMove); 13454 this.off(doc, 'mouseup', this.handleMouseUp); 13455 this.off(doc, 'touchmove', this.handleMouseMove); 13456 this.off(doc, 'touchend', this.handleMouseUp); 13457 13458 this.update(); 13459 }; 13460 13461 /** 13462 * Update slider 13463 * 13464 * @method update 13465 */ 13466 13467 Slider.prototype.update = function update() { 13468 // In VolumeBar init we have a setTimeout for update that pops and update to the end of the 13469 // execution stack. The player is destroyed before then update will cause an error 13470 if (!this.el_) return; 13471 13472 // If scrubbing, we could use a cached value to make the handle keep up with the user's mouse. 13473 // On HTML5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later. 13474 // var progress = (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration(); 13475 var progress = this.getPercent(); 13476 var bar = this.bar; 13477 13478 // If there's no bar... 13479 if (!bar) return; 13480 13481 // Protect against no duration and other division issues 13482 if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) { 13483 progress = 0; 13484 } 13485 13486 // Convert to a percentage for setting 13487 var percentage = (progress * 100).toFixed(2) + '%'; 13488 13489 // Set the new bar width or height 13490 if (this.vertical()) { 13491 bar.el().style.height = percentage; 13492 } else { 13493 bar.el().style.width = percentage; 13494 } 13495 }; 13496 13497 /** 13498 * Calculate distance for slider 13499 * 13500 * @param {Object} event Event object 13501 * @method calculateDistance 13502 */ 13503 13504 Slider.prototype.calculateDistance = function calculateDistance(event) { 13505 var position = Dom.getPointerPosition(this.el_, event); 13506 if (this.vertical()) { 13507 return position.y; 13508 } 13509 return position.x; 13510 }; 13511 13512 /** 13513 * Handle on focus for slider 13514 * 13515 * @method handleFocus 13516 */ 13517 13518 Slider.prototype.handleFocus = function handleFocus() { 13519 this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); 13520 }; 13521 13522 /** 13523 * Handle key press for slider 13524 * 13525 * @param {Object} event Event object 13526 * @method handleKeyPress 13527 */ 13528 13529 Slider.prototype.handleKeyPress = function handleKeyPress(event) { 13530 if (event.which === 37 || event.which === 40) { 13531 // Left and Down Arrows 13532 event.preventDefault(); 13533 this.stepBack(); 13534 } else if (event.which === 38 || event.which === 39) { 13535 // Up and Right Arrows 13536 event.preventDefault(); 13537 this.stepForward(); 13538 } 13539 }; 13540 13541 /** 13542 * Handle on blur for slider 13543 * 13544 * @method handleBlur 13545 */ 13546 13547 Slider.prototype.handleBlur = function handleBlur() { 13548 this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); 13549 }; 13550 13551 /** 13552 * Listener for click events on slider, used to prevent clicks 13553 * from bubbling up to parent elements like button menus. 13554 * 13555 * @param {Object} event Event object 13556 * @method handleClick 13557 */ 13558 13559 Slider.prototype.handleClick = function handleClick(event) { 13560 event.stopImmediatePropagation(); 13561 event.preventDefault(); 13562 }; 13563 13564 /** 13565 * Get/set if slider is horizontal for vertical 13566 * 13567 * @param {Boolean} bool True if slider is vertical, false is horizontal 13568 * @return {Boolean} True if slider is vertical, false is horizontal 13569 * @method vertical 13570 */ 13571 13572 Slider.prototype.vertical = function vertical(bool) { 13573 if (bool === undefined) { 13574 return this.vertical_ || false; 13575 } 13576 13577 this.vertical_ = !!bool; 13578 13579 if (this.vertical_) { 13580 this.addClass('vjs-slider-vertical'); 13581 } else { 13582 this.addClass('vjs-slider-horizontal'); 13583 } 13584 13585 return this; 13586 }; 13587 13588 return Slider; 13589 })(_componentJs2['default']); 13590 13591 _componentJs2['default'].registerComponent('Slider', Slider); 13592 exports['default'] = Slider; 13593 module.exports = exports['default']; 13594 13595 },{"../component.js":67,"../utils/dom.js":134,"object.assign":45}],117:[function(_dereq_,module,exports){ 13596 /** 13597 * @file flash-rtmp.js 13598 */ 13599 'use strict'; 13600 13601 exports.__esModule = true; 13602 function FlashRtmpDecorator(Flash) { 13603 Flash.streamingFormats = { 13604 'rtmp/mp4': 'MP4', 13605 'rtmp/flv': 'FLV' 13606 }; 13607 13608 Flash.streamFromParts = function (connection, stream) { 13609 return connection + '&' + stream; 13610 }; 13611 13612 Flash.streamToParts = function (src) { 13613 var parts = { 13614 connection: '', 13615 stream: '' 13616 }; 13617 13618 if (!src) return parts; 13619 13620 // Look for the normal URL separator we expect, '&'. 13621 // If found, we split the URL into two pieces around the 13622 // first '&'. 13623 var connEnd = src.search(/&(?!\w+=)/); 13624 var streamBegin = undefined; 13625 if (connEnd !== -1) { 13626 streamBegin = connEnd + 1; 13627 } else { 13628 // If there's not a '&', we use the last '/' as the delimiter. 13629 connEnd = streamBegin = src.lastIndexOf('/') + 1; 13630 if (connEnd === 0) { 13631 // really, there's not a '/'? 13632 connEnd = streamBegin = src.length; 13633 } 13634 } 13635 parts.connection = src.substring(0, connEnd); 13636 parts.stream = src.substring(streamBegin, src.length); 13637 13638 return parts; 13639 }; 13640 13641 Flash.isStreamingType = function (srcType) { 13642 return srcType in Flash.streamingFormats; 13643 }; 13644 13645 // RTMP has four variations, any string starting 13646 // with one of these protocols should be valid 13647 Flash.RTMP_RE = /^rtmp[set]?:\/\//i; 13648 13649 Flash.isStreamingSrc = function (src) { 13650 return Flash.RTMP_RE.test(src); 13651 }; 13652 13653 /** 13654 * A source handler for RTMP urls 13655 * @type {Object} 13656 */ 13657 Flash.rtmpSourceHandler = {}; 13658 13659 /** 13660 * Check if Flash can play the given videotype 13661 * @param {String} type The mimetype to check 13662 * @return {String} 'probably', 'maybe', or '' (empty string) 13663 */ 13664 Flash.rtmpSourceHandler.canPlayType = function (type) { 13665 if (Flash.isStreamingType(type)) { 13666 return 'maybe'; 13667 } 13668 13669 return ''; 13670 }; 13671 13672 /** 13673 * Check if Flash can handle the source natively 13674 * @param {Object} source The source object 13675 * @return {String} 'probably', 'maybe', or '' (empty string) 13676 */ 13677 Flash.rtmpSourceHandler.canHandleSource = function (source) { 13678 var can = Flash.rtmpSourceHandler.canPlayType(source.type); 13679 13680 if (can) { 13681 return can; 13682 } 13683 13684 if (Flash.isStreamingSrc(source.src)) { 13685 return 'maybe'; 13686 } 13687 13688 return ''; 13689 }; 13690 13691 /** 13692 * Pass the source to the flash object 13693 * Adaptive source handlers will have more complicated workflows before passing 13694 * video data to the video element 13695 * @param {Object} source The source object 13696 * @param {Flash} tech The instance of the Flash tech 13697 */ 13698 Flash.rtmpSourceHandler.handleSource = function (source, tech) { 13699 var srcParts = Flash.streamToParts(source.src); 13700 13701 tech['setRtmpConnection'](srcParts.connection); 13702 tech['setRtmpStream'](srcParts.stream); 13703 }; 13704 13705 // Register the native source handler 13706 Flash.registerSourceHandler(Flash.rtmpSourceHandler); 13707 13708 return Flash; 13709 } 13710 13711 exports['default'] = FlashRtmpDecorator; 13712 module.exports = exports['default']; 13713 13714 },{}],118:[function(_dereq_,module,exports){ 13715 /** 13716 * @file flash.js 13717 * VideoJS-SWF - Custom Flash Player with HTML5-ish API 13718 * https://github.com/zencoder/video-js-swf 13719 * Not using setupTriggers. Using global onEvent func to distribute events 13720 */ 13721 13722 'use strict'; 13723 13724 exports.__esModule = true; 13725 13726 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 13727 13728 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 13729 13730 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 13731 13732 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 13733 13734 var _tech = _dereq_('./tech'); 13735 13736 var _tech2 = _interopRequireDefault(_tech); 13737 13738 var _utilsDomJs = _dereq_('../utils/dom.js'); 13739 13740 var Dom = _interopRequireWildcard(_utilsDomJs); 13741 13742 var _utilsUrlJs = _dereq_('../utils/url.js'); 13743 13744 var Url = _interopRequireWildcard(_utilsUrlJs); 13745 13746 var _utilsTimeRangesJs = _dereq_('../utils/time-ranges.js'); 13747 13748 var _flashRtmp = _dereq_('./flash-rtmp'); 13749 13750 var _flashRtmp2 = _interopRequireDefault(_flashRtmp); 13751 13752 var _component = _dereq_('../component'); 13753 13754 var _component2 = _interopRequireDefault(_component); 13755 13756 var _globalWindow = _dereq_('global/window'); 13757 13758 var _globalWindow2 = _interopRequireDefault(_globalWindow); 13759 13760 var _objectAssign = _dereq_('object.assign'); 13761 13762 var _objectAssign2 = _interopRequireDefault(_objectAssign); 13763 13764 var navigator = _globalWindow2['default'].navigator; 13765 /** 13766 * Flash Media Controller - Wrapper for fallback SWF API 13767 * 13768 * @param {Object=} options Object of option names and values 13769 * @param {Function=} ready Ready callback function 13770 * @extends Tech 13771 * @class Flash 13772 */ 13773 13774 var Flash = (function (_Tech) { 13775 _inherits(Flash, _Tech); 13776 13777 function Flash(options, ready) { 13778 _classCallCheck(this, Flash); 13779 13780 _Tech.call(this, options, ready); 13781 13782 // Set the source when ready 13783 if (options.source) { 13784 this.ready(function () { 13785 this.setSource(options.source); 13786 }, true); 13787 } 13788 13789 // Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers 13790 // This allows resetting the playhead when we catch the reload 13791 if (options.startTime) { 13792 this.ready(function () { 13793 this.load(); 13794 this.play(); 13795 this.currentTime(options.startTime); 13796 }, true); 13797 } 13798 13799 // Add global window functions that the swf expects 13800 // A 4.x workflow we weren't able to solve for in 5.0 13801 // because of the need to hard code these functions 13802 // into the swf for security reasons 13803 _globalWindow2['default'].videojs = _globalWindow2['default'].videojs || {}; 13804 _globalWindow2['default'].videojs.Flash = _globalWindow2['default'].videojs.Flash || {}; 13805 _globalWindow2['default'].videojs.Flash.onReady = Flash.onReady; 13806 _globalWindow2['default'].videojs.Flash.onEvent = Flash.onEvent; 13807 _globalWindow2['default'].videojs.Flash.onError = Flash.onError; 13808 13809 this.on('seeked', function () { 13810 this.lastSeekTarget_ = undefined; 13811 }); 13812 } 13813 13814 // Create setters and getters for attributes 13815 13816 /** 13817 * Create the component's DOM element 13818 * 13819 * @return {Element} 13820 * @method createEl 13821 */ 13822 13823 Flash.prototype.createEl = function createEl() { 13824 var options = this.options_; 13825 13826 // If video.js is hosted locally you should also set the location 13827 // for the hosted swf, which should be relative to the page (not video.js) 13828 // Otherwise this adds a CDN url. 13829 // The CDN also auto-adds a swf URL for that specific version. 13830 if (!options.swf) { 13831 options.swf = '//vjs.zencdn.net/swf/5.0.1/video-js.swf'; 13832 } 13833 13834 // Generate ID for swf object 13835 var objId = options.techId; 13836 13837 // Merge default flashvars with ones passed in to init 13838 var flashVars = _objectAssign2['default']({ 13839 13840 // SWF Callback Functions 13841 'readyFunction': 'videojs.Flash.onReady', 13842 'eventProxyFunction': 'videojs.Flash.onEvent', 13843 'errorEventProxyFunction': 'videojs.Flash.onError', 13844 13845 // Player Settings 13846 'autoplay': options.autoplay, 13847 'preload': options.preload, 13848 'loop': options.loop, 13849 'muted': options.muted 13850 13851 }, options.flashVars); 13852 13853 // Merge default parames with ones passed in 13854 var params = _objectAssign2['default']({ 13855 'wmode': 'opaque', // Opaque is needed to overlay controls, but can affect playback performance 13856 'bgcolor': '#000000' // Using bgcolor prevents a white flash when the object is loading 13857 }, options.params); 13858 13859 // Merge default attributes with ones passed in 13860 var attributes = _objectAssign2['default']({ 13861 'id': objId, 13862 'name': objId, // Both ID and Name needed or swf to identify itself 13863 'class': 'vjs-tech' 13864 }, options.attributes); 13865 13866 this.el_ = Flash.embed(options.swf, flashVars, params, attributes); 13867 this.el_.tech = this; 13868 13869 return this.el_; 13870 }; 13871 13872 /** 13873 * Play for flash tech 13874 * 13875 * @method play 13876 */ 13877 13878 Flash.prototype.play = function play() { 13879 if (this.ended()) { 13880 this.setCurrentTime(0); 13881 } 13882 this.el_.vjs_play(); 13883 }; 13884 13885 /** 13886 * Pause for flash tech 13887 * 13888 * @method pause 13889 */ 13890 13891 Flash.prototype.pause = function pause() { 13892 this.el_.vjs_pause(); 13893 }; 13894 13895 /** 13896 * Get/set video 13897 * 13898 * @param {Object=} src Source object 13899 * @return {Object} 13900 * @method src 13901 */ 13902 13903 Flash.prototype.src = function src(_src) { 13904 if (_src === undefined) { 13905 return this.currentSrc(); 13906 } 13907 13908 // Setting src through `src` not `setSrc` will be deprecated 13909 return this.setSrc(_src); 13910 }; 13911 13912 /** 13913 * Set video 13914 * 13915 * @param {Object=} src Source object 13916 * @deprecated 13917 * @method setSrc 13918 */ 13919 13920 Flash.prototype.setSrc = function setSrc(src) { 13921 // Make sure source URL is absolute. 13922 src = Url.getAbsoluteURL(src); 13923 this.el_.vjs_src(src); 13924 13925 // Currently the SWF doesn't autoplay if you load a source later. 13926 // e.g. Load player w/ no source, wait 2s, set src. 13927 if (this.autoplay()) { 13928 var tech = this; 13929 this.setTimeout(function () { 13930 tech.play(); 13931 }, 0); 13932 } 13933 }; 13934 13935 /** 13936 * Returns true if the tech is currently seeking. 13937 * @return {boolean} true if seeking 13938 */ 13939 13940 Flash.prototype.seeking = function seeking() { 13941 return this.lastSeekTarget_ !== undefined; 13942 }; 13943 13944 /** 13945 * Set current time 13946 * 13947 * @param {Number} time Current time of video 13948 * @method setCurrentTime 13949 */ 13950 13951 Flash.prototype.setCurrentTime = function setCurrentTime(time) { 13952 var seekable = this.seekable(); 13953 if (seekable.length) { 13954 // clamp to the current seekable range 13955 time = time > seekable.start(0) ? time : seekable.start(0); 13956 time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); 13957 13958 this.lastSeekTarget_ = time; 13959 this.trigger('seeking'); 13960 this.el_.vjs_setProperty('currentTime', time); 13961 _Tech.prototype.setCurrentTime.call(this); 13962 } 13963 }; 13964 13965 /** 13966 * Get current time 13967 * 13968 * @param {Number=} time Current time of video 13969 * @return {Number} Current time 13970 * @method currentTime 13971 */ 13972 13973 Flash.prototype.currentTime = function currentTime(time) { 13974 // when seeking make the reported time keep up with the requested time 13975 // by reading the time we're seeking to 13976 if (this.seeking()) { 13977 return this.lastSeekTarget_ || 0; 13978 } 13979 return this.el_.vjs_getProperty('currentTime'); 13980 }; 13981 13982 /** 13983 * Get current source 13984 * 13985 * @method currentSrc 13986 */ 13987 13988 Flash.prototype.currentSrc = function currentSrc() { 13989 if (this.currentSource_) { 13990 return this.currentSource_.src; 13991 } else { 13992 return this.el_.vjs_getProperty('currentSrc'); 13993 } 13994 }; 13995 13996 /** 13997 * Load media into player 13998 * 13999 * @method load 14000 */ 14001 14002 Flash.prototype.load = function load() { 14003 this.el_.vjs_load(); 14004 }; 14005 14006 /** 14007 * Get poster 14008 * 14009 * @method poster 14010 */ 14011 14012 Flash.prototype.poster = function poster() { 14013 this.el_.vjs_getProperty('poster'); 14014 }; 14015 14016 /** 14017 * Poster images are not handled by the Flash tech so make this a no-op 14018 * 14019 * @method setPoster 14020 */ 14021 14022 Flash.prototype.setPoster = function setPoster() {}; 14023 14024 /** 14025 * Determine if can seek in media 14026 * 14027 * @return {TimeRangeObject} 14028 * @method seekable 14029 */ 14030 14031 Flash.prototype.seekable = function seekable() { 14032 var duration = this.duration(); 14033 if (duration === 0) { 14034 return _utilsTimeRangesJs.createTimeRange(); 14035 } 14036 return _utilsTimeRangesJs.createTimeRange(0, duration); 14037 }; 14038 14039 /** 14040 * Get buffered time range 14041 * 14042 * @return {TimeRangeObject} 14043 * @method buffered 14044 */ 14045 14046 Flash.prototype.buffered = function buffered() { 14047 var ranges = this.el_.vjs_getProperty('buffered'); 14048 if (ranges.length === 0) { 14049 return _utilsTimeRangesJs.createTimeRange(); 14050 } 14051 return _utilsTimeRangesJs.createTimeRange(ranges[0][0], ranges[0][1]); 14052 }; 14053 14054 /** 14055 * Get fullscreen support - 14056 * Flash does not allow fullscreen through javascript 14057 * so always returns false 14058 * 14059 * @return {Boolean} false 14060 * @method supportsFullScreen 14061 */ 14062 14063 Flash.prototype.supportsFullScreen = function supportsFullScreen() { 14064 return false; // Flash does not allow fullscreen through javascript 14065 }; 14066 14067 /** 14068 * Request to enter fullscreen 14069 * Flash does not allow fullscreen through javascript 14070 * so always returns false 14071 * 14072 * @return {Boolean} false 14073 * @method enterFullScreen 14074 */ 14075 14076 Flash.prototype.enterFullScreen = function enterFullScreen() { 14077 return false; 14078 }; 14079 14080 return Flash; 14081 })(_tech2['default']); 14082 14083 var _api = Flash.prototype; 14084 var _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(','); 14085 var _readOnly = 'networkState,readyState,initialTime,duration,startOffsetTime,paused,ended,videoTracks,audioTracks,videoWidth,videoHeight'.split(','); 14086 14087 function _createSetter(attr) { 14088 var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1); 14089 _api['set' + attrUpper] = function (val) { 14090 return this.el_.vjs_setProperty(attr, val); 14091 }; 14092 } 14093 function _createGetter(attr) { 14094 _api[attr] = function () { 14095 return this.el_.vjs_getProperty(attr); 14096 }; 14097 } 14098 14099 // Create getter and setters for all read/write attributes 14100 for (var i = 0; i < _readWrite.length; i++) { 14101 _createGetter(_readWrite[i]); 14102 _createSetter(_readWrite[i]); 14103 } 14104 14105 // Create getters for read-only attributes 14106 for (var i = 0; i < _readOnly.length; i++) { 14107 _createGetter(_readOnly[i]); 14108 } 14109 14110 /* Flash Support Testing -------------------------------------------------------- */ 14111 14112 Flash.isSupported = function () { 14113 return Flash.version()[0] >= 10; 14114 // return swfobject.hasFlashPlayerVersion('10'); 14115 }; 14116 14117 // Add Source Handler pattern functions to this tech 14118 _tech2['default'].withSourceHandlers(Flash); 14119 14120 /* 14121 * The default native source handler. 14122 * This simply passes the source to the video element. Nothing fancy. 14123 * 14124 * @param {Object} source The source object 14125 * @param {Flash} tech The instance of the Flash tech 14126 */ 14127 Flash.nativeSourceHandler = {}; 14128 14129 /** 14130 * Check if Flash can play the given videotype 14131 * @param {String} type The mimetype to check 14132 * @return {String} 'probably', 'maybe', or '' (empty string) 14133 */ 14134 Flash.nativeSourceHandler.canPlayType = function (type) { 14135 if (type in Flash.formats) { 14136 return 'maybe'; 14137 } 14138 14139 return ''; 14140 }; 14141 14142 /* 14143 * Check Flash can handle the source natively 14144 * 14145 * @param {Object} source The source object 14146 * @return {String} 'probably', 'maybe', or '' (empty string) 14147 */ 14148 Flash.nativeSourceHandler.canHandleSource = function (source) { 14149 var type; 14150 14151 function guessMimeType(src) { 14152 var ext = Url.getFileExtension(src); 14153 if (ext) { 14154 return 'video/' + ext; 14155 } 14156 return ''; 14157 } 14158 14159 if (!source.type) { 14160 type = guessMimeType(source.src); 14161 } else { 14162 // Strip code information from the type because we don't get that specific 14163 type = source.type.replace(/;.*/, '').toLowerCase(); 14164 } 14165 14166 return Flash.nativeSourceHandler.canPlayType(type); 14167 }; 14168 14169 /* 14170 * Pass the source to the flash object 14171 * Adaptive source handlers will have more complicated workflows before passing 14172 * video data to the video element 14173 * 14174 * @param {Object} source The source object 14175 * @param {Flash} tech The instance of the Flash tech 14176 */ 14177 Flash.nativeSourceHandler.handleSource = function (source, tech) { 14178 tech.setSrc(source.src); 14179 }; 14180 14181 /* 14182 * Clean up the source handler when disposing the player or switching sources.. 14183 * (no cleanup is needed when supporting the format natively) 14184 */ 14185 Flash.nativeSourceHandler.dispose = function () {}; 14186 14187 // Register the native source handler 14188 Flash.registerSourceHandler(Flash.nativeSourceHandler); 14189 14190 Flash.formats = { 14191 'video/flv': 'FLV', 14192 'video/x-flv': 'FLV', 14193 'video/mp4': 'MP4', 14194 'video/m4v': 'MP4' 14195 }; 14196 14197 Flash.onReady = function (currSwf) { 14198 var el = Dom.getEl(currSwf); 14199 var tech = el && el.tech; 14200 14201 // if there is no el then the tech has been disposed 14202 // and the tech element was removed from the player div 14203 if (tech && tech.el()) { 14204 // check that the flash object is really ready 14205 Flash.checkReady(tech); 14206 } 14207 }; 14208 14209 // The SWF isn't always ready when it says it is. Sometimes the API functions still need to be added to the object. 14210 // If it's not ready, we set a timeout to check again shortly. 14211 Flash.checkReady = function (tech) { 14212 // stop worrying if the tech has been disposed 14213 if (!tech.el()) { 14214 return; 14215 } 14216 14217 // check if API property exists 14218 if (tech.el().vjs_getProperty) { 14219 // tell tech it's ready 14220 tech.triggerReady(); 14221 } else { 14222 // wait longer 14223 this.setTimeout(function () { 14224 Flash['checkReady'](tech); 14225 }, 50); 14226 } 14227 }; 14228 14229 // Trigger events from the swf on the player 14230 Flash.onEvent = function (swfID, eventName) { 14231 var tech = Dom.getEl(swfID).tech; 14232 tech.trigger(eventName); 14233 }; 14234 14235 // Log errors from the swf 14236 Flash.onError = function (swfID, err) { 14237 var tech = Dom.getEl(swfID).tech; 14238 14239 // trigger MEDIA_ERR_SRC_NOT_SUPPORTED 14240 if (err === 'srcnotfound') { 14241 return tech.error(4); 14242 } 14243 14244 // trigger a custom error 14245 tech.error('FLASH: ' + err); 14246 }; 14247 14248 // Flash Version Check 14249 Flash.version = function () { 14250 var version = '0,0,0'; 14251 14252 // IE 14253 try { 14254 version = new _globalWindow2['default'].ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; 14255 14256 // other browsers 14257 } catch (e) { 14258 try { 14259 if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) { 14260 version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; 14261 } 14262 } catch (err) {} 14263 } 14264 return version.split(','); 14265 }; 14266 14267 // Flash embedding method. Only used in non-iframe mode 14268 Flash.embed = function (swf, flashVars, params, attributes) { 14269 var code = Flash.getEmbedCode(swf, flashVars, params, attributes); 14270 14271 // Get element by embedding code and retrieving created element 14272 var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0]; 14273 14274 return obj; 14275 }; 14276 14277 Flash.getEmbedCode = function (swf, flashVars, params, attributes) { 14278 var objTag = '<object type="application/x-shockwave-flash" '; 14279 var flashVarsString = ''; 14280 var paramsString = ''; 14281 var attrsString = ''; 14282 14283 // Convert flash vars to string 14284 if (flashVars) { 14285 Object.getOwnPropertyNames(flashVars).forEach(function (key) { 14286 flashVarsString += key + '=' + flashVars[key] + '&'; 14287 }); 14288 } 14289 14290 // Add swf, flashVars, and other default params 14291 params = _objectAssign2['default']({ 14292 'movie': swf, 14293 'flashvars': flashVarsString, 14294 'allowScriptAccess': 'always', // Required to talk to swf 14295 'allowNetworking': 'all' // All should be default, but having security issues. 14296 }, params); 14297 14298 // Create param tags string 14299 Object.getOwnPropertyNames(params).forEach(function (key) { 14300 paramsString += '<param name="' + key + '" value="' + params[key] + '" />'; 14301 }); 14302 14303 attributes = _objectAssign2['default']({ 14304 // Add swf to attributes (need both for IE and Others to work) 14305 'data': swf, 14306 14307 // Default to 100% width/height 14308 'width': '100%', 14309 'height': '100%' 14310 14311 }, attributes); 14312 14313 // Create Attributes string 14314 Object.getOwnPropertyNames(attributes).forEach(function (key) { 14315 attrsString += key + '="' + attributes[key] + '" '; 14316 }); 14317 14318 return '' + objTag + attrsString + '>' + paramsString + '</object>'; 14319 }; 14320 14321 // Run Flash through the RTMP decorator 14322 _flashRtmp2['default'](Flash); 14323 14324 _component2['default'].registerComponent('Flash', Flash); 14325 _tech2['default'].registerTech('Flash', Flash); 14326 exports['default'] = Flash; 14327 module.exports = exports['default']; 14328 14329 },{"../component":67,"../utils/dom.js":134,"../utils/time-ranges.js":142,"../utils/url.js":144,"./flash-rtmp":117,"./tech":121,"global/window":2,"object.assign":45}],119:[function(_dereq_,module,exports){ 14330 /** 14331 * @file html5.js 14332 * HTML5 Media Controller - Wrapper for HTML5 Media API 14333 */ 14334 14335 'use strict'; 14336 14337 exports.__esModule = true; 14338 14339 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 14340 14341 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 14342 14343 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 14344 14345 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 14346 14347 var _techJs = _dereq_('./tech.js'); 14348 14349 var _techJs2 = _interopRequireDefault(_techJs); 14350 14351 var _component = _dereq_('../component'); 14352 14353 var _component2 = _interopRequireDefault(_component); 14354 14355 var _utilsDomJs = _dereq_('../utils/dom.js'); 14356 14357 var Dom = _interopRequireWildcard(_utilsDomJs); 14358 14359 var _utilsUrlJs = _dereq_('../utils/url.js'); 14360 14361 var Url = _interopRequireWildcard(_utilsUrlJs); 14362 14363 var _utilsFnJs = _dereq_('../utils/fn.js'); 14364 14365 var Fn = _interopRequireWildcard(_utilsFnJs); 14366 14367 var _utilsLogJs = _dereq_('../utils/log.js'); 14368 14369 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 14370 14371 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 14372 14373 var browser = _interopRequireWildcard(_utilsBrowserJs); 14374 14375 var _globalDocument = _dereq_('global/document'); 14376 14377 var _globalDocument2 = _interopRequireDefault(_globalDocument); 14378 14379 var _globalWindow = _dereq_('global/window'); 14380 14381 var _globalWindow2 = _interopRequireDefault(_globalWindow); 14382 14383 var _objectAssign = _dereq_('object.assign'); 14384 14385 var _objectAssign2 = _interopRequireDefault(_objectAssign); 14386 14387 var _utilsMergeOptionsJs = _dereq_('../utils/merge-options.js'); 14388 14389 var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); 14390 14391 /** 14392 * HTML5 Media Controller - Wrapper for HTML5 Media API 14393 * 14394 * @param {Object=} options Object of option names and values 14395 * @param {Function=} ready Ready callback function 14396 * @extends Tech 14397 * @class Html5 14398 */ 14399 14400 var Html5 = (function (_Tech) { 14401 _inherits(Html5, _Tech); 14402 14403 function Html5(options, ready) { 14404 _classCallCheck(this, Html5); 14405 14406 _Tech.call(this, options, ready); 14407 14408 var source = options.source; 14409 14410 // Set the source if one is provided 14411 // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted) 14412 // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source 14413 // anyway so the error gets fired. 14414 if (source && (this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) { 14415 this.setSource(source); 14416 } else { 14417 this.handleLateInit_(this.el_); 14418 } 14419 14420 if (this.el_.hasChildNodes()) { 14421 14422 var nodes = this.el_.childNodes; 14423 var nodesLength = nodes.length; 14424 var removeNodes = []; 14425 14426 while (nodesLength--) { 14427 var node = nodes[nodesLength]; 14428 var nodeName = node.nodeName.toLowerCase(); 14429 14430 if (nodeName === 'track') { 14431 if (!this.featuresNativeTextTracks) { 14432 // Empty video tag tracks so the built-in player doesn't use them also. 14433 // This may not be fast enough to stop HTML5 browsers from reading the tags 14434 // so we'll need to turn off any default tracks if we're manually doing 14435 // captions and subtitles. videoElement.textTracks 14436 removeNodes.push(node); 14437 } else { 14438 // store HTMLTrackElement and TextTrack to remote list 14439 this.remoteTextTrackEls().addTrackElement_(node); 14440 this.remoteTextTracks().addTrack_(node.track); 14441 } 14442 } 14443 } 14444 14445 for (var i = 0; i < removeNodes.length; i++) { 14446 this.el_.removeChild(removeNodes[i]); 14447 } 14448 } 14449 14450 if (this.featuresNativeTextTracks) { 14451 this.handleTextTrackChange_ = Fn.bind(this, this.handleTextTrackChange); 14452 this.handleTextTrackAdd_ = Fn.bind(this, this.handleTextTrackAdd); 14453 this.handleTextTrackRemove_ = Fn.bind(this, this.handleTextTrackRemove); 14454 this.proxyNativeTextTracks_(); 14455 } 14456 14457 // Determine if native controls should be used 14458 // Our goal should be to get the custom controls on mobile solid everywhere 14459 // so we can remove this all together. Right now this will block custom 14460 // controls on touch enabled laptops like the Chrome Pixel 14461 if (browser.TOUCH_ENABLED && options.nativeControlsForTouch === true || browser.IS_IPHONE || browser.IS_NATIVE_ANDROID) { 14462 this.setControls(true); 14463 } 14464 14465 this.triggerReady(); 14466 } 14467 14468 /* HTML5 Support Testing ---------------------------------------------------- */ 14469 14470 /* 14471 * Element for testing browser HTML5 video capabilities 14472 * 14473 * @type {Element} 14474 * @constant 14475 * @private 14476 */ 14477 14478 /** 14479 * Dispose of html5 media element 14480 * 14481 * @method dispose 14482 */ 14483 14484 Html5.prototype.dispose = function dispose() { 14485 var tt = this.el().textTracks; 14486 var emulatedTt = this.textTracks(); 14487 14488 // remove native event listeners 14489 if (tt && tt.removeEventListener) { 14490 tt.removeEventListener('change', this.handleTextTrackChange_); 14491 tt.removeEventListener('addtrack', this.handleTextTrackAdd_); 14492 tt.removeEventListener('removetrack', this.handleTextTrackRemove_); 14493 } 14494 14495 // clearout the emulated text track list. 14496 var i = emulatedTt.length; 14497 14498 while (i--) { 14499 emulatedTt.removeTrack_(emulatedTt[i]); 14500 } 14501 14502 Html5.disposeMediaElement(this.el_); 14503 _Tech.prototype.dispose.call(this); 14504 }; 14505 14506 /** 14507 * Create the component's DOM element 14508 * 14509 * @return {Element} 14510 * @method createEl 14511 */ 14512 14513 Html5.prototype.createEl = function createEl() { 14514 var el = this.options_.tag; 14515 14516 // Check if this browser supports moving the element into the box. 14517 // On the iPhone video will break if you move the element, 14518 // So we have to create a brand new element. 14519 if (!el || this['movingMediaElementInDOM'] === false) { 14520 14521 // If the original tag is still there, clone and remove it. 14522 if (el) { 14523 var clone = el.cloneNode(true); 14524 el.parentNode.insertBefore(clone, el); 14525 Html5.disposeMediaElement(el); 14526 el = clone; 14527 } else { 14528 el = _globalDocument2['default'].createElement('video'); 14529 14530 // determine if native controls should be used 14531 var tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag); 14532 var attributes = _utilsMergeOptionsJs2['default']({}, tagAttributes); 14533 if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) { 14534 delete attributes.controls; 14535 } 14536 14537 Dom.setElAttributes(el, _objectAssign2['default'](attributes, { 14538 id: this.options_.techId, 14539 'class': 'vjs-tech' 14540 })); 14541 } 14542 } 14543 14544 // Update specific tag settings, in case they were overridden 14545 var settingsAttrs = ['autoplay', 'preload', 'loop', 'muted']; 14546 for (var i = settingsAttrs.length - 1; i >= 0; i--) { 14547 var attr = settingsAttrs[i]; 14548 var overwriteAttrs = {}; 14549 if (typeof this.options_[attr] !== 'undefined') { 14550 overwriteAttrs[attr] = this.options_[attr]; 14551 } 14552 Dom.setElAttributes(el, overwriteAttrs); 14553 } 14554 14555 return el; 14556 // jenniisawesome = true; 14557 }; 14558 14559 // If we're loading the playback object after it has started loading 14560 // or playing the video (often with autoplay on) then the loadstart event 14561 // has already fired and we need to fire it manually because many things 14562 // rely on it. 14563 14564 Html5.prototype.handleLateInit_ = function handleLateInit_(el) { 14565 var _this = this; 14566 14567 if (el.networkState === 0 || el.networkState === 3) { 14568 // The video element hasn't started loading the source yet 14569 // or didn't find a source 14570 return; 14571 } 14572 14573 if (el.readyState === 0) { 14574 var _ret = (function () { 14575 // NetworkState is set synchronously BUT loadstart is fired at the 14576 // end of the current stack, usually before setInterval(fn, 0). 14577 // So at this point we know loadstart may have already fired or is 14578 // about to fire, and either way the player hasn't seen it yet. 14579 // We don't want to fire loadstart prematurely here and cause a 14580 // double loadstart so we'll wait and see if it happens between now 14581 // and the next loop, and fire it if not. 14582 // HOWEVER, we also want to make sure it fires before loadedmetadata 14583 // which could also happen between now and the next loop, so we'll 14584 // watch for that also. 14585 var loadstartFired = false; 14586 var setLoadstartFired = function setLoadstartFired() { 14587 loadstartFired = true; 14588 }; 14589 _this.on('loadstart', setLoadstartFired); 14590 14591 var triggerLoadstart = function triggerLoadstart() { 14592 // We did miss the original loadstart. Make sure the player 14593 // sees loadstart before loadedmetadata 14594 if (!loadstartFired) { 14595 this.trigger('loadstart'); 14596 } 14597 }; 14598 _this.on('loadedmetadata', triggerLoadstart); 14599 14600 _this.ready(function () { 14601 this.off('loadstart', setLoadstartFired); 14602 this.off('loadedmetadata', triggerLoadstart); 14603 14604 if (!loadstartFired) { 14605 // We did miss the original native loadstart. Fire it now. 14606 this.trigger('loadstart'); 14607 } 14608 }); 14609 14610 return { 14611 v: undefined 14612 }; 14613 })(); 14614 14615 if (typeof _ret === 'object') return _ret.v; 14616 } 14617 14618 // From here on we know that loadstart already fired and we missed it. 14619 // The other readyState events aren't as much of a problem if we double 14620 // them, so not going to go to as much trouble as loadstart to prevent 14621 // that unless we find reason to. 14622 var eventsToTrigger = ['loadstart']; 14623 14624 // loadedmetadata: newly equal to HAVE_METADATA (1) or greater 14625 eventsToTrigger.push('loadedmetadata'); 14626 14627 // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater 14628 if (el.readyState >= 2) { 14629 eventsToTrigger.push('loadeddata'); 14630 } 14631 14632 // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater 14633 if (el.readyState >= 3) { 14634 eventsToTrigger.push('canplay'); 14635 } 14636 14637 // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4) 14638 if (el.readyState >= 4) { 14639 eventsToTrigger.push('canplaythrough'); 14640 } 14641 14642 // We still need to give the player time to add event listeners 14643 this.ready(function () { 14644 eventsToTrigger.forEach(function (type) { 14645 this.trigger(type); 14646 }, this); 14647 }); 14648 }; 14649 14650 Html5.prototype.proxyNativeTextTracks_ = function proxyNativeTextTracks_() { 14651 var tt = this.el().textTracks; 14652 14653 if (tt) { 14654 // Add tracks - if player is initialised after DOM loaded, textTracks 14655 // will not trigger addtrack 14656 for (var i = 0; i < tt.length; i++) { 14657 this.textTracks().addTrack_(tt[i]); 14658 } 14659 14660 if (tt.addEventListener) { 14661 tt.addEventListener('change', this.handleTextTrackChange_); 14662 tt.addEventListener('addtrack', this.handleTextTrackAdd_); 14663 tt.addEventListener('removetrack', this.handleTextTrackRemove_); 14664 } 14665 } 14666 }; 14667 14668 Html5.prototype.handleTextTrackChange = function handleTextTrackChange(e) { 14669 var tt = this.textTracks(); 14670 this.textTracks().trigger({ 14671 type: 'change', 14672 target: tt, 14673 currentTarget: tt, 14674 srcElement: tt 14675 }); 14676 }; 14677 14678 Html5.prototype.handleTextTrackAdd = function handleTextTrackAdd(e) { 14679 this.textTracks().addTrack_(e.track); 14680 }; 14681 14682 Html5.prototype.handleTextTrackRemove = function handleTextTrackRemove(e) { 14683 this.textTracks().removeTrack_(e.track); 14684 }; 14685 14686 /** 14687 * Play for html5 tech 14688 * 14689 * @method play 14690 */ 14691 14692 Html5.prototype.play = function play() { 14693 this.el_.play(); 14694 }; 14695 14696 /** 14697 * Pause for html5 tech 14698 * 14699 * @method pause 14700 */ 14701 14702 Html5.prototype.pause = function pause() { 14703 this.el_.pause(); 14704 }; 14705 14706 /** 14707 * Paused for html5 tech 14708 * 14709 * @return {Boolean} 14710 * @method paused 14711 */ 14712 14713 Html5.prototype.paused = function paused() { 14714 return this.el_.paused; 14715 }; 14716 14717 /** 14718 * Get current time 14719 * 14720 * @return {Number} 14721 * @method currentTime 14722 */ 14723 14724 Html5.prototype.currentTime = function currentTime() { 14725 return this.el_.currentTime; 14726 }; 14727 14728 /** 14729 * Set current time 14730 * 14731 * @param {Number} seconds Current time of video 14732 * @method setCurrentTime 14733 */ 14734 14735 Html5.prototype.setCurrentTime = function setCurrentTime(seconds) { 14736 try { 14737 this.el_.currentTime = seconds; 14738 } catch (e) { 14739 _utilsLogJs2['default'](e, 'Video is not ready. (Video.js)'); 14740 // this.warning(VideoJS.warnings.videoNotReady); 14741 } 14742 }; 14743 14744 /** 14745 * Get duration 14746 * 14747 * @return {Number} 14748 * @method duration 14749 */ 14750 14751 Html5.prototype.duration = function duration() { 14752 return this.el_.duration || 0; 14753 }; 14754 14755 /** 14756 * Get a TimeRange object that represents the intersection 14757 * of the time ranges for which the user agent has all 14758 * relevant media 14759 * 14760 * @return {TimeRangeObject} 14761 * @method buffered 14762 */ 14763 14764 Html5.prototype.buffered = function buffered() { 14765 return this.el_.buffered; 14766 }; 14767 14768 /** 14769 * Get volume level 14770 * 14771 * @return {Number} 14772 * @method volume 14773 */ 14774 14775 Html5.prototype.volume = function volume() { 14776 return this.el_.volume; 14777 }; 14778 14779 /** 14780 * Set volume level 14781 * 14782 * @param {Number} percentAsDecimal Volume percent as a decimal 14783 * @method setVolume 14784 */ 14785 14786 Html5.prototype.setVolume = function setVolume(percentAsDecimal) { 14787 this.el_.volume = percentAsDecimal; 14788 }; 14789 14790 /** 14791 * Get if muted 14792 * 14793 * @return {Boolean} 14794 * @method muted 14795 */ 14796 14797 Html5.prototype.muted = function muted() { 14798 return this.el_.muted; 14799 }; 14800 14801 /** 14802 * Set muted 14803 * 14804 * @param {Boolean} If player is to be muted or note 14805 * @method setMuted 14806 */ 14807 14808 Html5.prototype.setMuted = function setMuted(muted) { 14809 this.el_.muted = muted; 14810 }; 14811 14812 /** 14813 * Get player width 14814 * 14815 * @return {Number} 14816 * @method width 14817 */ 14818 14819 Html5.prototype.width = function width() { 14820 return this.el_.offsetWidth; 14821 }; 14822 14823 /** 14824 * Get player height 14825 * 14826 * @return {Number} 14827 * @method height 14828 */ 14829 14830 Html5.prototype.height = function height() { 14831 return this.el_.offsetHeight; 14832 }; 14833 14834 /** 14835 * Get if there is fullscreen support 14836 * 14837 * @return {Boolean} 14838 * @method supportsFullScreen 14839 */ 14840 14841 Html5.prototype.supportsFullScreen = function supportsFullScreen() { 14842 if (typeof this.el_.webkitEnterFullScreen === 'function') { 14843 var userAgent = _globalWindow2['default'].navigator.userAgent; 14844 // Seems to be broken in Chromium/Chrome && Safari in Leopard 14845 if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) { 14846 return true; 14847 } 14848 } 14849 return false; 14850 }; 14851 14852 /** 14853 * Request to enter fullscreen 14854 * 14855 * @method enterFullScreen 14856 */ 14857 14858 Html5.prototype.enterFullScreen = function enterFullScreen() { 14859 var video = this.el_; 14860 14861 if ('webkitDisplayingFullscreen' in video) { 14862 this.one('webkitbeginfullscreen', function () { 14863 this.one('webkitendfullscreen', function () { 14864 this.trigger('fullscreenchange', { isFullscreen: false }); 14865 }); 14866 14867 this.trigger('fullscreenchange', { isFullscreen: true }); 14868 }); 14869 } 14870 14871 if (video.paused && video.networkState <= video.HAVE_METADATA) { 14872 // attempt to prime the video element for programmatic access 14873 // this isn't necessary on the desktop but shouldn't hurt 14874 this.el_.play(); 14875 14876 // playing and pausing synchronously during the transition to fullscreen 14877 // can get iOS ~6.1 devices into a play/pause loop 14878 this.setTimeout(function () { 14879 video.pause(); 14880 video.webkitEnterFullScreen(); 14881 }, 0); 14882 } else { 14883 video.webkitEnterFullScreen(); 14884 } 14885 }; 14886 14887 /** 14888 * Request to exit fullscreen 14889 * 14890 * @method exitFullScreen 14891 */ 14892 14893 Html5.prototype.exitFullScreen = function exitFullScreen() { 14894 this.el_.webkitExitFullScreen(); 14895 }; 14896 14897 /** 14898 * Get/set video 14899 * 14900 * @param {Object=} src Source object 14901 * @return {Object} 14902 * @method src 14903 */ 14904 14905 Html5.prototype.src = function src(_src) { 14906 if (_src === undefined) { 14907 return this.el_.src; 14908 } else { 14909 // Setting src through `src` instead of `setSrc` will be deprecated 14910 this.setSrc(_src); 14911 } 14912 }; 14913 14914 /** 14915 * Set video 14916 * 14917 * @param {Object} src Source object 14918 * @deprecated 14919 * @method setSrc 14920 */ 14921 14922 Html5.prototype.setSrc = function setSrc(src) { 14923 this.el_.src = src; 14924 }; 14925 14926 /** 14927 * Load media into player 14928 * 14929 * @method load 14930 */ 14931 14932 Html5.prototype.load = function load() { 14933 this.el_.load(); 14934 }; 14935 14936 /** 14937 * Reset the tech. Removes all sources and calls `load`. 14938 * 14939 * @method reset 14940 */ 14941 14942 Html5.prototype.reset = function reset() { 14943 Html5.resetMediaElement(this.el_); 14944 }; 14945 14946 /** 14947 * Get current source 14948 * 14949 * @return {Object} 14950 * @method currentSrc 14951 */ 14952 14953 Html5.prototype.currentSrc = function currentSrc() { 14954 if (this.currentSource_) { 14955 return this.currentSource_.src; 14956 } else { 14957 return this.el_.currentSrc; 14958 } 14959 }; 14960 14961 /** 14962 * Get poster 14963 * 14964 * @return {String} 14965 * @method poster 14966 */ 14967 14968 Html5.prototype.poster = function poster() { 14969 return this.el_.poster; 14970 }; 14971 14972 /** 14973 * Set poster 14974 * 14975 * @param {String} val URL to poster image 14976 * @method 14977 */ 14978 14979 Html5.prototype.setPoster = function setPoster(val) { 14980 this.el_.poster = val; 14981 }; 14982 14983 /** 14984 * Get preload attribute 14985 * 14986 * @return {String} 14987 * @method preload 14988 */ 14989 14990 Html5.prototype.preload = function preload() { 14991 return this.el_.preload; 14992 }; 14993 14994 /** 14995 * Set preload attribute 14996 * 14997 * @param {String} val Value for preload attribute 14998 * @method setPreload 14999 */ 15000 15001 Html5.prototype.setPreload = function setPreload(val) { 15002 this.el_.preload = val; 15003 }; 15004 15005 /** 15006 * Get autoplay attribute 15007 * 15008 * @return {String} 15009 * @method autoplay 15010 */ 15011 15012 Html5.prototype.autoplay = function autoplay() { 15013 return this.el_.autoplay; 15014 }; 15015 15016 /** 15017 * Set autoplay attribute 15018 * 15019 * @param {String} val Value for preload attribute 15020 * @method setAutoplay 15021 */ 15022 15023 Html5.prototype.setAutoplay = function setAutoplay(val) { 15024 this.el_.autoplay = val; 15025 }; 15026 15027 /** 15028 * Get controls attribute 15029 * 15030 * @return {String} 15031 * @method controls 15032 */ 15033 15034 Html5.prototype.controls = function controls() { 15035 return this.el_.controls; 15036 }; 15037 15038 /** 15039 * Set controls attribute 15040 * 15041 * @param {String} val Value for controls attribute 15042 * @method setControls 15043 */ 15044 15045 Html5.prototype.setControls = function setControls(val) { 15046 this.el_.controls = !!val; 15047 }; 15048 15049 /** 15050 * Get loop attribute 15051 * 15052 * @return {String} 15053 * @method loop 15054 */ 15055 15056 Html5.prototype.loop = function loop() { 15057 return this.el_.loop; 15058 }; 15059 15060 /** 15061 * Set loop attribute 15062 * 15063 * @param {String} val Value for loop attribute 15064 * @method setLoop 15065 */ 15066 15067 Html5.prototype.setLoop = function setLoop(val) { 15068 this.el_.loop = val; 15069 }; 15070 15071 /** 15072 * Get error value 15073 * 15074 * @return {String} 15075 * @method error 15076 */ 15077 15078 Html5.prototype.error = function error() { 15079 return this.el_.error; 15080 }; 15081 15082 /** 15083 * Get whether or not the player is in the "seeking" state 15084 * 15085 * @return {Boolean} 15086 * @method seeking 15087 */ 15088 15089 Html5.prototype.seeking = function seeking() { 15090 return this.el_.seeking; 15091 }; 15092 15093 /** 15094 * Get a TimeRanges object that represents the 15095 * ranges of the media resource to which it is possible 15096 * for the user agent to seek. 15097 * 15098 * @return {TimeRangeObject} 15099 * @method seekable 15100 */ 15101 15102 Html5.prototype.seekable = function seekable() { 15103 return this.el_.seekable; 15104 }; 15105 15106 /** 15107 * Get if video ended 15108 * 15109 * @return {Boolean} 15110 * @method ended 15111 */ 15112 15113 Html5.prototype.ended = function ended() { 15114 return this.el_.ended; 15115 }; 15116 15117 /** 15118 * Get the value of the muted content attribute 15119 * This attribute has no dynamic effect, it only 15120 * controls the default state of the element 15121 * 15122 * @return {Boolean} 15123 * @method defaultMuted 15124 */ 15125 15126 Html5.prototype.defaultMuted = function defaultMuted() { 15127 return this.el_.defaultMuted; 15128 }; 15129 15130 /** 15131 * Get desired speed at which the media resource is to play 15132 * 15133 * @return {Number} 15134 * @method playbackRate 15135 */ 15136 15137 Html5.prototype.playbackRate = function playbackRate() { 15138 return this.el_.playbackRate; 15139 }; 15140 15141 /** 15142 * Returns a TimeRanges object that represents the ranges of the 15143 * media resource that the user agent has played. 15144 * @return {TimeRangeObject} the range of points on the media 15145 * timeline that has been reached through normal playback 15146 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played 15147 */ 15148 15149 Html5.prototype.played = function played() { 15150 return this.el_.played; 15151 }; 15152 15153 /** 15154 * Set desired speed at which the media resource is to play 15155 * 15156 * @param {Number} val Speed at which the media resource is to play 15157 * @method setPlaybackRate 15158 */ 15159 15160 Html5.prototype.setPlaybackRate = function setPlaybackRate(val) { 15161 this.el_.playbackRate = val; 15162 }; 15163 15164 /** 15165 * Get the current state of network activity for the element, from 15166 * the list below 15167 * NETWORK_EMPTY (numeric value 0) 15168 * NETWORK_IDLE (numeric value 1) 15169 * NETWORK_LOADING (numeric value 2) 15170 * NETWORK_NO_SOURCE (numeric value 3) 15171 * 15172 * @return {Number} 15173 * @method networkState 15174 */ 15175 15176 Html5.prototype.networkState = function networkState() { 15177 return this.el_.networkState; 15178 }; 15179 15180 /** 15181 * Get a value that expresses the current state of the element 15182 * with respect to rendering the current playback position, from 15183 * the codes in the list below 15184 * HAVE_NOTHING (numeric value 0) 15185 * HAVE_METADATA (numeric value 1) 15186 * HAVE_CURRENT_DATA (numeric value 2) 15187 * HAVE_FUTURE_DATA (numeric value 3) 15188 * HAVE_ENOUGH_DATA (numeric value 4) 15189 * 15190 * @return {Number} 15191 * @method readyState 15192 */ 15193 15194 Html5.prototype.readyState = function readyState() { 15195 return this.el_.readyState; 15196 }; 15197 15198 /** 15199 * Get width of video 15200 * 15201 * @return {Number} 15202 * @method videoWidth 15203 */ 15204 15205 Html5.prototype.videoWidth = function videoWidth() { 15206 return this.el_.videoWidth; 15207 }; 15208 15209 /** 15210 * Get height of video 15211 * 15212 * @return {Number} 15213 * @method videoHeight 15214 */ 15215 15216 Html5.prototype.videoHeight = function videoHeight() { 15217 return this.el_.videoHeight; 15218 }; 15219 15220 /** 15221 * Get text tracks 15222 * 15223 * @return {TextTrackList} 15224 * @method textTracks 15225 */ 15226 15227 Html5.prototype.textTracks = function textTracks() { 15228 return _Tech.prototype.textTracks.call(this); 15229 }; 15230 15231 /** 15232 * Creates and returns a text track object 15233 * 15234 * @param {String} kind Text track kind (subtitles, captions, descriptions 15235 * chapters and metadata) 15236 * @param {String=} label Label to identify the text track 15237 * @param {String=} language Two letter language abbreviation 15238 * @return {TextTrackObject} 15239 * @method addTextTrack 15240 */ 15241 15242 Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) { 15243 if (!this['featuresNativeTextTracks']) { 15244 return _Tech.prototype.addTextTrack.call(this, kind, label, language); 15245 } 15246 15247 return this.el_.addTextTrack(kind, label, language); 15248 }; 15249 15250 /** 15251 * Creates a remote text track object and returns a html track element 15252 * 15253 * @param {Object} options The object should contain values for 15254 * kind, language, label and src (location of the WebVTT file) 15255 * @return {HTMLTrackElement} 15256 * @method addRemoteTextTrack 15257 */ 15258 15259 Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack() { 15260 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 15261 15262 if (!this['featuresNativeTextTracks']) { 15263 return _Tech.prototype.addRemoteTextTrack.call(this, options); 15264 } 15265 15266 var htmlTrackElement = _globalDocument2['default'].createElement('track'); 15267 15268 if (options.kind) { 15269 htmlTrackElement.kind = options.kind; 15270 } 15271 if (options.label) { 15272 htmlTrackElement.label = options.label; 15273 } 15274 if (options.language || options.srclang) { 15275 htmlTrackElement.srclang = options.language || options.srclang; 15276 } 15277 if (options['default']) { 15278 htmlTrackElement['default'] = options['default']; 15279 } 15280 if (options.id) { 15281 htmlTrackElement.id = options.id; 15282 } 15283 if (options.src) { 15284 htmlTrackElement.src = options.src; 15285 } 15286 15287 this.el().appendChild(htmlTrackElement); 15288 15289 // store HTMLTrackElement and TextTrack to remote list 15290 this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); 15291 this.remoteTextTracks().addTrack_(htmlTrackElement.track); 15292 15293 return htmlTrackElement; 15294 }; 15295 15296 /** 15297 * Remove remote text track from TextTrackList object 15298 * 15299 * @param {TextTrackObject} track Texttrack object to remove 15300 * @method removeRemoteTextTrack 15301 */ 15302 15303 Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { 15304 if (!this['featuresNativeTextTracks']) { 15305 return _Tech.prototype.removeRemoteTextTrack.call(this, track); 15306 } 15307 15308 var tracks = undefined, 15309 i = undefined; 15310 15311 var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); 15312 15313 // remove HTMLTrackElement and TextTrack from remote list 15314 this.remoteTextTrackEls().removeTrackElement_(trackElement); 15315 this.remoteTextTracks().removeTrack_(track); 15316 15317 tracks = this.$$('track'); 15318 15319 i = tracks.length; 15320 while (i--) { 15321 if (track === tracks[i] || track === tracks[i].track) { 15322 this.el().removeChild(tracks[i]); 15323 } 15324 } 15325 }; 15326 15327 return Html5; 15328 })(_techJs2['default']); 15329 15330 Html5.TEST_VID = _globalDocument2['default'].createElement('video'); 15331 var track = _globalDocument2['default'].createElement('track'); 15332 track.kind = 'captions'; 15333 track.srclang = 'en'; 15334 track.label = 'English'; 15335 Html5.TEST_VID.appendChild(track); 15336 15337 /* 15338 * Check if HTML5 video is supported by this browser/device 15339 * 15340 * @return {Boolean} 15341 */ 15342 Html5.isSupported = function () { 15343 // IE9 with no Media Player is a LIAR! (#984) 15344 try { 15345 Html5.TEST_VID['volume'] = 0.5; 15346 } catch (e) { 15347 return false; 15348 } 15349 15350 return !!Html5.TEST_VID.canPlayType; 15351 }; 15352 15353 // Add Source Handler pattern functions to this tech 15354 _techJs2['default'].withSourceHandlers(Html5); 15355 15356 /* 15357 * The default native source handler. 15358 * This simply passes the source to the video element. Nothing fancy. 15359 * 15360 * @param {Object} source The source object 15361 * @param {Html5} tech The instance of the HTML5 tech 15362 */ 15363 Html5.nativeSourceHandler = {}; 15364 15365 /* 15366 * Check if the video element can play the given videotype 15367 * 15368 * @param {String} type The mimetype to check 15369 * @return {String} 'probably', 'maybe', or '' (empty string) 15370 */ 15371 Html5.nativeSourceHandler.canPlayType = function (type) { 15372 // IE9 on Windows 7 without MediaPlayer throws an error here 15373 // https://github.com/videojs/video.js/issues/519 15374 try { 15375 return Html5.TEST_VID.canPlayType(type); 15376 } catch (e) { 15377 return ''; 15378 } 15379 }; 15380 15381 /* 15382 * Check if the video element can handle the source natively 15383 * 15384 * @param {Object} source The source object 15385 * @return {String} 'probably', 'maybe', or '' (empty string) 15386 */ 15387 Html5.nativeSourceHandler.canHandleSource = function (source) { 15388 var match, ext; 15389 15390 // If a type was provided we should rely on that 15391 if (source.type) { 15392 return Html5.nativeSourceHandler.canPlayType(source.type); 15393 } else if (source.src) { 15394 // If no type, fall back to checking 'video/[EXTENSION]' 15395 ext = Url.getFileExtension(source.src); 15396 15397 return Html5.nativeSourceHandler.canPlayType('video/' + ext); 15398 } 15399 15400 return ''; 15401 }; 15402 15403 /* 15404 * Pass the source to the video element 15405 * Adaptive source handlers will have more complicated workflows before passing 15406 * video data to the video element 15407 * 15408 * @param {Object} source The source object 15409 * @param {Html5} tech The instance of the Html5 tech 15410 */ 15411 Html5.nativeSourceHandler.handleSource = function (source, tech) { 15412 tech.setSrc(source.src); 15413 }; 15414 15415 /* 15416 * Clean up the source handler when disposing the player or switching sources.. 15417 * (no cleanup is needed when supporting the format natively) 15418 */ 15419 Html5.nativeSourceHandler.dispose = function () {}; 15420 15421 // Register the native source handler 15422 Html5.registerSourceHandler(Html5.nativeSourceHandler); 15423 15424 /* 15425 * Check if the volume can be changed in this browser/device. 15426 * Volume cannot be changed in a lot of mobile devices. 15427 * Specifically, it can't be changed from 1 on iOS. 15428 * 15429 * @return {Boolean} 15430 */ 15431 Html5.canControlVolume = function () { 15432 var volume = Html5.TEST_VID.volume; 15433 Html5.TEST_VID.volume = volume / 2 + 0.1; 15434 return volume !== Html5.TEST_VID.volume; 15435 }; 15436 15437 /* 15438 * Check if playbackRate is supported in this browser/device. 15439 * 15440 * @return {Number} [description] 15441 */ 15442 Html5.canControlPlaybackRate = function () { 15443 var playbackRate = Html5.TEST_VID.playbackRate; 15444 Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1; 15445 return playbackRate !== Html5.TEST_VID.playbackRate; 15446 }; 15447 15448 /* 15449 * Check to see if native text tracks are supported by this browser/device 15450 * 15451 * @return {Boolean} 15452 */ 15453 Html5.supportsNativeTextTracks = function () { 15454 var supportsTextTracks; 15455 15456 // Figure out native text track support 15457 // If mode is a number, we cannot change it because it'll disappear from view. 15458 // Browsers with numeric modes include IE10 and older (<=2013) samsung android models. 15459 // Firefox isn't playing nice either with modifying the mode 15460 // TODO: Investigate firefox: https://github.com/videojs/video.js/issues/1862 15461 supportsTextTracks = !!Html5.TEST_VID.textTracks; 15462 if (supportsTextTracks && Html5.TEST_VID.textTracks.length > 0) { 15463 supportsTextTracks = typeof Html5.TEST_VID.textTracks[0]['mode'] !== 'number'; 15464 } 15465 if (supportsTextTracks && browser.IS_FIREFOX) { 15466 supportsTextTracks = false; 15467 } 15468 if (supportsTextTracks && !('onremovetrack' in Html5.TEST_VID.textTracks)) { 15469 supportsTextTracks = false; 15470 } 15471 15472 return supportsTextTracks; 15473 }; 15474 15475 /** 15476 * An array of events available on the Html5 tech. 15477 * 15478 * @private 15479 * @type {Array} 15480 */ 15481 Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange']; 15482 15483 /* 15484 * Set the tech's volume control support status 15485 * 15486 * @type {Boolean} 15487 */ 15488 Html5.prototype['featuresVolumeControl'] = Html5.canControlVolume(); 15489 15490 /* 15491 * Set the tech's playbackRate support status 15492 * 15493 * @type {Boolean} 15494 */ 15495 Html5.prototype['featuresPlaybackRate'] = Html5.canControlPlaybackRate(); 15496 15497 /* 15498 * Set the tech's status on moving the video element. 15499 * In iOS, if you move a video element in the DOM, it breaks video playback. 15500 * 15501 * @type {Boolean} 15502 */ 15503 Html5.prototype['movingMediaElementInDOM'] = !browser.IS_IOS; 15504 15505 /* 15506 * Set the the tech's fullscreen resize support status. 15507 * HTML video is able to automatically resize when going to fullscreen. 15508 * (No longer appears to be used. Can probably be removed.) 15509 */ 15510 Html5.prototype['featuresFullscreenResize'] = true; 15511 15512 /* 15513 * Set the tech's progress event support status 15514 * (this disables the manual progress events of the Tech) 15515 */ 15516 Html5.prototype['featuresProgressEvents'] = true; 15517 15518 /* 15519 * Sets the tech's status on native text track support 15520 * 15521 * @type {Boolean} 15522 */ 15523 Html5.prototype['featuresNativeTextTracks'] = Html5.supportsNativeTextTracks(); 15524 15525 // HTML5 Feature detection and Device Fixes --------------------------------- // 15526 var canPlayType = undefined; 15527 var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; 15528 var mp4RE = /^video\/mp4/i; 15529 15530 Html5.patchCanPlayType = function () { 15531 // Android 4.0 and above can play HLS to some extent but it reports being unable to do so 15532 if (browser.ANDROID_VERSION >= 4.0) { 15533 if (!canPlayType) { 15534 canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType; 15535 } 15536 15537 Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { 15538 if (type && mpegurlRE.test(type)) { 15539 return 'maybe'; 15540 } 15541 return canPlayType.call(this, type); 15542 }; 15543 } 15544 15545 // Override Android 2.2 and less canPlayType method which is broken 15546 if (browser.IS_OLD_ANDROID) { 15547 if (!canPlayType) { 15548 canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType; 15549 } 15550 15551 Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { 15552 if (type && mp4RE.test(type)) { 15553 return 'maybe'; 15554 } 15555 return canPlayType.call(this, type); 15556 }; 15557 } 15558 }; 15559 15560 Html5.unpatchCanPlayType = function () { 15561 var r = Html5.TEST_VID.constructor.prototype.canPlayType; 15562 Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType; 15563 canPlayType = null; 15564 return r; 15565 }; 15566 15567 // by default, patch the video element 15568 Html5.patchCanPlayType(); 15569 15570 Html5.disposeMediaElement = function (el) { 15571 if (!el) { 15572 return; 15573 } 15574 15575 if (el.parentNode) { 15576 el.parentNode.removeChild(el); 15577 } 15578 15579 // remove any child track or source nodes to prevent their loading 15580 while (el.hasChildNodes()) { 15581 el.removeChild(el.firstChild); 15582 } 15583 15584 // remove any src reference. not setting `src=''` because that causes a warning 15585 // in firefox 15586 el.removeAttribute('src'); 15587 15588 // force the media element to update its loading state by calling load() 15589 // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793) 15590 if (typeof el.load === 'function') { 15591 // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) 15592 (function () { 15593 try { 15594 el.load(); 15595 } catch (e) { 15596 // not supported 15597 } 15598 })(); 15599 } 15600 }; 15601 15602 Html5.resetMediaElement = function (el) { 15603 if (!el) { 15604 return; 15605 } 15606 15607 var sources = el.querySelectorAll('source'); 15608 var i = sources.length; 15609 while (i--) { 15610 el.removeChild(sources[i]); 15611 } 15612 15613 // remove any src reference. 15614 // not setting `src=''` because that throws an error 15615 el.removeAttribute('src'); 15616 15617 if (typeof el.load === 'function') { 15618 // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) 15619 (function () { 15620 try { 15621 el.load(); 15622 } catch (e) {} 15623 })(); 15624 } 15625 }; 15626 15627 _component2['default'].registerComponent('Html5', Html5); 15628 _techJs2['default'].registerTech('Html5', Html5); 15629 exports['default'] = Html5; 15630 module.exports = exports['default']; 15631 15632 },{"../component":67,"../utils/browser.js":131,"../utils/dom.js":134,"../utils/fn.js":136,"../utils/log.js":139,"../utils/merge-options.js":140,"../utils/url.js":144,"./tech.js":121,"global/document":1,"global/window":2,"object.assign":45}],120:[function(_dereq_,module,exports){ 15633 /** 15634 * @file loader.js 15635 */ 15636 'use strict'; 15637 15638 exports.__esModule = true; 15639 15640 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 15641 15642 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 15643 15644 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 15645 15646 var _componentJs = _dereq_('../component.js'); 15647 15648 var _componentJs2 = _interopRequireDefault(_componentJs); 15649 15650 var _techJs = _dereq_('./tech.js'); 15651 15652 var _techJs2 = _interopRequireDefault(_techJs); 15653 15654 var _globalWindow = _dereq_('global/window'); 15655 15656 var _globalWindow2 = _interopRequireDefault(_globalWindow); 15657 15658 var _utilsToTitleCaseJs = _dereq_('../utils/to-title-case.js'); 15659 15660 var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs); 15661 15662 /** 15663 * The Media Loader is the component that decides which playback technology to load 15664 * when the player is initialized. 15665 * 15666 * @param {Object} player Main Player 15667 * @param {Object=} options Object of option names and values 15668 * @param {Function=} ready Ready callback function 15669 * @extends Component 15670 * @class MediaLoader 15671 */ 15672 15673 var MediaLoader = (function (_Component) { 15674 _inherits(MediaLoader, _Component); 15675 15676 function MediaLoader(player, options, ready) { 15677 _classCallCheck(this, MediaLoader); 15678 15679 _Component.call(this, player, options, ready); 15680 15681 // If there are no sources when the player is initialized, 15682 // load the first supported playback technology. 15683 15684 if (!options.playerOptions['sources'] || options.playerOptions['sources'].length === 0) { 15685 for (var i = 0, j = options.playerOptions['techOrder']; i < j.length; i++) { 15686 var techName = _utilsToTitleCaseJs2['default'](j[i]); 15687 var tech = _techJs2['default'].getTech(techName); 15688 // Support old behavior of techs being registered as components. 15689 // Remove once that deprecated behavior is removed. 15690 if (!techName) { 15691 tech = _componentJs2['default'].getComponent(techName); 15692 } 15693 15694 // Check if the browser supports this technology 15695 if (tech && tech.isSupported()) { 15696 player.loadTech_(techName); 15697 break; 15698 } 15699 } 15700 } else { 15701 // // Loop through playback technologies (HTML5, Flash) and check for support. 15702 // // Then load the best source. 15703 // // A few assumptions here: 15704 // // All playback technologies respect preload false. 15705 player.src(options.playerOptions['sources']); 15706 } 15707 } 15708 15709 return MediaLoader; 15710 })(_componentJs2['default']); 15711 15712 _componentJs2['default'].registerComponent('MediaLoader', MediaLoader); 15713 exports['default'] = MediaLoader; 15714 module.exports = exports['default']; 15715 15716 },{"../component.js":67,"../utils/to-title-case.js":143,"./tech.js":121,"global/window":2}],121:[function(_dereq_,module,exports){ 15717 /** 15718 * @file tech.js 15719 * Media Technology Controller - Base class for media playback 15720 * technology controllers like Flash and HTML5 15721 */ 15722 15723 'use strict'; 15724 15725 exports.__esModule = true; 15726 15727 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 15728 15729 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 15730 15731 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 15732 15733 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 15734 15735 var _component = _dereq_('../component'); 15736 15737 var _component2 = _interopRequireDefault(_component); 15738 15739 var _tracksHtmlTrackElement = _dereq_('../tracks/html-track-element'); 15740 15741 var _tracksHtmlTrackElement2 = _interopRequireDefault(_tracksHtmlTrackElement); 15742 15743 var _tracksHtmlTrackElementList = _dereq_('../tracks/html-track-element-list'); 15744 15745 var _tracksHtmlTrackElementList2 = _interopRequireDefault(_tracksHtmlTrackElementList); 15746 15747 var _utilsMergeOptionsJs = _dereq_('../utils/merge-options.js'); 15748 15749 var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs); 15750 15751 var _tracksTextTrack = _dereq_('../tracks/text-track'); 15752 15753 var _tracksTextTrack2 = _interopRequireDefault(_tracksTextTrack); 15754 15755 var _tracksTextTrackList = _dereq_('../tracks/text-track-list'); 15756 15757 var _tracksTextTrackList2 = _interopRequireDefault(_tracksTextTrackList); 15758 15759 var _utilsFnJs = _dereq_('../utils/fn.js'); 15760 15761 var Fn = _interopRequireWildcard(_utilsFnJs); 15762 15763 var _utilsLogJs = _dereq_('../utils/log.js'); 15764 15765 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 15766 15767 var _utilsTimeRangesJs = _dereq_('../utils/time-ranges.js'); 15768 15769 var _utilsBufferJs = _dereq_('../utils/buffer.js'); 15770 15771 var _mediaErrorJs = _dereq_('../media-error.js'); 15772 15773 var _mediaErrorJs2 = _interopRequireDefault(_mediaErrorJs); 15774 15775 var _globalWindow = _dereq_('global/window'); 15776 15777 var _globalWindow2 = _interopRequireDefault(_globalWindow); 15778 15779 var _globalDocument = _dereq_('global/document'); 15780 15781 var _globalDocument2 = _interopRequireDefault(_globalDocument); 15782 15783 /** 15784 * Base class for media (HTML5 Video, Flash) controllers 15785 * 15786 * @param {Object=} options Options object 15787 * @param {Function=} ready Ready callback function 15788 * @extends Component 15789 * @class Tech 15790 */ 15791 15792 var Tech = (function (_Component) { 15793 _inherits(Tech, _Component); 15794 15795 function Tech() { 15796 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 15797 var ready = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1]; 15798 15799 _classCallCheck(this, Tech); 15800 15801 // we don't want the tech to report user activity automatically. 15802 // This is done manually in addControlsListeners 15803 options.reportTouchActivity = false; 15804 _Component.call(this, null, options, ready); 15805 15806 // keep track of whether the current source has played at all to 15807 // implement a very limited played() 15808 this.hasStarted_ = false; 15809 this.on('playing', function () { 15810 this.hasStarted_ = true; 15811 }); 15812 this.on('loadstart', function () { 15813 this.hasStarted_ = false; 15814 }); 15815 15816 this.textTracks_ = options.textTracks; 15817 15818 // Manually track progress in cases where the browser/flash player doesn't report it. 15819 if (!this.featuresProgressEvents) { 15820 this.manualProgressOn(); 15821 } 15822 15823 // Manually track timeupdates in cases where the browser/flash player doesn't report it. 15824 if (!this.featuresTimeupdateEvents) { 15825 this.manualTimeUpdatesOn(); 15826 } 15827 15828 if (options.nativeCaptions === false || options.nativeTextTracks === false) { 15829 this.featuresNativeTextTracks = false; 15830 } 15831 15832 if (!this.featuresNativeTextTracks) { 15833 this.on('ready', this.emulateTextTracks); 15834 } 15835 15836 this.initTextTrackListeners(); 15837 15838 // Turn on component tap events 15839 this.emitTapEvents(); 15840 } 15841 15842 /* 15843 * List of associated text tracks 15844 * 15845 * @type {Array} 15846 * @private 15847 */ 15848 15849 /* Fallbacks for unsupported event types 15850 ================================================================================ */ 15851 // Manually trigger progress events based on changes to the buffered amount 15852 // Many flash players and older HTML5 browsers don't send progress or progress-like events 15853 /** 15854 * Turn on progress events 15855 * 15856 * @method manualProgressOn 15857 */ 15858 15859 Tech.prototype.manualProgressOn = function manualProgressOn() { 15860 this.on('durationchange', this.onDurationChange); 15861 15862 this.manualProgress = true; 15863 15864 // Trigger progress watching when a source begins loading 15865 this.one('ready', this.trackProgress); 15866 }; 15867 15868 /** 15869 * Turn off progress events 15870 * 15871 * @method manualProgressOff 15872 */ 15873 15874 Tech.prototype.manualProgressOff = function manualProgressOff() { 15875 this.manualProgress = false; 15876 this.stopTrackingProgress(); 15877 15878 this.off('durationchange', this.onDurationChange); 15879 }; 15880 15881 /** 15882 * Track progress 15883 * 15884 * @method trackProgress 15885 */ 15886 15887 Tech.prototype.trackProgress = function trackProgress() { 15888 this.stopTrackingProgress(); 15889 this.progressInterval = this.setInterval(Fn.bind(this, function () { 15890 // Don't trigger unless buffered amount is greater than last time 15891 15892 var numBufferedPercent = this.bufferedPercent(); 15893 15894 if (this.bufferedPercent_ !== numBufferedPercent) { 15895 this.trigger('progress'); 15896 } 15897 15898 this.bufferedPercent_ = numBufferedPercent; 15899 15900 if (numBufferedPercent === 1) { 15901 this.stopTrackingProgress(); 15902 } 15903 }), 500); 15904 }; 15905 15906 /** 15907 * Update duration 15908 * 15909 * @method onDurationChange 15910 */ 15911 15912 Tech.prototype.onDurationChange = function onDurationChange() { 15913 this.duration_ = this.duration(); 15914 }; 15915 15916 /** 15917 * Create and get TimeRange object for buffering 15918 * 15919 * @return {TimeRangeObject} 15920 * @method buffered 15921 */ 15922 15923 Tech.prototype.buffered = function buffered() { 15924 return _utilsTimeRangesJs.createTimeRange(0, 0); 15925 }; 15926 15927 /** 15928 * Get buffered percent 15929 * 15930 * @return {Number} 15931 * @method bufferedPercent 15932 */ 15933 15934 Tech.prototype.bufferedPercent = function bufferedPercent() { 15935 return _utilsBufferJs.bufferedPercent(this.buffered(), this.duration_); 15936 }; 15937 15938 /** 15939 * Stops tracking progress by clearing progress interval 15940 * 15941 * @method stopTrackingProgress 15942 */ 15943 15944 Tech.prototype.stopTrackingProgress = function stopTrackingProgress() { 15945 this.clearInterval(this.progressInterval); 15946 }; 15947 15948 /*! Time Tracking -------------------------------------------------------------- */ 15949 /** 15950 * Set event listeners for on play and pause and tracking current time 15951 * 15952 * @method manualTimeUpdatesOn 15953 */ 15954 15955 Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() { 15956 this.manualTimeUpdates = true; 15957 15958 this.on('play', this.trackCurrentTime); 15959 this.on('pause', this.stopTrackingCurrentTime); 15960 }; 15961 15962 /** 15963 * Remove event listeners for on play and pause and tracking current time 15964 * 15965 * @method manualTimeUpdatesOff 15966 */ 15967 15968 Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() { 15969 this.manualTimeUpdates = false; 15970 this.stopTrackingCurrentTime(); 15971 this.off('play', this.trackCurrentTime); 15972 this.off('pause', this.stopTrackingCurrentTime); 15973 }; 15974 15975 /** 15976 * Tracks current time 15977 * 15978 * @method trackCurrentTime 15979 */ 15980 15981 Tech.prototype.trackCurrentTime = function trackCurrentTime() { 15982 if (this.currentTimeInterval) { 15983 this.stopTrackingCurrentTime(); 15984 } 15985 this.currentTimeInterval = this.setInterval(function () { 15986 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); 15987 }, 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 15988 }; 15989 15990 /** 15991 * Turn off play progress tracking (when paused or dragging) 15992 * 15993 * @method stopTrackingCurrentTime 15994 */ 15995 15996 Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() { 15997 this.clearInterval(this.currentTimeInterval); 15998 15999 // #1002 - if the video ends right before the next timeupdate would happen, 16000 // the progress bar won't make it all the way to the end 16001 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); 16002 }; 16003 16004 /** 16005 * Turn off any manual progress or timeupdate tracking 16006 * 16007 * @method dispose 16008 */ 16009 16010 Tech.prototype.dispose = function dispose() { 16011 // clear out text tracks because we can't reuse them between techs 16012 var textTracks = this.textTracks(); 16013 16014 if (textTracks) { 16015 var i = textTracks.length; 16016 while (i--) { 16017 this.removeRemoteTextTrack(textTracks[i]); 16018 } 16019 } 16020 16021 // Turn off any manual progress or timeupdate tracking 16022 if (this.manualProgress) { 16023 this.manualProgressOff(); 16024 } 16025 16026 if (this.manualTimeUpdates) { 16027 this.manualTimeUpdatesOff(); 16028 } 16029 16030 _Component.prototype.dispose.call(this); 16031 }; 16032 16033 /** 16034 * Reset the tech. Removes all sources and resets readyState. 16035 * 16036 * @method reset 16037 */ 16038 16039 Tech.prototype.reset = function reset() {}; 16040 16041 /** 16042 * When invoked without an argument, returns a MediaError object 16043 * representing the current error state of the player or null if 16044 * there is no error. When invoked with an argument, set the current 16045 * error state of the player. 16046 * @param {MediaError=} err Optional an error object 16047 * @return {MediaError} the current error object or null 16048 * @method error 16049 */ 16050 16051 Tech.prototype.error = function error(err) { 16052 if (err !== undefined) { 16053 if (err instanceof _mediaErrorJs2['default']) { 16054 this.error_ = err; 16055 } else { 16056 this.error_ = new _mediaErrorJs2['default'](err); 16057 } 16058 this.trigger('error'); 16059 } 16060 return this.error_; 16061 }; 16062 16063 /** 16064 * Return the time ranges that have been played through for the 16065 * current source. This implementation is incomplete. It does not 16066 * track the played time ranges, only whether the source has played 16067 * at all or not. 16068 * @return {TimeRangeObject} a single time range if this video has 16069 * played or an empty set of ranges if not. 16070 * @method played 16071 */ 16072 16073 Tech.prototype.played = function played() { 16074 if (this.hasStarted_) { 16075 return _utilsTimeRangesJs.createTimeRange(0, 0); 16076 } 16077 return _utilsTimeRangesJs.createTimeRange(); 16078 }; 16079 16080 /** 16081 * Set current time 16082 * 16083 * @method setCurrentTime 16084 */ 16085 16086 Tech.prototype.setCurrentTime = function setCurrentTime() { 16087 // improve the accuracy of manual timeupdates 16088 if (this.manualTimeUpdates) { 16089 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); 16090 } 16091 }; 16092 16093 /** 16094 * Initialize texttrack listeners 16095 * 16096 * @method initTextTrackListeners 16097 */ 16098 16099 Tech.prototype.initTextTrackListeners = function initTextTrackListeners() { 16100 var textTrackListChanges = Fn.bind(this, function () { 16101 this.trigger('texttrackchange'); 16102 }); 16103 16104 var tracks = this.textTracks(); 16105 16106 if (!tracks) return; 16107 16108 tracks.addEventListener('removetrack', textTrackListChanges); 16109 tracks.addEventListener('addtrack', textTrackListChanges); 16110 16111 this.on('dispose', Fn.bind(this, function () { 16112 tracks.removeEventListener('removetrack', textTrackListChanges); 16113 tracks.removeEventListener('addtrack', textTrackListChanges); 16114 })); 16115 }; 16116 16117 /** 16118 * Emulate texttracks 16119 * 16120 * @method emulateTextTracks 16121 */ 16122 16123 Tech.prototype.emulateTextTracks = function emulateTextTracks() { 16124 var _this = this; 16125 16126 var tracks = this.textTracks(); 16127 if (!tracks) { 16128 return; 16129 } 16130 16131 if (!_globalWindow2['default']['WebVTT'] && this.el().parentNode != null) { 16132 (function () { 16133 var script = _globalDocument2['default'].createElement('script'); 16134 script.src = _this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js'; 16135 script.onload = function () { 16136 _this.trigger('vttjsloaded'); 16137 }; 16138 script.onerror = function () { 16139 _this.trigger('vttjserror'); 16140 }; 16141 _this.on('dispose', function () { 16142 script.onload = null; 16143 script.onerror = null; 16144 }); 16145 _this.el().parentNode.appendChild(script); 16146 _globalWindow2['default']['WebVTT'] = true; 16147 })(); 16148 } 16149 16150 var updateDisplay = function updateDisplay() { 16151 return _this.trigger('texttrackchange'); 16152 }; 16153 var textTracksChanges = function textTracksChanges() { 16154 updateDisplay(); 16155 16156 for (var i = 0; i < tracks.length; i++) { 16157 var track = tracks[i]; 16158 track.removeEventListener('cuechange', updateDisplay); 16159 if (track.mode === 'showing') { 16160 track.addEventListener('cuechange', updateDisplay); 16161 } 16162 } 16163 }; 16164 16165 textTracksChanges(); 16166 tracks.addEventListener('change', textTracksChanges); 16167 16168 this.on('dispose', function () { 16169 tracks.removeEventListener('change', textTracksChanges); 16170 }); 16171 }; 16172 16173 /* 16174 * Provide default methods for text tracks. 16175 * 16176 * Html5 tech overrides these. 16177 */ 16178 16179 /** 16180 * Get texttracks 16181 * 16182 * @returns {TextTrackList} 16183 * @method textTracks 16184 */ 16185 16186 Tech.prototype.textTracks = function textTracks() { 16187 this.textTracks_ = this.textTracks_ || new _tracksTextTrackList2['default'](); 16188 return this.textTracks_; 16189 }; 16190 16191 /** 16192 * Get remote texttracks 16193 * 16194 * @returns {TextTrackList} 16195 * @method remoteTextTracks 16196 */ 16197 16198 Tech.prototype.remoteTextTracks = function remoteTextTracks() { 16199 this.remoteTextTracks_ = this.remoteTextTracks_ || new _tracksTextTrackList2['default'](); 16200 return this.remoteTextTracks_; 16201 }; 16202 16203 /** 16204 * Get remote htmltrackelements 16205 * 16206 * @returns {HTMLTrackElementList} 16207 * @method remoteTextTrackEls 16208 */ 16209 16210 Tech.prototype.remoteTextTrackEls = function remoteTextTrackEls() { 16211 this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new _tracksHtmlTrackElementList2['default'](); 16212 return this.remoteTextTrackEls_; 16213 }; 16214 16215 /** 16216 * Creates and returns a remote text track object 16217 * 16218 * @param {String} kind Text track kind (subtitles, captions, descriptions 16219 * chapters and metadata) 16220 * @param {String=} label Label to identify the text track 16221 * @param {String=} language Two letter language abbreviation 16222 * @return {TextTrackObject} 16223 * @method addTextTrack 16224 */ 16225 16226 Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) { 16227 if (!kind) { 16228 throw new Error('TextTrack kind is required but was not provided'); 16229 } 16230 16231 return createTrackHelper(this, kind, label, language); 16232 }; 16233 16234 /** 16235 * Creates a remote text track object and returns a emulated html track element 16236 * 16237 * @param {Object} options The object should contain values for 16238 * kind, language, label and src (location of the WebVTT file) 16239 * @return {HTMLTrackElement} 16240 * @method addRemoteTextTrack 16241 */ 16242 16243 Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack(options) { 16244 var track = _utilsMergeOptionsJs2['default'](options, { 16245 tech: this 16246 }); 16247 16248 var htmlTrackElement = new _tracksHtmlTrackElement2['default'](track); 16249 16250 // store HTMLTrackElement and TextTrack to remote list 16251 this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); 16252 this.remoteTextTracks().addTrack_(htmlTrackElement.track); 16253 16254 // must come after remoteTextTracks() 16255 this.textTracks().addTrack_(htmlTrackElement.track); 16256 16257 return htmlTrackElement; 16258 }; 16259 16260 /** 16261 * Remove remote texttrack 16262 * 16263 * @param {TextTrackObject} track Texttrack to remove 16264 * @method removeRemoteTextTrack 16265 */ 16266 16267 Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { 16268 this.textTracks().removeTrack_(track); 16269 16270 var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); 16271 16272 // remove HTMLTrackElement and TextTrack from remote list 16273 this.remoteTextTrackEls().removeTrackElement_(trackElement); 16274 this.remoteTextTracks().removeTrack_(track); 16275 }; 16276 16277 /** 16278 * Provide a default setPoster method for techs 16279 * Poster support for techs should be optional, so we don't want techs to 16280 * break if they don't have a way to set a poster. 16281 * 16282 * @method setPoster 16283 */ 16284 16285 Tech.prototype.setPoster = function setPoster() {}; 16286 16287 /* 16288 * Check if the tech can support the given type 16289 * 16290 * The base tech does not support any type, but source handlers might 16291 * overwrite this. 16292 * 16293 * @param {String} type The mimetype to check 16294 * @return {String} 'probably', 'maybe', or '' (empty string) 16295 */ 16296 16297 Tech.prototype.canPlayType = function canPlayType() { 16298 return ''; 16299 }; 16300 16301 /* 16302 * Return whether the argument is a Tech or not. 16303 * Can be passed either a Class like `Html5` or a instance like `player.tech_` 16304 * 16305 * @param {Object} component An item to check 16306 * @return {Boolean} Whether it is a tech or not 16307 */ 16308 16309 Tech.isTech = function isTech(component) { 16310 return component.prototype instanceof Tech || component instanceof Tech || component === Tech; 16311 }; 16312 16313 /** 16314 * Registers a Tech 16315 * 16316 * @param {String} name Name of the Tech to register 16317 * @param {Object} tech The tech to register 16318 * @static 16319 * @method registerComponent 16320 */ 16321 16322 Tech.registerTech = function registerTech(name, tech) { 16323 if (!Tech.techs_) { 16324 Tech.techs_ = {}; 16325 } 16326 16327 if (!Tech.isTech(tech)) { 16328 throw new Error('Tech ' + name + ' must be a Tech'); 16329 } 16330 16331 Tech.techs_[name] = tech; 16332 return tech; 16333 }; 16334 16335 /** 16336 * Gets a component by name 16337 * 16338 * @param {String} name Name of the component to get 16339 * @return {Component} 16340 * @static 16341 * @method getComponent 16342 */ 16343 16344 Tech.getTech = function getTech(name) { 16345 if (Tech.techs_ && Tech.techs_[name]) { 16346 return Tech.techs_[name]; 16347 } 16348 16349 if (_globalWindow2['default'] && _globalWindow2['default'].videojs && _globalWindow2['default'].videojs[name]) { 16350 _utilsLogJs2['default'].warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)'); 16351 return _globalWindow2['default'].videojs[name]; 16352 } 16353 }; 16354 16355 return Tech; 16356 })(_component2['default']); 16357 16358 Tech.prototype.textTracks_; 16359 16360 var createTrackHelper = function createTrackHelper(self, kind, label, language) { 16361 var options = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4]; 16362 16363 var tracks = self.textTracks(); 16364 16365 options.kind = kind; 16366 16367 if (label) { 16368 options.label = label; 16369 } 16370 if (language) { 16371 options.language = language; 16372 } 16373 options.tech = self; 16374 16375 var track = new _tracksTextTrack2['default'](options); 16376 tracks.addTrack_(track); 16377 16378 return track; 16379 }; 16380 16381 Tech.prototype.featuresVolumeControl = true; 16382 16383 // Resizing plugins using request fullscreen reloads the plugin 16384 Tech.prototype.featuresFullscreenResize = false; 16385 Tech.prototype.featuresPlaybackRate = false; 16386 16387 // Optional events that we can manually mimic with timers 16388 // currently not triggered by video-js-swf 16389 Tech.prototype.featuresProgressEvents = false; 16390 Tech.prototype.featuresTimeupdateEvents = false; 16391 16392 Tech.prototype.featuresNativeTextTracks = false; 16393 16394 /* 16395 * A functional mixin for techs that want to use the Source Handler pattern. 16396 * 16397 * ##### EXAMPLE: 16398 * 16399 * Tech.withSourceHandlers.call(MyTech); 16400 * 16401 */ 16402 Tech.withSourceHandlers = function (_Tech) { 16403 /* 16404 * Register a source handler 16405 * Source handlers are scripts for handling specific formats. 16406 * The source handler pattern is used for adaptive formats (HLS, DASH) that 16407 * manually load video data and feed it into a Source Buffer (Media Source Extensions) 16408 * @param {Function} handler The source handler 16409 * @param {Boolean} first Register it before any existing handlers 16410 */ 16411 _Tech.registerSourceHandler = function (handler, index) { 16412 var handlers = _Tech.sourceHandlers; 16413 16414 if (!handlers) { 16415 handlers = _Tech.sourceHandlers = []; 16416 } 16417 16418 if (index === undefined) { 16419 // add to the end of the list 16420 index = handlers.length; 16421 } 16422 16423 handlers.splice(index, 0, handler); 16424 }; 16425 16426 /* 16427 * Check if the tech can support the given type 16428 * @param {String} type The mimetype to check 16429 * @return {String} 'probably', 'maybe', or '' (empty string) 16430 */ 16431 _Tech.canPlayType = function (type) { 16432 var handlers = _Tech.sourceHandlers || []; 16433 var can = undefined; 16434 16435 for (var i = 0; i < handlers.length; i++) { 16436 can = handlers[i].canPlayType(type); 16437 16438 if (can) { 16439 return can; 16440 } 16441 } 16442 16443 return ''; 16444 }; 16445 16446 /* 16447 * Return the first source handler that supports the source 16448 * TODO: Answer question: should 'probably' be prioritized over 'maybe' 16449 * @param {Object} source The source object 16450 * @returns {Object} The first source handler that supports the source 16451 * @returns {null} Null if no source handler is found 16452 */ 16453 _Tech.selectSourceHandler = function (source) { 16454 var handlers = _Tech.sourceHandlers || []; 16455 var can = undefined; 16456 16457 for (var i = 0; i < handlers.length; i++) { 16458 can = handlers[i].canHandleSource(source); 16459 16460 if (can) { 16461 return handlers[i]; 16462 } 16463 } 16464 16465 return null; 16466 }; 16467 16468 /* 16469 * Check if the tech can support the given source 16470 * @param {Object} srcObj The source object 16471 * @return {String} 'probably', 'maybe', or '' (empty string) 16472 */ 16473 _Tech.canPlaySource = function (srcObj) { 16474 var sh = _Tech.selectSourceHandler(srcObj); 16475 16476 if (sh) { 16477 return sh.canHandleSource(srcObj); 16478 } 16479 16480 return ''; 16481 }; 16482 16483 /* 16484 * When using a source handler, prefer its implementation of 16485 * any function normally provided by the tech. 16486 */ 16487 var deferrable = ['seekable', 'duration']; 16488 16489 deferrable.forEach(function (fnName) { 16490 var originalFn = this[fnName]; 16491 16492 if (typeof originalFn !== 'function') { 16493 return; 16494 } 16495 16496 this[fnName] = function () { 16497 if (this.sourceHandler_ && this.sourceHandler_[fnName]) { 16498 return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments); 16499 } 16500 return originalFn.apply(this, arguments); 16501 }; 16502 }, _Tech.prototype); 16503 16504 /* 16505 * Create a function for setting the source using a source object 16506 * and source handlers. 16507 * Should never be called unless a source handler was found. 16508 * @param {Object} source A source object with src and type keys 16509 * @return {Tech} self 16510 */ 16511 _Tech.prototype.setSource = function (source) { 16512 var sh = _Tech.selectSourceHandler(source); 16513 16514 if (!sh) { 16515 // Fall back to a native source hander when unsupported sources are 16516 // deliberately set 16517 if (_Tech.nativeSourceHandler) { 16518 sh = _Tech.nativeSourceHandler; 16519 } else { 16520 _utilsLogJs2['default'].error('No source hander found for the current source.'); 16521 } 16522 } 16523 16524 // Dispose any existing source handler 16525 this.disposeSourceHandler(); 16526 this.off('dispose', this.disposeSourceHandler); 16527 16528 this.currentSource_ = source; 16529 this.sourceHandler_ = sh.handleSource(source, this); 16530 this.on('dispose', this.disposeSourceHandler); 16531 16532 return this; 16533 }; 16534 16535 /* 16536 * Clean up any existing source handler 16537 */ 16538 _Tech.prototype.disposeSourceHandler = function () { 16539 if (this.sourceHandler_ && this.sourceHandler_.dispose) { 16540 this.sourceHandler_.dispose(); 16541 } 16542 }; 16543 }; 16544 16545 _component2['default'].registerComponent('Tech', Tech); 16546 // Old name for Tech 16547 _component2['default'].registerComponent('MediaTechController', Tech); 16548 Tech.registerTech('Tech', Tech); 16549 exports['default'] = Tech; 16550 module.exports = exports['default']; 16551 16552 },{"../component":67,"../media-error.js":105,"../tracks/html-track-element":123,"../tracks/html-track-element-list":122,"../tracks/text-track":130,"../tracks/text-track-list":128,"../utils/buffer.js":132,"../utils/fn.js":136,"../utils/log.js":139,"../utils/merge-options.js":140,"../utils/time-ranges.js":142,"global/document":1,"global/window":2}],122:[function(_dereq_,module,exports){ 16553 /** 16554 * @file html-track-element-list.js 16555 */ 16556 16557 'use strict'; 16558 16559 exports.__esModule = true; 16560 16561 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 16562 16563 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 16564 16565 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 16566 16567 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 16568 16569 var browser = _interopRequireWildcard(_utilsBrowserJs); 16570 16571 var _globalDocument = _dereq_('global/document'); 16572 16573 var _globalDocument2 = _interopRequireDefault(_globalDocument); 16574 16575 var HtmlTrackElementList = (function () { 16576 function HtmlTrackElementList() { 16577 var trackElements = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; 16578 16579 _classCallCheck(this, HtmlTrackElementList); 16580 16581 var list = this; 16582 16583 if (browser.IS_IE8) { 16584 list = _globalDocument2['default'].createElement('custom'); 16585 16586 for (var prop in HtmlTrackElementList.prototype) { 16587 if (prop !== 'constructor') { 16588 list[prop] = HtmlTrackElementList.prototype[prop]; 16589 } 16590 } 16591 } 16592 16593 list.trackElements_ = []; 16594 16595 Object.defineProperty(list, 'length', { 16596 get: function get() { 16597 return this.trackElements_.length; 16598 } 16599 }); 16600 16601 for (var i = 0, _length = trackElements.length; i < _length; i++) { 16602 list.addTrackElement_(trackElements[i]); 16603 } 16604 16605 if (browser.IS_IE8) { 16606 return list; 16607 } 16608 } 16609 16610 HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) { 16611 this.trackElements_.push(trackElement); 16612 }; 16613 16614 HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) { 16615 var trackElement_ = undefined; 16616 16617 for (var i = 0, _length2 = this.trackElements_.length; i < _length2; i++) { 16618 if (track === this.trackElements_[i].track) { 16619 trackElement_ = this.trackElements_[i]; 16620 16621 break; 16622 } 16623 } 16624 16625 return trackElement_; 16626 }; 16627 16628 HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) { 16629 for (var i = 0, _length3 = this.trackElements_.length; i < _length3; i++) { 16630 if (trackElement === this.trackElements_[i]) { 16631 this.trackElements_.splice(i, 1); 16632 16633 break; 16634 } 16635 } 16636 }; 16637 16638 return HtmlTrackElementList; 16639 })(); 16640 16641 exports['default'] = HtmlTrackElementList; 16642 module.exports = exports['default']; 16643 16644 },{"../utils/browser.js":131,"global/document":1}],123:[function(_dereq_,module,exports){ 16645 /** 16646 * @file html-track-element.js 16647 */ 16648 16649 'use strict'; 16650 16651 exports.__esModule = true; 16652 16653 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 16654 16655 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 16656 16657 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 16658 16659 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16660 16661 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 16662 16663 var browser = _interopRequireWildcard(_utilsBrowserJs); 16664 16665 var _globalDocument = _dereq_('global/document'); 16666 16667 var _globalDocument2 = _interopRequireDefault(_globalDocument); 16668 16669 var _eventTarget = _dereq_('../event-target'); 16670 16671 var _eventTarget2 = _interopRequireDefault(_eventTarget); 16672 16673 var _tracksTextTrack = _dereq_('../tracks/text-track'); 16674 16675 var _tracksTextTrack2 = _interopRequireDefault(_tracksTextTrack); 16676 16677 var NONE = 0; 16678 var LOADING = 1; 16679 var LOADED = 2; 16680 var ERROR = 3; 16681 16682 /** 16683 * https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement 16684 * 16685 * interface HTMLTrackElement : HTMLElement { 16686 * attribute DOMString kind; 16687 * attribute DOMString src; 16688 * attribute DOMString srclang; 16689 * attribute DOMString label; 16690 * attribute boolean default; 16691 * 16692 * const unsigned short NONE = 0; 16693 * const unsigned short LOADING = 1; 16694 * const unsigned short LOADED = 2; 16695 * const unsigned short ERROR = 3; 16696 * readonly attribute unsigned short readyState; 16697 * 16698 * readonly attribute TextTrack track; 16699 * }; 16700 * 16701 * @param {Object} options TextTrack configuration 16702 * @class HTMLTrackElement 16703 */ 16704 16705 var HTMLTrackElement = (function (_EventTarget) { 16706 _inherits(HTMLTrackElement, _EventTarget); 16707 16708 function HTMLTrackElement() { 16709 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 16710 16711 _classCallCheck(this, HTMLTrackElement); 16712 16713 _EventTarget.call(this); 16714 16715 var readyState = undefined, 16716 trackElement = this; 16717 16718 if (browser.IS_IE8) { 16719 trackElement = _globalDocument2['default'].createElement('custom'); 16720 16721 for (var prop in HTMLTrackElement.prototype) { 16722 if (prop !== 'constructor') { 16723 trackElement[prop] = HTMLTrackElement.prototype[prop]; 16724 } 16725 } 16726 } 16727 16728 var track = new _tracksTextTrack2['default'](options); 16729 16730 trackElement.kind = track.kind; 16731 trackElement.src = track.src; 16732 trackElement.srclang = track.language; 16733 trackElement.label = track.label; 16734 trackElement['default'] = track['default']; 16735 16736 Object.defineProperty(trackElement, 'readyState', { 16737 get: function get() { 16738 return readyState; 16739 } 16740 }); 16741 16742 Object.defineProperty(trackElement, 'track', { 16743 get: function get() { 16744 return track; 16745 } 16746 }); 16747 16748 readyState = NONE; 16749 16750 track.addEventListener('loadeddata', function () { 16751 readyState = LOADED; 16752 16753 trackElement.trigger({ 16754 type: 'load', 16755 target: trackElement 16756 }); 16757 }); 16758 16759 if (browser.IS_IE8) { 16760 return trackElement; 16761 } 16762 } 16763 16764 return HTMLTrackElement; 16765 })(_eventTarget2['default']); 16766 16767 HTMLTrackElement.prototype.allowedEvents_ = { 16768 load: 'load' 16769 }; 16770 16771 HTMLTrackElement.NONE = NONE; 16772 HTMLTrackElement.LOADING = LOADING; 16773 HTMLTrackElement.LOADED = LOADED; 16774 HTMLTrackElement.ERROR = ERROR; 16775 16776 exports['default'] = HTMLTrackElement; 16777 module.exports = exports['default']; 16778 16779 },{"../event-target":101,"../tracks/text-track":130,"../utils/browser.js":131,"global/document":1}],124:[function(_dereq_,module,exports){ 16780 /** 16781 * @file text-track-cue-list.js 16782 */ 16783 'use strict'; 16784 16785 exports.__esModule = true; 16786 16787 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 16788 16789 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 16790 16791 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 16792 16793 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 16794 16795 var browser = _interopRequireWildcard(_utilsBrowserJs); 16796 16797 var _globalDocument = _dereq_('global/document'); 16798 16799 var _globalDocument2 = _interopRequireDefault(_globalDocument); 16800 16801 /** 16802 * A List of text track cues as defined in: 16803 * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist 16804 * 16805 * interface TextTrackCueList { 16806 * readonly attribute unsigned long length; 16807 * getter TextTrackCue (unsigned long index); 16808 * TextTrackCue? getCueById(DOMString id); 16809 * }; 16810 * 16811 * @param {Array} cues A list of cues to be initialized with 16812 * @class TextTrackCueList 16813 */ 16814 16815 var TextTrackCueList = (function () { 16816 function TextTrackCueList(cues) { 16817 _classCallCheck(this, TextTrackCueList); 16818 16819 var list = this; 16820 16821 if (browser.IS_IE8) { 16822 list = _globalDocument2['default'].createElement('custom'); 16823 16824 for (var prop in TextTrackCueList.prototype) { 16825 if (prop !== 'constructor') { 16826 list[prop] = TextTrackCueList.prototype[prop]; 16827 } 16828 } 16829 } 16830 16831 TextTrackCueList.prototype.setCues_.call(list, cues); 16832 16833 Object.defineProperty(list, 'length', { 16834 get: function get() { 16835 return this.length_; 16836 } 16837 }); 16838 16839 if (browser.IS_IE8) { 16840 return list; 16841 } 16842 } 16843 16844 /** 16845 * A setter for cues in this list 16846 * 16847 * @param {Array} cues an array of cues 16848 * @method setCues_ 16849 * @private 16850 */ 16851 16852 TextTrackCueList.prototype.setCues_ = function setCues_(cues) { 16853 var oldLength = this.length || 0; 16854 var i = 0; 16855 var l = cues.length; 16856 16857 this.cues_ = cues; 16858 this.length_ = cues.length; 16859 16860 var defineProp = function defineProp(index) { 16861 if (!('' + index in this)) { 16862 Object.defineProperty(this, '' + index, { 16863 get: function get() { 16864 return this.cues_[index]; 16865 } 16866 }); 16867 } 16868 }; 16869 16870 if (oldLength < l) { 16871 i = oldLength; 16872 16873 for (; i < l; i++) { 16874 defineProp.call(this, i); 16875 } 16876 } 16877 }; 16878 16879 /** 16880 * Get a cue that is currently in the Cue list by id 16881 * 16882 * @param {String} id 16883 * @method getCueById 16884 * @return {Object} a single cue 16885 */ 16886 16887 TextTrackCueList.prototype.getCueById = function getCueById(id) { 16888 var result = null; 16889 16890 for (var i = 0, l = this.length; i < l; i++) { 16891 var cue = this[i]; 16892 16893 if (cue.id === id) { 16894 result = cue; 16895 break; 16896 } 16897 } 16898 16899 return result; 16900 }; 16901 16902 return TextTrackCueList; 16903 })(); 16904 16905 exports['default'] = TextTrackCueList; 16906 module.exports = exports['default']; 16907 16908 },{"../utils/browser.js":131,"global/document":1}],125:[function(_dereq_,module,exports){ 16909 /** 16910 * @file text-track-display.js 16911 */ 16912 'use strict'; 16913 16914 exports.__esModule = true; 16915 16916 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 16917 16918 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 16919 16920 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 16921 16922 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16923 16924 var _component = _dereq_('../component'); 16925 16926 var _component2 = _interopRequireDefault(_component); 16927 16928 var _menuMenuJs = _dereq_('../menu/menu.js'); 16929 16930 var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs); 16931 16932 var _menuMenuItemJs = _dereq_('../menu/menu-item.js'); 16933 16934 var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs); 16935 16936 var _menuMenuButtonJs = _dereq_('../menu/menu-button.js'); 16937 16938 var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs); 16939 16940 var _utilsFnJs = _dereq_('../utils/fn.js'); 16941 16942 var Fn = _interopRequireWildcard(_utilsFnJs); 16943 16944 var _globalDocument = _dereq_('global/document'); 16945 16946 var _globalDocument2 = _interopRequireDefault(_globalDocument); 16947 16948 var _globalWindow = _dereq_('global/window'); 16949 16950 var _globalWindow2 = _interopRequireDefault(_globalWindow); 16951 16952 var darkGray = '#222'; 16953 var lightGray = '#ccc'; 16954 var fontMap = { 16955 monospace: 'monospace', 16956 sansSerif: 'sans-serif', 16957 serif: 'serif', 16958 monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace', 16959 monospaceSerif: '"Courier New", monospace', 16960 proportionalSansSerif: 'sans-serif', 16961 proportionalSerif: 'serif', 16962 casual: '"Comic Sans MS", Impact, fantasy', 16963 script: '"Monotype Corsiva", cursive', 16964 smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif' 16965 }; 16966 16967 /** 16968 * The component for displaying text track cues 16969 * 16970 * @param {Object} player Main Player 16971 * @param {Object=} options Object of option names and values 16972 * @param {Function=} ready Ready callback function 16973 * @extends Component 16974 * @class TextTrackDisplay 16975 */ 16976 16977 var TextTrackDisplay = (function (_Component) { 16978 _inherits(TextTrackDisplay, _Component); 16979 16980 function TextTrackDisplay(player, options, ready) { 16981 _classCallCheck(this, TextTrackDisplay); 16982 16983 _Component.call(this, player, options, ready); 16984 16985 player.on('loadstart', Fn.bind(this, this.toggleDisplay)); 16986 player.on('texttrackchange', Fn.bind(this, this.updateDisplay)); 16987 16988 // This used to be called during player init, but was causing an error 16989 // if a track should show by default and the display hadn't loaded yet. 16990 // Should probably be moved to an external track loader when we support 16991 // tracks that don't need a display. 16992 player.ready(Fn.bind(this, function () { 16993 if (player.tech_ && player.tech_['featuresNativeTextTracks']) { 16994 this.hide(); 16995 return; 16996 } 16997 16998 player.on('fullscreenchange', Fn.bind(this, this.updateDisplay)); 16999 17000 var tracks = this.options_.playerOptions['tracks'] || []; 17001 for (var i = 0; i < tracks.length; i++) { 17002 var track = tracks[i]; 17003 this.player_.addRemoteTextTrack(track); 17004 } 17005 })); 17006 } 17007 17008 /** 17009 * Add cue HTML to display 17010 * 17011 * @param {Number} color Hex number for color, like #f0e 17012 * @param {Number} opacity Value for opacity,0.0 - 1.0 17013 * @return {RGBAColor} In the form 'rgba(255, 0, 0, 0.3)' 17014 * @method constructColor 17015 */ 17016 17017 /** 17018 * Toggle display texttracks 17019 * 17020 * @method toggleDisplay 17021 */ 17022 17023 TextTrackDisplay.prototype.toggleDisplay = function toggleDisplay() { 17024 if (this.player_.tech_ && this.player_.tech_['featuresNativeTextTracks']) { 17025 this.hide(); 17026 } else { 17027 this.show(); 17028 } 17029 }; 17030 17031 /** 17032 * Create the component's DOM element 17033 * 17034 * @return {Element} 17035 * @method createEl 17036 */ 17037 17038 TextTrackDisplay.prototype.createEl = function createEl() { 17039 return _Component.prototype.createEl.call(this, 'div', { 17040 className: 'vjs-text-track-display' 17041 }, { 17042 'aria-live': 'assertive', 17043 'aria-atomic': 'true' 17044 }); 17045 }; 17046 17047 /** 17048 * Clear display texttracks 17049 * 17050 * @method clearDisplay 17051 */ 17052 17053 TextTrackDisplay.prototype.clearDisplay = function clearDisplay() { 17054 if (typeof _globalWindow2['default']['WebVTT'] === 'function') { 17055 _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], [], this.el_); 17056 } 17057 }; 17058 17059 /** 17060 * Update display texttracks 17061 * 17062 * @method updateDisplay 17063 */ 17064 17065 TextTrackDisplay.prototype.updateDisplay = function updateDisplay() { 17066 var tracks = this.player_.textTracks(); 17067 17068 this.clearDisplay(); 17069 17070 if (!tracks) { 17071 return; 17072 } 17073 17074 // Track display prioritization model: if multiple tracks are 'showing', 17075 // display the first 'subtitles' or 'captions' track which is 'showing', 17076 // otherwise display the first 'descriptions' track which is 'showing' 17077 17078 var descriptionsTrack = null; 17079 var captionsSubtitlesTrack = null; 17080 17081 var i = tracks.length; 17082 while (i--) { 17083 var track = tracks[i]; 17084 if (track['mode'] === 'showing') { 17085 if (track['kind'] === 'descriptions') { 17086 descriptionsTrack = track; 17087 } else { 17088 captionsSubtitlesTrack = track; 17089 } 17090 } 17091 } 17092 17093 if (captionsSubtitlesTrack) { 17094 this.updateForTrack(captionsSubtitlesTrack); 17095 } else if (descriptionsTrack) { 17096 this.updateForTrack(descriptionsTrack); 17097 } 17098 }; 17099 17100 /** 17101 * Add texttrack to texttrack list 17102 * 17103 * @param {TextTrackObject} track Texttrack object to be added to list 17104 * @method updateForTrack 17105 */ 17106 17107 TextTrackDisplay.prototype.updateForTrack = function updateForTrack(track) { 17108 if (typeof _globalWindow2['default']['WebVTT'] !== 'function' || !track['activeCues']) { 17109 return; 17110 } 17111 17112 var overrides = this.player_['textTrackSettings'].getValues(); 17113 17114 var cues = []; 17115 for (var _i = 0; _i < track['activeCues'].length; _i++) { 17116 cues.push(track['activeCues'][_i]); 17117 } 17118 17119 _globalWindow2['default']['WebVTT']['processCues'](_globalWindow2['default'], cues, this.el_); 17120 17121 var i = cues.length; 17122 while (i--) { 17123 var cue = cues[i]; 17124 if (!cue) { 17125 continue; 17126 } 17127 17128 var cueDiv = cue.displayState; 17129 if (overrides.color) { 17130 cueDiv.firstChild.style.color = overrides.color; 17131 } 17132 if (overrides.textOpacity) { 17133 tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity)); 17134 } 17135 if (overrides.backgroundColor) { 17136 cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor; 17137 } 17138 if (overrides.backgroundOpacity) { 17139 tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity)); 17140 } 17141 if (overrides.windowColor) { 17142 if (overrides.windowOpacity) { 17143 tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity)); 17144 } else { 17145 cueDiv.style.backgroundColor = overrides.windowColor; 17146 } 17147 } 17148 if (overrides.edgeStyle) { 17149 if (overrides.edgeStyle === 'dropshadow') { 17150 cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray; 17151 } else if (overrides.edgeStyle === 'raised') { 17152 cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray; 17153 } else if (overrides.edgeStyle === 'depressed') { 17154 cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray; 17155 } else if (overrides.edgeStyle === 'uniform') { 17156 cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray; 17157 } 17158 } 17159 if (overrides.fontPercent && overrides.fontPercent !== 1) { 17160 var fontSize = _globalWindow2['default'].parseFloat(cueDiv.style.fontSize); 17161 cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px'; 17162 cueDiv.style.height = 'auto'; 17163 cueDiv.style.top = 'auto'; 17164 cueDiv.style.bottom = '2px'; 17165 } 17166 if (overrides.fontFamily && overrides.fontFamily !== 'default') { 17167 if (overrides.fontFamily === 'small-caps') { 17168 cueDiv.firstChild.style.fontVariant = 'small-caps'; 17169 } else { 17170 cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily]; 17171 } 17172 } 17173 } 17174 }; 17175 17176 return TextTrackDisplay; 17177 })(_component2['default']); 17178 17179 function constructColor(color, opacity) { 17180 return 'rgba(' + 17181 // color looks like "#f0e" 17182 parseInt(color[1] + color[1], 16) + ',' + parseInt(color[2] + color[2], 16) + ',' + parseInt(color[3] + color[3], 16) + ',' + opacity + ')'; 17183 } 17184 17185 /** 17186 * Try to update style 17187 * Some style changes will throw an error, particularly in IE8. Those should be noops. 17188 * 17189 * @param {Element} el The element to be styles 17190 * @param {CSSProperty} style The CSS property to be styled 17191 * @param {CSSStyle} rule The actual style to be applied to the property 17192 * @method tryUpdateStyle 17193 */ 17194 function tryUpdateStyle(el, style, rule) { 17195 // 17196 try { 17197 el.style[style] = rule; 17198 } catch (e) {} 17199 } 17200 17201 _component2['default'].registerComponent('TextTrackDisplay', TextTrackDisplay); 17202 exports['default'] = TextTrackDisplay; 17203 module.exports = exports['default']; 17204 17205 },{"../component":67,"../menu/menu-button.js":106,"../menu/menu-item.js":107,"../menu/menu.js":108,"../utils/fn.js":136,"global/document":1,"global/window":2}],126:[function(_dereq_,module,exports){ 17206 /** 17207 * @file text-track-enums.js 17208 */ 17209 17210 /** 17211 * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode 17212 * 17213 * enum TextTrackMode { "disabled", "hidden", "showing" }; 17214 */ 17215 'use strict'; 17216 17217 exports.__esModule = true; 17218 var TextTrackMode = { 17219 disabled: 'disabled', 17220 hidden: 'hidden', 17221 showing: 'showing' 17222 }; 17223 17224 /** 17225 * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind 17226 * 17227 * enum TextTrackKind { 17228 * "subtitles", 17229 * "captions", 17230 * "descriptions", 17231 * "chapters", 17232 * "metadata" 17233 * }; 17234 */ 17235 var TextTrackKind = { 17236 subtitles: 'subtitles', 17237 captions: 'captions', 17238 descriptions: 'descriptions', 17239 chapters: 'chapters', 17240 metadata: 'metadata' 17241 }; 17242 17243 /* jshint ignore:start */ 17244 // we ignore jshint here because it does not see 17245 // TextTrackMode or TextTrackKind as defined here somehow... 17246 exports.TextTrackMode = TextTrackMode; 17247 exports.TextTrackKind = TextTrackKind; 17248 17249 /* jshint ignore:end */ 17250 17251 },{}],127:[function(_dereq_,module,exports){ 17252 /** 17253 * Utilities for capturing text track state and re-creating tracks 17254 * based on a capture. 17255 * 17256 * @file text-track-list-converter.js 17257 */ 17258 17259 /** 17260 * Examine a single text track and return a JSON-compatible javascript 17261 * object that represents the text track's state. 17262 * @param track {TextTrackObject} the text track to query 17263 * @return {Object} a serializable javascript representation of the 17264 * @private 17265 */ 17266 'use strict'; 17267 17268 exports.__esModule = true; 17269 var trackToJson_ = function trackToJson_(track) { 17270 var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) { 17271 if (track[prop]) { 17272 acc[prop] = track[prop]; 17273 } 17274 17275 return acc; 17276 }, { 17277 cues: track.cues && Array.prototype.map.call(track.cues, function (cue) { 17278 return { 17279 startTime: cue.startTime, 17280 endTime: cue.endTime, 17281 text: cue.text, 17282 id: cue.id 17283 }; 17284 }) 17285 }); 17286 17287 return ret; 17288 }; 17289 17290 /** 17291 * Examine a tech and return a JSON-compatible javascript array that 17292 * represents the state of all text tracks currently configured. The 17293 * return array is compatible with `jsonToTextTracks`. 17294 * @param tech {tech} the tech object to query 17295 * @return {Array} a serializable javascript representation of the 17296 * @function textTracksToJson 17297 */ 17298 var textTracksToJson = function textTracksToJson(tech) { 17299 17300 var trackEls = tech.$$('track'); 17301 17302 var trackObjs = Array.prototype.map.call(trackEls, function (t) { 17303 return t.track; 17304 }); 17305 var tracks = Array.prototype.map.call(trackEls, function (trackEl) { 17306 var json = trackToJson_(trackEl.track); 17307 if (trackEl.src) { 17308 json.src = trackEl.src; 17309 } 17310 return json; 17311 }); 17312 17313 return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) { 17314 return trackObjs.indexOf(track) === -1; 17315 }).map(trackToJson_)); 17316 }; 17317 17318 /** 17319 * Creates a set of remote text tracks on a tech based on an array of 17320 * javascript text track representations. 17321 * @param json {Array} an array of text track representation objects, 17322 * like those that would be produced by `textTracksToJson` 17323 * @param tech {tech} the tech to create text tracks on 17324 * @function jsonToTextTracks 17325 */ 17326 var jsonToTextTracks = function jsonToTextTracks(json, tech) { 17327 json.forEach(function (track) { 17328 var addedTrack = tech.addRemoteTextTrack(track).track; 17329 if (!track.src && track.cues) { 17330 track.cues.forEach(function (cue) { 17331 return addedTrack.addCue(cue); 17332 }); 17333 } 17334 }); 17335 17336 return tech.textTracks(); 17337 }; 17338 17339 exports['default'] = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ }; 17340 module.exports = exports['default']; 17341 17342 },{}],128:[function(_dereq_,module,exports){ 17343 /** 17344 * @file text-track-list.js 17345 */ 17346 'use strict'; 17347 17348 exports.__esModule = true; 17349 17350 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 17351 17352 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 17353 17354 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 17355 17356 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 17357 17358 var _eventTarget = _dereq_('../event-target'); 17359 17360 var _eventTarget2 = _interopRequireDefault(_eventTarget); 17361 17362 var _utilsFnJs = _dereq_('../utils/fn.js'); 17363 17364 var Fn = _interopRequireWildcard(_utilsFnJs); 17365 17366 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 17367 17368 var browser = _interopRequireWildcard(_utilsBrowserJs); 17369 17370 var _globalDocument = _dereq_('global/document'); 17371 17372 var _globalDocument2 = _interopRequireDefault(_globalDocument); 17373 17374 /** 17375 * A text track list as defined in: 17376 * https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist 17377 * 17378 * interface TextTrackList : EventTarget { 17379 * readonly attribute unsigned long length; 17380 * getter TextTrack (unsigned long index); 17381 * TextTrack? getTrackById(DOMString id); 17382 * 17383 * attribute EventHandler onchange; 17384 * attribute EventHandler onaddtrack; 17385 * attribute EventHandler onremovetrack; 17386 * }; 17387 * 17388 * @param {Track[]} tracks A list of tracks to initialize the list with 17389 * @extends EventTarget 17390 * @class TextTrackList 17391 */ 17392 17393 var TextTrackList = (function (_EventTarget) { 17394 _inherits(TextTrackList, _EventTarget); 17395 17396 function TextTrackList() { 17397 var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; 17398 17399 _classCallCheck(this, TextTrackList); 17400 17401 _EventTarget.call(this); 17402 var list = this; 17403 17404 if (browser.IS_IE8) { 17405 list = _globalDocument2['default'].createElement('custom'); 17406 17407 for (var prop in TextTrackList.prototype) { 17408 if (prop !== 'constructor') { 17409 list[prop] = TextTrackList.prototype[prop]; 17410 } 17411 } 17412 } 17413 17414 list.tracks_ = []; 17415 17416 Object.defineProperty(list, 'length', { 17417 get: function get() { 17418 return this.tracks_.length; 17419 } 17420 }); 17421 17422 for (var i = 0; i < tracks.length; i++) { 17423 list.addTrack_(tracks[i]); 17424 } 17425 17426 if (browser.IS_IE8) { 17427 return list; 17428 } 17429 } 17430 17431 /** 17432 * change - One or more tracks in the track list have been enabled or disabled. 17433 * addtrack - A track has been added to the track list. 17434 * removetrack - A track has been removed from the track list. 17435 */ 17436 17437 /** 17438 * Add TextTrack from TextTrackList 17439 * 17440 * @param {TextTrack} track 17441 * @method addTrack_ 17442 * @private 17443 */ 17444 17445 TextTrackList.prototype.addTrack_ = function addTrack_(track) { 17446 var index = this.tracks_.length; 17447 17448 if (!('' + index in this)) { 17449 Object.defineProperty(this, index, { 17450 get: function get() { 17451 return this.tracks_[index]; 17452 } 17453 }); 17454 } 17455 17456 track.addEventListener('modechange', Fn.bind(this, function () { 17457 this.trigger('change'); 17458 })); 17459 17460 // Do not add duplicate tracks 17461 if (this.tracks_.indexOf(track) === -1) { 17462 this.tracks_.push(track); 17463 this.trigger({ 17464 track: track, 17465 type: 'addtrack' 17466 }); 17467 } 17468 }; 17469 17470 /** 17471 * Remove TextTrack from TextTrackList 17472 * NOTE: Be mindful of what is passed in as it may be a HTMLTrackElement 17473 * 17474 * @param {TextTrack} rtrack 17475 * @method removeTrack_ 17476 * @private 17477 */ 17478 17479 TextTrackList.prototype.removeTrack_ = function removeTrack_(rtrack) { 17480 var track = undefined; 17481 17482 for (var i = 0, l = this.length; i < l; i++) { 17483 if (this[i] === rtrack) { 17484 track = this[i]; 17485 if (track.off) { 17486 track.off(); 17487 } 17488 17489 this.tracks_.splice(i, 1); 17490 17491 break; 17492 } 17493 } 17494 17495 if (!track) { 17496 return; 17497 } 17498 17499 this.trigger({ 17500 track: track, 17501 type: 'removetrack' 17502 }); 17503 }; 17504 17505 /** 17506 * Get a TextTrack from TextTrackList by a tracks id 17507 * 17508 * @param {String} id - the id of the track to get 17509 * @method getTrackById 17510 * @return {TextTrack} 17511 * @private 17512 */ 17513 17514 TextTrackList.prototype.getTrackById = function getTrackById(id) { 17515 var result = null; 17516 17517 for (var i = 0, l = this.length; i < l; i++) { 17518 var track = this[i]; 17519 17520 if (track.id === id) { 17521 result = track; 17522 break; 17523 } 17524 } 17525 17526 return result; 17527 }; 17528 17529 return TextTrackList; 17530 })(_eventTarget2['default']); 17531 17532 TextTrackList.prototype.allowedEvents_ = { 17533 change: 'change', 17534 addtrack: 'addtrack', 17535 removetrack: 'removetrack' 17536 }; 17537 17538 // emulate attribute EventHandler support to allow for feature detection 17539 for (var _event in TextTrackList.prototype.allowedEvents_) { 17540 TextTrackList.prototype['on' + _event] = null; 17541 } 17542 17543 exports['default'] = TextTrackList; 17544 module.exports = exports['default']; 17545 17546 },{"../event-target":101,"../utils/browser.js":131,"../utils/fn.js":136,"global/document":1}],129:[function(_dereq_,module,exports){ 17547 /** 17548 * @file text-track-settings.js 17549 */ 17550 'use strict'; 17551 17552 exports.__esModule = true; 17553 17554 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 17555 17556 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 17557 17558 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 17559 17560 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 17561 17562 var _component = _dereq_('../component'); 17563 17564 var _component2 = _interopRequireDefault(_component); 17565 17566 var _utilsEventsJs = _dereq_('../utils/events.js'); 17567 17568 var Events = _interopRequireWildcard(_utilsEventsJs); 17569 17570 var _utilsFnJs = _dereq_('../utils/fn.js'); 17571 17572 var Fn = _interopRequireWildcard(_utilsFnJs); 17573 17574 var _utilsLogJs = _dereq_('../utils/log.js'); 17575 17576 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 17577 17578 var _safeJsonParseTuple = _dereq_('safe-json-parse/tuple'); 17579 17580 var _safeJsonParseTuple2 = _interopRequireDefault(_safeJsonParseTuple); 17581 17582 var _globalWindow = _dereq_('global/window'); 17583 17584 var _globalWindow2 = _interopRequireDefault(_globalWindow); 17585 17586 /** 17587 * Manipulate settings of texttracks 17588 * 17589 * @param {Object} player Main Player 17590 * @param {Object=} options Object of option names and values 17591 * @extends Component 17592 * @class TextTrackSettings 17593 */ 17594 17595 var TextTrackSettings = (function (_Component) { 17596 _inherits(TextTrackSettings, _Component); 17597 17598 function TextTrackSettings(player, options) { 17599 _classCallCheck(this, TextTrackSettings); 17600 17601 _Component.call(this, player, options); 17602 this.hide(); 17603 17604 // Grab `persistTextTrackSettings` from the player options if not passed in child options 17605 if (options.persistTextTrackSettings === undefined) { 17606 this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings; 17607 } 17608 17609 Events.on(this.$('.vjs-done-button'), 'click', Fn.bind(this, function () { 17610 this.saveSettings(); 17611 this.hide(); 17612 })); 17613 17614 Events.on(this.$('.vjs-default-button'), 'click', Fn.bind(this, function () { 17615 this.$('.vjs-fg-color > select').selectedIndex = 0; 17616 this.$('.vjs-bg-color > select').selectedIndex = 0; 17617 this.$('.window-color > select').selectedIndex = 0; 17618 this.$('.vjs-text-opacity > select').selectedIndex = 0; 17619 this.$('.vjs-bg-opacity > select').selectedIndex = 0; 17620 this.$('.vjs-window-opacity > select').selectedIndex = 0; 17621 this.$('.vjs-edge-style select').selectedIndex = 0; 17622 this.$('.vjs-font-family select').selectedIndex = 0; 17623 this.$('.vjs-font-percent select').selectedIndex = 2; 17624 this.updateDisplay(); 17625 })); 17626 17627 Events.on(this.$('.vjs-fg-color > select'), 'change', Fn.bind(this, this.updateDisplay)); 17628 Events.on(this.$('.vjs-bg-color > select'), 'change', Fn.bind(this, this.updateDisplay)); 17629 Events.on(this.$('.window-color > select'), 'change', Fn.bind(this, this.updateDisplay)); 17630 Events.on(this.$('.vjs-text-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); 17631 Events.on(this.$('.vjs-bg-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); 17632 Events.on(this.$('.vjs-window-opacity > select'), 'change', Fn.bind(this, this.updateDisplay)); 17633 Events.on(this.$('.vjs-font-percent select'), 'change', Fn.bind(this, this.updateDisplay)); 17634 Events.on(this.$('.vjs-edge-style select'), 'change', Fn.bind(this, this.updateDisplay)); 17635 Events.on(this.$('.vjs-font-family select'), 'change', Fn.bind(this, this.updateDisplay)); 17636 17637 if (this.options_.persistTextTrackSettings) { 17638 this.restoreSettings(); 17639 } 17640 } 17641 17642 /** 17643 * Create the component's DOM element 17644 * 17645 * @return {Element} 17646 * @method createEl 17647 */ 17648 17649 TextTrackSettings.prototype.createEl = function createEl() { 17650 return _Component.prototype.createEl.call(this, 'div', { 17651 className: 'vjs-caption-settings vjs-modal-overlay', 17652 innerHTML: captionOptionsMenuTemplate() 17653 }); 17654 }; 17655 17656 /** 17657 * Get texttrack settings 17658 * Settings are 17659 * .vjs-edge-style 17660 * .vjs-font-family 17661 * .vjs-fg-color 17662 * .vjs-text-opacity 17663 * .vjs-bg-color 17664 * .vjs-bg-opacity 17665 * .window-color 17666 * .vjs-window-opacity 17667 * 17668 * @return {Object} 17669 * @method getValues 17670 */ 17671 17672 TextTrackSettings.prototype.getValues = function getValues() { 17673 var textEdge = getSelectedOptionValue(this.$('.vjs-edge-style select')); 17674 var fontFamily = getSelectedOptionValue(this.$('.vjs-font-family select')); 17675 var fgColor = getSelectedOptionValue(this.$('.vjs-fg-color > select')); 17676 var textOpacity = getSelectedOptionValue(this.$('.vjs-text-opacity > select')); 17677 var bgColor = getSelectedOptionValue(this.$('.vjs-bg-color > select')); 17678 var bgOpacity = getSelectedOptionValue(this.$('.vjs-bg-opacity > select')); 17679 var windowColor = getSelectedOptionValue(this.$('.window-color > select')); 17680 var windowOpacity = getSelectedOptionValue(this.$('.vjs-window-opacity > select')); 17681 var fontPercent = _globalWindow2['default']['parseFloat'](getSelectedOptionValue(this.$('.vjs-font-percent > select'))); 17682 17683 var result = { 17684 'backgroundOpacity': bgOpacity, 17685 'textOpacity': textOpacity, 17686 'windowOpacity': windowOpacity, 17687 'edgeStyle': textEdge, 17688 'fontFamily': fontFamily, 17689 'color': fgColor, 17690 'backgroundColor': bgColor, 17691 'windowColor': windowColor, 17692 'fontPercent': fontPercent 17693 }; 17694 for (var _name in result) { 17695 if (result[_name] === '' || result[_name] === 'none' || _name === 'fontPercent' && result[_name] === 1.00) { 17696 delete result[_name]; 17697 } 17698 } 17699 return result; 17700 }; 17701 17702 /** 17703 * Set texttrack settings 17704 * Settings are 17705 * .vjs-edge-style 17706 * .vjs-font-family 17707 * .vjs-fg-color 17708 * .vjs-text-opacity 17709 * .vjs-bg-color 17710 * .vjs-bg-opacity 17711 * .window-color 17712 * .vjs-window-opacity 17713 * 17714 * @param {Object} values Object with texttrack setting values 17715 * @method setValues 17716 */ 17717 17718 TextTrackSettings.prototype.setValues = function setValues(values) { 17719 setSelectedOption(this.$('.vjs-edge-style select'), values.edgeStyle); 17720 setSelectedOption(this.$('.vjs-font-family select'), values.fontFamily); 17721 setSelectedOption(this.$('.vjs-fg-color > select'), values.color); 17722 setSelectedOption(this.$('.vjs-text-opacity > select'), values.textOpacity); 17723 setSelectedOption(this.$('.vjs-bg-color > select'), values.backgroundColor); 17724 setSelectedOption(this.$('.vjs-bg-opacity > select'), values.backgroundOpacity); 17725 setSelectedOption(this.$('.window-color > select'), values.windowColor); 17726 setSelectedOption(this.$('.vjs-window-opacity > select'), values.windowOpacity); 17727 17728 var fontPercent = values.fontPercent; 17729 17730 if (fontPercent) { 17731 fontPercent = fontPercent.toFixed(2); 17732 } 17733 17734 setSelectedOption(this.$('.vjs-font-percent > select'), fontPercent); 17735 }; 17736 17737 /** 17738 * Restore texttrack settings 17739 * 17740 * @method restoreSettings 17741 */ 17742 17743 TextTrackSettings.prototype.restoreSettings = function restoreSettings() { 17744 var err = undefined, 17745 values = undefined; 17746 17747 try { 17748 var _safeParseTuple = _safeJsonParseTuple2['default'](_globalWindow2['default'].localStorage.getItem('vjs-text-track-settings')); 17749 17750 err = _safeParseTuple[0]; 17751 values = _safeParseTuple[1]; 17752 17753 if (err) { 17754 _utilsLogJs2['default'].error(err); 17755 } 17756 } catch (e) { 17757 _utilsLogJs2['default'].warn(e); 17758 } 17759 17760 if (values) { 17761 this.setValues(values); 17762 } 17763 }; 17764 17765 /** 17766 * Save texttrack settings to local storage 17767 * 17768 * @method saveSettings 17769 */ 17770 17771 TextTrackSettings.prototype.saveSettings = function saveSettings() { 17772 if (!this.options_.persistTextTrackSettings) { 17773 return; 17774 } 17775 17776 var values = this.getValues(); 17777 try { 17778 if (Object.getOwnPropertyNames(values).length > 0) { 17779 _globalWindow2['default'].localStorage.setItem('vjs-text-track-settings', JSON.stringify(values)); 17780 } else { 17781 _globalWindow2['default'].localStorage.removeItem('vjs-text-track-settings'); 17782 } 17783 } catch (e) { 17784 _utilsLogJs2['default'].warn(e); 17785 } 17786 }; 17787 17788 /** 17789 * Update display of texttrack settings 17790 * 17791 * @method updateDisplay 17792 */ 17793 17794 TextTrackSettings.prototype.updateDisplay = function updateDisplay() { 17795 var ttDisplay = this.player_.getChild('textTrackDisplay'); 17796 if (ttDisplay) { 17797 ttDisplay.updateDisplay(); 17798 } 17799 }; 17800 17801 return TextTrackSettings; 17802 })(_component2['default']); 17803 17804 _component2['default'].registerComponent('TextTrackSettings', TextTrackSettings); 17805 17806 function getSelectedOptionValue(target) { 17807 var selectedOption = undefined; 17808 // not all browsers support selectedOptions, so, fallback to options 17809 if (target.selectedOptions) { 17810 selectedOption = target.selectedOptions[0]; 17811 } else if (target.options) { 17812 selectedOption = target.options[target.options.selectedIndex]; 17813 } 17814 17815 return selectedOption.value; 17816 } 17817 17818 function setSelectedOption(target, value) { 17819 if (!value) { 17820 return; 17821 } 17822 17823 var i = undefined; 17824 for (i = 0; i < target.options.length; i++) { 17825 var option = target.options[i]; 17826 if (option.value === value) { 17827 break; 17828 } 17829 } 17830 17831 target.selectedIndex = i; 17832 } 17833 17834 function captionOptionsMenuTemplate() { 17835 var template = '<div class="vjs-tracksettings">\n <div class="vjs-tracksettings-colors">\n <div class="vjs-fg-color vjs-tracksetting">\n <label class="vjs-label">Foreground</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-text-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Opaque</option>\n </select>\n </span>\n </div> <!-- vjs-fg-color -->\n <div class="vjs-bg-color vjs-tracksetting">\n <label class="vjs-label">Background</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-bg-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Transparent</option>\n <option value="0">Transparent</option>\n </select>\n </span>\n </div> <!-- vjs-bg-color -->\n <div class="window-color vjs-tracksetting">\n <label class="vjs-label">Window</label>\n <select>\n <option value="">---</option>\n <option value="#FFF">White</option>\n <option value="#000">Black</option>\n <option value="#F00">Red</option>\n <option value="#0F0">Green</option>\n <option value="#00F">Blue</option>\n <option value="#FF0">Yellow</option>\n <option value="#F0F">Magenta</option>\n <option value="#0FF">Cyan</option>\n </select>\n <span class="vjs-window-opacity vjs-opacity">\n <select>\n <option value="">---</option>\n <option value="1">Opaque</option>\n <option value="0.5">Semi-Transparent</option>\n <option value="0">Transparent</option>\n </select>\n </span>\n </div> <!-- vjs-window-color -->\n </div> <!-- vjs-tracksettings -->\n <div class="vjs-tracksettings-font">\n <div class="vjs-font-percent vjs-tracksetting">\n <label class="vjs-label">Font Size</label>\n <select>\n <option value="0.50">50%</option>\n <option value="0.75">75%</option>\n <option value="1.00" selected>100%</option>\n <option value="1.25">125%</option>\n <option value="1.50">150%</option>\n <option value="1.75">175%</option>\n <option value="2.00">200%</option>\n <option value="3.00">300%</option>\n <option value="4.00">400%</option>\n </select>\n </div> <!-- vjs-font-percent -->\n <div class="vjs-edge-style vjs-tracksetting">\n <label class="vjs-label">Text Edge Style</label>\n <select>\n <option value="none">None</option>\n <option value="raised">Raised</option>\n <option value="depressed">Depressed</option>\n <option value="uniform">Uniform</option>\n <option value="dropshadow">Dropshadow</option>\n </select>\n </div> <!-- vjs-edge-style -->\n <div class="vjs-font-family vjs-tracksetting">\n <label class="vjs-label">Font Family</label>\n <select>\n <option value="">Default</option>\n <option value="monospaceSerif">Monospace Serif</option>\n <option value="proportionalSerif">Proportional Serif</option>\n <option value="monospaceSansSerif">Monospace Sans-Serif</option>\n <option value="proportionalSansSerif">Proportional Sans-Serif</option>\n <option value="casual">Casual</option>\n <option value="script">Script</option>\n <option value="small-caps">Small Caps</option>\n </select>\n </div> <!-- vjs-font-family -->\n </div>\n </div>\n <div class="vjs-tracksettings-controls">\n <button class="vjs-default-button">Defaults</button>\n <button class="vjs-done-button">Done</button>\n </div>'; 17836 17837 return template; 17838 } 17839 17840 exports['default'] = TextTrackSettings; 17841 module.exports = exports['default']; 17842 17843 },{"../component":67,"../utils/events.js":135,"../utils/fn.js":136,"../utils/log.js":139,"global/window":2,"safe-json-parse/tuple":54}],130:[function(_dereq_,module,exports){ 17844 /** 17845 * @file text-track.js 17846 */ 17847 'use strict'; 17848 17849 exports.__esModule = true; 17850 17851 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 17852 17853 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 17854 17855 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 17856 17857 function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 17858 17859 var _textTrackCueList = _dereq_('./text-track-cue-list'); 17860 17861 var _textTrackCueList2 = _interopRequireDefault(_textTrackCueList); 17862 17863 var _utilsFnJs = _dereq_('../utils/fn.js'); 17864 17865 var Fn = _interopRequireWildcard(_utilsFnJs); 17866 17867 var _utilsGuidJs = _dereq_('../utils/guid.js'); 17868 17869 var Guid = _interopRequireWildcard(_utilsGuidJs); 17870 17871 var _utilsBrowserJs = _dereq_('../utils/browser.js'); 17872 17873 var browser = _interopRequireWildcard(_utilsBrowserJs); 17874 17875 var _textTrackEnums = _dereq_('./text-track-enums'); 17876 17877 var TextTrackEnum = _interopRequireWildcard(_textTrackEnums); 17878 17879 var _utilsLogJs = _dereq_('../utils/log.js'); 17880 17881 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 17882 17883 var _eventTarget = _dereq_('../event-target'); 17884 17885 var _eventTarget2 = _interopRequireDefault(_eventTarget); 17886 17887 var _globalDocument = _dereq_('global/document'); 17888 17889 var _globalDocument2 = _interopRequireDefault(_globalDocument); 17890 17891 var _globalWindow = _dereq_('global/window'); 17892 17893 var _globalWindow2 = _interopRequireDefault(_globalWindow); 17894 17895 var _utilsUrlJs = _dereq_('../utils/url.js'); 17896 17897 var _xhr = _dereq_('xhr'); 17898 17899 var _xhr2 = _interopRequireDefault(_xhr); 17900 17901 /** 17902 * takes a webvtt file contents and parses it into cues 17903 * 17904 * @param {String} srcContent webVTT file contents 17905 * @param {Track} track track to addcues to 17906 */ 17907 var parseCues = function parseCues(srcContent, track) { 17908 var parser = new _globalWindow2['default'].WebVTT.Parser(_globalWindow2['default'], _globalWindow2['default'].vttjs, _globalWindow2['default'].WebVTT.StringDecoder()); 17909 17910 parser.oncue = function (cue) { 17911 track.addCue(cue); 17912 }; 17913 17914 parser.onparsingerror = function (error) { 17915 _utilsLogJs2['default'].error(error); 17916 }; 17917 17918 parser.onflush = function () { 17919 track.trigger({ 17920 type: 'loadeddata', 17921 target: track 17922 }); 17923 }; 17924 17925 parser.parse(srcContent); 17926 parser.flush(); 17927 }; 17928 17929 /** 17930 * load a track from a specifed url 17931 * 17932 * @param {String} src url to load track from 17933 * @param {Track} track track to addcues to 17934 */ 17935 var loadTrack = function loadTrack(src, track) { 17936 var opts = { 17937 uri: src 17938 }; 17939 var crossOrigin = _utilsUrlJs.isCrossOrigin(src); 17940 17941 if (crossOrigin) { 17942 opts.cors = crossOrigin; 17943 } 17944 17945 _xhr2['default'](opts, Fn.bind(this, function (err, response, responseBody) { 17946 if (err) { 17947 return _utilsLogJs2['default'].error(err, response); 17948 } 17949 17950 track.loaded_ = true; 17951 17952 // Make sure that vttjs has loaded, otherwise, wait till it finished loading 17953 // NOTE: this is only used for the alt/video.novtt.js build 17954 if (typeof _globalWindow2['default'].WebVTT !== 'function') { 17955 if (track.tech_) { 17956 (function () { 17957 var loadHandler = function loadHandler() { 17958 return parseCues(responseBody, track); 17959 }; 17960 track.tech_.on('vttjsloaded', loadHandler); 17961 track.tech_.on('vttjserror', function () { 17962 _utilsLogJs2['default'].error('vttjs failed to load, stopping trying to process ' + track.src); 17963 track.tech_.off('vttjsloaded', loadHandler); 17964 }); 17965 })(); 17966 } 17967 } else { 17968 parseCues(responseBody, track); 17969 } 17970 })); 17971 }; 17972 17973 /** 17974 * A single text track as defined in: 17975 * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack 17976 * 17977 * interface TextTrack : EventTarget { 17978 * readonly attribute TextTrackKind kind; 17979 * readonly attribute DOMString label; 17980 * readonly attribute DOMString language; 17981 * 17982 * readonly attribute DOMString id; 17983 * readonly attribute DOMString inBandMetadataTrackDispatchType; 17984 * 17985 * attribute TextTrackMode mode; 17986 * 17987 * readonly attribute TextTrackCueList? cues; 17988 * readonly attribute TextTrackCueList? activeCues; 17989 * 17990 * void addCue(TextTrackCue cue); 17991 * void removeCue(TextTrackCue cue); 17992 * 17993 * attribute EventHandler oncuechange; 17994 * }; 17995 * 17996 * @param {Object=} options Object of option names and values 17997 * @extends EventTarget 17998 * @class TextTrack 17999 */ 18000 18001 var TextTrack = (function (_EventTarget) { 18002 _inherits(TextTrack, _EventTarget); 18003 18004 function TextTrack() { 18005 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 18006 18007 _classCallCheck(this, TextTrack); 18008 18009 _EventTarget.call(this); 18010 if (!options.tech) { 18011 throw new Error('A tech was not provided.'); 18012 } 18013 18014 var tt = this; 18015 18016 if (browser.IS_IE8) { 18017 tt = _globalDocument2['default'].createElement('custom'); 18018 18019 for (var prop in TextTrack.prototype) { 18020 if (prop !== 'constructor') { 18021 tt[prop] = TextTrack.prototype[prop]; 18022 } 18023 } 18024 } 18025 18026 tt.tech_ = options.tech; 18027 18028 var mode = TextTrackEnum.TextTrackMode[options.mode] || 'disabled'; 18029 var kind = TextTrackEnum.TextTrackKind[options.kind] || 'subtitles'; 18030 var label = options.label || ''; 18031 var language = options.language || options.srclang || ''; 18032 var id = options.id || 'vjs_text_track_' + Guid.newGUID(); 18033 18034 if (kind === 'metadata' || kind === 'chapters') { 18035 mode = 'hidden'; 18036 } 18037 18038 tt.cues_ = []; 18039 tt.activeCues_ = []; 18040 18041 var cues = new _textTrackCueList2['default'](tt.cues_); 18042 var activeCues = new _textTrackCueList2['default'](tt.activeCues_); 18043 var changed = false; 18044 var timeupdateHandler = Fn.bind(tt, function () { 18045 this.activeCues; 18046 if (changed) { 18047 this.trigger('cuechange'); 18048 changed = false; 18049 } 18050 }); 18051 18052 if (mode !== 'disabled') { 18053 tt.tech_.on('timeupdate', timeupdateHandler); 18054 } 18055 18056 Object.defineProperty(tt, 'kind', { 18057 get: function get() { 18058 return kind; 18059 }, 18060 set: function set() {} 18061 }); 18062 18063 Object.defineProperty(tt, 'label', { 18064 get: function get() { 18065 return label; 18066 }, 18067 set: function set() {} 18068 }); 18069 18070 Object.defineProperty(tt, 'language', { 18071 get: function get() { 18072 return language; 18073 }, 18074 set: function set() {} 18075 }); 18076 18077 Object.defineProperty(tt, 'id', { 18078 get: function get() { 18079 return id; 18080 }, 18081 set: function set() {} 18082 }); 18083 18084 Object.defineProperty(tt, 'mode', { 18085 get: function get() { 18086 return mode; 18087 }, 18088 set: function set(newMode) { 18089 if (!TextTrackEnum.TextTrackMode[newMode]) { 18090 return; 18091 } 18092 mode = newMode; 18093 if (mode === 'showing') { 18094 this.tech_.on('timeupdate', timeupdateHandler); 18095 } 18096 this.trigger('modechange'); 18097 } 18098 }); 18099 18100 Object.defineProperty(tt, 'cues', { 18101 get: function get() { 18102 if (!this.loaded_) { 18103 return null; 18104 } 18105 18106 return cues; 18107 }, 18108 set: function set() {} 18109 }); 18110 18111 Object.defineProperty(tt, 'activeCues', { 18112 get: function get() { 18113 if (!this.loaded_) { 18114 return null; 18115 } 18116 18117 // nothing to do 18118 if (this.cues.length === 0) { 18119 return activeCues; 18120 } 18121 18122 var ct = this.tech_.currentTime(); 18123 var active = []; 18124 18125 for (var i = 0, l = this.cues.length; i < l; i++) { 18126 var cue = this.cues[i]; 18127 18128 if (cue.startTime <= ct && cue.endTime >= ct) { 18129 active.push(cue); 18130 } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) { 18131 active.push(cue); 18132 } 18133 } 18134 18135 changed = false; 18136 18137 if (active.length !== this.activeCues_.length) { 18138 changed = true; 18139 } else { 18140 for (var i = 0; i < active.length; i++) { 18141 if (this.activeCues_.indexOf(active[i]) === -1) { 18142 changed = true; 18143 } 18144 } 18145 } 18146 18147 this.activeCues_ = active; 18148 activeCues.setCues_(this.activeCues_); 18149 18150 return activeCues; 18151 }, 18152 set: function set() {} 18153 }); 18154 18155 if (options.src) { 18156 tt.src = options.src; 18157 loadTrack(options.src, tt); 18158 } else { 18159 tt.loaded_ = true; 18160 } 18161 18162 if (browser.IS_IE8) { 18163 return tt; 18164 } 18165 } 18166 18167 /** 18168 * cuechange - One or more cues in the track have become active or stopped being active. 18169 */ 18170 18171 /** 18172 * add a cue to the internal list of cues 18173 * 18174 * @param {Object} cue the cue to add to our internal list 18175 * @method addCue 18176 */ 18177 18178 TextTrack.prototype.addCue = function addCue(cue) { 18179 var tracks = this.tech_.textTracks(); 18180 18181 if (tracks) { 18182 for (var i = 0; i < tracks.length; i++) { 18183 if (tracks[i] !== this) { 18184 tracks[i].removeCue(cue); 18185 } 18186 } 18187 } 18188 18189 this.cues_.push(cue); 18190 this.cues.setCues_(this.cues_); 18191 }; 18192 18193 /** 18194 * remvoe a cue from our internal list 18195 * 18196 * @param {Object} removeCue the cue to remove from our internal list 18197 * @method removeCue 18198 */ 18199 18200 TextTrack.prototype.removeCue = function removeCue(_removeCue) { 18201 var removed = false; 18202 18203 for (var i = 0, l = this.cues_.length; i < l; i++) { 18204 var cue = this.cues_[i]; 18205 18206 if (cue === _removeCue) { 18207 this.cues_.splice(i, 1); 18208 removed = true; 18209 } 18210 } 18211 18212 if (removed) { 18213 this.cues.setCues_(this.cues_); 18214 } 18215 }; 18216 18217 return TextTrack; 18218 })(_eventTarget2['default']); 18219 18220 TextTrack.prototype.allowedEvents_ = { 18221 cuechange: 'cuechange' 18222 }; 18223 18224 exports['default'] = TextTrack; 18225 module.exports = exports['default']; 18226 18227 },{"../event-target":101,"../utils/browser.js":131,"../utils/fn.js":136,"../utils/guid.js":138,"../utils/log.js":139,"../utils/url.js":144,"./text-track-cue-list":124,"./text-track-enums":126,"global/document":1,"global/window":2,"xhr":56}],131:[function(_dereq_,module,exports){ 18228 /** 18229 * @file browser.js 18230 */ 18231 'use strict'; 18232 18233 exports.__esModule = true; 18234 18235 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 18236 18237 var _globalDocument = _dereq_('global/document'); 18238 18239 var _globalDocument2 = _interopRequireDefault(_globalDocument); 18240 18241 var _globalWindow = _dereq_('global/window'); 18242 18243 var _globalWindow2 = _interopRequireDefault(_globalWindow); 18244 18245 var USER_AGENT = _globalWindow2['default'].navigator.userAgent; 18246 var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT); 18247 var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null; 18248 18249 /* 18250 * Device is an iPhone 18251 * 18252 * @type {Boolean} 18253 * @constant 18254 * @private 18255 */ 18256 var IS_IPAD = /iPad/i.test(USER_AGENT); 18257 18258 exports.IS_IPAD = IS_IPAD; 18259 // The Facebook app's UIWebView identifies as both an iPhone and iPad, so 18260 // to identify iPhones, we need to exclude iPads. 18261 // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ 18262 var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD; 18263 exports.IS_IPHONE = IS_IPHONE; 18264 var IS_IPOD = /iPod/i.test(USER_AGENT); 18265 exports.IS_IPOD = IS_IPOD; 18266 var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD; 18267 18268 exports.IS_IOS = IS_IOS; 18269 var IOS_VERSION = (function () { 18270 var match = USER_AGENT.match(/OS (\d+)_/i); 18271 if (match && match[1]) { 18272 return match[1]; 18273 } 18274 })(); 18275 18276 exports.IOS_VERSION = IOS_VERSION; 18277 var IS_ANDROID = /Android/i.test(USER_AGENT); 18278 exports.IS_ANDROID = IS_ANDROID; 18279 var ANDROID_VERSION = (function () { 18280 // This matches Android Major.Minor.Patch versions 18281 // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned 18282 var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i), 18283 major, 18284 minor; 18285 18286 if (!match) { 18287 return null; 18288 } 18289 18290 major = match[1] && parseFloat(match[1]); 18291 minor = match[2] && parseFloat(match[2]); 18292 18293 if (major && minor) { 18294 return parseFloat(match[1] + '.' + match[2]); 18295 } else if (major) { 18296 return major; 18297 } else { 18298 return null; 18299 } 18300 })(); 18301 exports.ANDROID_VERSION = ANDROID_VERSION; 18302 // Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser 18303 var IS_OLD_ANDROID = IS_ANDROID && /webkit/i.test(USER_AGENT) && ANDROID_VERSION < 2.3; 18304 exports.IS_OLD_ANDROID = IS_OLD_ANDROID; 18305 var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537; 18306 18307 exports.IS_NATIVE_ANDROID = IS_NATIVE_ANDROID; 18308 var IS_FIREFOX = /Firefox/i.test(USER_AGENT); 18309 exports.IS_FIREFOX = IS_FIREFOX; 18310 var IS_CHROME = /Chrome/i.test(USER_AGENT); 18311 exports.IS_CHROME = IS_CHROME; 18312 var IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT); 18313 18314 exports.IS_IE8 = IS_IE8; 18315 var TOUCH_ENABLED = !!('ontouchstart' in _globalWindow2['default'] || _globalWindow2['default'].DocumentTouch && _globalDocument2['default'] instanceof _globalWindow2['default'].DocumentTouch); 18316 exports.TOUCH_ENABLED = TOUCH_ENABLED; 18317 var BACKGROUND_SIZE_SUPPORTED = ('backgroundSize' in _globalDocument2['default'].createElement('video').style); 18318 exports.BACKGROUND_SIZE_SUPPORTED = BACKGROUND_SIZE_SUPPORTED; 18319 18320 },{"global/document":1,"global/window":2}],132:[function(_dereq_,module,exports){ 18321 /** 18322 * @file buffer.js 18323 */ 18324 'use strict'; 18325 18326 exports.__esModule = true; 18327 exports.bufferedPercent = bufferedPercent; 18328 18329 var _timeRangesJs = _dereq_('./time-ranges.js'); 18330 18331 /** 18332 * Compute how much your video has been buffered 18333 * 18334 * @param {Object} Buffered object 18335 * @param {Number} Total duration 18336 * @return {Number} Percent buffered of the total duration 18337 * @private 18338 * @function bufferedPercent 18339 */ 18340 18341 function bufferedPercent(buffered, duration) { 18342 var bufferedDuration = 0, 18343 start, 18344 end; 18345 18346 if (!duration) { 18347 return 0; 18348 } 18349 18350 if (!buffered || !buffered.length) { 18351 buffered = _timeRangesJs.createTimeRange(0, 0); 18352 } 18353 18354 for (var i = 0; i < buffered.length; i++) { 18355 start = buffered.start(i); 18356 end = buffered.end(i); 18357 18358 // buffered end can be bigger than duration by a very small fraction 18359 if (end > duration) { 18360 end = duration; 18361 } 18362 18363 bufferedDuration += end - start; 18364 } 18365 18366 return bufferedDuration / duration; 18367 } 18368 18369 },{"./time-ranges.js":142}],133:[function(_dereq_,module,exports){ 18370 'use strict'; 18371 18372 exports.__esModule = true; 18373 18374 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 18375 18376 var _logJs = _dereq_('./log.js'); 18377 18378 var _logJs2 = _interopRequireDefault(_logJs); 18379 18380 /** 18381 * Object containing the default behaviors for available handler methods. 18382 * 18383 * @private 18384 * @type {Object} 18385 */ 18386 var defaultBehaviors = { 18387 get: function get(obj, key) { 18388 return obj[key]; 18389 }, 18390 set: function set(obj, key, value) { 18391 obj[key] = value; 18392 return true; 18393 } 18394 }; 18395 18396 /** 18397 * Expose private objects publicly using a Proxy to log deprecation warnings. 18398 * 18399 * Browsers that do not support Proxy objects will simply return the `target` 18400 * object, so it can be directly exposed. 18401 * 18402 * @param {Object} target The target object. 18403 * @param {Object} messages Messages to display from a Proxy. Only operations 18404 * with an associated message will be proxied. 18405 * @param {String} [messages.get] 18406 * @param {String} [messages.set] 18407 * @return {Object} A Proxy if supported or the `target` argument. 18408 */ 18409 18410 exports['default'] = function (target) { 18411 var messages = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 18412 18413 if (typeof Proxy === 'function') { 18414 var _ret = (function () { 18415 var handler = {}; 18416 18417 // Build a handler object based on those keys that have both messages 18418 // and default behaviors. 18419 Object.keys(messages).forEach(function (key) { 18420 if (defaultBehaviors.hasOwnProperty(key)) { 18421 handler[key] = function () { 18422 _logJs2['default'].warn(messages[key]); 18423 return defaultBehaviors[key].apply(this, arguments); 18424 }; 18425 } 18426 }); 18427 18428 return { 18429 v: new Proxy(target, handler) 18430 }; 18431 })(); 18432 18433 if (typeof _ret === 'object') return _ret.v; 18434 } 18435 return target; 18436 }; 18437 18438 module.exports = exports['default']; 18439 18440 },{"./log.js":139}],134:[function(_dereq_,module,exports){ 18441 /** 18442 * @file dom.js 18443 */ 18444 'use strict'; 18445 18446 exports.__esModule = true; 18447 exports.getEl = getEl; 18448 exports.createEl = createEl; 18449 exports.textContent = textContent; 18450 exports.insertElFirst = insertElFirst; 18451 exports.getElData = getElData; 18452 exports.hasElData = hasElData; 18453 exports.removeElData = removeElData; 18454 exports.hasElClass = hasElClass; 18455 exports.addElClass = addElClass; 18456 exports.removeElClass = removeElClass; 18457 exports.toggleElClass = toggleElClass; 18458 exports.setElAttributes = setElAttributes; 18459 exports.getElAttributes = getElAttributes; 18460 exports.blockTextSelection = blockTextSelection; 18461 exports.unblockTextSelection = unblockTextSelection; 18462 exports.findElPosition = findElPosition; 18463 exports.getPointerPosition = getPointerPosition; 18464 exports.isEl = isEl; 18465 exports.isTextNode = isTextNode; 18466 exports.emptyEl = emptyEl; 18467 exports.normalizeContent = normalizeContent; 18468 exports.appendContent = appendContent; 18469 exports.insertContent = insertContent; 18470 18471 var _templateObject = _taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.']); 18472 18473 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 18474 18475 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 18476 18477 function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } 18478 18479 var _globalDocument = _dereq_('global/document'); 18480 18481 var _globalDocument2 = _interopRequireDefault(_globalDocument); 18482 18483 var _globalWindow = _dereq_('global/window'); 18484 18485 var _globalWindow2 = _interopRequireDefault(_globalWindow); 18486 18487 var _guidJs = _dereq_('./guid.js'); 18488 18489 var Guid = _interopRequireWildcard(_guidJs); 18490 18491 var _logJs = _dereq_('./log.js'); 18492 18493 var _logJs2 = _interopRequireDefault(_logJs); 18494 18495 var _tsml = _dereq_('tsml'); 18496 18497 var _tsml2 = _interopRequireDefault(_tsml); 18498 18499 /** 18500 * Detect if a value is a string with any non-whitespace characters. 18501 * 18502 * @param {String} str 18503 * @return {Boolean} 18504 */ 18505 function isNonBlankString(str) { 18506 return typeof str === 'string' && /\S/.test(str); 18507 } 18508 18509 /** 18510 * Throws an error if the passed string has whitespace. This is used by 18511 * class methods to be relatively consistent with the classList API. 18512 * 18513 * @param {String} str 18514 * @return {Boolean} 18515 */ 18516 function throwIfWhitespace(str) { 18517 if (/\s/.test(str)) { 18518 throw new Error('class has illegal whitespace characters'); 18519 } 18520 } 18521 18522 /** 18523 * Produce a regular expression for matching a class name. 18524 * 18525 * @param {String} className 18526 * @return {RegExp} 18527 */ 18528 function classRegExp(className) { 18529 return new RegExp('(^|\\s)' + className + '($|\\s)'); 18530 } 18531 18532 /** 18533 * Creates functions to query the DOM using a given method. 18534 * 18535 * @function createQuerier 18536 * @private 18537 * @param {String} method 18538 * @return {Function} 18539 */ 18540 function createQuerier(method) { 18541 return function (selector, context) { 18542 if (!isNonBlankString(selector)) { 18543 return _globalDocument2['default'][method](null); 18544 } 18545 if (isNonBlankString(context)) { 18546 context = _globalDocument2['default'].querySelector(context); 18547 } 18548 return (isEl(context) ? context : _globalDocument2['default'])[method](selector); 18549 }; 18550 } 18551 18552 /** 18553 * Shorthand for document.getElementById() 18554 * Also allows for CSS (jQuery) ID syntax. But nothing other than IDs. 18555 * 18556 * @param {String} id Element ID 18557 * @return {Element} Element with supplied ID 18558 * @function getEl 18559 */ 18560 18561 function getEl(id) { 18562 if (id.indexOf('#') === 0) { 18563 id = id.slice(1); 18564 } 18565 18566 return _globalDocument2['default'].getElementById(id); 18567 } 18568 18569 /** 18570 * Creates an element and applies properties. 18571 * 18572 * @param {String} [tagName='div'] Name of tag to be created. 18573 * @param {Object} [properties={}] Element properties to be applied. 18574 * @param {Object} [attributes={}] Element attributes to be applied. 18575 * @return {Element} 18576 * @function createEl 18577 */ 18578 18579 function createEl() { 18580 var tagName = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; 18581 var properties = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 18582 var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 18583 18584 var el = _globalDocument2['default'].createElement(tagName); 18585 18586 Object.getOwnPropertyNames(properties).forEach(function (propName) { 18587 var val = properties[propName]; 18588 18589 // See #2176 18590 // We originally were accepting both properties and attributes in the 18591 // same object, but that doesn't work so well. 18592 if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') { 18593 _logJs2['default'].warn(_tsml2['default'](_templateObject, propName, val)); 18594 el.setAttribute(propName, val); 18595 } else { 18596 el[propName] = val; 18597 } 18598 }); 18599 18600 Object.getOwnPropertyNames(attributes).forEach(function (attrName) { 18601 var val = attributes[attrName]; 18602 el.setAttribute(attrName, attributes[attrName]); 18603 }); 18604 18605 return el; 18606 } 18607 18608 /** 18609 * Injects text into an element, replacing any existing contents entirely. 18610 * 18611 * @param {Element} el 18612 * @param {String} text 18613 * @return {Element} 18614 * @function textContent 18615 */ 18616 18617 function textContent(el, text) { 18618 if (typeof el.textContent === 'undefined') { 18619 el.innerText = text; 18620 } else { 18621 el.textContent = text; 18622 } 18623 } 18624 18625 /** 18626 * Insert an element as the first child node of another 18627 * 18628 * @param {Element} child Element to insert 18629 * @param {Element} parent Element to insert child into 18630 * @private 18631 * @function insertElFirst 18632 */ 18633 18634 function insertElFirst(child, parent) { 18635 if (parent.firstChild) { 18636 parent.insertBefore(child, parent.firstChild); 18637 } else { 18638 parent.appendChild(child); 18639 } 18640 } 18641 18642 /** 18643 * Element Data Store. Allows for binding data to an element without putting it directly on the element. 18644 * Ex. Event listeners are stored here. 18645 * (also from jsninja.com, slightly modified and updated for closure compiler) 18646 * 18647 * @type {Object} 18648 * @private 18649 */ 18650 var elData = {}; 18651 18652 /* 18653 * Unique attribute name to store an element's guid in 18654 * 18655 * @type {String} 18656 * @constant 18657 * @private 18658 */ 18659 var elIdAttr = 'vdata' + new Date().getTime(); 18660 18661 /** 18662 * Returns the cache object where data for an element is stored 18663 * 18664 * @param {Element} el Element to store data for. 18665 * @return {Object} 18666 * @function getElData 18667 */ 18668 18669 function getElData(el) { 18670 var id = el[elIdAttr]; 18671 18672 if (!id) { 18673 id = el[elIdAttr] = Guid.newGUID(); 18674 } 18675 18676 if (!elData[id]) { 18677 elData[id] = {}; 18678 } 18679 18680 return elData[id]; 18681 } 18682 18683 /** 18684 * Returns whether or not an element has cached data 18685 * 18686 * @param {Element} el A dom element 18687 * @return {Boolean} 18688 * @private 18689 * @function hasElData 18690 */ 18691 18692 function hasElData(el) { 18693 var id = el[elIdAttr]; 18694 18695 if (!id) { 18696 return false; 18697 } 18698 18699 return !!Object.getOwnPropertyNames(elData[id]).length; 18700 } 18701 18702 /** 18703 * Delete data for the element from the cache and the guid attr from getElementById 18704 * 18705 * @param {Element} el Remove data for an element 18706 * @private 18707 * @function removeElData 18708 */ 18709 18710 function removeElData(el) { 18711 var id = el[elIdAttr]; 18712 18713 if (!id) { 18714 return; 18715 } 18716 18717 // Remove all stored data 18718 delete elData[id]; 18719 18720 // Remove the elIdAttr property from the DOM node 18721 try { 18722 delete el[elIdAttr]; 18723 } catch (e) { 18724 if (el.removeAttribute) { 18725 el.removeAttribute(elIdAttr); 18726 } else { 18727 // IE doesn't appear to support removeAttribute on the document element 18728 el[elIdAttr] = null; 18729 } 18730 } 18731 } 18732 18733 /** 18734 * Check if an element has a CSS class 18735 * 18736 * @function hasElClass 18737 * @param {Element} element Element to check 18738 * @param {String} classToCheck Classname to check 18739 */ 18740 18741 function hasElClass(element, classToCheck) { 18742 if (element.classList) { 18743 return element.classList.contains(classToCheck); 18744 } else { 18745 throwIfWhitespace(classToCheck); 18746 return classRegExp(classToCheck).test(element.className); 18747 } 18748 } 18749 18750 /** 18751 * Add a CSS class name to an element 18752 * 18753 * @function addElClass 18754 * @param {Element} element Element to add class name to 18755 * @param {String} classToAdd Classname to add 18756 */ 18757 18758 function addElClass(element, classToAdd) { 18759 if (element.classList) { 18760 element.classList.add(classToAdd); 18761 18762 // Don't need to `throwIfWhitespace` here because `hasElClass` will do it 18763 // in the case of classList not being supported. 18764 } else if (!hasElClass(element, classToAdd)) { 18765 element.className = (element.className + ' ' + classToAdd).trim(); 18766 } 18767 18768 return element; 18769 } 18770 18771 /** 18772 * Remove a CSS class name from an element 18773 * 18774 * @function removeElClass 18775 * @param {Element} element Element to remove from class name 18776 * @param {String} classToRemove Classname to remove 18777 */ 18778 18779 function removeElClass(element, classToRemove) { 18780 if (element.classList) { 18781 element.classList.remove(classToRemove); 18782 } else { 18783 throwIfWhitespace(classToRemove); 18784 element.className = element.className.split(/\s+/).filter(function (c) { 18785 return c !== classToRemove; 18786 }).join(' '); 18787 } 18788 18789 return element; 18790 } 18791 18792 /** 18793 * Adds or removes a CSS class name on an element depending on an optional 18794 * condition or the presence/absence of the class name. 18795 * 18796 * @function toggleElClass 18797 * @param {Element} element 18798 * @param {String} classToToggle 18799 * @param {Boolean|Function} [predicate] 18800 * Can be a function that returns a Boolean. If `true`, the class 18801 * will be added; if `false`, the class will be removed. If not 18802 * given, the class will be added if not present and vice versa. 18803 */ 18804 18805 function toggleElClass(element, classToToggle, predicate) { 18806 18807 // This CANNOT use `classList` internally because IE does not support the 18808 // second parameter to the `classList.toggle()` method! Which is fine because 18809 // `classList` will be used by the add/remove functions. 18810 var has = hasElClass(element, classToToggle); 18811 18812 if (typeof predicate === 'function') { 18813 predicate = predicate(element, classToToggle); 18814 } 18815 18816 if (typeof predicate !== 'boolean') { 18817 predicate = !has; 18818 } 18819 18820 // If the necessary class operation matches the current state of the 18821 // element, no action is required. 18822 if (predicate === has) { 18823 return; 18824 } 18825 18826 if (predicate) { 18827 addElClass(element, classToToggle); 18828 } else { 18829 removeElClass(element, classToToggle); 18830 } 18831 18832 return element; 18833 } 18834 18835 /** 18836 * Apply attributes to an HTML element. 18837 * 18838 * @param {Element} el Target element. 18839 * @param {Object=} attributes Element attributes to be applied. 18840 * @private 18841 * @function setElAttributes 18842 */ 18843 18844 function setElAttributes(el, attributes) { 18845 Object.getOwnPropertyNames(attributes).forEach(function (attrName) { 18846 var attrValue = attributes[attrName]; 18847 18848 if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) { 18849 el.removeAttribute(attrName); 18850 } else { 18851 el.setAttribute(attrName, attrValue === true ? '' : attrValue); 18852 } 18853 }); 18854 } 18855 18856 /** 18857 * Get an element's attribute values, as defined on the HTML tag 18858 * Attributes are not the same as properties. They're defined on the tag 18859 * or with setAttribute (which shouldn't be used with HTML) 18860 * This will return true or false for boolean attributes. 18861 * 18862 * @param {Element} tag Element from which to get tag attributes 18863 * @return {Object} 18864 * @private 18865 * @function getElAttributes 18866 */ 18867 18868 function getElAttributes(tag) { 18869 var obj, knownBooleans, attrs, attrName, attrVal; 18870 18871 obj = {}; 18872 18873 // known boolean attributes 18874 // we can check for matching boolean properties, but older browsers 18875 // won't know about HTML5 boolean attributes that we still read from 18876 knownBooleans = ',' + 'autoplay,controls,loop,muted,default' + ','; 18877 18878 if (tag && tag.attributes && tag.attributes.length > 0) { 18879 attrs = tag.attributes; 18880 18881 for (var i = attrs.length - 1; i >= 0; i--) { 18882 attrName = attrs[i].name; 18883 attrVal = attrs[i].value; 18884 18885 // check for known booleans 18886 // the matching element property will return a value for typeof 18887 if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) { 18888 // the value of an included boolean attribute is typically an empty 18889 // string ('') which would equal false if we just check for a false value. 18890 // we also don't want support bad code like autoplay='false' 18891 attrVal = attrVal !== null ? true : false; 18892 } 18893 18894 obj[attrName] = attrVal; 18895 } 18896 } 18897 18898 return obj; 18899 } 18900 18901 /** 18902 * Attempt to block the ability to select text while dragging controls 18903 * 18904 * @return {Boolean} 18905 * @function blockTextSelection 18906 */ 18907 18908 function blockTextSelection() { 18909 _globalDocument2['default'].body.focus(); 18910 _globalDocument2['default'].onselectstart = function () { 18911 return false; 18912 }; 18913 } 18914 18915 /** 18916 * Turn off text selection blocking 18917 * 18918 * @return {Boolean} 18919 * @function unblockTextSelection 18920 */ 18921 18922 function unblockTextSelection() { 18923 _globalDocument2['default'].onselectstart = function () { 18924 return true; 18925 }; 18926 } 18927 18928 /** 18929 * Offset Left 18930 * getBoundingClientRect technique from 18931 * John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/ 18932 * 18933 * @function findElPosition 18934 * @param {Element} el Element from which to get offset 18935 * @return {Object} 18936 */ 18937 18938 function findElPosition(el) { 18939 var box = undefined; 18940 18941 if (el.getBoundingClientRect && el.parentNode) { 18942 box = el.getBoundingClientRect(); 18943 } 18944 18945 if (!box) { 18946 return { 18947 left: 0, 18948 top: 0 18949 }; 18950 } 18951 18952 var docEl = _globalDocument2['default'].documentElement; 18953 var body = _globalDocument2['default'].body; 18954 18955 var clientLeft = docEl.clientLeft || body.clientLeft || 0; 18956 var scrollLeft = _globalWindow2['default'].pageXOffset || body.scrollLeft; 18957 var left = box.left + scrollLeft - clientLeft; 18958 18959 var clientTop = docEl.clientTop || body.clientTop || 0; 18960 var scrollTop = _globalWindow2['default'].pageYOffset || body.scrollTop; 18961 var top = box.top + scrollTop - clientTop; 18962 18963 // Android sometimes returns slightly off decimal values, so need to round 18964 return { 18965 left: Math.round(left), 18966 top: Math.round(top) 18967 }; 18968 } 18969 18970 /** 18971 * Get pointer position in element 18972 * Returns an object with x and y coordinates. 18973 * The base on the coordinates are the bottom left of the element. 18974 * 18975 * @function getPointerPosition 18976 * @param {Element} el Element on which to get the pointer position on 18977 * @param {Event} event Event object 18978 * @return {Object} This object will have x and y coordinates corresponding to the mouse position 18979 */ 18980 18981 function getPointerPosition(el, event) { 18982 var position = {}; 18983 var box = findElPosition(el); 18984 var boxW = el.offsetWidth; 18985 var boxH = el.offsetHeight; 18986 18987 var boxY = box.top; 18988 var boxX = box.left; 18989 var pageY = event.pageY; 18990 var pageX = event.pageX; 18991 18992 if (event.changedTouches) { 18993 pageX = event.changedTouches[0].pageX; 18994 pageY = event.changedTouches[0].pageY; 18995 } 18996 18997 position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH)); 18998 position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW)); 18999 19000 return position; 19001 } 19002 19003 /** 19004 * Determines, via duck typing, whether or not a value is a DOM element. 19005 * 19006 * @function isEl 19007 * @param {Mixed} value 19008 * @return {Boolean} 19009 */ 19010 19011 function isEl(value) { 19012 return !!value && typeof value === 'object' && value.nodeType === 1; 19013 } 19014 19015 /** 19016 * Determines, via duck typing, whether or not a value is a text node. 19017 * 19018 * @param {Mixed} value 19019 * @return {Boolean} 19020 */ 19021 19022 function isTextNode(value) { 19023 return !!value && typeof value === 'object' && value.nodeType === 3; 19024 } 19025 19026 /** 19027 * Empties the contents of an element. 19028 * 19029 * @function emptyEl 19030 * @param {Element} el 19031 * @return {Element} 19032 */ 19033 19034 function emptyEl(el) { 19035 while (el.firstChild) { 19036 el.removeChild(el.firstChild); 19037 } 19038 return el; 19039 } 19040 19041 /** 19042 * Normalizes content for eventual insertion into the DOM. 19043 * 19044 * This allows a wide range of content definition methods, but protects 19045 * from falling into the trap of simply writing to `innerHTML`, which is 19046 * an XSS concern. 19047 * 19048 * The content for an element can be passed in multiple types and 19049 * combinations, whose behavior is as follows: 19050 * 19051 * - String 19052 * Normalized into a text node. 19053 * 19054 * - Element, TextNode 19055 * Passed through. 19056 * 19057 * - Array 19058 * A one-dimensional array of strings, elements, nodes, or functions (which 19059 * return single strings, elements, or nodes). 19060 * 19061 * - Function 19062 * If the sole argument, is expected to produce a string, element, 19063 * node, or array. 19064 * 19065 * @function normalizeContent 19066 * @param {String|Element|TextNode|Array|Function} content 19067 * @return {Array} 19068 */ 19069 19070 function normalizeContent(content) { 19071 19072 // First, invoke content if it is a function. If it produces an array, 19073 // that needs to happen before normalization. 19074 if (typeof content === 'function') { 19075 content = content(); 19076 } 19077 19078 // Next up, normalize to an array, so one or many items can be normalized, 19079 // filtered, and returned. 19080 return (Array.isArray(content) ? content : [content]).map(function (value) { 19081 19082 // First, invoke value if it is a function to produce a new value, 19083 // which will be subsequently normalized to a Node of some kind. 19084 if (typeof value === 'function') { 19085 value = value(); 19086 } 19087 19088 if (isEl(value) || isTextNode(value)) { 19089 return value; 19090 } 19091 19092 if (typeof value === 'string' && /\S/.test(value)) { 19093 return _globalDocument2['default'].createTextNode(value); 19094 } 19095 }).filter(function (value) { 19096 return value; 19097 }); 19098 } 19099 19100 /** 19101 * Normalizes and appends content to an element. 19102 * 19103 * @function appendContent 19104 * @param {Element} el 19105 * @param {String|Element|TextNode|Array|Function} content 19106 * See: `normalizeContent` 19107 * @return {Element} 19108 */ 19109 19110 function appendContent(el, content) { 19111 normalizeContent(content).forEach(function (node) { 19112 return el.appendChild(node); 19113 }); 19114 return el; 19115 } 19116 19117 /** 19118 * Normalizes and inserts content into an element; this is identical to 19119 * `appendContent()`, except it empties the element first. 19120 * 19121 * @function insertContent 19122 * @param {Element} el 19123 * @param {String|Element|TextNode|Array|Function} content 19124 * See: `normalizeContent` 19125 * @return {Element} 19126 */ 19127 19128 function insertContent(el, content) { 19129 return appendContent(emptyEl(el), content); 19130 } 19131 19132 /** 19133 * Finds a single DOM element matching `selector` within the optional 19134 * `context` of another DOM element (defaulting to `document`). 19135 * 19136 * @function $ 19137 * @param {String} selector 19138 * A valid CSS selector, which will be passed to `querySelector`. 19139 * 19140 * @param {Element|String} [context=document] 19141 * A DOM element within which to query. Can also be a selector 19142 * string in which case the first matching element will be used 19143 * as context. If missing (or no element matches selector), falls 19144 * back to `document`. 19145 * 19146 * @return {Element|null} 19147 */ 19148 var $ = createQuerier('querySelector'); 19149 19150 exports.$ = $; 19151 /** 19152 * Finds a all DOM elements matching `selector` within the optional 19153 * `context` of another DOM element (defaulting to `document`). 19154 * 19155 * @function $$ 19156 * @param {String} selector 19157 * A valid CSS selector, which will be passed to `querySelectorAll`. 19158 * 19159 * @param {Element|String} [context=document] 19160 * A DOM element within which to query. Can also be a selector 19161 * string in which case the first matching element will be used 19162 * as context. If missing (or no element matches selector), falls 19163 * back to `document`. 19164 * 19165 * @return {NodeList} 19166 */ 19167 var $$ = createQuerier('querySelectorAll'); 19168 exports.$$ = $$; 19169 19170 },{"./guid.js":138,"./log.js":139,"global/document":1,"global/window":2,"tsml":55}],135:[function(_dereq_,module,exports){ 19171 /** 19172 * @file events.js 19173 * 19174 * Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/) 19175 * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible) 19176 * This should work very similarly to jQuery's events, however it's based off the book version which isn't as 19177 * robust as jquery's, so there's probably some differences. 19178 */ 19179 19180 'use strict'; 19181 19182 exports.__esModule = true; 19183 exports.on = on; 19184 exports.off = off; 19185 exports.trigger = trigger; 19186 exports.one = one; 19187 exports.fixEvent = fixEvent; 19188 19189 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19190 19191 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 19192 19193 var _domJs = _dereq_('./dom.js'); 19194 19195 var Dom = _interopRequireWildcard(_domJs); 19196 19197 var _guidJs = _dereq_('./guid.js'); 19198 19199 var Guid = _interopRequireWildcard(_guidJs); 19200 19201 var _globalWindow = _dereq_('global/window'); 19202 19203 var _globalWindow2 = _interopRequireDefault(_globalWindow); 19204 19205 var _globalDocument = _dereq_('global/document'); 19206 19207 var _globalDocument2 = _interopRequireDefault(_globalDocument); 19208 19209 /** 19210 * Add an event listener to element 19211 * It stores the handler function in a separate cache object 19212 * and adds a generic handler to the element's event, 19213 * along with a unique id (guid) to the element. 19214 * 19215 * @param {Element|Object} elem Element or object to bind listeners to 19216 * @param {String|Array} type Type of event to bind to. 19217 * @param {Function} fn Event listener. 19218 * @method on 19219 */ 19220 19221 function on(elem, type, fn) { 19222 if (Array.isArray(type)) { 19223 return _handleMultipleEvents(on, elem, type, fn); 19224 } 19225 19226 var data = Dom.getElData(elem); 19227 19228 // We need a place to store all our handler data 19229 if (!data.handlers) data.handlers = {}; 19230 19231 if (!data.handlers[type]) data.handlers[type] = []; 19232 19233 if (!fn.guid) fn.guid = Guid.newGUID(); 19234 19235 data.handlers[type].push(fn); 19236 19237 if (!data.dispatcher) { 19238 data.disabled = false; 19239 19240 data.dispatcher = function (event, hash) { 19241 19242 if (data.disabled) return; 19243 event = fixEvent(event); 19244 19245 var handlers = data.handlers[event.type]; 19246 19247 if (handlers) { 19248 // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off. 19249 var handlersCopy = handlers.slice(0); 19250 19251 for (var m = 0, n = handlersCopy.length; m < n; m++) { 19252 if (event.isImmediatePropagationStopped()) { 19253 break; 19254 } else { 19255 handlersCopy[m].call(elem, event, hash); 19256 } 19257 } 19258 } 19259 }; 19260 } 19261 19262 if (data.handlers[type].length === 1) { 19263 if (elem.addEventListener) { 19264 elem.addEventListener(type, data.dispatcher, false); 19265 } else if (elem.attachEvent) { 19266 elem.attachEvent('on' + type, data.dispatcher); 19267 } 19268 } 19269 } 19270 19271 /** 19272 * Removes event listeners from an element 19273 * 19274 * @param {Element|Object} elem Object to remove listeners from 19275 * @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element. 19276 * @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type. 19277 * @method off 19278 */ 19279 19280 function off(elem, type, fn) { 19281 // Don't want to add a cache object through getElData if not needed 19282 if (!Dom.hasElData(elem)) return; 19283 19284 var data = Dom.getElData(elem); 19285 19286 // If no events exist, nothing to unbind 19287 if (!data.handlers) { 19288 return; 19289 } 19290 19291 if (Array.isArray(type)) { 19292 return _handleMultipleEvents(off, elem, type, fn); 19293 } 19294 19295 // Utility function 19296 var removeType = function removeType(t) { 19297 data.handlers[t] = []; 19298 _cleanUpEvents(elem, t); 19299 }; 19300 19301 // Are we removing all bound events? 19302 if (!type) { 19303 for (var t in data.handlers) { 19304 removeType(t); 19305 }return; 19306 } 19307 19308 var handlers = data.handlers[type]; 19309 19310 // If no handlers exist, nothing to unbind 19311 if (!handlers) return; 19312 19313 // If no listener was provided, remove all listeners for type 19314 if (!fn) { 19315 removeType(type); 19316 return; 19317 } 19318 19319 // We're only removing a single handler 19320 if (fn.guid) { 19321 for (var n = 0; n < handlers.length; n++) { 19322 if (handlers[n].guid === fn.guid) { 19323 handlers.splice(n--, 1); 19324 } 19325 } 19326 } 19327 19328 _cleanUpEvents(elem, type); 19329 } 19330 19331 /** 19332 * Trigger an event for an element 19333 * 19334 * @param {Element|Object} elem Element to trigger an event on 19335 * @param {Event|Object|String} event A string (the type) or an event object with a type attribute 19336 * @param {Object} [hash] data hash to pass along with the event 19337 * @return {Boolean=} Returned only if default was prevented 19338 * @method trigger 19339 */ 19340 19341 function trigger(elem, event, hash) { 19342 // Fetches element data and a reference to the parent (for bubbling). 19343 // Don't want to add a data object to cache for every parent, 19344 // so checking hasElData first. 19345 var elemData = Dom.hasElData(elem) ? Dom.getElData(elem) : {}; 19346 var parent = elem.parentNode || elem.ownerDocument; 19347 // type = event.type || event, 19348 // handler; 19349 19350 // If an event name was passed as a string, creates an event out of it 19351 if (typeof event === 'string') { 19352 event = { type: event, target: elem }; 19353 } 19354 // Normalizes the event properties. 19355 event = fixEvent(event); 19356 19357 // If the passed element has a dispatcher, executes the established handlers. 19358 if (elemData.dispatcher) { 19359 elemData.dispatcher.call(elem, event, hash); 19360 } 19361 19362 // Unless explicitly stopped or the event does not bubble (e.g. media events) 19363 // recursively calls this function to bubble the event up the DOM. 19364 if (parent && !event.isPropagationStopped() && event.bubbles === true) { 19365 trigger.call(null, parent, event, hash); 19366 19367 // If at the top of the DOM, triggers the default action unless disabled. 19368 } else if (!parent && !event.defaultPrevented) { 19369 var targetData = Dom.getElData(event.target); 19370 19371 // Checks if the target has a default action for this event. 19372 if (event.target[event.type]) { 19373 // Temporarily disables event dispatching on the target as we have already executed the handler. 19374 targetData.disabled = true; 19375 // Executes the default action. 19376 if (typeof event.target[event.type] === 'function') { 19377 event.target[event.type](); 19378 } 19379 // Re-enables event dispatching. 19380 targetData.disabled = false; 19381 } 19382 } 19383 19384 // Inform the triggerer if the default was prevented by returning false 19385 return !event.defaultPrevented; 19386 } 19387 19388 /** 19389 * Trigger a listener only once for an event 19390 * 19391 * @param {Element|Object} elem Element or object to 19392 * @param {String|Array} type Name/type of event 19393 * @param {Function} fn Event handler function 19394 * @method one 19395 */ 19396 19397 function one(elem, type, fn) { 19398 if (Array.isArray(type)) { 19399 return _handleMultipleEvents(one, elem, type, fn); 19400 } 19401 var func = function func() { 19402 off(elem, type, func); 19403 fn.apply(this, arguments); 19404 }; 19405 // copy the guid to the new function so it can removed using the original function's ID 19406 func.guid = fn.guid = fn.guid || Guid.newGUID(); 19407 on(elem, type, func); 19408 } 19409 19410 /** 19411 * Fix a native event to have standard property values 19412 * 19413 * @param {Object} event Event object to fix 19414 * @return {Object} 19415 * @private 19416 * @method fixEvent 19417 */ 19418 19419 function fixEvent(event) { 19420 19421 function returnTrue() { 19422 return true; 19423 } 19424 function returnFalse() { 19425 return false; 19426 } 19427 19428 // Test if fixing up is needed 19429 // Used to check if !event.stopPropagation instead of isPropagationStopped 19430 // But native events return true for stopPropagation, but don't have 19431 // other expected methods like isPropagationStopped. Seems to be a problem 19432 // with the Javascript Ninja code. So we're just overriding all events now. 19433 if (!event || !event.isPropagationStopped) { 19434 var old = event || _globalWindow2['default'].event; 19435 19436 event = {}; 19437 // Clone the old object so that we can modify the values event = {}; 19438 // IE8 Doesn't like when you mess with native event properties 19439 // Firefox returns false for event.hasOwnProperty('type') and other props 19440 // which makes copying more difficult. 19441 // TODO: Probably best to create a whitelist of event props 19442 for (var key in old) { 19443 // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y 19444 // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation 19445 // and webkitMovementX/Y 19446 if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') { 19447 // Chrome 32+ warns if you try to copy deprecated returnValue, but 19448 // we still want to if preventDefault isn't supported (IE8). 19449 if (!(key === 'returnValue' && old.preventDefault)) { 19450 event[key] = old[key]; 19451 } 19452 } 19453 } 19454 19455 // The event occurred on this element 19456 if (!event.target) { 19457 event.target = event.srcElement || _globalDocument2['default']; 19458 } 19459 19460 // Handle which other element the event is related to 19461 if (!event.relatedTarget) { 19462 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; 19463 } 19464 19465 // Stop the default browser action 19466 event.preventDefault = function () { 19467 if (old.preventDefault) { 19468 old.preventDefault(); 19469 } 19470 event.returnValue = false; 19471 old.returnValue = false; 19472 event.defaultPrevented = true; 19473 }; 19474 19475 event.defaultPrevented = false; 19476 19477 // Stop the event from bubbling 19478 event.stopPropagation = function () { 19479 if (old.stopPropagation) { 19480 old.stopPropagation(); 19481 } 19482 event.cancelBubble = true; 19483 old.cancelBubble = true; 19484 event.isPropagationStopped = returnTrue; 19485 }; 19486 19487 event.isPropagationStopped = returnFalse; 19488 19489 // Stop the event from bubbling and executing other handlers 19490 event.stopImmediatePropagation = function () { 19491 if (old.stopImmediatePropagation) { 19492 old.stopImmediatePropagation(); 19493 } 19494 event.isImmediatePropagationStopped = returnTrue; 19495 event.stopPropagation(); 19496 }; 19497 19498 event.isImmediatePropagationStopped = returnFalse; 19499 19500 // Handle mouse position 19501 if (event.clientX != null) { 19502 var doc = _globalDocument2['default'].documentElement, 19503 body = _globalDocument2['default'].body; 19504 19505 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); 19506 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); 19507 } 19508 19509 // Handle key presses 19510 event.which = event.charCode || event.keyCode; 19511 19512 // Fix button for mouse clicks: 19513 // 0 == left; 1 == middle; 2 == right 19514 if (event.button != null) { 19515 event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0; 19516 } 19517 } 19518 19519 // Returns fixed-up instance 19520 return event; 19521 } 19522 19523 /** 19524 * Clean up the listener cache and dispatchers 19525 * 19526 * @param {Element|Object} elem Element to clean up 19527 * @param {String} type Type of event to clean up 19528 * @private 19529 * @method _cleanUpEvents 19530 */ 19531 function _cleanUpEvents(elem, type) { 19532 var data = Dom.getElData(elem); 19533 19534 // Remove the events of a particular type if there are none left 19535 if (data.handlers[type].length === 0) { 19536 delete data.handlers[type]; 19537 // data.handlers[type] = null; 19538 // Setting to null was causing an error with data.handlers 19539 19540 // Remove the meta-handler from the element 19541 if (elem.removeEventListener) { 19542 elem.removeEventListener(type, data.dispatcher, false); 19543 } else if (elem.detachEvent) { 19544 elem.detachEvent('on' + type, data.dispatcher); 19545 } 19546 } 19547 19548 // Remove the events object if there are no types left 19549 if (Object.getOwnPropertyNames(data.handlers).length <= 0) { 19550 delete data.handlers; 19551 delete data.dispatcher; 19552 delete data.disabled; 19553 } 19554 19555 // Finally remove the element data if there is no data left 19556 if (Object.getOwnPropertyNames(data).length === 0) { 19557 Dom.removeElData(elem); 19558 } 19559 } 19560 19561 /** 19562 * Loops through an array of event types and calls the requested method for each type. 19563 * 19564 * @param {Function} fn The event method we want to use. 19565 * @param {Element|Object} elem Element or object to bind listeners to 19566 * @param {String} type Type of event to bind to. 19567 * @param {Function} callback Event listener. 19568 * @private 19569 * @function _handleMultipleEvents 19570 */ 19571 function _handleMultipleEvents(fn, elem, types, callback) { 19572 types.forEach(function (type) { 19573 //Call the event method for each one of the types 19574 fn(elem, type, callback); 19575 }); 19576 } 19577 19578 },{"./dom.js":134,"./guid.js":138,"global/document":1,"global/window":2}],136:[function(_dereq_,module,exports){ 19579 /** 19580 * @file fn.js 19581 */ 19582 'use strict'; 19583 19584 exports.__esModule = true; 19585 19586 var _guidJs = _dereq_('./guid.js'); 19587 19588 /** 19589 * Bind (a.k.a proxy or Context). A simple method for changing the context of a function 19590 * It also stores a unique id on the function so it can be easily removed from events 19591 * 19592 * @param {*} context The object to bind as scope 19593 * @param {Function} fn The function to be bound to a scope 19594 * @param {Number=} uid An optional unique ID for the function to be set 19595 * @return {Function} 19596 * @private 19597 * @method bind 19598 */ 19599 var bind = function bind(context, fn, uid) { 19600 // Make sure the function has a unique ID 19601 if (!fn.guid) { 19602 fn.guid = _guidJs.newGUID(); 19603 } 19604 19605 // Create the new function that changes the context 19606 var ret = function ret() { 19607 return fn.apply(context, arguments); 19608 }; 19609 19610 // Allow for the ability to individualize this function 19611 // Needed in the case where multiple objects might share the same prototype 19612 // IF both items add an event listener with the same function, then you try to remove just one 19613 // it will remove both because they both have the same guid. 19614 // when using this, you need to use the bind method when you remove the listener as well. 19615 // currently used in text tracks 19616 ret.guid = uid ? uid + '_' + fn.guid : fn.guid; 19617 19618 return ret; 19619 }; 19620 exports.bind = bind; 19621 19622 },{"./guid.js":138}],137:[function(_dereq_,module,exports){ 19623 /** 19624 * @file format-time.js 19625 * 19626 * Format seconds as a time string, H:MM:SS or M:SS 19627 * Supplying a guide (in seconds) will force a number of leading zeros 19628 * to cover the length of the guide 19629 * 19630 * @param {Number} seconds Number of seconds to be turned into a string 19631 * @param {Number} guide Number (in seconds) to model the string after 19632 * @return {String} Time formatted as H:MM:SS or M:SS 19633 * @private 19634 * @function formatTime 19635 */ 19636 'use strict'; 19637 19638 exports.__esModule = true; 19639 function formatTime(seconds) { 19640 var guide = arguments.length <= 1 || arguments[1] === undefined ? seconds : arguments[1]; 19641 return (function () { 19642 seconds = seconds < 0 ? 0 : seconds; 19643 var s = Math.floor(seconds % 60); 19644 var m = Math.floor(seconds / 60 % 60); 19645 var h = Math.floor(seconds / 3600); 19646 var gm = Math.floor(guide / 60 % 60); 19647 var gh = Math.floor(guide / 3600); 19648 19649 // handle invalid times 19650 if (isNaN(seconds) || seconds === Infinity) { 19651 // '-' is false for all relational operators (e.g. <, >=) so this setting 19652 // will add the minimum number of fields specified by the guide 19653 h = m = s = '-'; 19654 } 19655 19656 // Check if we need to show hours 19657 h = h > 0 || gh > 0 ? h + ':' : ''; 19658 19659 // If hours are showing, we may need to add a leading zero. 19660 // Always show at least one digit of minutes. 19661 m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':'; 19662 19663 // Check if leading zero is need for seconds 19664 s = s < 10 ? '0' + s : s; 19665 19666 return h + m + s; 19667 })(); 19668 } 19669 19670 exports['default'] = formatTime; 19671 module.exports = exports['default']; 19672 19673 },{}],138:[function(_dereq_,module,exports){ 19674 /** 19675 * @file guid.js 19676 * 19677 * Unique ID for an element or function 19678 * @type {Number} 19679 * @private 19680 */ 19681 "use strict"; 19682 19683 exports.__esModule = true; 19684 exports.newGUID = newGUID; 19685 var _guid = 1; 19686 19687 /** 19688 * Get the next unique ID 19689 * 19690 * @return {String} 19691 * @function newGUID 19692 */ 19693 19694 function newGUID() { 19695 return _guid++; 19696 } 19697 19698 },{}],139:[function(_dereq_,module,exports){ 19699 /** 19700 * @file log.js 19701 */ 19702 'use strict'; 19703 19704 exports.__esModule = true; 19705 19706 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19707 19708 var _globalWindow = _dereq_('global/window'); 19709 19710 var _globalWindow2 = _interopRequireDefault(_globalWindow); 19711 19712 /** 19713 * Log plain debug messages 19714 */ 19715 var log = function log() { 19716 _logType(null, arguments); 19717 }; 19718 19719 /** 19720 * Keep a history of log messages 19721 * @type {Array} 19722 */ 19723 log.history = []; 19724 19725 /** 19726 * Log error messages 19727 */ 19728 log.error = function () { 19729 _logType('error', arguments); 19730 }; 19731 19732 /** 19733 * Log warning messages 19734 */ 19735 log.warn = function () { 19736 _logType('warn', arguments); 19737 }; 19738 19739 /** 19740 * Log messages to the console and history based on the type of message 19741 * 19742 * @param {String} type The type of message, or `null` for `log` 19743 * @param {Object} args The args to be passed to the log 19744 * @private 19745 * @method _logType 19746 */ 19747 function _logType(type, args) { 19748 // convert args to an array to get array functions 19749 var argsArray = Array.prototype.slice.call(args); 19750 // if there's no console then don't try to output messages 19751 // they will still be stored in log.history 19752 // Was setting these once outside of this function, but containing them 19753 // in the function makes it easier to test cases where console doesn't exist 19754 var noop = function noop() {}; 19755 19756 var console = _globalWindow2['default']['console'] || { 19757 'log': noop, 19758 'warn': noop, 19759 'error': noop 19760 }; 19761 19762 if (type) { 19763 // add the type to the front of the message 19764 argsArray.unshift(type.toUpperCase() + ':'); 19765 } else { 19766 // default to log with no prefix 19767 type = 'log'; 19768 } 19769 19770 // add to history 19771 log.history.push(argsArray); 19772 19773 // add console prefix after adding to history 19774 argsArray.unshift('VIDEOJS:'); 19775 19776 // call appropriate log function 19777 if (console[type].apply) { 19778 console[type].apply(console, argsArray); 19779 } else { 19780 // ie8 doesn't allow error.apply, but it will just join() the array anyway 19781 console[type](argsArray.join(' ')); 19782 } 19783 } 19784 19785 exports['default'] = log; 19786 module.exports = exports['default']; 19787 19788 },{"global/window":2}],140:[function(_dereq_,module,exports){ 19789 /** 19790 * @file merge-options.js 19791 */ 19792 'use strict'; 19793 19794 exports.__esModule = true; 19795 exports['default'] = mergeOptions; 19796 19797 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19798 19799 var _lodashCompatObjectMerge = _dereq_('lodash-compat/object/merge'); 19800 19801 var _lodashCompatObjectMerge2 = _interopRequireDefault(_lodashCompatObjectMerge); 19802 19803 function isPlain(obj) { 19804 return !!obj && typeof obj === 'object' && obj.toString() === '[object Object]' && obj.constructor === Object; 19805 } 19806 19807 /** 19808 * Merge customizer. video.js simply overwrites non-simple objects 19809 * (like arrays) instead of attempting to overlay them. 19810 * @see https://lodash.com/docs#merge 19811 */ 19812 var customizer = function customizer(destination, source) { 19813 // If we're not working with a plain object, copy the value as is 19814 // If source is an array, for instance, it will replace destination 19815 if (!isPlain(source)) { 19816 return source; 19817 } 19818 19819 // If the new value is a plain object but the first object value is not 19820 // we need to create a new object for the first object to merge with. 19821 // This makes it consistent with how merge() works by default 19822 // and also protects from later changes the to first object affecting 19823 // the second object's values. 19824 if (!isPlain(destination)) { 19825 return mergeOptions(source); 19826 } 19827 }; 19828 19829 /** 19830 * Merge one or more options objects, recursively merging **only** 19831 * plain object properties. Previously `deepMerge`. 19832 * 19833 * @param {...Object} source One or more objects to merge 19834 * @returns {Object} a new object that is the union of all 19835 * provided objects 19836 * @function mergeOptions 19837 */ 19838 19839 function mergeOptions() { 19840 // contruct the call dynamically to handle the variable number of 19841 // objects to merge 19842 var args = Array.prototype.slice.call(arguments); 19843 19844 // unshift an empty object into the front of the call as the target 19845 // of the merge 19846 args.unshift({}); 19847 19848 // customize conflict resolution to match our historical merge behavior 19849 args.push(customizer); 19850 19851 _lodashCompatObjectMerge2['default'].apply(null, args); 19852 19853 // return the mutated result object 19854 return args[0]; 19855 } 19856 19857 module.exports = exports['default']; 19858 19859 },{"lodash-compat/object/merge":40}],141:[function(_dereq_,module,exports){ 19860 'use strict'; 19861 19862 exports.__esModule = true; 19863 19864 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19865 19866 var _globalDocument = _dereq_('global/document'); 19867 19868 var _globalDocument2 = _interopRequireDefault(_globalDocument); 19869 19870 var createStyleElement = function createStyleElement(className) { 19871 var style = _globalDocument2['default'].createElement('style'); 19872 style.className = className; 19873 19874 return style; 19875 }; 19876 19877 exports.createStyleElement = createStyleElement; 19878 var setTextContent = function setTextContent(el, content) { 19879 if (el.styleSheet) { 19880 el.styleSheet.cssText = content; 19881 } else { 19882 el.textContent = content; 19883 } 19884 }; 19885 exports.setTextContent = setTextContent; 19886 19887 },{"global/document":1}],142:[function(_dereq_,module,exports){ 19888 'use strict'; 19889 19890 exports.__esModule = true; 19891 exports.createTimeRanges = createTimeRanges; 19892 19893 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19894 19895 var _logJs = _dereq_('./log.js'); 19896 19897 var _logJs2 = _interopRequireDefault(_logJs); 19898 19899 /** 19900 * @file time-ranges.js 19901 * 19902 * Should create a fake TimeRange object 19903 * Mimics an HTML5 time range instance, which has functions that 19904 * return the start and end times for a range 19905 * TimeRanges are returned by the buffered() method 19906 * 19907 * @param {(Number|Array)} Start of a single range or an array of ranges 19908 * @param {Number} End of a single range 19909 * @private 19910 * @method createTimeRanges 19911 */ 19912 19913 function createTimeRanges(start, end) { 19914 if (Array.isArray(start)) { 19915 return createTimeRangesObj(start); 19916 } else if (start === undefined || end === undefined) { 19917 return createTimeRangesObj(); 19918 } 19919 return createTimeRangesObj([[start, end]]); 19920 } 19921 19922 exports.createTimeRange = createTimeRanges; 19923 19924 function createTimeRangesObj(ranges) { 19925 if (ranges === undefined || ranges.length === 0) { 19926 return { 19927 length: 0, 19928 start: function start() { 19929 throw new Error('This TimeRanges object is empty'); 19930 }, 19931 end: function end() { 19932 throw new Error('This TimeRanges object is empty'); 19933 } 19934 }; 19935 } 19936 return { 19937 length: ranges.length, 19938 start: getRange.bind(null, 'start', 0, ranges), 19939 end: getRange.bind(null, 'end', 1, ranges) 19940 }; 19941 } 19942 19943 function getRange(fnName, valueIndex, ranges, rangeIndex) { 19944 if (rangeIndex === undefined) { 19945 _logJs2['default'].warn('DEPRECATED: Function \'' + fnName + '\' on \'TimeRanges\' called without an index argument.'); 19946 rangeIndex = 0; 19947 } 19948 rangeCheck(fnName, rangeIndex, ranges.length - 1); 19949 return ranges[rangeIndex][valueIndex]; 19950 } 19951 19952 function rangeCheck(fnName, index, maxIndex) { 19953 if (index < 0 || index > maxIndex) { 19954 throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is greater than or equal to the maximum bound (' + maxIndex + ').'); 19955 } 19956 } 19957 19958 },{"./log.js":139}],143:[function(_dereq_,module,exports){ 19959 /** 19960 * @file to-title-case.js 19961 * 19962 * Uppercase the first letter of a string 19963 * 19964 * @param {String} string String to be uppercased 19965 * @return {String} 19966 * @private 19967 * @method toTitleCase 19968 */ 19969 "use strict"; 19970 19971 exports.__esModule = true; 19972 function toTitleCase(string) { 19973 return string.charAt(0).toUpperCase() + string.slice(1); 19974 } 19975 19976 exports["default"] = toTitleCase; 19977 module.exports = exports["default"]; 19978 19979 },{}],144:[function(_dereq_,module,exports){ 19980 /** 19981 * @file url.js 19982 */ 19983 'use strict'; 19984 19985 exports.__esModule = true; 19986 19987 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 19988 19989 var _globalDocument = _dereq_('global/document'); 19990 19991 var _globalDocument2 = _interopRequireDefault(_globalDocument); 19992 19993 var _globalWindow = _dereq_('global/window'); 19994 19995 var _globalWindow2 = _interopRequireDefault(_globalWindow); 19996 19997 /** 19998 * Resolve and parse the elements of a URL 19999 * 20000 * @param {String} url The url to parse 20001 * @return {Object} An object of url details 20002 * @method parseUrl 20003 */ 20004 var parseUrl = function parseUrl(url) { 20005 var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; 20006 20007 // add the url to an anchor and let the browser parse the URL 20008 var a = _globalDocument2['default'].createElement('a'); 20009 a.href = url; 20010 20011 // IE8 (and 9?) Fix 20012 // ie8 doesn't parse the URL correctly until the anchor is actually 20013 // added to the body, and an innerHTML is needed to trigger the parsing 20014 var addToBody = a.host === '' && a.protocol !== 'file:'; 20015 var div = undefined; 20016 if (addToBody) { 20017 div = _globalDocument2['default'].createElement('div'); 20018 div.innerHTML = '<a href="' + url + '"></a>'; 20019 a = div.firstChild; 20020 // prevent the div from affecting layout 20021 div.setAttribute('style', 'display:none; position:absolute;'); 20022 _globalDocument2['default'].body.appendChild(div); 20023 } 20024 20025 // Copy the specific URL properties to a new object 20026 // This is also needed for IE8 because the anchor loses its 20027 // properties when it's removed from the dom 20028 var details = {}; 20029 for (var i = 0; i < props.length; i++) { 20030 details[props[i]] = a[props[i]]; 20031 } 20032 20033 // IE9 adds the port to the host property unlike everyone else. If 20034 // a port identifier is added for standard ports, strip it. 20035 if (details.protocol === 'http:') { 20036 details.host = details.host.replace(/:80$/, ''); 20037 } 20038 if (details.protocol === 'https:') { 20039 details.host = details.host.replace(/:443$/, ''); 20040 } 20041 20042 if (addToBody) { 20043 _globalDocument2['default'].body.removeChild(div); 20044 } 20045 20046 return details; 20047 }; 20048 20049 exports.parseUrl = parseUrl; 20050 /** 20051 * Get absolute version of relative URL. Used to tell flash correct URL. 20052 * http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue 20053 * 20054 * @param {String} url URL to make absolute 20055 * @return {String} Absolute URL 20056 * @private 20057 * @method getAbsoluteURL 20058 */ 20059 var getAbsoluteURL = function getAbsoluteURL(url) { 20060 // Check if absolute URL 20061 if (!url.match(/^https?:\/\//)) { 20062 // Convert to absolute URL. Flash hosted off-site needs an absolute URL. 20063 var div = _globalDocument2['default'].createElement('div'); 20064 div.innerHTML = '<a href="' + url + '">x</a>'; 20065 url = div.firstChild.href; 20066 } 20067 20068 return url; 20069 }; 20070 20071 exports.getAbsoluteURL = getAbsoluteURL; 20072 /** 20073 * Returns the extension of the passed file name. It will return an empty string if you pass an invalid path 20074 * 20075 * @param {String} path The fileName path like '/path/to/file.mp4' 20076 * @returns {String} The extension in lower case or an empty string if no extension could be found. 20077 * @method getFileExtension 20078 */ 20079 var getFileExtension = function getFileExtension(path) { 20080 if (typeof path === 'string') { 20081 var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i; 20082 var pathParts = splitPathRe.exec(path); 20083 20084 if (pathParts) { 20085 return pathParts.pop().toLowerCase(); 20086 } 20087 } 20088 20089 return ''; 20090 }; 20091 20092 exports.getFileExtension = getFileExtension; 20093 /** 20094 * Returns whether the url passed is a cross domain request or not. 20095 * 20096 * @param {String} url The url to check 20097 * @return {Boolean} Whether it is a cross domain request or not 20098 * @method isCrossOrigin 20099 */ 20100 var isCrossOrigin = function isCrossOrigin(url) { 20101 var winLoc = _globalWindow2['default'].location; 20102 var urlInfo = parseUrl(url); 20103 20104 // IE8 protocol relative urls will return ':' for protocol 20105 var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; 20106 20107 // Check if url is for another domain/origin 20108 // IE8 doesn't know location.origin, so we won't rely on it here 20109 var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host; 20110 20111 return crossOrigin; 20112 }; 20113 exports.isCrossOrigin = isCrossOrigin; 20114 20115 },{"global/document":1,"global/window":2}],145:[function(_dereq_,module,exports){ 20116 /** 20117 * @file video.js 20118 */ 20119 'use strict'; 20120 20121 exports.__esModule = true; 20122 20123 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } 20124 20125 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 20126 20127 var _globalWindow = _dereq_('global/window'); 20128 20129 var _globalWindow2 = _interopRequireDefault(_globalWindow); 20130 20131 var _globalDocument = _dereq_('global/document'); 20132 20133 var _globalDocument2 = _interopRequireDefault(_globalDocument); 20134 20135 var _setup = _dereq_('./setup'); 20136 20137 var setup = _interopRequireWildcard(_setup); 20138 20139 var _utilsStylesheetJs = _dereq_('./utils/stylesheet.js'); 20140 20141 var stylesheet = _interopRequireWildcard(_utilsStylesheetJs); 20142 20143 var _component = _dereq_('./component'); 20144 20145 var _component2 = _interopRequireDefault(_component); 20146 20147 var _eventTarget = _dereq_('./event-target'); 20148 20149 var _eventTarget2 = _interopRequireDefault(_eventTarget); 20150 20151 var _utilsEventsJs = _dereq_('./utils/events.js'); 20152 20153 var Events = _interopRequireWildcard(_utilsEventsJs); 20154 20155 var _player = _dereq_('./player'); 20156 20157 var _player2 = _interopRequireDefault(_player); 20158 20159 var _pluginsJs = _dereq_('./plugins.js'); 20160 20161 var _pluginsJs2 = _interopRequireDefault(_pluginsJs); 20162 20163 var _srcJsUtilsMergeOptionsJs = _dereq_('../../src/js/utils/merge-options.js'); 20164 20165 var _srcJsUtilsMergeOptionsJs2 = _interopRequireDefault(_srcJsUtilsMergeOptionsJs); 20166 20167 var _utilsFnJs = _dereq_('./utils/fn.js'); 20168 20169 var Fn = _interopRequireWildcard(_utilsFnJs); 20170 20171 var _tracksTextTrackJs = _dereq_('./tracks/text-track.js'); 20172 20173 var _tracksTextTrackJs2 = _interopRequireDefault(_tracksTextTrackJs); 20174 20175 var _objectAssign = _dereq_('object.assign'); 20176 20177 var _objectAssign2 = _interopRequireDefault(_objectAssign); 20178 20179 var _utilsTimeRangesJs = _dereq_('./utils/time-ranges.js'); 20180 20181 var _utilsFormatTimeJs = _dereq_('./utils/format-time.js'); 20182 20183 var _utilsFormatTimeJs2 = _interopRequireDefault(_utilsFormatTimeJs); 20184 20185 var _utilsLogJs = _dereq_('./utils/log.js'); 20186 20187 var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs); 20188 20189 var _utilsDomJs = _dereq_('./utils/dom.js'); 20190 20191 var Dom = _interopRequireWildcard(_utilsDomJs); 20192 20193 var _utilsBrowserJs = _dereq_('./utils/browser.js'); 20194 20195 var browser = _interopRequireWildcard(_utilsBrowserJs); 20196 20197 var _utilsUrlJs = _dereq_('./utils/url.js'); 20198 20199 var Url = _interopRequireWildcard(_utilsUrlJs); 20200 20201 var _extendJs = _dereq_('./extend.js'); 20202 20203 var _extendJs2 = _interopRequireDefault(_extendJs); 20204 20205 var _lodashCompatObjectMerge = _dereq_('lodash-compat/object/merge'); 20206 20207 var _lodashCompatObjectMerge2 = _interopRequireDefault(_lodashCompatObjectMerge); 20208 20209 var _utilsCreateDeprecationProxyJs = _dereq_('./utils/create-deprecation-proxy.js'); 20210 20211 var _utilsCreateDeprecationProxyJs2 = _interopRequireDefault(_utilsCreateDeprecationProxyJs); 20212 20213 var _xhr = _dereq_('xhr'); 20214 20215 var _xhr2 = _interopRequireDefault(_xhr); 20216 20217 // Include the built-in techs 20218 20219 var _techTechJs = _dereq_('./tech/tech.js'); 20220 20221 var _techTechJs2 = _interopRequireDefault(_techTechJs); 20222 20223 var _techHtml5Js = _dereq_('./tech/html5.js'); 20224 20225 var _techHtml5Js2 = _interopRequireDefault(_techHtml5Js); 20226 20227 var _techFlashJs = _dereq_('./tech/flash.js'); 20228 20229 var _techFlashJs2 = _interopRequireDefault(_techFlashJs); 20230 20231 // HTML5 Element Shim for IE8 20232 if (typeof HTMLVideoElement === 'undefined') { 20233 _globalDocument2['default'].createElement('video'); 20234 _globalDocument2['default'].createElement('audio'); 20235 _globalDocument2['default'].createElement('track'); 20236 } 20237 20238 /** 20239 * Doubles as the main function for users to create a player instance and also 20240 * the main library object. 20241 * The `videojs` function can be used to initialize or retrieve a player. 20242 * ```js 20243 * var myPlayer = videojs('my_video_id'); 20244 * ``` 20245 * 20246 * @param {String|Element} id Video element or video element ID 20247 * @param {Object=} options Optional options object for config/settings 20248 * @param {Function=} ready Optional ready callback 20249 * @return {Player} A player instance 20250 * @mixes videojs 20251 * @method videojs 20252 */ 20253 var videojs = function videojs(id, options, ready) { 20254 var tag = undefined; // Element of ID 20255 20256 // Allow for element or ID to be passed in 20257 // String ID 20258 if (typeof id === 'string') { 20259 20260 // Adjust for jQuery ID syntax 20261 if (id.indexOf('#') === 0) { 20262 id = id.slice(1); 20263 } 20264 20265 // If a player instance has already been created for this ID return it. 20266 if (videojs.getPlayers()[id]) { 20267 20268 // If options or ready funtion are passed, warn 20269 if (options) { 20270 _utilsLogJs2['default'].warn('Player "' + id + '" is already initialised. Options will not be applied.'); 20271 } 20272 20273 if (ready) { 20274 videojs.getPlayers()[id].ready(ready); 20275 } 20276 20277 return videojs.getPlayers()[id]; 20278 20279 // Otherwise get element for ID 20280 } else { 20281 tag = Dom.getEl(id); 20282 } 20283 20284 // ID is a media element 20285 } else { 20286 tag = id; 20287 } 20288 20289 // Check for a useable element 20290 if (!tag || !tag.nodeName) { 20291 // re: nodeName, could be a box div also 20292 throw new TypeError('The element or ID supplied is not valid. (videojs)'); // Returns 20293 } 20294 20295 // Element may have a player attr referring to an already created player instance. 20296 // If not, set up a new player and return the instance. 20297 return tag['player'] || _player2['default'].players[tag.playerId] || new _player2['default'](tag, options, ready); 20298 }; 20299 20300 // Add default styles 20301 if (_globalWindow2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) { 20302 var style = Dom.$('.vjs-styles-defaults'); 20303 20304 if (!style) { 20305 style = stylesheet.createStyleElement('vjs-styles-defaults'); 20306 var head = Dom.$('head'); 20307 head.insertBefore(style, head.firstChild); 20308 stylesheet.setTextContent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); 20309 } 20310 } 20311 20312 // Run Auto-load players 20313 // You have to wait at least once in case this script is loaded after your video in the DOM (weird behavior only with minified version) 20314 setup.autoSetupTimeout(1, videojs); 20315 20316 /* 20317 * Current software version (semver) 20318 * 20319 * @type {String} 20320 */ 20321 videojs.VERSION = '5.9.0'; 20322 20323 /** 20324 * The global options object. These are the settings that take effect 20325 * if no overrides are specified when the player is created. 20326 * 20327 * ```js 20328 * videojs.options.autoplay = true 20329 * // -> all players will autoplay by default 20330 * ``` 20331 * 20332 * @type {Object} 20333 */ 20334 videojs.options = _player2['default'].prototype.options_; 20335 20336 /** 20337 * Get an object with the currently created players, keyed by player ID 20338 * 20339 * @return {Object} The created players 20340 * @mixes videojs 20341 * @method getPlayers 20342 */ 20343 videojs.getPlayers = function () { 20344 return _player2['default'].players; 20345 }; 20346 20347 /** 20348 * For backward compatibility, expose players object. 20349 * 20350 * @deprecated 20351 * @memberOf videojs 20352 * @property {Object|Proxy} players 20353 */ 20354 videojs.players = _utilsCreateDeprecationProxyJs2['default'](_player2['default'].players, { 20355 get: 'Access to videojs.players is deprecated; use videojs.getPlayers instead', 20356 set: 'Modification of videojs.players is deprecated' 20357 }); 20358 20359 /** 20360 * Get a component class object by name 20361 * ```js 20362 * var VjsButton = videojs.getComponent('Button'); 20363 * // Create a new instance of the component 20364 * var myButton = new VjsButton(myPlayer); 20365 * ``` 20366 * 20367 * @return {Component} Component identified by name 20368 * @mixes videojs 20369 * @method getComponent 20370 */ 20371 videojs.getComponent = _component2['default'].getComponent; 20372 20373 /** 20374 * Register a component so it can referred to by name 20375 * Used when adding to other 20376 * components, either through addChild 20377 * `component.addChild('myComponent')` 20378 * or through default children options 20379 * `{ children: ['myComponent'] }`. 20380 * ```js 20381 * // Get a component to subclass 20382 * var VjsButton = videojs.getComponent('Button'); 20383 * // Subclass the component (see 'extend' doc for more info) 20384 * var MySpecialButton = videojs.extend(VjsButton, {}); 20385 * // Register the new component 20386 * VjsButton.registerComponent('MySepcialButton', MySepcialButton); 20387 * // (optionally) add the new component as a default player child 20388 * myPlayer.addChild('MySepcialButton'); 20389 * ``` 20390 * NOTE: You could also just initialize the component before adding. 20391 * `component.addChild(new MyComponent());` 20392 * 20393 * @param {String} The class name of the component 20394 * @param {Component} The component class 20395 * @return {Component} The newly registered component 20396 * @mixes videojs 20397 * @method registerComponent 20398 */ 20399 videojs.registerComponent = function (name, comp) { 20400 if (_techTechJs2['default'].isTech(comp)) { 20401 _utilsLogJs2['default'].warn('The ' + name + ' tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)'); 20402 } 20403 20404 _component2['default'].registerComponent.call(_component2['default'], name, comp); 20405 }; 20406 20407 /** 20408 * Get a Tech class object by name 20409 * ```js 20410 * var Html5 = videojs.getTech('Html5'); 20411 * // Create a new instance of the component 20412 * var html5 = new Html5(options); 20413 * ``` 20414 * 20415 * @return {Tech} Tech identified by name 20416 * @mixes videojs 20417 * @method getComponent 20418 */ 20419 videojs.getTech = _techTechJs2['default'].getTech; 20420 20421 /** 20422 * Register a Tech so it can referred to by name. 20423 * This is used in the tech order for the player. 20424 * 20425 * ```js 20426 * // get the Html5 Tech 20427 * var Html5 = videojs.getTech('Html5'); 20428 * var MyTech = videojs.extend(Html5, {}); 20429 * // Register the new Tech 20430 * VjsButton.registerTech('Tech', MyTech); 20431 * var player = videojs('myplayer', { 20432 * techOrder: ['myTech', 'html5'] 20433 * }); 20434 * ``` 20435 * 20436 * @param {String} The class name of the tech 20437 * @param {Tech} The tech class 20438 * @return {Tech} The newly registered Tech 20439 * @mixes videojs 20440 * @method registerTech 20441 */ 20442 videojs.registerTech = _techTechJs2['default'].registerTech; 20443 20444 /** 20445 * A suite of browser and device tests 20446 * 20447 * @type {Object} 20448 * @private 20449 */ 20450 videojs.browser = browser; 20451 20452 /** 20453 * Whether or not the browser supports touch events. Included for backward 20454 * compatibility with 4.x, but deprecated. Use `videojs.browser.TOUCH_ENABLED` 20455 * instead going forward. 20456 * 20457 * @deprecated 20458 * @type {Boolean} 20459 */ 20460 videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED; 20461 20462 /** 20463 * Subclass an existing class 20464 * Mimics ES6 subclassing with the `extend` keyword 20465 * ```js 20466 * // Create a basic javascript 'class' 20467 * function MyClass(name){ 20468 * // Set a property at initialization 20469 * this.myName = name; 20470 * } 20471 * // Create an instance method 20472 * MyClass.prototype.sayMyName = function(){ 20473 * alert(this.myName); 20474 * }; 20475 * // Subclass the exisitng class and change the name 20476 * // when initializing 20477 * var MySubClass = videojs.extend(MyClass, { 20478 * constructor: function(name) { 20479 * // Call the super class constructor for the subclass 20480 * MyClass.call(this, name) 20481 * } 20482 * }); 20483 * // Create an instance of the new sub class 20484 * var myInstance = new MySubClass('John'); 20485 * myInstance.sayMyName(); // -> should alert "John" 20486 * ``` 20487 * 20488 * @param {Function} The Class to subclass 20489 * @param {Object} An object including instace methods for the new class 20490 * Optionally including a `constructor` function 20491 * @return {Function} The newly created subclass 20492 * @mixes videojs 20493 * @method extend 20494 */ 20495 videojs.extend = _extendJs2['default']; 20496 20497 /** 20498 * Merge two options objects recursively 20499 * Performs a deep merge like lodash.merge but **only merges plain objects** 20500 * (not arrays, elements, anything else) 20501 * Other values will be copied directly from the second object. 20502 * ```js 20503 * var defaultOptions = { 20504 * foo: true, 20505 * bar: { 20506 * a: true, 20507 * b: [1,2,3] 20508 * } 20509 * }; 20510 * var newOptions = { 20511 * foo: false, 20512 * bar: { 20513 * b: [4,5,6] 20514 * } 20515 * }; 20516 * var result = videojs.mergeOptions(defaultOptions, newOptions); 20517 * // result.foo = false; 20518 * // result.bar.a = true; 20519 * // result.bar.b = [4,5,6]; 20520 * ``` 20521 * 20522 * @param {Object} defaults The options object whose values will be overriden 20523 * @param {Object} overrides The options object with values to override the first 20524 * @param {Object} etc Any number of additional options objects 20525 * 20526 * @return {Object} a new object with the merged values 20527 * @mixes videojs 20528 * @method mergeOptions 20529 */ 20530 videojs.mergeOptions = _srcJsUtilsMergeOptionsJs2['default']; 20531 20532 /** 20533 * Change the context (this) of a function 20534 * 20535 * videojs.bind(newContext, function(){ 20536 * this === newContext 20537 * }); 20538 * 20539 * NOTE: as of v5.0 we require an ES5 shim, so you should use the native 20540 * `function(){}.bind(newContext);` instead of this. 20541 * 20542 * @param {*} context The object to bind as scope 20543 * @param {Function} fn The function to be bound to a scope 20544 * @param {Number=} uid An optional unique ID for the function to be set 20545 * @return {Function} 20546 */ 20547 videojs.bind = Fn.bind; 20548 20549 /** 20550 * Create a Video.js player plugin 20551 * Plugins are only initialized when options for the plugin are included 20552 * in the player options, or the plugin function on the player instance is 20553 * called. 20554 * **See the plugin guide in the docs for a more detailed example** 20555 * ```js 20556 * // Make a plugin that alerts when the player plays 20557 * videojs.plugin('myPlugin', function(myPluginOptions) { 20558 * myPluginOptions = myPluginOptions || {}; 20559 * 20560 * var player = this; 20561 * var alertText = myPluginOptions.text || 'Player is playing!' 20562 * 20563 * player.on('play', function(){ 20564 * alert(alertText); 20565 * }); 20566 * }); 20567 * // USAGE EXAMPLES 20568 * // EXAMPLE 1: New player with plugin options, call plugin immediately 20569 * var player1 = videojs('idOne', { 20570 * myPlugin: { 20571 * text: 'Custom text!' 20572 * } 20573 * }); 20574 * // Click play 20575 * // --> Should alert 'Custom text!' 20576 * // EXAMPLE 3: New player, initialize plugin later 20577 * var player3 = videojs('idThree'); 20578 * // Click play 20579 * // --> NO ALERT 20580 * // Click pause 20581 * // Initialize plugin using the plugin function on the player instance 20582 * player3.myPlugin({ 20583 * text: 'Plugin added later!' 20584 * }); 20585 * // Click play 20586 * // --> Should alert 'Plugin added later!' 20587 * ``` 20588 * 20589 * @param {String} name The plugin name 20590 * @param {Function} fn The plugin function that will be called with options 20591 * @mixes videojs 20592 * @method plugin 20593 */ 20594 videojs.plugin = _pluginsJs2['default']; 20595 20596 /** 20597 * Adding languages so that they're available to all players. 20598 * ```js 20599 * videojs.addLanguage('es', { 'Hello': 'Hola' }); 20600 * ``` 20601 * 20602 * @param {String} code The language code or dictionary property 20603 * @param {Object} data The data values to be translated 20604 * @return {Object} The resulting language dictionary object 20605 * @mixes videojs 20606 * @method addLanguage 20607 */ 20608 videojs.addLanguage = function (code, data) { 20609 var _merge; 20610 20611 code = ('' + code).toLowerCase(); 20612 return _lodashCompatObjectMerge2['default'](videojs.options.languages, (_merge = {}, _merge[code] = data, _merge))[code]; 20613 }; 20614 20615 /** 20616 * Log debug messages. 20617 * 20618 * @param {...Object} messages One or more messages to log 20619 */ 20620 videojs.log = _utilsLogJs2['default']; 20621 20622 /** 20623 * Creates an emulated TimeRange object. 20624 * 20625 * @param {Number|Array} start Start time in seconds or an array of ranges 20626 * @param {Number} end End time in seconds 20627 * @return {Object} Fake TimeRange object 20628 * @method createTimeRange 20629 */ 20630 videojs.createTimeRange = videojs.createTimeRanges = _utilsTimeRangesJs.createTimeRanges; 20631 20632 /** 20633 * Format seconds as a time string, H:MM:SS or M:SS 20634 * Supplying a guide (in seconds) will force a number of leading zeros 20635 * to cover the length of the guide 20636 * 20637 * @param {Number} seconds Number of seconds to be turned into a string 20638 * @param {Number} guide Number (in seconds) to model the string after 20639 * @return {String} Time formatted as H:MM:SS or M:SS 20640 * @method formatTime 20641 */ 20642 videojs.formatTime = _utilsFormatTimeJs2['default']; 20643 20644 /** 20645 * Resolve and parse the elements of a URL 20646 * 20647 * @param {String} url The url to parse 20648 * @return {Object} An object of url details 20649 * @method parseUrl 20650 */ 20651 videojs.parseUrl = Url.parseUrl; 20652 20653 /** 20654 * Returns whether the url passed is a cross domain request or not. 20655 * 20656 * @param {String} url The url to check 20657 * @return {Boolean} Whether it is a cross domain request or not 20658 * @method isCrossOrigin 20659 */ 20660 videojs.isCrossOrigin = Url.isCrossOrigin; 20661 20662 /** 20663 * Event target class. 20664 * 20665 * @type {Function} 20666 */ 20667 videojs.EventTarget = _eventTarget2['default']; 20668 20669 /** 20670 * Add an event listener to element 20671 * It stores the handler function in a separate cache object 20672 * and adds a generic handler to the element's event, 20673 * along with a unique id (guid) to the element. 20674 * 20675 * @param {Element|Object} elem Element or object to bind listeners to 20676 * @param {String|Array} type Type of event to bind to. 20677 * @param {Function} fn Event listener. 20678 * @method on 20679 */ 20680 videojs.on = Events.on; 20681 20682 /** 20683 * Trigger a listener only once for an event 20684 * 20685 * @param {Element|Object} elem Element or object to 20686 * @param {String|Array} type Name/type of event 20687 * @param {Function} fn Event handler function 20688 * @method one 20689 */ 20690 videojs.one = Events.one; 20691 20692 /** 20693 * Removes event listeners from an element 20694 * 20695 * @param {Element|Object} elem Object to remove listeners from 20696 * @param {String|Array=} type Type of listener to remove. Don't include to remove all events from element. 20697 * @param {Function} fn Specific listener to remove. Don't include to remove listeners for an event type. 20698 * @method off 20699 */ 20700 videojs.off = Events.off; 20701 20702 /** 20703 * Trigger an event for an element 20704 * 20705 * @param {Element|Object} elem Element to trigger an event on 20706 * @param {Event|Object|String} event A string (the type) or an event object with a type attribute 20707 * @param {Object} [hash] data hash to pass along with the event 20708 * @return {Boolean=} Returned only if default was prevented 20709 * @method trigger 20710 */ 20711 videojs.trigger = Events.trigger; 20712 20713 /** 20714 * A cross-browser XMLHttpRequest wrapper. Here's a simple example: 20715 * 20716 * videojs.xhr({ 20717 * body: someJSONString, 20718 * uri: "/foo", 20719 * headers: { 20720 * "Content-Type": "application/json" 20721 * } 20722 * }, function (err, resp, body) { 20723 * // check resp.statusCode 20724 * }); 20725 * 20726 * Check out the [full 20727 * documentation](https://github.com/Raynos/xhr/blob/v2.1.0/README.md) 20728 * for more options. 20729 * 20730 * @param {Object} options settings for the request. 20731 * @return {XMLHttpRequest|XDomainRequest} the request object. 20732 * @see https://github.com/Raynos/xhr 20733 */ 20734 videojs.xhr = _xhr2['default']; 20735 20736 /** 20737 * TextTrack class 20738 * 20739 * @type {Function} 20740 */ 20741 videojs.TextTrack = _tracksTextTrackJs2['default']; 20742 20743 /** 20744 * Determines, via duck typing, whether or not a value is a DOM element. 20745 * 20746 * @method isEl 20747 * @param {Mixed} value 20748 * @return {Boolean} 20749 */ 20750 videojs.isEl = Dom.isEl; 20751 20752 /** 20753 * Determines, via duck typing, whether or not a value is a text node. 20754 * 20755 * @method isTextNode 20756 * @param {Mixed} value 20757 * @return {Boolean} 20758 */ 20759 videojs.isTextNode = Dom.isTextNode; 20760 20761 /** 20762 * Creates an element and applies properties. 20763 * 20764 * @method createEl 20765 * @param {String} [tagName='div'] Name of tag to be created. 20766 * @param {Object} [properties={}] Element properties to be applied. 20767 * @param {Object} [attributes={}] Element attributes to be applied. 20768 * @return {Element} 20769 */ 20770 videojs.createEl = Dom.createEl; 20771 20772 /** 20773 * Check if an element has a CSS class 20774 * 20775 * @method hasClass 20776 * @param {Element} element Element to check 20777 * @param {String} classToCheck Classname to check 20778 */ 20779 videojs.hasClass = Dom.hasElClass; 20780 20781 /** 20782 * Add a CSS class name to an element 20783 * 20784 * @method addClass 20785 * @param {Element} element Element to add class name to 20786 * @param {String} classToAdd Classname to add 20787 */ 20788 videojs.addClass = Dom.addElClass; 20789 20790 /** 20791 * Remove a CSS class name from an element 20792 * 20793 * @method removeClass 20794 * @param {Element} element Element to remove from class name 20795 * @param {String} classToRemove Classname to remove 20796 */ 20797 videojs.removeClass = Dom.removeElClass; 20798 20799 /** 20800 * Adds or removes a CSS class name on an element depending on an optional 20801 * condition or the presence/absence of the class name. 20802 * 20803 * @method toggleElClass 20804 * @param {Element} element 20805 * @param {String} classToToggle 20806 * @param {Boolean|Function} [predicate] 20807 * Can be a function that returns a Boolean. If `true`, the class 20808 * will be added; if `false`, the class will be removed. If not 20809 * given, the class will be added if not present and vice versa. 20810 */ 20811 videojs.toggleClass = Dom.toggleElClass; 20812 20813 /** 20814 * Apply attributes to an HTML element. 20815 * 20816 * @method setAttributes 20817 * @param {Element} el Target element. 20818 * @param {Object=} attributes Element attributes to be applied. 20819 */ 20820 videojs.setAttributes = Dom.setElAttributes; 20821 20822 /** 20823 * Get an element's attribute values, as defined on the HTML tag 20824 * Attributes are not the same as properties. They're defined on the tag 20825 * or with setAttribute (which shouldn't be used with HTML) 20826 * This will return true or false for boolean attributes. 20827 * 20828 * @method getAttributes 20829 * @param {Element} tag Element from which to get tag attributes 20830 * @return {Object} 20831 */ 20832 videojs.getAttributes = Dom.getElAttributes; 20833 20834 /** 20835 * Empties the contents of an element. 20836 * 20837 * @method emptyEl 20838 * @param {Element} el 20839 * @return {Element} 20840 */ 20841 videojs.emptyEl = Dom.emptyEl; 20842 20843 /** 20844 * Normalizes and appends content to an element. 20845 * 20846 * The content for an element can be passed in multiple types and 20847 * combinations, whose behavior is as follows: 20848 * 20849 * - String 20850 * Normalized into a text node. 20851 * 20852 * - Element, TextNode 20853 * Passed through. 20854 * 20855 * - Array 20856 * A one-dimensional array of strings, elements, nodes, or functions (which 20857 * return single strings, elements, or nodes). 20858 * 20859 * - Function 20860 * If the sole argument, is expected to produce a string, element, 20861 * node, or array. 20862 * 20863 * @method appendContent 20864 * @param {Element} el 20865 * @param {String|Element|TextNode|Array|Function} content 20866 * @return {Element} 20867 */ 20868 videojs.appendContent = Dom.appendContent; 20869 20870 /** 20871 * Normalizes and inserts content into an element; this is identical to 20872 * `appendContent()`, except it empties the element first. 20873 * 20874 * The content for an element can be passed in multiple types and 20875 * combinations, whose behavior is as follows: 20876 * 20877 * - String 20878 * Normalized into a text node. 20879 * 20880 * - Element, TextNode 20881 * Passed through. 20882 * 20883 * - Array 20884 * A one-dimensional array of strings, elements, nodes, or functions (which 20885 * return single strings, elements, or nodes). 20886 * 20887 * - Function 20888 * If the sole argument, is expected to produce a string, element, 20889 * node, or array. 20890 * 20891 * @method insertContent 20892 * @param {Element} el 20893 * @param {String|Element|TextNode|Array|Function} content 20894 * @return {Element} 20895 */ 20896 videojs.insertContent = Dom.insertContent; 20897 20898 /* 20899 * Custom Universal Module Definition (UMD) 20900 * 20901 * Video.js will never be a non-browser lib so we can simplify UMD a bunch and 20902 * still support requirejs and browserify. This also needs to be closure 20903 * compiler compatible, so string keys are used. 20904 */ 20905 if (typeof define === 'function' && define['amd']) { 20906 define('videojs', [], function () { 20907 return videojs; 20908 }); 20909 20910 // checking that module is an object too because of umdjs/umd#35 20911 } else if (typeof exports === 'object' && typeof module === 'object') { 20912 module['exports'] = videojs; 20913 } 20914 20915 exports['default'] = videojs; 20916 module.exports = exports['default']; 20917 20918 },{"../../src/js/utils/merge-options.js":140,"./component":67,"./event-target":101,"./extend.js":102,"./player":110,"./plugins.js":111,"./setup":115,"./tech/flash.js":118,"./tech/html5.js":119,"./tech/tech.js":121,"./tracks/text-track.js":130,"./utils/browser.js":131,"./utils/create-deprecation-proxy.js":133,"./utils/dom.js":134,"./utils/events.js":135,"./utils/fn.js":136,"./utils/format-time.js":137,"./utils/log.js":139,"./utils/stylesheet.js":141,"./utils/time-ranges.js":142,"./utils/url.js":144,"global/document":1,"global/window":2,"lodash-compat/object/merge":40,"object.assign":45,"xhr":56}]},{},[145])(145) 20919 }); 20920 20921 20922 //# sourceMappingURL=video.js.map 20923 /* vtt.js - v0.12.1 (https://github.com/mozilla/vtt.js) built on 08-07-2015 */ 20924 20925 (function(root) { 20926 var vttjs = root.vttjs = {}; 20927 var cueShim = vttjs.VTTCue; 20928 var regionShim = vttjs.VTTRegion; 20929 var oldVTTCue = root.VTTCue; 20930 var oldVTTRegion = root.VTTRegion; 20931 20932 vttjs.shim = function() { 20933 vttjs.VTTCue = cueShim; 20934 vttjs.VTTRegion = regionShim; 20935 }; 20936 20937 vttjs.restore = function() { 20938 vttjs.VTTCue = oldVTTCue; 20939 vttjs.VTTRegion = oldVTTRegion; 20940 }; 20941 }(this)); 20942 20943 /** 20944 * Copyright 2013 vtt.js Contributors 20945 * 20946 * Licensed under the Apache License, Version 2.0 (the "License"); 20947 * you may not use this file except in compliance with the License. 20948 * You may obtain a copy of the License at 20949 * 20950 * http://www.apache.org/licenses/LICENSE-2.0 20951 * 20952 * Unless required by applicable law or agreed to in writing, software 20953 * distributed under the License is distributed on an "AS IS" BASIS, 20954 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20955 * See the License for the specific language governing permissions and 20956 * limitations under the License. 20957 */ 20958 20959 (function(root, vttjs) { 20960 20961 var autoKeyword = "auto"; 20962 var directionSetting = { 20963 "": true, 20964 "lr": true, 20965 "rl": true 20966 }; 20967 var alignSetting = { 20968 "start": true, 20969 "middle": true, 20970 "end": true, 20971 "left": true, 20972 "right": true 20973 }; 20974 20975 function findDirectionSetting(value) { 20976 if (typeof value !== "string") { 20977 return false; 20978 } 20979 var dir = directionSetting[value.toLowerCase()]; 20980 return dir ? value.toLowerCase() : false; 20981 } 20982 20983 function findAlignSetting(value) { 20984 if (typeof value !== "string") { 20985 return false; 20986 } 20987 var align = alignSetting[value.toLowerCase()]; 20988 return align ? value.toLowerCase() : false; 20989 } 20990 20991 function extend(obj) { 20992 var i = 1; 20993 for (; i < arguments.length; i++) { 20994 var cobj = arguments[i]; 20995 for (var p in cobj) { 20996 obj[p] = cobj[p]; 20997 } 20998 } 20999 21000 return obj; 21001 } 21002 21003 function VTTCue(startTime, endTime, text) { 21004 var cue = this; 21005 var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); 21006 var baseObj = {}; 21007 21008 if (isIE8) { 21009 cue = document.createElement('custom'); 21010 } else { 21011 baseObj.enumerable = true; 21012 } 21013 21014 /** 21015 * Shim implementation specific properties. These properties are not in 21016 * the spec. 21017 */ 21018 21019 // Lets us know when the VTTCue's data has changed in such a way that we need 21020 // to recompute its display state. This lets us compute its display state 21021 // lazily. 21022 cue.hasBeenReset = false; 21023 21024 /** 21025 * VTTCue and TextTrackCue properties 21026 * http://dev.w3.org/html5/webvtt/#vttcue-interface 21027 */ 21028 21029 var _id = ""; 21030 var _pauseOnExit = false; 21031 var _startTime = startTime; 21032 var _endTime = endTime; 21033 var _text = text; 21034 var _region = null; 21035 var _vertical = ""; 21036 var _snapToLines = true; 21037 var _line = "auto"; 21038 var _lineAlign = "start"; 21039 var _position = 50; 21040 var _positionAlign = "middle"; 21041 var _size = 50; 21042 var _align = "middle"; 21043 21044 Object.defineProperty(cue, 21045 "id", extend({}, baseObj, { 21046 get: function() { 21047 return _id; 21048 }, 21049 set: function(value) { 21050 _id = "" + value; 21051 } 21052 })); 21053 21054 Object.defineProperty(cue, 21055 "pauseOnExit", extend({}, baseObj, { 21056 get: function() { 21057 return _pauseOnExit; 21058 }, 21059 set: function(value) { 21060 _pauseOnExit = !!value; 21061 } 21062 })); 21063 21064 Object.defineProperty(cue, 21065 "startTime", extend({}, baseObj, { 21066 get: function() { 21067 return _startTime; 21068 }, 21069 set: function(value) { 21070 if (typeof value !== "number") { 21071 throw new TypeError("Start time must be set to a number."); 21072 } 21073 _startTime = value; 21074 this.hasBeenReset = true; 21075 } 21076 })); 21077 21078 Object.defineProperty(cue, 21079 "endTime", extend({}, baseObj, { 21080 get: function() { 21081 return _endTime; 21082 }, 21083 set: function(value) { 21084 if (typeof value !== "number") { 21085 throw new TypeError("End time must be set to a number."); 21086 } 21087 _endTime = value; 21088 this.hasBeenReset = true; 21089 } 21090 })); 21091 21092 Object.defineProperty(cue, 21093 "text", extend({}, baseObj, { 21094 get: function() { 21095 return _text; 21096 }, 21097 set: function(value) { 21098 _text = "" + value; 21099 this.hasBeenReset = true; 21100 } 21101 })); 21102 21103 Object.defineProperty(cue, 21104 "region", extend({}, baseObj, { 21105 get: function() { 21106 return _region; 21107 }, 21108 set: function(value) { 21109 _region = value; 21110 this.hasBeenReset = true; 21111 } 21112 })); 21113 21114 Object.defineProperty(cue, 21115 "vertical", extend({}, baseObj, { 21116 get: function() { 21117 return _vertical; 21118 }, 21119 set: function(value) { 21120 var setting = findDirectionSetting(value); 21121 // Have to check for false because the setting an be an empty string. 21122 if (setting === false) { 21123 throw new SyntaxError("An invalid or illegal string was specified."); 21124 } 21125 _vertical = setting; 21126 this.hasBeenReset = true; 21127 } 21128 })); 21129 21130 Object.defineProperty(cue, 21131 "snapToLines", extend({}, baseObj, { 21132 get: function() { 21133 return _snapToLines; 21134 }, 21135 set: function(value) { 21136 _snapToLines = !!value; 21137 this.hasBeenReset = true; 21138 } 21139 })); 21140 21141 Object.defineProperty(cue, 21142 "line", extend({}, baseObj, { 21143 get: function() { 21144 return _line; 21145 }, 21146 set: function(value) { 21147 if (typeof value !== "number" && value !== autoKeyword) { 21148 throw new SyntaxError("An invalid number or illegal string was specified."); 21149 } 21150 _line = value; 21151 this.hasBeenReset = true; 21152 } 21153 })); 21154 21155 Object.defineProperty(cue, 21156 "lineAlign", extend({}, baseObj, { 21157 get: function() { 21158 return _lineAlign; 21159 }, 21160 set: function(value) { 21161 var setting = findAlignSetting(value); 21162 if (!setting) { 21163 throw new SyntaxError("An invalid or illegal string was specified."); 21164 } 21165 _lineAlign = setting; 21166 this.hasBeenReset = true; 21167 } 21168 })); 21169 21170 Object.defineProperty(cue, 21171 "position", extend({}, baseObj, { 21172 get: function() { 21173 return _position; 21174 }, 21175 set: function(value) { 21176 if (value < 0 || value > 100) { 21177 throw new Error("Position must be between 0 and 100."); 21178 } 21179 _position = value; 21180 this.hasBeenReset = true; 21181 } 21182 })); 21183 21184 Object.defineProperty(cue, 21185 "positionAlign", extend({}, baseObj, { 21186 get: function() { 21187 return _positionAlign; 21188 }, 21189 set: function(value) { 21190 var setting = findAlignSetting(value); 21191 if (!setting) { 21192 throw new SyntaxError("An invalid or illegal string was specified."); 21193 } 21194 _positionAlign = setting; 21195 this.hasBeenReset = true; 21196 } 21197 })); 21198 21199 Object.defineProperty(cue, 21200 "size", extend({}, baseObj, { 21201 get: function() { 21202 return _size; 21203 }, 21204 set: function(value) { 21205 if (value < 0 || value > 100) { 21206 throw new Error("Size must be between 0 and 100."); 21207 } 21208 _size = value; 21209 this.hasBeenReset = true; 21210 } 21211 })); 21212 21213 Object.defineProperty(cue, 21214 "align", extend({}, baseObj, { 21215 get: function() { 21216 return _align; 21217 }, 21218 set: function(value) { 21219 var setting = findAlignSetting(value); 21220 if (!setting) { 21221 throw new SyntaxError("An invalid or illegal string was specified."); 21222 } 21223 _align = setting; 21224 this.hasBeenReset = true; 21225 } 21226 })); 21227 21228 /** 21229 * Other <track> spec defined properties 21230 */ 21231 21232 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state 21233 cue.displayState = undefined; 21234 21235 if (isIE8) { 21236 return cue; 21237 } 21238 } 21239 21240 /** 21241 * VTTCue methods 21242 */ 21243 21244 VTTCue.prototype.getCueAsHTML = function() { 21245 // Assume WebVTT.convertCueToDOMTree is on the global. 21246 return WebVTT.convertCueToDOMTree(window, this.text); 21247 }; 21248 21249 root.VTTCue = root.VTTCue || VTTCue; 21250 vttjs.VTTCue = VTTCue; 21251 }(this, (this.vttjs || {}))); 21252 21253 /** 21254 * Copyright 2013 vtt.js Contributors 21255 * 21256 * Licensed under the Apache License, Version 2.0 (the "License"); 21257 * you may not use this file except in compliance with the License. 21258 * You may obtain a copy of the License at 21259 * 21260 * http://www.apache.org/licenses/LICENSE-2.0 21261 * 21262 * Unless required by applicable law or agreed to in writing, software 21263 * distributed under the License is distributed on an "AS IS" BASIS, 21264 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21265 * See the License for the specific language governing permissions and 21266 * limitations under the License. 21267 */ 21268 21269 (function(root, vttjs) { 21270 21271 var scrollSetting = { 21272 "": true, 21273 "up": true 21274 }; 21275 21276 function findScrollSetting(value) { 21277 if (typeof value !== "string") { 21278 return false; 21279 } 21280 var scroll = scrollSetting[value.toLowerCase()]; 21281 return scroll ? value.toLowerCase() : false; 21282 } 21283 21284 function isValidPercentValue(value) { 21285 return typeof value === "number" && (value >= 0 && value <= 100); 21286 } 21287 21288 // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface 21289 function VTTRegion() { 21290 var _width = 100; 21291 var _lines = 3; 21292 var _regionAnchorX = 0; 21293 var _regionAnchorY = 100; 21294 var _viewportAnchorX = 0; 21295 var _viewportAnchorY = 100; 21296 var _scroll = ""; 21297 21298 Object.defineProperties(this, { 21299 "width": { 21300 enumerable: true, 21301 get: function() { 21302 return _width; 21303 }, 21304 set: function(value) { 21305 if (!isValidPercentValue(value)) { 21306 throw new Error("Width must be between 0 and 100."); 21307 } 21308 _width = value; 21309 } 21310 }, 21311 "lines": { 21312 enumerable: true, 21313 get: function() { 21314 return _lines; 21315 }, 21316 set: function(value) { 21317 if (typeof value !== "number") { 21318 throw new TypeError("Lines must be set to a number."); 21319 } 21320 _lines = value; 21321 } 21322 }, 21323 "regionAnchorY": { 21324 enumerable: true, 21325 get: function() { 21326 return _regionAnchorY; 21327 }, 21328 set: function(value) { 21329 if (!isValidPercentValue(value)) { 21330 throw new Error("RegionAnchorX must be between 0 and 100."); 21331 } 21332 _regionAnchorY = value; 21333 } 21334 }, 21335 "regionAnchorX": { 21336 enumerable: true, 21337 get: function() { 21338 return _regionAnchorX; 21339 }, 21340 set: function(value) { 21341 if(!isValidPercentValue(value)) { 21342 throw new Error("RegionAnchorY must be between 0 and 100."); 21343 } 21344 _regionAnchorX = value; 21345 } 21346 }, 21347 "viewportAnchorY": { 21348 enumerable: true, 21349 get: function() { 21350 return _viewportAnchorY; 21351 }, 21352 set: function(value) { 21353 if (!isValidPercentValue(value)) { 21354 throw new Error("ViewportAnchorY must be between 0 and 100."); 21355 } 21356 _viewportAnchorY = value; 21357 } 21358 }, 21359 "viewportAnchorX": { 21360 enumerable: true, 21361 get: function() { 21362 return _viewportAnchorX; 21363 }, 21364 set: function(value) { 21365 if (!isValidPercentValue(value)) { 21366 throw new Error("ViewportAnchorX must be between 0 and 100."); 21367 } 21368 _viewportAnchorX = value; 21369 } 21370 }, 21371 "scroll": { 21372 enumerable: true, 21373 get: function() { 21374 return _scroll; 21375 }, 21376 set: function(value) { 21377 var setting = findScrollSetting(value); 21378 // Have to check for false as an empty string is a legal value. 21379 if (setting === false) { 21380 throw new SyntaxError("An invalid or illegal string was specified."); 21381 } 21382 _scroll = setting; 21383 } 21384 } 21385 }); 21386 } 21387 21388 root.VTTRegion = root.VTTRegion || VTTRegion; 21389 vttjs.VTTRegion = VTTRegion; 21390 }(this, (this.vttjs || {}))); 21391 21392 /** 21393 * Copyright 2013 vtt.js Contributors 21394 * 21395 * Licensed under the Apache License, Version 2.0 (the "License"); 21396 * you may not use this file except in compliance with the License. 21397 * You may obtain a copy of the License at 21398 * 21399 * http://www.apache.org/licenses/LICENSE-2.0 21400 * 21401 * Unless required by applicable law or agreed to in writing, software 21402 * distributed under the License is distributed on an "AS IS" BASIS, 21403 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21404 * See the License for the specific language governing permissions and 21405 * limitations under the License. 21406 */ 21407 21408 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 21409 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 21410 21411 (function(global) { 21412 21413 var _objCreate = Object.create || (function() { 21414 function F() {} 21415 return function(o) { 21416 if (arguments.length !== 1) { 21417 throw new Error('Object.create shim only accepts one parameter.'); 21418 } 21419 F.prototype = o; 21420 return new F(); 21421 }; 21422 })(); 21423 21424 // Creates a new ParserError object from an errorData object. The errorData 21425 // object should have default code and message properties. The default message 21426 // property can be overriden by passing in a message parameter. 21427 // See ParsingError.Errors below for acceptable errors. 21428 function ParsingError(errorData, message) { 21429 this.name = "ParsingError"; 21430 this.code = errorData.code; 21431 this.message = message || errorData.message; 21432 } 21433 ParsingError.prototype = _objCreate(Error.prototype); 21434 ParsingError.prototype.constructor = ParsingError; 21435 21436 // ParsingError metadata for acceptable ParsingErrors. 21437 ParsingError.Errors = { 21438 BadSignature: { 21439 code: 0, 21440 message: "Malformed WebVTT signature." 21441 }, 21442 BadTimeStamp: { 21443 code: 1, 21444 message: "Malformed time stamp." 21445 } 21446 }; 21447 21448 // Try to parse input as a time stamp. 21449 function parseTimeStamp(input) { 21450 21451 function computeSeconds(h, m, s, f) { 21452 return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; 21453 } 21454 21455 var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); 21456 if (!m) { 21457 return null; 21458 } 21459 21460 if (m[3]) { 21461 // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] 21462 return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]); 21463 } else if (m[1] > 59) { 21464 // Timestamp takes the form of [hours]:[minutes].[milliseconds] 21465 // First position is hours as it's over 59. 21466 return computeSeconds(m[1], m[2], 0, m[4]); 21467 } else { 21468 // Timestamp takes the form of [minutes]:[seconds].[milliseconds] 21469 return computeSeconds(0, m[1], m[2], m[4]); 21470 } 21471 } 21472 21473 // A settings object holds key/value pairs and will ignore anything but the first 21474 // assignment to a specific key. 21475 function Settings() { 21476 this.values = _objCreate(null); 21477 } 21478 21479 Settings.prototype = { 21480 // Only accept the first assignment to any key. 21481 set: function(k, v) { 21482 if (!this.get(k) && v !== "") { 21483 this.values[k] = v; 21484 } 21485 }, 21486 // Return the value for a key, or a default value. 21487 // If 'defaultKey' is passed then 'dflt' is assumed to be an object with 21488 // a number of possible default values as properties where 'defaultKey' is 21489 // the key of the property that will be chosen; otherwise it's assumed to be 21490 // a single value. 21491 get: function(k, dflt, defaultKey) { 21492 if (defaultKey) { 21493 return this.has(k) ? this.values[k] : dflt[defaultKey]; 21494 } 21495 return this.has(k) ? this.values[k] : dflt; 21496 }, 21497 // Check whether we have a value for a key. 21498 has: function(k) { 21499 return k in this.values; 21500 }, 21501 // Accept a setting if its one of the given alternatives. 21502 alt: function(k, v, a) { 21503 for (var n = 0; n < a.length; ++n) { 21504 if (v === a[n]) { 21505 this.set(k, v); 21506 break; 21507 } 21508 } 21509 }, 21510 // Accept a setting if its a valid (signed) integer. 21511 integer: function(k, v) { 21512 if (/^-?\d+$/.test(v)) { // integer 21513 this.set(k, parseInt(v, 10)); 21514 } 21515 }, 21516 // Accept a setting if its a valid percentage. 21517 percent: function(k, v) { 21518 var m; 21519 if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) { 21520 v = parseFloat(v); 21521 if (v >= 0 && v <= 100) { 21522 this.set(k, v); 21523 return true; 21524 } 21525 } 21526 return false; 21527 } 21528 }; 21529 21530 // Helper function to parse input into groups separated by 'groupDelim', and 21531 // interprete each group as a key/value pair separated by 'keyValueDelim'. 21532 function parseOptions(input, callback, keyValueDelim, groupDelim) { 21533 var groups = groupDelim ? input.split(groupDelim) : [input]; 21534 for (var i in groups) { 21535 if (typeof groups[i] !== "string") { 21536 continue; 21537 } 21538 var kv = groups[i].split(keyValueDelim); 21539 if (kv.length !== 2) { 21540 continue; 21541 } 21542 var k = kv[0]; 21543 var v = kv[1]; 21544 callback(k, v); 21545 } 21546 } 21547 21548 function parseCue(input, cue, regionList) { 21549 // Remember the original input if we need to throw an error. 21550 var oInput = input; 21551 // 4.1 WebVTT timestamp 21552 function consumeTimeStamp() { 21553 var ts = parseTimeStamp(input); 21554 if (ts === null) { 21555 throw new ParsingError(ParsingError.Errors.BadTimeStamp, 21556 "Malformed timestamp: " + oInput); 21557 } 21558 // Remove time stamp from input. 21559 input = input.replace(/^[^\sa-zA-Z-]+/, ""); 21560 return ts; 21561 } 21562 21563 // 4.4.2 WebVTT cue settings 21564 function consumeCueSettings(input, cue) { 21565 var settings = new Settings(); 21566 21567 parseOptions(input, function (k, v) { 21568 switch (k) { 21569 case "region": 21570 // Find the last region we parsed with the same region id. 21571 for (var i = regionList.length - 1; i >= 0; i--) { 21572 if (regionList[i].id === v) { 21573 settings.set(k, regionList[i].region); 21574 break; 21575 } 21576 } 21577 break; 21578 case "vertical": 21579 settings.alt(k, v, ["rl", "lr"]); 21580 break; 21581 case "line": 21582 var vals = v.split(","), 21583 vals0 = vals[0]; 21584 settings.integer(k, vals0); 21585 settings.percent(k, vals0) ? settings.set("snapToLines", false) : null; 21586 settings.alt(k, vals0, ["auto"]); 21587 if (vals.length === 2) { 21588 settings.alt("lineAlign", vals[1], ["start", "middle", "end"]); 21589 } 21590 break; 21591 case "position": 21592 vals = v.split(","); 21593 settings.percent(k, vals[0]); 21594 if (vals.length === 2) { 21595 settings.alt("positionAlign", vals[1], ["start", "middle", "end"]); 21596 } 21597 break; 21598 case "size": 21599 settings.percent(k, v); 21600 break; 21601 case "align": 21602 settings.alt(k, v, ["start", "middle", "end", "left", "right"]); 21603 break; 21604 } 21605 }, /:/, /\s/); 21606 21607 // Apply default values for any missing fields. 21608 cue.region = settings.get("region", null); 21609 cue.vertical = settings.get("vertical", ""); 21610 cue.line = settings.get("line", "auto"); 21611 cue.lineAlign = settings.get("lineAlign", "start"); 21612 cue.snapToLines = settings.get("snapToLines", true); 21613 cue.size = settings.get("size", 100); 21614 cue.align = settings.get("align", "middle"); 21615 cue.position = settings.get("position", { 21616 start: 0, 21617 left: 0, 21618 middle: 50, 21619 end: 100, 21620 right: 100 21621 }, cue.align); 21622 cue.positionAlign = settings.get("positionAlign", { 21623 start: "start", 21624 left: "start", 21625 middle: "middle", 21626 end: "end", 21627 right: "end" 21628 }, cue.align); 21629 } 21630 21631 function skipWhitespace() { 21632 input = input.replace(/^\s+/, ""); 21633 } 21634 21635 // 4.1 WebVTT cue timings. 21636 skipWhitespace(); 21637 cue.startTime = consumeTimeStamp(); // (1) collect cue start time 21638 skipWhitespace(); 21639 if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->" 21640 throw new ParsingError(ParsingError.Errors.BadTimeStamp, 21641 "Malformed time stamp (time stamps must be separated by '-->'): " + 21642 oInput); 21643 } 21644 input = input.substr(3); 21645 skipWhitespace(); 21646 cue.endTime = consumeTimeStamp(); // (5) collect cue end time 21647 21648 // 4.1 WebVTT cue settings list. 21649 skipWhitespace(); 21650 consumeCueSettings(input, cue); 21651 } 21652 21653 var ESCAPE = { 21654 "&": "&", 21655 "<": "<", 21656 ">": ">", 21657 "‎": "\u200e", 21658 "‏": "\u200f", 21659 " ": "\u00a0" 21660 }; 21661 21662 var TAG_NAME = { 21663 c: "span", 21664 i: "i", 21665 b: "b", 21666 u: "u", 21667 ruby: "ruby", 21668 rt: "rt", 21669 v: "span", 21670 lang: "span" 21671 }; 21672 21673 var TAG_ANNOTATION = { 21674 v: "title", 21675 lang: "lang" 21676 }; 21677 21678 var NEEDS_PARENT = { 21679 rt: "ruby" 21680 }; 21681 21682 // Parse content into a document fragment. 21683 function parseContent(window, input) { 21684 function nextToken() { 21685 // Check for end-of-string. 21686 if (!input) { 21687 return null; 21688 } 21689 21690 // Consume 'n' characters from the input. 21691 function consume(result) { 21692 input = input.substr(result.length); 21693 return result; 21694 } 21695 21696 var m = input.match(/^([^<]*)(<[^>]+>?)?/); 21697 // If there is some text before the next tag, return it, otherwise return 21698 // the tag. 21699 return consume(m[1] ? m[1] : m[2]); 21700 } 21701 21702 // Unescape a string 's'. 21703 function unescape1(e) { 21704 return ESCAPE[e]; 21705 } 21706 function unescape(s) { 21707 while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) { 21708 s = s.replace(m[0], unescape1); 21709 } 21710 return s; 21711 } 21712 21713 function shouldAdd(current, element) { 21714 return !NEEDS_PARENT[element.localName] || 21715 NEEDS_PARENT[element.localName] === current.localName; 21716 } 21717 21718 // Create an element for this tag. 21719 function createElement(type, annotation) { 21720 var tagName = TAG_NAME[type]; 21721 if (!tagName) { 21722 return null; 21723 } 21724 var element = window.document.createElement(tagName); 21725 element.localName = tagName; 21726 var name = TAG_ANNOTATION[type]; 21727 if (name && annotation) { 21728 element[name] = annotation.trim(); 21729 } 21730 return element; 21731 } 21732 21733 var rootDiv = window.document.createElement("div"), 21734 current = rootDiv, 21735 t, 21736 tagStack = []; 21737 21738 while ((t = nextToken()) !== null) { 21739 if (t[0] === '<') { 21740 if (t[1] === "/") { 21741 // If the closing tag matches, move back up to the parent node. 21742 if (tagStack.length && 21743 tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) { 21744 tagStack.pop(); 21745 current = current.parentNode; 21746 } 21747 // Otherwise just ignore the end tag. 21748 continue; 21749 } 21750 var ts = parseTimeStamp(t.substr(1, t.length - 2)); 21751 var node; 21752 if (ts) { 21753 // Timestamps are lead nodes as well. 21754 node = window.document.createProcessingInstruction("timestamp", ts); 21755 current.appendChild(node); 21756 continue; 21757 } 21758 var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); 21759 // If we can't parse the tag, skip to the next tag. 21760 if (!m) { 21761 continue; 21762 } 21763 // Try to construct an element, and ignore the tag if we couldn't. 21764 node = createElement(m[1], m[3]); 21765 if (!node) { 21766 continue; 21767 } 21768 // Determine if the tag should be added based on the context of where it 21769 // is placed in the cuetext. 21770 if (!shouldAdd(current, node)) { 21771 continue; 21772 } 21773 // Set the class list (as a list of classes, separated by space). 21774 if (m[2]) { 21775 node.className = m[2].substr(1).replace('.', ' '); 21776 } 21777 // Append the node to the current node, and enter the scope of the new 21778 // node. 21779 tagStack.push(m[1]); 21780 current.appendChild(node); 21781 current = node; 21782 continue; 21783 } 21784 21785 // Text nodes are leaf nodes. 21786 current.appendChild(window.document.createTextNode(unescape(t))); 21787 } 21788 21789 return rootDiv; 21790 } 21791 21792 // This is a list of all the Unicode characters that have a strong 21793 // right-to-left category. What this means is that these characters are 21794 // written right-to-left for sure. It was generated by pulling all the strong 21795 // right-to-left characters out of the Unicode data table. That table can 21796 // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt 21797 var strongRTLChars = [0x05BE, 0x05C0, 0x05C3, 0x05C6, 0x05D0, 0x05D1, 21798 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 21799 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 21800 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05F0, 0x05F1, 21801 0x05F2, 0x05F3, 0x05F4, 0x0608, 0x060B, 0x060D, 0x061B, 0x061E, 0x061F, 21802 0x0620, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 21803 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 21804 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 21805 0x063B, 0x063C, 0x063D, 0x063E, 0x063F, 0x0640, 0x0641, 0x0642, 0x0643, 21806 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x066D, 0x066E, 21807 0x066F, 0x0671, 0x0672, 0x0673, 0x0674, 0x0675, 0x0676, 0x0677, 0x0678, 21808 0x0679, 0x067A, 0x067B, 0x067C, 0x067D, 0x067E, 0x067F, 0x0680, 0x0681, 21809 0x0682, 0x0683, 0x0684, 0x0685, 0x0686, 0x0687, 0x0688, 0x0689, 0x068A, 21810 0x068B, 0x068C, 0x068D, 0x068E, 0x068F, 0x0690, 0x0691, 0x0692, 0x0693, 21811 0x0694, 0x0695, 0x0696, 0x0697, 0x0698, 0x0699, 0x069A, 0x069B, 0x069C, 21812 0x069D, 0x069E, 0x069F, 0x06A0, 0x06A1, 0x06A2, 0x06A3, 0x06A4, 0x06A5, 21813 0x06A6, 0x06A7, 0x06A8, 0x06A9, 0x06AA, 0x06AB, 0x06AC, 0x06AD, 0x06AE, 21814 0x06AF, 0x06B0, 0x06B1, 0x06B2, 0x06B3, 0x06B4, 0x06B5, 0x06B6, 0x06B7, 21815 0x06B8, 0x06B9, 0x06BA, 0x06BB, 0x06BC, 0x06BD, 0x06BE, 0x06BF, 0x06C0, 21816 0x06C1, 0x06C2, 0x06C3, 0x06C4, 0x06C5, 0x06C6, 0x06C7, 0x06C8, 0x06C9, 21817 0x06CA, 0x06CB, 0x06CC, 0x06CD, 0x06CE, 0x06CF, 0x06D0, 0x06D1, 0x06D2, 21818 0x06D3, 0x06D4, 0x06D5, 0x06E5, 0x06E6, 0x06EE, 0x06EF, 0x06FA, 0x06FB, 21819 0x06FC, 0x06FD, 0x06FE, 0x06FF, 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 21820 0x0705, 0x0706, 0x0707, 0x0708, 0x0709, 0x070A, 0x070B, 0x070C, 0x070D, 21821 0x070F, 0x0710, 0x0712, 0x0713, 0x0714, 0x0715, 0x0716, 0x0717, 0x0718, 21822 0x0719, 0x071A, 0x071B, 0x071C, 0x071D, 0x071E, 0x071F, 0x0720, 0x0721, 21823 0x0722, 0x0723, 0x0724, 0x0725, 0x0726, 0x0727, 0x0728, 0x0729, 0x072A, 21824 0x072B, 0x072C, 0x072D, 0x072E, 0x072F, 0x074D, 0x074E, 0x074F, 0x0750, 21825 0x0751, 0x0752, 0x0753, 0x0754, 0x0755, 0x0756, 0x0757, 0x0758, 0x0759, 21826 0x075A, 0x075B, 0x075C, 0x075D, 0x075E, 0x075F, 0x0760, 0x0761, 0x0762, 21827 0x0763, 0x0764, 0x0765, 0x0766, 0x0767, 0x0768, 0x0769, 0x076A, 0x076B, 21828 0x076C, 0x076D, 0x076E, 0x076F, 0x0770, 0x0771, 0x0772, 0x0773, 0x0774, 21829 0x0775, 0x0776, 0x0777, 0x0778, 0x0779, 0x077A, 0x077B, 0x077C, 0x077D, 21830 0x077E, 0x077F, 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0786, 21831 0x0787, 0x0788, 0x0789, 0x078A, 0x078B, 0x078C, 0x078D, 0x078E, 0x078F, 21832 0x0790, 0x0791, 0x0792, 0x0793, 0x0794, 0x0795, 0x0796, 0x0797, 0x0798, 21833 0x0799, 0x079A, 0x079B, 0x079C, 0x079D, 0x079E, 0x079F, 0x07A0, 0x07A1, 21834 0x07A2, 0x07A3, 0x07A4, 0x07A5, 0x07B1, 0x07C0, 0x07C1, 0x07C2, 0x07C3, 21835 0x07C4, 0x07C5, 0x07C6, 0x07C7, 0x07C8, 0x07C9, 0x07CA, 0x07CB, 0x07CC, 21836 0x07CD, 0x07CE, 0x07CF, 0x07D0, 0x07D1, 0x07D2, 0x07D3, 0x07D4, 0x07D5, 21837 0x07D6, 0x07D7, 0x07D8, 0x07D9, 0x07DA, 0x07DB, 0x07DC, 0x07DD, 0x07DE, 21838 0x07DF, 0x07E0, 0x07E1, 0x07E2, 0x07E3, 0x07E4, 0x07E5, 0x07E6, 0x07E7, 21839 0x07E8, 0x07E9, 0x07EA, 0x07F4, 0x07F5, 0x07FA, 0x0800, 0x0801, 0x0802, 21840 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809, 0x080A, 0x080B, 21841 0x080C, 0x080D, 0x080E, 0x080F, 0x0810, 0x0811, 0x0812, 0x0813, 0x0814, 21842 0x0815, 0x081A, 0x0824, 0x0828, 0x0830, 0x0831, 0x0832, 0x0833, 0x0834, 21843 0x0835, 0x0836, 0x0837, 0x0838, 0x0839, 0x083A, 0x083B, 0x083C, 0x083D, 21844 0x083E, 0x0840, 0x0841, 0x0842, 0x0843, 0x0844, 0x0845, 0x0846, 0x0847, 21845 0x0848, 0x0849, 0x084A, 0x084B, 0x084C, 0x084D, 0x084E, 0x084F, 0x0850, 21846 0x0851, 0x0852, 0x0853, 0x0854, 0x0855, 0x0856, 0x0857, 0x0858, 0x085E, 21847 0x08A0, 0x08A2, 0x08A3, 0x08A4, 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 21848 0x08AA, 0x08AB, 0x08AC, 0x200F, 0xFB1D, 0xFB1F, 0xFB20, 0xFB21, 0xFB22, 21849 0xFB23, 0xFB24, 0xFB25, 0xFB26, 0xFB27, 0xFB28, 0xFB2A, 0xFB2B, 0xFB2C, 21850 0xFB2D, 0xFB2E, 0xFB2F, 0xFB30, 0xFB31, 0xFB32, 0xFB33, 0xFB34, 0xFB35, 21851 0xFB36, 0xFB38, 0xFB39, 0xFB3A, 0xFB3B, 0xFB3C, 0xFB3E, 0xFB40, 0xFB41, 21852 0xFB43, 0xFB44, 0xFB46, 0xFB47, 0xFB48, 0xFB49, 0xFB4A, 0xFB4B, 0xFB4C, 21853 0xFB4D, 0xFB4E, 0xFB4F, 0xFB50, 0xFB51, 0xFB52, 0xFB53, 0xFB54, 0xFB55, 21854 0xFB56, 0xFB57, 0xFB58, 0xFB59, 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D, 0xFB5E, 21855 0xFB5F, 0xFB60, 0xFB61, 0xFB62, 0xFB63, 0xFB64, 0xFB65, 0xFB66, 0xFB67, 21856 0xFB68, 0xFB69, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D, 0xFB6E, 0xFB6F, 0xFB70, 21857 0xFB71, 0xFB72, 0xFB73, 0xFB74, 0xFB75, 0xFB76, 0xFB77, 0xFB78, 0xFB79, 21858 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, 0xFB7E, 0xFB7F, 0xFB80, 0xFB81, 0xFB82, 21859 0xFB83, 0xFB84, 0xFB85, 0xFB86, 0xFB87, 0xFB88, 0xFB89, 0xFB8A, 0xFB8B, 21860 0xFB8C, 0xFB8D, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, 0xFB92, 0xFB93, 0xFB94, 21861 0xFB95, 0xFB96, 0xFB97, 0xFB98, 0xFB99, 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D, 21862 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3, 0xFBA4, 0xFBA5, 0xFBA6, 21863 0xFBA7, 0xFBA8, 0xFBA9, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, 0xFBAE, 0xFBAF, 21864 0xFBB0, 0xFBB1, 0xFBB2, 0xFBB3, 0xFBB4, 0xFBB5, 0xFBB6, 0xFBB7, 0xFBB8, 21865 0xFBB9, 0xFBBA, 0xFBBB, 0xFBBC, 0xFBBD, 0xFBBE, 0xFBBF, 0xFBC0, 0xFBC1, 21866 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6, 0xFBD7, 0xFBD8, 0xFBD9, 0xFBDA, 0xFBDB, 21867 0xFBDC, 0xFBDD, 0xFBDE, 0xFBDF, 0xFBE0, 0xFBE1, 0xFBE2, 0xFBE3, 0xFBE4, 21868 0xFBE5, 0xFBE6, 0xFBE7, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEB, 0xFBEC, 0xFBED, 21869 0xFBEE, 0xFBEF, 0xFBF0, 0xFBF1, 0xFBF2, 0xFBF3, 0xFBF4, 0xFBF5, 0xFBF6, 21870 0xFBF7, 0xFBF8, 0xFBF9, 0xFBFA, 0xFBFB, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF, 21871 0xFC00, 0xFC01, 0xFC02, 0xFC03, 0xFC04, 0xFC05, 0xFC06, 0xFC07, 0xFC08, 21872 0xFC09, 0xFC0A, 0xFC0B, 0xFC0C, 0xFC0D, 0xFC0E, 0xFC0F, 0xFC10, 0xFC11, 21873 0xFC12, 0xFC13, 0xFC14, 0xFC15, 0xFC16, 0xFC17, 0xFC18, 0xFC19, 0xFC1A, 21874 0xFC1B, 0xFC1C, 0xFC1D, 0xFC1E, 0xFC1F, 0xFC20, 0xFC21, 0xFC22, 0xFC23, 21875 0xFC24, 0xFC25, 0xFC26, 0xFC27, 0xFC28, 0xFC29, 0xFC2A, 0xFC2B, 0xFC2C, 21876 0xFC2D, 0xFC2E, 0xFC2F, 0xFC30, 0xFC31, 0xFC32, 0xFC33, 0xFC34, 0xFC35, 21877 0xFC36, 0xFC37, 0xFC38, 0xFC39, 0xFC3A, 0xFC3B, 0xFC3C, 0xFC3D, 0xFC3E, 21878 0xFC3F, 0xFC40, 0xFC41, 0xFC42, 0xFC43, 0xFC44, 0xFC45, 0xFC46, 0xFC47, 21879 0xFC48, 0xFC49, 0xFC4A, 0xFC4B, 0xFC4C, 0xFC4D, 0xFC4E, 0xFC4F, 0xFC50, 21880 0xFC51, 0xFC52, 0xFC53, 0xFC54, 0xFC55, 0xFC56, 0xFC57, 0xFC58, 0xFC59, 21881 0xFC5A, 0xFC5B, 0xFC5C, 0xFC5D, 0xFC5E, 0xFC5F, 0xFC60, 0xFC61, 0xFC62, 21882 0xFC63, 0xFC64, 0xFC65, 0xFC66, 0xFC67, 0xFC68, 0xFC69, 0xFC6A, 0xFC6B, 21883 0xFC6C, 0xFC6D, 0xFC6E, 0xFC6F, 0xFC70, 0xFC71, 0xFC72, 0xFC73, 0xFC74, 21884 0xFC75, 0xFC76, 0xFC77, 0xFC78, 0xFC79, 0xFC7A, 0xFC7B, 0xFC7C, 0xFC7D, 21885 0xFC7E, 0xFC7F, 0xFC80, 0xFC81, 0xFC82, 0xFC83, 0xFC84, 0xFC85, 0xFC86, 21886 0xFC87, 0xFC88, 0xFC89, 0xFC8A, 0xFC8B, 0xFC8C, 0xFC8D, 0xFC8E, 0xFC8F, 21887 0xFC90, 0xFC91, 0xFC92, 0xFC93, 0xFC94, 0xFC95, 0xFC96, 0xFC97, 0xFC98, 21888 0xFC99, 0xFC9A, 0xFC9B, 0xFC9C, 0xFC9D, 0xFC9E, 0xFC9F, 0xFCA0, 0xFCA1, 21889 0xFCA2, 0xFCA3, 0xFCA4, 0xFCA5, 0xFCA6, 0xFCA7, 0xFCA8, 0xFCA9, 0xFCAA, 21890 0xFCAB, 0xFCAC, 0xFCAD, 0xFCAE, 0xFCAF, 0xFCB0, 0xFCB1, 0xFCB2, 0xFCB3, 21891 0xFCB4, 0xFCB5, 0xFCB6, 0xFCB7, 0xFCB8, 0xFCB9, 0xFCBA, 0xFCBB, 0xFCBC, 21892 0xFCBD, 0xFCBE, 0xFCBF, 0xFCC0, 0xFCC1, 0xFCC2, 0xFCC3, 0xFCC4, 0xFCC5, 21893 0xFCC6, 0xFCC7, 0xFCC8, 0xFCC9, 0xFCCA, 0xFCCB, 0xFCCC, 0xFCCD, 0xFCCE, 21894 0xFCCF, 0xFCD0, 0xFCD1, 0xFCD2, 0xFCD3, 0xFCD4, 0xFCD5, 0xFCD6, 0xFCD7, 21895 0xFCD8, 0xFCD9, 0xFCDA, 0xFCDB, 0xFCDC, 0xFCDD, 0xFCDE, 0xFCDF, 0xFCE0, 21896 0xFCE1, 0xFCE2, 0xFCE3, 0xFCE4, 0xFCE5, 0xFCE6, 0xFCE7, 0xFCE8, 0xFCE9, 21897 0xFCEA, 0xFCEB, 0xFCEC, 0xFCED, 0xFCEE, 0xFCEF, 0xFCF0, 0xFCF1, 0xFCF2, 21898 0xFCF3, 0xFCF4, 0xFCF5, 0xFCF6, 0xFCF7, 0xFCF8, 0xFCF9, 0xFCFA, 0xFCFB, 21899 0xFCFC, 0xFCFD, 0xFCFE, 0xFCFF, 0xFD00, 0xFD01, 0xFD02, 0xFD03, 0xFD04, 21900 0xFD05, 0xFD06, 0xFD07, 0xFD08, 0xFD09, 0xFD0A, 0xFD0B, 0xFD0C, 0xFD0D, 21901 0xFD0E, 0xFD0F, 0xFD10, 0xFD11, 0xFD12, 0xFD13, 0xFD14, 0xFD15, 0xFD16, 21902 0xFD17, 0xFD18, 0xFD19, 0xFD1A, 0xFD1B, 0xFD1C, 0xFD1D, 0xFD1E, 0xFD1F, 21903 0xFD20, 0xFD21, 0xFD22, 0xFD23, 0xFD24, 0xFD25, 0xFD26, 0xFD27, 0xFD28, 21904 0xFD29, 0xFD2A, 0xFD2B, 0xFD2C, 0xFD2D, 0xFD2E, 0xFD2F, 0xFD30, 0xFD31, 21905 0xFD32, 0xFD33, 0xFD34, 0xFD35, 0xFD36, 0xFD37, 0xFD38, 0xFD39, 0xFD3A, 21906 0xFD3B, 0xFD3C, 0xFD3D, 0xFD50, 0xFD51, 0xFD52, 0xFD53, 0xFD54, 0xFD55, 21907 0xFD56, 0xFD57, 0xFD58, 0xFD59, 0xFD5A, 0xFD5B, 0xFD5C, 0xFD5D, 0xFD5E, 21908 0xFD5F, 0xFD60, 0xFD61, 0xFD62, 0xFD63, 0xFD64, 0xFD65, 0xFD66, 0xFD67, 21909 0xFD68, 0xFD69, 0xFD6A, 0xFD6B, 0xFD6C, 0xFD6D, 0xFD6E, 0xFD6F, 0xFD70, 21910 0xFD71, 0xFD72, 0xFD73, 0xFD74, 0xFD75, 0xFD76, 0xFD77, 0xFD78, 0xFD79, 21911 0xFD7A, 0xFD7B, 0xFD7C, 0xFD7D, 0xFD7E, 0xFD7F, 0xFD80, 0xFD81, 0xFD82, 21912 0xFD83, 0xFD84, 0xFD85, 0xFD86, 0xFD87, 0xFD88, 0xFD89, 0xFD8A, 0xFD8B, 21913 0xFD8C, 0xFD8D, 0xFD8E, 0xFD8F, 0xFD92, 0xFD93, 0xFD94, 0xFD95, 0xFD96, 21914 0xFD97, 0xFD98, 0xFD99, 0xFD9A, 0xFD9B, 0xFD9C, 0xFD9D, 0xFD9E, 0xFD9F, 21915 0xFDA0, 0xFDA1, 0xFDA2, 0xFDA3, 0xFDA4, 0xFDA5, 0xFDA6, 0xFDA7, 0xFDA8, 21916 0xFDA9, 0xFDAA, 0xFDAB, 0xFDAC, 0xFDAD, 0xFDAE, 0xFDAF, 0xFDB0, 0xFDB1, 21917 0xFDB2, 0xFDB3, 0xFDB4, 0xFDB5, 0xFDB6, 0xFDB7, 0xFDB8, 0xFDB9, 0xFDBA, 21918 0xFDBB, 0xFDBC, 0xFDBD, 0xFDBE, 0xFDBF, 0xFDC0, 0xFDC1, 0xFDC2, 0xFDC3, 21919 0xFDC4, 0xFDC5, 0xFDC6, 0xFDC7, 0xFDF0, 0xFDF1, 0xFDF2, 0xFDF3, 0xFDF4, 21920 0xFDF5, 0xFDF6, 0xFDF7, 0xFDF8, 0xFDF9, 0xFDFA, 0xFDFB, 0xFDFC, 0xFE70, 21921 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 21922 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, 0xFE80, 0xFE81, 0xFE82, 0xFE83, 21923 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 21924 0xFE8D, 0xFE8E, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 21925 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 21926 0xFE9F, 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 21927 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, 0xFEB0, 21928 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 21929 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0, 0xFEC1, 0xFEC2, 21930 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 21931 0xFECC, 0xFECD, 0xFECE, 0xFECF, 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 21932 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 21933 0xFEDE, 0xFEDF, 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 21934 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, 21935 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 21936 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0x10800, 0x10801, 0x10802, 0x10803, 21937 0x10804, 0x10805, 0x10808, 0x1080A, 0x1080B, 0x1080C, 0x1080D, 0x1080E, 21938 0x1080F, 0x10810, 0x10811, 0x10812, 0x10813, 0x10814, 0x10815, 0x10816, 21939 0x10817, 0x10818, 0x10819, 0x1081A, 0x1081B, 0x1081C, 0x1081D, 0x1081E, 21940 0x1081F, 0x10820, 0x10821, 0x10822, 0x10823, 0x10824, 0x10825, 0x10826, 21941 0x10827, 0x10828, 0x10829, 0x1082A, 0x1082B, 0x1082C, 0x1082D, 0x1082E, 21942 0x1082F, 0x10830, 0x10831, 0x10832, 0x10833, 0x10834, 0x10835, 0x10837, 21943 0x10838, 0x1083C, 0x1083F, 0x10840, 0x10841, 0x10842, 0x10843, 0x10844, 21944 0x10845, 0x10846, 0x10847, 0x10848, 0x10849, 0x1084A, 0x1084B, 0x1084C, 21945 0x1084D, 0x1084E, 0x1084F, 0x10850, 0x10851, 0x10852, 0x10853, 0x10854, 21946 0x10855, 0x10857, 0x10858, 0x10859, 0x1085A, 0x1085B, 0x1085C, 0x1085D, 21947 0x1085E, 0x1085F, 0x10900, 0x10901, 0x10902, 0x10903, 0x10904, 0x10905, 21948 0x10906, 0x10907, 0x10908, 0x10909, 0x1090A, 0x1090B, 0x1090C, 0x1090D, 21949 0x1090E, 0x1090F, 0x10910, 0x10911, 0x10912, 0x10913, 0x10914, 0x10915, 21950 0x10916, 0x10917, 0x10918, 0x10919, 0x1091A, 0x1091B, 0x10920, 0x10921, 21951 0x10922, 0x10923, 0x10924, 0x10925, 0x10926, 0x10927, 0x10928, 0x10929, 21952 0x1092A, 0x1092B, 0x1092C, 0x1092D, 0x1092E, 0x1092F, 0x10930, 0x10931, 21953 0x10932, 0x10933, 0x10934, 0x10935, 0x10936, 0x10937, 0x10938, 0x10939, 21954 0x1093F, 0x10980, 0x10981, 0x10982, 0x10983, 0x10984, 0x10985, 0x10986, 21955 0x10987, 0x10988, 0x10989, 0x1098A, 0x1098B, 0x1098C, 0x1098D, 0x1098E, 21956 0x1098F, 0x10990, 0x10991, 0x10992, 0x10993, 0x10994, 0x10995, 0x10996, 21957 0x10997, 0x10998, 0x10999, 0x1099A, 0x1099B, 0x1099C, 0x1099D, 0x1099E, 21958 0x1099F, 0x109A0, 0x109A1, 0x109A2, 0x109A3, 0x109A4, 0x109A5, 0x109A6, 21959 0x109A7, 0x109A8, 0x109A9, 0x109AA, 0x109AB, 0x109AC, 0x109AD, 0x109AE, 21960 0x109AF, 0x109B0, 0x109B1, 0x109B2, 0x109B3, 0x109B4, 0x109B5, 0x109B6, 21961 0x109B7, 0x109BE, 0x109BF, 0x10A00, 0x10A10, 0x10A11, 0x10A12, 0x10A13, 21962 0x10A15, 0x10A16, 0x10A17, 0x10A19, 0x10A1A, 0x10A1B, 0x10A1C, 0x10A1D, 21963 0x10A1E, 0x10A1F, 0x10A20, 0x10A21, 0x10A22, 0x10A23, 0x10A24, 0x10A25, 21964 0x10A26, 0x10A27, 0x10A28, 0x10A29, 0x10A2A, 0x10A2B, 0x10A2C, 0x10A2D, 21965 0x10A2E, 0x10A2F, 0x10A30, 0x10A31, 0x10A32, 0x10A33, 0x10A40, 0x10A41, 21966 0x10A42, 0x10A43, 0x10A44, 0x10A45, 0x10A46, 0x10A47, 0x10A50, 0x10A51, 21967 0x10A52, 0x10A53, 0x10A54, 0x10A55, 0x10A56, 0x10A57, 0x10A58, 0x10A60, 21968 0x10A61, 0x10A62, 0x10A63, 0x10A64, 0x10A65, 0x10A66, 0x10A67, 0x10A68, 21969 0x10A69, 0x10A6A, 0x10A6B, 0x10A6C, 0x10A6D, 0x10A6E, 0x10A6F, 0x10A70, 21970 0x10A71, 0x10A72, 0x10A73, 0x10A74, 0x10A75, 0x10A76, 0x10A77, 0x10A78, 21971 0x10A79, 0x10A7A, 0x10A7B, 0x10A7C, 0x10A7D, 0x10A7E, 0x10A7F, 0x10B00, 21972 0x10B01, 0x10B02, 0x10B03, 0x10B04, 0x10B05, 0x10B06, 0x10B07, 0x10B08, 21973 0x10B09, 0x10B0A, 0x10B0B, 0x10B0C, 0x10B0D, 0x10B0E, 0x10B0F, 0x10B10, 21974 0x10B11, 0x10B12, 0x10B13, 0x10B14, 0x10B15, 0x10B16, 0x10B17, 0x10B18, 21975 0x10B19, 0x10B1A, 0x10B1B, 0x10B1C, 0x10B1D, 0x10B1E, 0x10B1F, 0x10B20, 21976 0x10B21, 0x10B22, 0x10B23, 0x10B24, 0x10B25, 0x10B26, 0x10B27, 0x10B28, 21977 0x10B29, 0x10B2A, 0x10B2B, 0x10B2C, 0x10B2D, 0x10B2E, 0x10B2F, 0x10B30, 21978 0x10B31, 0x10B32, 0x10B33, 0x10B34, 0x10B35, 0x10B40, 0x10B41, 0x10B42, 21979 0x10B43, 0x10B44, 0x10B45, 0x10B46, 0x10B47, 0x10B48, 0x10B49, 0x10B4A, 21980 0x10B4B, 0x10B4C, 0x10B4D, 0x10B4E, 0x10B4F, 0x10B50, 0x10B51, 0x10B52, 21981 0x10B53, 0x10B54, 0x10B55, 0x10B58, 0x10B59, 0x10B5A, 0x10B5B, 0x10B5C, 21982 0x10B5D, 0x10B5E, 0x10B5F, 0x10B60, 0x10B61, 0x10B62, 0x10B63, 0x10B64, 21983 0x10B65, 0x10B66, 0x10B67, 0x10B68, 0x10B69, 0x10B6A, 0x10B6B, 0x10B6C, 21984 0x10B6D, 0x10B6E, 0x10B6F, 0x10B70, 0x10B71, 0x10B72, 0x10B78, 0x10B79, 21985 0x10B7A, 0x10B7B, 0x10B7C, 0x10B7D, 0x10B7E, 0x10B7F, 0x10C00, 0x10C01, 21986 0x10C02, 0x10C03, 0x10C04, 0x10C05, 0x10C06, 0x10C07, 0x10C08, 0x10C09, 21987 0x10C0A, 0x10C0B, 0x10C0C, 0x10C0D, 0x10C0E, 0x10C0F, 0x10C10, 0x10C11, 21988 0x10C12, 0x10C13, 0x10C14, 0x10C15, 0x10C16, 0x10C17, 0x10C18, 0x10C19, 21989 0x10C1A, 0x10C1B, 0x10C1C, 0x10C1D, 0x10C1E, 0x10C1F, 0x10C20, 0x10C21, 21990 0x10C22, 0x10C23, 0x10C24, 0x10C25, 0x10C26, 0x10C27, 0x10C28, 0x10C29, 21991 0x10C2A, 0x10C2B, 0x10C2C, 0x10C2D, 0x10C2E, 0x10C2F, 0x10C30, 0x10C31, 21992 0x10C32, 0x10C33, 0x10C34, 0x10C35, 0x10C36, 0x10C37, 0x10C38, 0x10C39, 21993 0x10C3A, 0x10C3B, 0x10C3C, 0x10C3D, 0x10C3E, 0x10C3F, 0x10C40, 0x10C41, 21994 0x10C42, 0x10C43, 0x10C44, 0x10C45, 0x10C46, 0x10C47, 0x10C48, 0x1EE00, 21995 0x1EE01, 0x1EE02, 0x1EE03, 0x1EE05, 0x1EE06, 0x1EE07, 0x1EE08, 0x1EE09, 21996 0x1EE0A, 0x1EE0B, 0x1EE0C, 0x1EE0D, 0x1EE0E, 0x1EE0F, 0x1EE10, 0x1EE11, 21997 0x1EE12, 0x1EE13, 0x1EE14, 0x1EE15, 0x1EE16, 0x1EE17, 0x1EE18, 0x1EE19, 21998 0x1EE1A, 0x1EE1B, 0x1EE1C, 0x1EE1D, 0x1EE1E, 0x1EE1F, 0x1EE21, 0x1EE22, 21999 0x1EE24, 0x1EE27, 0x1EE29, 0x1EE2A, 0x1EE2B, 0x1EE2C, 0x1EE2D, 0x1EE2E, 22000 0x1EE2F, 0x1EE30, 0x1EE31, 0x1EE32, 0x1EE34, 0x1EE35, 0x1EE36, 0x1EE37, 22001 0x1EE39, 0x1EE3B, 0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE4D, 0x1EE4E, 22002 0x1EE4F, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, 0x1EE5D, 22003 0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE67, 0x1EE68, 0x1EE69, 0x1EE6A, 22004 0x1EE6C, 0x1EE6D, 0x1EE6E, 0x1EE6F, 0x1EE70, 0x1EE71, 0x1EE72, 0x1EE74, 22005 0x1EE75, 0x1EE76, 0x1EE77, 0x1EE79, 0x1EE7A, 0x1EE7B, 0x1EE7C, 0x1EE7E, 22006 0x1EE80, 0x1EE81, 0x1EE82, 0x1EE83, 0x1EE84, 0x1EE85, 0x1EE86, 0x1EE87, 22007 0x1EE88, 0x1EE89, 0x1EE8B, 0x1EE8C, 0x1EE8D, 0x1EE8E, 0x1EE8F, 0x1EE90, 22008 0x1EE91, 0x1EE92, 0x1EE93, 0x1EE94, 0x1EE95, 0x1EE96, 0x1EE97, 0x1EE98, 22009 0x1EE99, 0x1EE9A, 0x1EE9B, 0x1EEA1, 0x1EEA2, 0x1EEA3, 0x1EEA5, 0x1EEA6, 22010 0x1EEA7, 0x1EEA8, 0x1EEA9, 0x1EEAB, 0x1EEAC, 0x1EEAD, 0x1EEAE, 0x1EEAF, 22011 0x1EEB0, 0x1EEB1, 0x1EEB2, 0x1EEB3, 0x1EEB4, 0x1EEB5, 0x1EEB6, 0x1EEB7, 22012 0x1EEB8, 0x1EEB9, 0x1EEBA, 0x1EEBB, 0x10FFFD]; 22013 22014 function determineBidi(cueDiv) { 22015 var nodeStack = [], 22016 text = "", 22017 charCode; 22018 22019 if (!cueDiv || !cueDiv.childNodes) { 22020 return "ltr"; 22021 } 22022 22023 function pushNodes(nodeStack, node) { 22024 for (var i = node.childNodes.length - 1; i >= 0; i--) { 22025 nodeStack.push(node.childNodes[i]); 22026 } 22027 } 22028 22029 function nextTextNode(nodeStack) { 22030 if (!nodeStack || !nodeStack.length) { 22031 return null; 22032 } 22033 22034 var node = nodeStack.pop(), 22035 text = node.textContent || node.innerText; 22036 if (text) { 22037 // TODO: This should match all unicode type B characters (paragraph 22038 // separator characters). See issue #115. 22039 var m = text.match(/^.*(\n|\r)/); 22040 if (m) { 22041 nodeStack.length = 0; 22042 return m[0]; 22043 } 22044 return text; 22045 } 22046 if (node.tagName === "ruby") { 22047 return nextTextNode(nodeStack); 22048 } 22049 if (node.childNodes) { 22050 pushNodes(nodeStack, node); 22051 return nextTextNode(nodeStack); 22052 } 22053 } 22054 22055 pushNodes(nodeStack, cueDiv); 22056 while ((text = nextTextNode(nodeStack))) { 22057 for (var i = 0; i < text.length; i++) { 22058 charCode = text.charCodeAt(i); 22059 for (var j = 0; j < strongRTLChars.length; j++) { 22060 if (strongRTLChars[j] === charCode) { 22061 return "rtl"; 22062 } 22063 } 22064 } 22065 } 22066 return "ltr"; 22067 } 22068 22069 function computeLinePos(cue) { 22070 if (typeof cue.line === "number" && 22071 (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) { 22072 return cue.line; 22073 } 22074 if (!cue.track || !cue.track.textTrackList || 22075 !cue.track.textTrackList.mediaElement) { 22076 return -1; 22077 } 22078 var track = cue.track, 22079 trackList = track.textTrackList, 22080 count = 0; 22081 for (var i = 0; i < trackList.length && trackList[i] !== track; i++) { 22082 if (trackList[i].mode === "showing") { 22083 count++; 22084 } 22085 } 22086 return ++count * -1; 22087 } 22088 22089 function StyleBox() { 22090 } 22091 22092 // Apply styles to a div. If there is no div passed then it defaults to the 22093 // div on 'this'. 22094 StyleBox.prototype.applyStyles = function(styles, div) { 22095 div = div || this.div; 22096 for (var prop in styles) { 22097 if (styles.hasOwnProperty(prop)) { 22098 div.style[prop] = styles[prop]; 22099 } 22100 } 22101 }; 22102 22103 StyleBox.prototype.formatStyle = function(val, unit) { 22104 return val === 0 ? 0 : val + unit; 22105 }; 22106 22107 // Constructs the computed display state of the cue (a div). Places the div 22108 // into the overlay which should be a block level element (usually a div). 22109 function CueStyleBox(window, cue, styleOptions) { 22110 var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); 22111 var color = "rgba(255, 255, 255, 1)"; 22112 var backgroundColor = "rgba(0, 0, 0, 0.8)"; 22113 22114 if (isIE8) { 22115 color = "rgb(255, 255, 255)"; 22116 backgroundColor = "rgb(0, 0, 0)"; 22117 } 22118 22119 StyleBox.call(this); 22120 this.cue = cue; 22121 22122 // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will 22123 // have inline positioning and will function as the cue background box. 22124 this.cueDiv = parseContent(window, cue.text); 22125 var styles = { 22126 color: color, 22127 backgroundColor: backgroundColor, 22128 position: "relative", 22129 left: 0, 22130 right: 0, 22131 top: 0, 22132 bottom: 0, 22133 display: "inline" 22134 }; 22135 22136 if (!isIE8) { 22137 styles.writingMode = cue.vertical === "" ? "horizontal-tb" 22138 : cue.vertical === "lr" ? "vertical-lr" 22139 : "vertical-rl"; 22140 styles.unicodeBidi = "plaintext"; 22141 } 22142 this.applyStyles(styles, this.cueDiv); 22143 22144 // Create an absolutely positioned div that will be used to position the cue 22145 // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS 22146 // mirrors of them except "middle" which is "center" in CSS. 22147 this.div = window.document.createElement("div"); 22148 styles = { 22149 textAlign: cue.align === "middle" ? "center" : cue.align, 22150 font: styleOptions.font, 22151 whiteSpace: "pre-line", 22152 position: "absolute" 22153 }; 22154 22155 if (!isIE8) { 22156 styles.direction = determineBidi(this.cueDiv); 22157 styles.writingMode = cue.vertical === "" ? "horizontal-tb" 22158 : cue.vertical === "lr" ? "vertical-lr" 22159 : "vertical-rl". 22160 stylesunicodeBidi = "plaintext"; 22161 } 22162 22163 this.applyStyles(styles); 22164 22165 this.div.appendChild(this.cueDiv); 22166 22167 // Calculate the distance from the reference edge of the viewport to the text 22168 // position of the cue box. The reference edge will be resolved later when 22169 // the box orientation styles are applied. 22170 var textPos = 0; 22171 switch (cue.positionAlign) { 22172 case "start": 22173 textPos = cue.position; 22174 break; 22175 case "middle": 22176 textPos = cue.position - (cue.size / 2); 22177 break; 22178 case "end": 22179 textPos = cue.position - cue.size; 22180 break; 22181 } 22182 22183 // Horizontal box orientation; textPos is the distance from the left edge of the 22184 // area to the left edge of the box and cue.size is the distance extending to 22185 // the right from there. 22186 if (cue.vertical === "") { 22187 this.applyStyles({ 22188 left: this.formatStyle(textPos, "%"), 22189 width: this.formatStyle(cue.size, "%") 22190 }); 22191 // Vertical box orientation; textPos is the distance from the top edge of the 22192 // area to the top edge of the box and cue.size is the height extending 22193 // downwards from there. 22194 } else { 22195 this.applyStyles({ 22196 top: this.formatStyle(textPos, "%"), 22197 height: this.formatStyle(cue.size, "%") 22198 }); 22199 } 22200 22201 this.move = function(box) { 22202 this.applyStyles({ 22203 top: this.formatStyle(box.top, "px"), 22204 bottom: this.formatStyle(box.bottom, "px"), 22205 left: this.formatStyle(box.left, "px"), 22206 right: this.formatStyle(box.right, "px"), 22207 height: this.formatStyle(box.height, "px"), 22208 width: this.formatStyle(box.width, "px") 22209 }); 22210 }; 22211 } 22212 CueStyleBox.prototype = _objCreate(StyleBox.prototype); 22213 CueStyleBox.prototype.constructor = CueStyleBox; 22214 22215 // Represents the co-ordinates of an Element in a way that we can easily 22216 // compute things with such as if it overlaps or intersects with another Element. 22217 // Can initialize it with either a StyleBox or another BoxPosition. 22218 function BoxPosition(obj) { 22219 var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); 22220 22221 // Either a BoxPosition was passed in and we need to copy it, or a StyleBox 22222 // was passed in and we need to copy the results of 'getBoundingClientRect' 22223 // as the object returned is readonly. All co-ordinate values are in reference 22224 // to the viewport origin (top left). 22225 var lh, height, width, top; 22226 if (obj.div) { 22227 height = obj.div.offsetHeight; 22228 width = obj.div.offsetWidth; 22229 top = obj.div.offsetTop; 22230 22231 var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && 22232 rects.getClientRects && rects.getClientRects(); 22233 obj = obj.div.getBoundingClientRect(); 22234 // In certain cases the outter div will be slightly larger then the sum of 22235 // the inner div's lines. This could be due to bold text, etc, on some platforms. 22236 // In this case we should get the average line height and use that. This will 22237 // result in the desired behaviour. 22238 lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length) 22239 : 0; 22240 22241 } 22242 this.left = obj.left; 22243 this.right = obj.right; 22244 this.top = obj.top || top; 22245 this.height = obj.height || height; 22246 this.bottom = obj.bottom || (top + (obj.height || height)); 22247 this.width = obj.width || width; 22248 this.lineHeight = lh !== undefined ? lh : obj.lineHeight; 22249 22250 if (isIE8 && !this.lineHeight) { 22251 this.lineHeight = 13; 22252 } 22253 } 22254 22255 // Move the box along a particular axis. Optionally pass in an amount to move 22256 // the box. If no amount is passed then the default is the line height of the 22257 // box. 22258 BoxPosition.prototype.move = function(axis, toMove) { 22259 toMove = toMove !== undefined ? toMove : this.lineHeight; 22260 switch (axis) { 22261 case "+x": 22262 this.left += toMove; 22263 this.right += toMove; 22264 break; 22265 case "-x": 22266 this.left -= toMove; 22267 this.right -= toMove; 22268 break; 22269 case "+y": 22270 this.top += toMove; 22271 this.bottom += toMove; 22272 break; 22273 case "-y": 22274 this.top -= toMove; 22275 this.bottom -= toMove; 22276 break; 22277 } 22278 }; 22279 22280 // Check if this box overlaps another box, b2. 22281 BoxPosition.prototype.overlaps = function(b2) { 22282 return this.left < b2.right && 22283 this.right > b2.left && 22284 this.top < b2.bottom && 22285 this.bottom > b2.top; 22286 }; 22287 22288 // Check if this box overlaps any other boxes in boxes. 22289 BoxPosition.prototype.overlapsAny = function(boxes) { 22290 for (var i = 0; i < boxes.length; i++) { 22291 if (this.overlaps(boxes[i])) { 22292 return true; 22293 } 22294 } 22295 return false; 22296 }; 22297 22298 // Check if this box is within another box. 22299 BoxPosition.prototype.within = function(container) { 22300 return this.top >= container.top && 22301 this.bottom <= container.bottom && 22302 this.left >= container.left && 22303 this.right <= container.right; 22304 }; 22305 22306 // Check if this box is entirely within the container or it is overlapping 22307 // on the edge opposite of the axis direction passed. For example, if "+x" is 22308 // passed and the box is overlapping on the left edge of the container, then 22309 // return true. 22310 BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) { 22311 switch (axis) { 22312 case "+x": 22313 return this.left < container.left; 22314 case "-x": 22315 return this.right > container.right; 22316 case "+y": 22317 return this.top < container.top; 22318 case "-y": 22319 return this.bottom > container.bottom; 22320 } 22321 }; 22322 22323 // Find the percentage of the area that this box is overlapping with another 22324 // box. 22325 BoxPosition.prototype.intersectPercentage = function(b2) { 22326 var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)), 22327 y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), 22328 intersectArea = x * y; 22329 return intersectArea / (this.height * this.width); 22330 }; 22331 22332 // Convert the positions from this box to CSS compatible positions using 22333 // the reference container's positions. This has to be done because this 22334 // box's positions are in reference to the viewport origin, whereas, CSS 22335 // values are in referecne to their respective edges. 22336 BoxPosition.prototype.toCSSCompatValues = function(reference) { 22337 return { 22338 top: this.top - reference.top, 22339 bottom: reference.bottom - this.bottom, 22340 left: this.left - reference.left, 22341 right: reference.right - this.right, 22342 height: this.height, 22343 width: this.width 22344 }; 22345 }; 22346 22347 // Get an object that represents the box's position without anything extra. 22348 // Can pass a StyleBox, HTMLElement, or another BoxPositon. 22349 BoxPosition.getSimpleBoxPosition = function(obj) { 22350 var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0; 22351 var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0; 22352 var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0; 22353 22354 obj = obj.div ? obj.div.getBoundingClientRect() : 22355 obj.tagName ? obj.getBoundingClientRect() : obj; 22356 var ret = { 22357 left: obj.left, 22358 right: obj.right, 22359 top: obj.top || top, 22360 height: obj.height || height, 22361 bottom: obj.bottom || (top + (obj.height || height)), 22362 width: obj.width || width 22363 }; 22364 return ret; 22365 }; 22366 22367 // Move a StyleBox to its specified, or next best, position. The containerBox 22368 // is the box that contains the StyleBox, such as a div. boxPositions are 22369 // a list of other boxes that the styleBox can't overlap with. 22370 function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) { 22371 22372 // Find the best position for a cue box, b, on the video. The axis parameter 22373 // is a list of axis, the order of which, it will move the box along. For example: 22374 // Passing ["+x", "-x"] will move the box first along the x axis in the positive 22375 // direction. If it doesn't find a good position for it there it will then move 22376 // it along the x axis in the negative direction. 22377 function findBestPosition(b, axis) { 22378 var bestPosition, 22379 specifiedPosition = new BoxPosition(b), 22380 percentage = 1; // Highest possible so the first thing we get is better. 22381 22382 for (var i = 0; i < axis.length; i++) { 22383 while (b.overlapsOppositeAxis(containerBox, axis[i]) || 22384 (b.within(containerBox) && b.overlapsAny(boxPositions))) { 22385 b.move(axis[i]); 22386 } 22387 // We found a spot where we aren't overlapping anything. This is our 22388 // best position. 22389 if (b.within(containerBox)) { 22390 return b; 22391 } 22392 var p = b.intersectPercentage(containerBox); 22393 // If we're outside the container box less then we were on our last try 22394 // then remember this position as the best position. 22395 if (percentage > p) { 22396 bestPosition = new BoxPosition(b); 22397 percentage = p; 22398 } 22399 // Reset the box position to the specified position. 22400 b = new BoxPosition(specifiedPosition); 22401 } 22402 return bestPosition || specifiedPosition; 22403 } 22404 22405 var boxPosition = new BoxPosition(styleBox), 22406 cue = styleBox.cue, 22407 linePos = computeLinePos(cue), 22408 axis = []; 22409 22410 // If we have a line number to align the cue to. 22411 if (cue.snapToLines) { 22412 var size; 22413 switch (cue.vertical) { 22414 case "": 22415 axis = [ "+y", "-y" ]; 22416 size = "height"; 22417 break; 22418 case "rl": 22419 axis = [ "+x", "-x" ]; 22420 size = "width"; 22421 break; 22422 case "lr": 22423 axis = [ "-x", "+x" ]; 22424 size = "width"; 22425 break; 22426 } 22427 22428 var step = boxPosition.lineHeight, 22429 position = step * Math.round(linePos), 22430 maxPosition = containerBox[size] + step, 22431 initialAxis = axis[0]; 22432 22433 // If the specified intial position is greater then the max position then 22434 // clamp the box to the amount of steps it would take for the box to 22435 // reach the max position. 22436 if (Math.abs(position) > maxPosition) { 22437 position = position < 0 ? -1 : 1; 22438 position *= Math.ceil(maxPosition / step) * step; 22439 } 22440 22441 // If computed line position returns negative then line numbers are 22442 // relative to the bottom of the video instead of the top. Therefore, we 22443 // need to increase our initial position by the length or width of the 22444 // video, depending on the writing direction, and reverse our axis directions. 22445 if (linePos < 0) { 22446 position += cue.vertical === "" ? containerBox.height : containerBox.width; 22447 axis = axis.reverse(); 22448 } 22449 22450 // Move the box to the specified position. This may not be its best 22451 // position. 22452 boxPosition.move(initialAxis, position); 22453 22454 } else { 22455 // If we have a percentage line value for the cue. 22456 var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100; 22457 22458 switch (cue.lineAlign) { 22459 case "middle": 22460 linePos -= (calculatedPercentage / 2); 22461 break; 22462 case "end": 22463 linePos -= calculatedPercentage; 22464 break; 22465 } 22466 22467 // Apply initial line position to the cue box. 22468 switch (cue.vertical) { 22469 case "": 22470 styleBox.applyStyles({ 22471 top: styleBox.formatStyle(linePos, "%") 22472 }); 22473 break; 22474 case "rl": 22475 styleBox.applyStyles({ 22476 left: styleBox.formatStyle(linePos, "%") 22477 }); 22478 break; 22479 case "lr": 22480 styleBox.applyStyles({ 22481 right: styleBox.formatStyle(linePos, "%") 22482 }); 22483 break; 22484 } 22485 22486 axis = [ "+y", "-x", "+x", "-y" ]; 22487 22488 // Get the box position again after we've applied the specified positioning 22489 // to it. 22490 boxPosition = new BoxPosition(styleBox); 22491 } 22492 22493 var bestPosition = findBestPosition(boxPosition, axis); 22494 styleBox.move(bestPosition.toCSSCompatValues(containerBox)); 22495 } 22496 22497 function WebVTT() { 22498 // Nothing 22499 } 22500 22501 // Helper to allow strings to be decoded instead of the default binary utf8 data. 22502 WebVTT.StringDecoder = function() { 22503 return { 22504 decode: function(data) { 22505 if (!data) { 22506 return ""; 22507 } 22508 if (typeof data !== "string") { 22509 throw new Error("Error - expected string data."); 22510 } 22511 return decodeURIComponent(encodeURIComponent(data)); 22512 } 22513 }; 22514 }; 22515 22516 WebVTT.convertCueToDOMTree = function(window, cuetext) { 22517 if (!window || !cuetext) { 22518 return null; 22519 } 22520 return parseContent(window, cuetext); 22521 }; 22522 22523 var FONT_SIZE_PERCENT = 0.05; 22524 var FONT_STYLE = "sans-serif"; 22525 var CUE_BACKGROUND_PADDING = "1.5%"; 22526 22527 // Runs the processing model over the cues and regions passed to it. 22528 // @param overlay A block level element (usually a div) that the computed cues 22529 // and regions will be placed into. 22530 WebVTT.processCues = function(window, cues, overlay) { 22531 if (!window || !cues || !overlay) { 22532 return null; 22533 } 22534 22535 // Remove all previous children. 22536 while (overlay.firstChild) { 22537 overlay.removeChild(overlay.firstChild); 22538 } 22539 22540 var paddedOverlay = window.document.createElement("div"); 22541 paddedOverlay.style.position = "absolute"; 22542 paddedOverlay.style.left = "0"; 22543 paddedOverlay.style.right = "0"; 22544 paddedOverlay.style.top = "0"; 22545 paddedOverlay.style.bottom = "0"; 22546 paddedOverlay.style.margin = CUE_BACKGROUND_PADDING; 22547 overlay.appendChild(paddedOverlay); 22548 22549 // Determine if we need to compute the display states of the cues. This could 22550 // be the case if a cue's state has been changed since the last computation or 22551 // if it has not been computed yet. 22552 function shouldCompute(cues) { 22553 for (var i = 0; i < cues.length; i++) { 22554 if (cues[i].hasBeenReset || !cues[i].displayState) { 22555 return true; 22556 } 22557 } 22558 return false; 22559 } 22560 22561 // We don't need to recompute the cues' display states. Just reuse them. 22562 if (!shouldCompute(cues)) { 22563 for (var i = 0; i < cues.length; i++) { 22564 paddedOverlay.appendChild(cues[i].displayState); 22565 } 22566 return; 22567 } 22568 22569 var boxPositions = [], 22570 containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), 22571 fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; 22572 var styleOptions = { 22573 font: fontSize + "px " + FONT_STYLE 22574 }; 22575 22576 (function() { 22577 var styleBox, cue; 22578 22579 for (var i = 0; i < cues.length; i++) { 22580 cue = cues[i]; 22581 22582 // Compute the intial position and styles of the cue div. 22583 styleBox = new CueStyleBox(window, cue, styleOptions); 22584 paddedOverlay.appendChild(styleBox.div); 22585 22586 // Move the cue div to it's correct line position. 22587 moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); 22588 22589 // Remember the computed div so that we don't have to recompute it later 22590 // if we don't have too. 22591 cue.displayState = styleBox.div; 22592 22593 boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox)); 22594 } 22595 })(); 22596 }; 22597 22598 WebVTT.Parser = function(window, vttjs, decoder) { 22599 if (!decoder) { 22600 decoder = vttjs; 22601 vttjs = {}; 22602 } 22603 if (!vttjs) { 22604 vttjs = {}; 22605 } 22606 22607 this.window = window; 22608 this.vttjs = vttjs; 22609 this.state = "INITIAL"; 22610 this.buffer = ""; 22611 this.decoder = decoder || new TextDecoder("utf8"); 22612 this.regionList = []; 22613 }; 22614 22615 WebVTT.Parser.prototype = { 22616 // If the error is a ParsingError then report it to the consumer if 22617 // possible. If it's not a ParsingError then throw it like normal. 22618 reportOrThrowError: function(e) { 22619 if (e instanceof ParsingError) { 22620 this.onparsingerror && this.onparsingerror(e); 22621 } else { 22622 throw e; 22623 } 22624 }, 22625 parse: function (data) { 22626 var self = this; 22627 22628 // If there is no data then we won't decode it, but will just try to parse 22629 // whatever is in buffer already. This may occur in circumstances, for 22630 // example when flush() is called. 22631 if (data) { 22632 // Try to decode the data that we received. 22633 self.buffer += self.decoder.decode(data, {stream: true}); 22634 } 22635 22636 function collectNextLine() { 22637 var buffer = self.buffer; 22638 var pos = 0; 22639 while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { 22640 ++pos; 22641 } 22642 var line = buffer.substr(0, pos); 22643 // Advance the buffer early in case we fail below. 22644 if (buffer[pos] === '\r') { 22645 ++pos; 22646 } 22647 if (buffer[pos] === '\n') { 22648 ++pos; 22649 } 22650 self.buffer = buffer.substr(pos); 22651 return line; 22652 } 22653 22654 // 3.4 WebVTT region and WebVTT region settings syntax 22655 function parseRegion(input) { 22656 var settings = new Settings(); 22657 22658 parseOptions(input, function (k, v) { 22659 switch (k) { 22660 case "id": 22661 settings.set(k, v); 22662 break; 22663 case "width": 22664 settings.percent(k, v); 22665 break; 22666 case "lines": 22667 settings.integer(k, v); 22668 break; 22669 case "regionanchor": 22670 case "viewportanchor": 22671 var xy = v.split(','); 22672 if (xy.length !== 2) { 22673 break; 22674 } 22675 // We have to make sure both x and y parse, so use a temporary 22676 // settings object here. 22677 var anchor = new Settings(); 22678 anchor.percent("x", xy[0]); 22679 anchor.percent("y", xy[1]); 22680 if (!anchor.has("x") || !anchor.has("y")) { 22681 break; 22682 } 22683 settings.set(k + "X", anchor.get("x")); 22684 settings.set(k + "Y", anchor.get("y")); 22685 break; 22686 case "scroll": 22687 settings.alt(k, v, ["up"]); 22688 break; 22689 } 22690 }, /=/, /\s/); 22691 22692 // Create the region, using default values for any values that were not 22693 // specified. 22694 if (settings.has("id")) { 22695 var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)(); 22696 region.width = settings.get("width", 100); 22697 region.lines = settings.get("lines", 3); 22698 region.regionAnchorX = settings.get("regionanchorX", 0); 22699 region.regionAnchorY = settings.get("regionanchorY", 100); 22700 region.viewportAnchorX = settings.get("viewportanchorX", 0); 22701 region.viewportAnchorY = settings.get("viewportanchorY", 100); 22702 region.scroll = settings.get("scroll", ""); 22703 // Register the region. 22704 self.onregion && self.onregion(region); 22705 // Remember the VTTRegion for later in case we parse any VTTCues that 22706 // reference it. 22707 self.regionList.push({ 22708 id: settings.get("id"), 22709 region: region 22710 }); 22711 } 22712 } 22713 22714 // 3.2 WebVTT metadata header syntax 22715 function parseHeader(input) { 22716 parseOptions(input, function (k, v) { 22717 switch (k) { 22718 case "Region": 22719 // 3.3 WebVTT region metadata header syntax 22720 parseRegion(v); 22721 break; 22722 } 22723 }, /:/); 22724 } 22725 22726 // 5.1 WebVTT file parsing. 22727 try { 22728 var line; 22729 if (self.state === "INITIAL") { 22730 // We can't start parsing until we have the first line. 22731 if (!/\r\n|\n/.test(self.buffer)) { 22732 return this; 22733 } 22734 22735 line = collectNextLine(); 22736 22737 var m = line.match(/^WEBVTT([ \t].*)?$/); 22738 if (!m || !m[0]) { 22739 throw new ParsingError(ParsingError.Errors.BadSignature); 22740 } 22741 22742 self.state = "HEADER"; 22743 } 22744 22745 var alreadyCollectedLine = false; 22746 while (self.buffer) { 22747 // We can't parse a line until we have the full line. 22748 if (!/\r\n|\n/.test(self.buffer)) { 22749 return this; 22750 } 22751 22752 if (!alreadyCollectedLine) { 22753 line = collectNextLine(); 22754 } else { 22755 alreadyCollectedLine = false; 22756 } 22757 22758 switch (self.state) { 22759 case "HEADER": 22760 // 13-18 - Allow a header (metadata) under the WEBVTT line. 22761 if (/:/.test(line)) { 22762 parseHeader(line); 22763 } else if (!line) { 22764 // An empty line terminates the header and starts the body (cues). 22765 self.state = "ID"; 22766 } 22767 continue; 22768 case "NOTE": 22769 // Ignore NOTE blocks. 22770 if (!line) { 22771 self.state = "ID"; 22772 } 22773 continue; 22774 case "ID": 22775 // Check for the start of NOTE blocks. 22776 if (/^NOTE($|[ \t])/.test(line)) { 22777 self.state = "NOTE"; 22778 break; 22779 } 22780 // 19-29 - Allow any number of line terminators, then initialize new cue values. 22781 if (!line) { 22782 continue; 22783 } 22784 self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); 22785 self.state = "CUE"; 22786 // 30-39 - Check if self line contains an optional identifier or timing data. 22787 if (line.indexOf("-->") === -1) { 22788 self.cue.id = line; 22789 continue; 22790 } 22791 // Process line as start of a cue. 22792 /*falls through*/ 22793 case "CUE": 22794 // 40 - Collect cue timings and settings. 22795 try { 22796 parseCue(line, self.cue, self.regionList); 22797 } catch (e) { 22798 self.reportOrThrowError(e); 22799 // In case of an error ignore rest of the cue. 22800 self.cue = null; 22801 self.state = "BADCUE"; 22802 continue; 22803 } 22804 self.state = "CUETEXT"; 22805 continue; 22806 case "CUETEXT": 22807 var hasSubstring = line.indexOf("-->") !== -1; 22808 // 34 - If we have an empty line then report the cue. 22809 // 35 - If we have the special substring '-->' then report the cue, 22810 // but do not collect the line as we need to process the current 22811 // one as a new cue. 22812 if (!line || hasSubstring && (alreadyCollectedLine = true)) { 22813 // We are done parsing self cue. 22814 self.oncue && self.oncue(self.cue); 22815 self.cue = null; 22816 self.state = "ID"; 22817 continue; 22818 } 22819 if (self.cue.text) { 22820 self.cue.text += "\n"; 22821 } 22822 self.cue.text += line; 22823 continue; 22824 case "BADCUE": // BADCUE 22825 // 54-62 - Collect and discard the remaining cue. 22826 if (!line) { 22827 self.state = "ID"; 22828 } 22829 continue; 22830 } 22831 } 22832 } catch (e) { 22833 self.reportOrThrowError(e); 22834 22835 // If we are currently parsing a cue, report what we have. 22836 if (self.state === "CUETEXT" && self.cue && self.oncue) { 22837 self.oncue(self.cue); 22838 } 22839 self.cue = null; 22840 // Enter BADWEBVTT state if header was not parsed correctly otherwise 22841 // another exception occurred so enter BADCUE state. 22842 self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE"; 22843 } 22844 return this; 22845 }, 22846 flush: function () { 22847 var self = this; 22848 try { 22849 // Finish decoding the stream. 22850 self.buffer += self.decoder.decode(); 22851 // Synthesize the end of the current cue or region. 22852 if (self.cue || self.state === "HEADER") { 22853 self.buffer += "\n\n"; 22854 self.parse(); 22855 } 22856 // If we've flushed, parsed, and we're still on the INITIAL state then 22857 // that means we don't have enough of the stream to parse the first 22858 // line. 22859 if (self.state === "INITIAL") { 22860 throw new ParsingError(ParsingError.Errors.BadSignature); 22861 } 22862 } catch(e) { 22863 self.reportOrThrowError(e); 22864 } 22865 self.onflush && self.onflush(); 22866 return this; 22867 } 22868 }; 22869 22870 global.WebVTT = WebVTT; 22871 22872 }(this, (this.vttjs || {})));