/** * @license * video.js 5.9.2 * copyright brightcove, inc. * available under apache license version 2.0 * * * includes vtt.js * available under apache license version 2.0 * */ (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 logs the number of milliseconds it took for the deferred function to be invoked */ var now = nativenow || function() { return new date().gettime(); }; module.exports = now; },{"../internal/getnative":20}],5:[function(_dereq_,module,exports){ var isobject = _dereq_('../lang/isobject'), now = _dereq_('../date/now'); /** used as the `typeerror` message for "functions" methods. */ var func_error_text = 'expected a function'; /* native method references for those with the same name as other `lodash` methods. */ var nativemax = math.max; /** * creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. the debounced function comes with a `cancel` method to cancel * delayed invocations. provide an options object to indicate that `func` * should be invoked on the leading and/or trailing edge of the `wait` timeout. * subsequent calls to the debounced function return the result of the last * `func` invocation. * * **note:** if `leading` and `trailing` options are `true`, `func` is invoked * on the trailing edge of the timeout only if the the debounced function is * invoked more than once during the `wait` timeout. * * see [david corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberof _ * @category function * @param {function} func the function to debounce. * @param {number} [wait=0] the number of milliseconds to delay. * @param {object} [options] the options object. * @param {boolean} [options.leading=false] specify invoking on the leading * edge of the timeout. * @param {number} [options.maxwait] the maximum time `func` is allowed to be * delayed before it's invoked. * @param {boolean} [options.trailing=true] specify invoking on the trailing * edge of the timeout. * @returns {function} returns the new debounced function. * @example * * // avoid costly calculations while the window size is in flux * jquery(window).on('resize', _.debounce(calculatelayout, 150)); * * // invoke `sendmail` when the click event is fired, debouncing subsequent calls * jquery('#postbox').on('click', _.debounce(sendmail, 300, { * 'leading': true, * 'trailing': false * })); * * // ensure `batchlog` is invoked once after 1 second of debounced calls * var source = new eventsource('/stream'); * jquery(source).on('message', _.debounce(batchlog, 250, { * 'maxwait': 1000 * })); * * // cancel a debounced call * var todochanges = _.debounce(batchlog, 1000); * object.observe(models.todo, todochanges); * * object.observe(models, function(changes) { * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { * todochanges.cancel(); * } * }, ['delete']); * * // ...at some point `models.todo` is changed * models.todo.completed = true; * * // ...before 1 second has passed `models.todo` is deleted * // which cancels the debounced `todochanges` call * delete models.todo; */ function debounce(func, wait, options) { var args, maxtimeoutid, result, stamp, thisarg, timeoutid, trailingcall, lastcalled = 0, maxwait = false, trailing = true; if (typeof func != 'function') { throw new typeerror(func_error_text); } wait = wait < 0 ? 0 : (+wait || 0); if (options === true) { var leading = true; trailing = false; } else if (isobject(options)) { leading = !!options.leading; maxwait = 'maxwait' in options && nativemax(+options.maxwait || 0, wait); trailing = 'trailing' in options ? !!options.trailing : trailing; } function cancel() { if (timeoutid) { cleartimeout(timeoutid); } if (maxtimeoutid) { cleartimeout(maxtimeoutid); } lastcalled = 0; maxtimeoutid = timeoutid = trailingcall = undefined; } function complete(iscalled, id) { if (id) { cleartimeout(id); } maxtimeoutid = timeoutid = trailingcall = undefined; if (iscalled) { lastcalled = now(); result = func.apply(thisarg, args); if (!timeoutid && !maxtimeoutid) { args = thisarg = undefined; } } } function delayed() { var remaining = wait - (now() - stamp); if (remaining <= 0 || remaining > wait) { complete(trailingcall, maxtimeoutid); } else { timeoutid = settimeout(delayed, remaining); } } function maxdelayed() { complete(trailing, timeoutid); } function debounced() { args = arguments; stamp = now(); thisarg = this; trailingcall = trailing && (timeoutid || !leading); if (maxwait === false) { var leadingcall = leading && !timeoutid; } else { if (!maxtimeoutid && !leading) { lastcalled = stamp; } var remaining = maxwait - (stamp - lastcalled), iscalled = remaining <= 0 || remaining > maxwait; if (iscalled) { if (maxtimeoutid) { maxtimeoutid = cleartimeout(maxtimeoutid); } lastcalled = stamp; result = func.apply(thisarg, args); } else if (!maxtimeoutid) { maxtimeoutid = settimeout(maxdelayed, remaining); } } if (iscalled && timeoutid) { timeoutid = cleartimeout(timeoutid); } else if (!timeoutid && wait !== maxwait) { timeoutid = settimeout(delayed, wait); } if (leadingcall) { iscalled = true; result = func.apply(thisarg, args); } if (iscalled && !timeoutid && !maxtimeoutid) { args = thisarg = undefined; } return result; } debounced.cancel = cancel; return debounced; } module.exports = debounce; },{"../date/now":4,"../lang/isobject":33}],6:[function(_dereq_,module,exports){ /** used as the `typeerror` message for "functions" methods. */ var func_error_text = 'expected a function'; /* native method references for those with the same name as other `lodash` methods. */ var nativemax = math.max; /** * creates a function that invokes `func` with the `this` binding of the * created function and arguments from `start` and beyond provided as an array. * * **note:** this method is based on the [rest parameter](https://developer.mozilla.org/web/javascript/reference/functions/rest_parameters). * * @static * @memberof _ * @category function * @param {function} func the function to apply a rest parameter to. * @param {number} [start=func.length-1] the start position of the rest parameter. * @returns {function} returns the new function. * @example * * var say = _.restparam(function(what, names) { * return what + ' ' + _.initial(names).join(', ') + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); * }); * * say('hello', 'fred', 'barney', 'pebbles'); * // => 'hello fred, barney, & pebbles' */ function restparam(func, start) { if (typeof func != 'function') { throw new typeerror(func_error_text); } start = nativemax(start === undefined ? (func.length - 1) : (+start || 0), 0); return function() { var args = arguments, index = -1, length = nativemax(args.length - start, 0), rest = array(length); while (++index < length) { rest[index] = args[start + index]; } switch (start) { case 0: return func.call(this, rest); case 1: return func.call(this, args[0], rest); case 2: return func.call(this, args[0], args[1], rest); } var otherargs = array(start + 1); index = -1; while (++index < start) { otherargs[index] = args[index]; } otherargs[start] = rest; return func.apply(this, otherargs); }; } module.exports = restparam; },{}],7:[function(_dereq_,module,exports){ var debounce = _dereq_('./debounce'), isobject = _dereq_('../lang/isobject'); /** used as the `typeerror` message for "functions" methods. */ var func_error_text = 'expected a function'; /** * creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. the throttled function comes with a `cancel` * method to cancel delayed invocations. provide an options object to indicate * that `func` should be invoked on the leading and/or trailing edge of the * `wait` timeout. subsequent calls to the throttled function return the * result of the last `func` call. * * **note:** if `leading` and `trailing` options are `true`, `func` is invoked * on the trailing edge of the timeout only if the the throttled function is * invoked more than once during the `wait` timeout. * * see [david corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) * for details over the differences between `_.throttle` and `_.debounce`. * * @static * @memberof _ * @category function * @param {function} func the function to throttle. * @param {number} [wait=0] the number of milliseconds to throttle invocations to. * @param {object} [options] the options object. * @param {boolean} [options.leading=true] specify invoking on the leading * edge of the timeout. * @param {boolean} [options.trailing=true] specify invoking on the trailing * edge of the timeout. * @returns {function} returns the new throttled function. * @example * * // avoid excessively updating the position while scrolling * jquery(window).on('scroll', _.throttle(updateposition, 100)); * * // invoke `renewtoken` when the click event is fired, but not more than once every 5 minutes * jquery('.interactive').on('click', _.throttle(renewtoken, 300000, { * 'trailing': false * })); * * // cancel a trailing throttled call * jquery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new typeerror(func_error_text); } if (options === false) { leading = false; } else if (isobject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce(func, wait, { 'leading': leading, 'maxwait': +wait, 'trailing': trailing }); } module.exports = throttle; },{"../lang/isobject":33,"./debounce":5}],8:[function(_dereq_,module,exports){ /** * copies the values of `source` to `array`. * * @private * @param {array} source the array to copy values from. * @param {array} [array=[]] the array to copy values to. * @returns {array} returns `array`. */ function arraycopy(source, array) { var index = -1, length = source.length; array || (array = array(length)); while (++index < length) { array[index] = source[index]; } return array; } module.exports = arraycopy; },{}],9:[function(_dereq_,module,exports){ /** * a specialized version of `_.foreach` for arrays without support for callback * shorthands and `this` binding. * * @private * @param {array} array the array to iterate over. * @param {function} iteratee the function invoked per iteration. * @returns {array} returns `array`. */ function arrayeach(array, iteratee) { var index = -1, length = array.length; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } module.exports = arrayeach; },{}],10:[function(_dereq_,module,exports){ /** * copies properties of `source` to `object`. * * @private * @param {object} source the object to copy properties from. * @param {array} props the property names to copy. * @param {object} [object={}] the object to copy properties to. * @returns {object} returns `object`. */ function basecopy(source, props, object) { object || (object = {}); var index = -1, length = props.length; while (++index < length) { var key = props[index]; object[key] = source[key]; } return object; } module.exports = basecopy; },{}],11:[function(_dereq_,module,exports){ var createbasefor = _dereq_('./createbasefor'); /** * the base implementation of `baseforin` and `baseforown` which iterates * over `object` properties returned by `keysfunc` invoking `iteratee` for * each property. iteratee functions may exit iteration early by explicitly * returning `false`. * * @private * @param {object} object the object to iterate over. * @param {function} iteratee the function invoked per iteration. * @param {function} keysfunc the function to get the keys of `object`. * @returns {object} returns `object`. */ var basefor = createbasefor(); module.exports = basefor; },{"./createbasefor":18}],12:[function(_dereq_,module,exports){ var basefor = _dereq_('./basefor'), keysin = _dereq_('../object/keysin'); /** * the base implementation of `_.forin` without support for callback * shorthands and `this` binding. * * @private * @param {object} object the object to iterate over. * @param {function} iteratee the function invoked per iteration. * @returns {object} returns `object`. */ function baseforin(object, iteratee) { return basefor(object, iteratee, keysin); } module.exports = baseforin; },{"../object/keysin":39,"./basefor":11}],13:[function(_dereq_,module,exports){ var arrayeach = _dereq_('./arrayeach'), basemergedeep = _dereq_('./basemergedeep'), isarray = _dereq_('../lang/isarray'), isarraylike = _dereq_('./isarraylike'), isobject = _dereq_('../lang/isobject'), isobjectlike = _dereq_('./isobjectlike'), istypedarray = _dereq_('../lang/istypedarray'), keys = _dereq_('../object/keys'); /** * the base implementation of `_.merge` without support for argument juggling, * multiple sources, and `this` binding `customizer` functions. * * @private * @param {object} object the destination object. * @param {object} source the source object. * @param {function} [customizer] the function to customize merged values. * @param {array} [stacka=[]] tracks traversed source objects. * @param {array} [stackb=[]] associates values with source counterparts. * @returns {object} returns `object`. */ function basemerge(object, source, customizer, stacka, stackb) { if (!isobject(object)) { return object; } var issrcarr = isarraylike(source) && (isarray(source) || istypedarray(source)), props = issrcarr ? undefined : keys(source); arrayeach(props || source, function(srcvalue, key) { if (props) { key = srcvalue; srcvalue = source[key]; } if (isobjectlike(srcvalue)) { stacka || (stacka = []); stackb || (stackb = []); basemergedeep(object, source, key, basemerge, customizer, stacka, stackb); } else { var value = object[key], result = customizer ? customizer(value, srcvalue, key, object, source) : undefined, iscommon = result === undefined; if (iscommon) { result = srcvalue; } if ((result !== undefined || (issrcarr && !(key in object))) && (iscommon || (result === result ? (result !== value) : (value === value)))) { object[key] = result; } } }); return object; } module.exports = basemerge; },{"../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){ var arraycopy = _dereq_('./arraycopy'), isarguments = _dereq_('../lang/isarguments'), isarray = _dereq_('../lang/isarray'), isarraylike = _dereq_('./isarraylike'), isplainobject = _dereq_('../lang/isplainobject'), istypedarray = _dereq_('../lang/istypedarray'), toplainobject = _dereq_('../lang/toplainobject'); /** * a specialized version of `basemerge` for arrays and objects which performs * deep merges and tracks traversed objects enabling objects with circular * references to be merged. * * @private * @param {object} object the destination object. * @param {object} source the source object. * @param {string} key the key of the value to merge. * @param {function} mergefunc the function to merge values. * @param {function} [customizer] the function to customize merged values. * @param {array} [stacka=[]] tracks traversed source objects. * @param {array} [stackb=[]] associates values with source counterparts. * @returns {boolean} returns `true` if the objects are equivalent, else `false`. */ function basemergedeep(object, source, key, mergefunc, customizer, stacka, stackb) { var length = stacka.length, srcvalue = source[key]; while (length--) { if (stacka[length] == srcvalue) { object[key] = stackb[length]; return; } } var value = object[key], result = customizer ? customizer(value, srcvalue, key, object, source) : undefined, iscommon = result === undefined; if (iscommon) { result = srcvalue; if (isarraylike(srcvalue) && (isarray(srcvalue) || istypedarray(srcvalue))) { result = isarray(value) ? value : (isarraylike(value) ? arraycopy(value) : []); } else if (isplainobject(srcvalue) || isarguments(srcvalue)) { result = isarguments(value) ? toplainobject(value) : (isplainobject(value) ? value : {}); } else { iscommon = false; } } // add the source value to the stack of traversed objects and associate // it with its merged value. stacka.push(srcvalue); stackb.push(result); if (iscommon) { // recursively merge objects and arrays (susceptible to call stack limits). object[key] = mergefunc(result, srcvalue, customizer, stacka, stackb); } else if (result === result ? (result !== value) : (value === value)) { object[key] = result; } } module.exports = basemergedeep; },{"../lang/isarguments":29,"../lang/isarray":30,"../lang/isplainobject":34,"../lang/istypedarray":36,"../lang/toplainobject":37,"./arraycopy":8,"./isarraylike":21}],15:[function(_dereq_,module,exports){ var toobject = _dereq_('./toobject'); /** * the base implementation of `_.property` without support for deep paths. * * @private * @param {string} key the key of the property to get. * @returns {function} returns the new function. */ function baseproperty(key) { return function(object) { return object == null ? undefined : toobject(object)[key]; }; } module.exports = baseproperty; },{"./toobject":28}],16:[function(_dereq_,module,exports){ var identity = _dereq_('../utility/identity'); /** * a specialized version of `basecallback` which only supports `this` binding * and specifying the number of arguments to provide to `func`. * * @private * @param {function} func the function to bind. * @param {*} thisarg the `this` binding of `func`. * @param {number} [argcount] the number of arguments to provide to `func`. * @returns {function} returns the callback. */ function bindcallback(func, thisarg, argcount) { if (typeof func != 'function') { return identity; } if (thisarg === undefined) { return func; } switch (argcount) { case 1: return function(value) { return func.call(thisarg, value); }; case 3: return function(value, index, collection) { return func.call(thisarg, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(thisarg, accumulator, value, index, collection); }; case 5: return function(value, other, key, object, source) { return func.call(thisarg, value, other, key, object, source); }; } return function() { return func.apply(thisarg, arguments); }; } module.exports = bindcallback; },{"../utility/identity":42}],17:[function(_dereq_,module,exports){ var bindcallback = _dereq_('./bindcallback'), isiterateecall = _dereq_('./isiterateecall'), restparam = _dereq_('../function/restparam'); /** * creates a `_.assign`, `_.defaults`, or `_.merge` function. * * @private * @param {function} assigner the function to assign values. * @returns {function} returns the new assigner function. */ function createassigner(assigner) { return restparam(function(object, sources) { var index = -1, length = object == null ? 0 : sources.length, customizer = length > 2 ? sources[length - 2] : undefined, guard = length > 2 ? sources[2] : undefined, thisarg = length > 1 ? sources[length - 1] : undefined; if (typeof customizer == 'function') { customizer = bindcallback(customizer, thisarg, 5); length -= 2; } else { customizer = typeof thisarg == 'function' ? thisarg : undefined; length -= (customizer ? 1 : 0); } if (guard && isiterateecall(sources[0], sources[1], guard)) { customizer = length < 3 ? undefined : customizer; length = 1; } while (++index < length) { var source = sources[index]; if (source) { assigner(object, source, customizer); } } return object; }); } module.exports = createassigner; },{"../function/restparam":6,"./bindcallback":16,"./isiterateecall":24}],18:[function(_dereq_,module,exports){ var toobject = _dereq_('./toobject'); /** * creates a base function for `_.forin` or `_.forinright`. * * @private * @param {boolean} [fromright] specify iterating from right to left. * @returns {function} returns the new base function. */ function createbasefor(fromright) { return function(object, iteratee, keysfunc) { var iterable = toobject(object), props = keysfunc(object), length = props.length, index = fromright ? length : -1; while ((fromright ? index-- : ++index < length)) { var key = props[index]; if (iteratee(iterable[key], key, iterable) === false) { break; } } return object; }; } module.exports = createbasefor; },{"./toobject":28}],19:[function(_dereq_,module,exports){ var baseproperty = _dereq_('./baseproperty'); /** * gets the "length" property value of `object`. * * **note:** this function is used to avoid a [jit bug](https://bugs.webkit.org/show_bug.cgi?id=142792) * that affects safari on at least ios 8.1-8.3 arm64. * * @private * @param {object} object the object to query. * @returns {*} returns the "length" value. */ var getlength = baseproperty('length'); module.exports = getlength; },{"./baseproperty":15}],20:[function(_dereq_,module,exports){ var isnative = _dereq_('../lang/isnative'); /** * gets the native function at `key` of `object`. * * @private * @param {object} object the object to query. * @param {string} key the key of the method to get. * @returns {*} returns the function if it's native, else `undefined`. */ function getnative(object, key) { var value = object == null ? undefined : object[key]; return isnative(value) ? value : undefined; } module.exports = getnative; },{"../lang/isnative":32}],21:[function(_dereq_,module,exports){ var getlength = _dereq_('./getlength'), islength = _dereq_('./islength'); /** * checks if `value` is array-like. * * @private * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is array-like, else `false`. */ function isarraylike(value) { return value != null && islength(getlength(value)); } module.exports = isarraylike; },{"./getlength":19,"./islength":25}],22:[function(_dereq_,module,exports){ /** * checks if `value` is a host object in ie < 9. * * @private * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is a host object, else `false`. */ var ishostobject = (function() { try { object({ 'tostring': 0 } + ''); } catch(e) { return function() { return false; }; } return function(value) { // ie < 9 presents many host objects as `object` objects that can coerce // to strings despite having improperly defined `tostring` methods. return typeof value.tostring != 'function' && typeof (value + '') == 'string'; }; }()); module.exports = ishostobject; },{}],23:[function(_dereq_,module,exports){ /** used to detect unsigned integer values. */ var reisuint = /^\d+$/; /** * used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) * of an array-like value. */ var max_safe_integer = 9007199254740991; /** * checks if `value` is a valid array-like index. * * @private * @param {*} value the value to check. * @param {number} [length=max_safe_integer] the upper bounds of a valid index. * @returns {boolean} returns `true` if `value` is a valid index, else `false`. */ function isindex(value, length) { value = (typeof value == 'number' || reisuint.test(value)) ? +value : -1; length = length == null ? max_safe_integer : length; return value > -1 && value % 1 == 0 && value < length; } module.exports = isindex; },{}],24:[function(_dereq_,module,exports){ var isarraylike = _dereq_('./isarraylike'), isindex = _dereq_('./isindex'), isobject = _dereq_('../lang/isobject'); /** * checks if the provided arguments are from an iteratee call. * * @private * @param {*} value the potential iteratee value argument. * @param {*} index the potential iteratee index or key argument. * @param {*} object the potential iteratee object argument. * @returns {boolean} returns `true` if the arguments are from an iteratee call, else `false`. */ function isiterateecall(value, index, object) { if (!isobject(object)) { return false; } var type = typeof index; if (type == 'number' ? (isarraylike(object) && isindex(index, object.length)) : (type == 'string' && index in object)) { var other = object[index]; return value === value ? (value === other) : (other !== other); } return false; } module.exports = isiterateecall; },{"../lang/isobject":33,"./isarraylike":21,"./isindex":23}],25:[function(_dereq_,module,exports){ /** * used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) * of an array-like value. */ var max_safe_integer = 9007199254740991; /** * checks if `value` is a valid array-like length. * * **note:** this function is based on [`tolength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). * * @private * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is a valid length, else `false`. */ function islength(value) { return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= max_safe_integer; } module.exports = islength; },{}],26:[function(_dereq_,module,exports){ /** * checks if `value` is object-like. * * @private * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is object-like, else `false`. */ function isobjectlike(value) { return !!value && typeof value == 'object'; } module.exports = isobjectlike; },{}],27:[function(_dereq_,module,exports){ var isarguments = _dereq_('../lang/isarguments'), isarray = _dereq_('../lang/isarray'), isindex = _dereq_('./isindex'), islength = _dereq_('./islength'), isstring = _dereq_('../lang/isstring'), keysin = _dereq_('../object/keysin'); /** used for native method references. */ var objectproto = object.prototype; /** used to check objects for own properties. */ var hasownproperty = objectproto.hasownproperty; /** * a fallback implementation of `object.keys` which creates an array of the * own enumerable property names of `object`. * * @private * @param {object} object the object to query. * @returns {array} returns the array of property names. */ function shimkeys(object) { var props = keysin(object), propslength = props.length, length = propslength && object.length; var allowindexes = !!length && islength(length) && (isarray(object) || isarguments(object) || isstring(object)); var index = -1, result = []; while (++index < propslength) { var key = props[index]; if ((allowindexes && isindex(key, length)) || hasownproperty.call(object, key)) { result.push(key); } } return result; } module.exports = shimkeys; },{"../lang/isarguments":29,"../lang/isarray":30,"../lang/isstring":35,"../object/keysin":39,"./isindex":23,"./islength":25}],28:[function(_dereq_,module,exports){ var isobject = _dereq_('../lang/isobject'), isstring = _dereq_('../lang/isstring'), support = _dereq_('../support'); /** * converts `value` to an object if it's not one. * * @private * @param {*} value the value to process. * @returns {object} returns the object. */ function toobject(value) { if (support.unindexedchars && isstring(value)) { var index = -1, length = value.length, result = object(value); while (++index < length) { result[index] = value.charat(index); } return result; } return isobject(value) ? value : object(value); } module.exports = toobject; },{"../lang/isobject":33,"../lang/isstring":35,"../support":41}],29:[function(_dereq_,module,exports){ var isarraylike = _dereq_('../internal/isarraylike'), isobjectlike = _dereq_('../internal/isobjectlike'); /** used for native method references. */ var objectproto = object.prototype; /** used to check objects for own properties. */ var hasownproperty = objectproto.hasownproperty; /** native method references. */ var propertyisenumerable = objectproto.propertyisenumerable; /** * checks if `value` is classified as an `arguments` object. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is correctly classified, else `false`. * @example * * _.isarguments(function() { return arguments; }()); * // => true * * _.isarguments([1, 2, 3]); * // => false */ function isarguments(value) { return isobjectlike(value) && isarraylike(value) && hasownproperty.call(value, 'callee') && !propertyisenumerable.call(value, 'callee'); } module.exports = isarguments; },{"../internal/isarraylike":21,"../internal/isobjectlike":26}],30:[function(_dereq_,module,exports){ var getnative = _dereq_('../internal/getnative'), islength = _dereq_('../internal/islength'), isobjectlike = _dereq_('../internal/isobjectlike'); /** `object#tostring` result references. */ var arraytag = '[object array]'; /** used for native method references. */ var objectproto = object.prototype; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /* native method references for those with the same name as other `lodash` methods. */ var nativeisarray = getnative(array, 'isarray'); /** * checks if `value` is classified as an `array` object. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is correctly classified, else `false`. * @example * * _.isarray([1, 2, 3]); * // => true * * _.isarray(function() { return arguments; }()); * // => false */ var isarray = nativeisarray || function(value) { return isobjectlike(value) && islength(value.length) && objtostring.call(value) == arraytag; }; module.exports = isarray; },{"../internal/getnative":20,"../internal/islength":25,"../internal/isobjectlike":26}],31:[function(_dereq_,module,exports){ var isobject = _dereq_('./isobject'); /** `object#tostring` result references. */ var functag = '[object function]'; /** used for native method references. */ var objectproto = object.prototype; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /** * checks if `value` is classified as a `function` object. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is correctly classified, else `false`. * @example * * _.isfunction(_); * // => true * * _.isfunction(/abc/); * // => false */ function isfunction(value) { // the use of `object#tostring` avoids issues with the `typeof` operator // in older versions of chrome and safari which return 'function' for regexes // and safari 8 which returns 'object' for typed array constructors. return isobject(value) && objtostring.call(value) == functag; } module.exports = isfunction; },{"./isobject":33}],32:[function(_dereq_,module,exports){ var isfunction = _dereq_('./isfunction'), ishostobject = _dereq_('../internal/ishostobject'), isobjectlike = _dereq_('../internal/isobjectlike'); /** used to detect host constructors (safari > 5). */ var reishostctor = /^\[object .+?constructor\]$/; /** used for native method references. */ var objectproto = object.prototype; /** used to resolve the decompiled source of functions. */ var fntostring = function.prototype.tostring; /** used to check objects for own properties. */ var hasownproperty = objectproto.hasownproperty; /** used to detect if a method is native. */ var reisnative = regexp('^' + fntostring.call(hasownproperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') .replace(/hasownproperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** * checks if `value` is a native function. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is a native function, else `false`. * @example * * _.isnative(array.prototype.push); * // => true * * _.isnative(_); * // => false */ function isnative(value) { if (value == null) { return false; } if (isfunction(value)) { return reisnative.test(fntostring.call(value)); } return isobjectlike(value) && (ishostobject(value) ? reisnative : reishostctor).test(value); } module.exports = isnative; },{"../internal/ishostobject":22,"../internal/isobjectlike":26,"./isfunction":31}],33:[function(_dereq_,module,exports){ /** * checks if `value` is the [language type](https://es5.github.io/#x8) of `object`. * (e.g. arrays, functions, objects, regexes, `new number(0)`, and `new string('')`) * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is an object, else `false`. * @example * * _.isobject({}); * // => true * * _.isobject([1, 2, 3]); * // => true * * _.isobject(1); * // => false */ function isobject(value) { // avoid a v8 jit bug in chrome 19-20. // see https://code.google.com/p/v8/issues/detail?id=2291 for more details. var type = typeof value; return !!value && (type == 'object' || type == 'function'); } module.exports = isobject; },{}],34:[function(_dereq_,module,exports){ var baseforin = _dereq_('../internal/baseforin'), isarguments = _dereq_('./isarguments'), ishostobject = _dereq_('../internal/ishostobject'), isobjectlike = _dereq_('../internal/isobjectlike'), support = _dereq_('../support'); /** `object#tostring` result references. */ var objecttag = '[object object]'; /** used for native method references. */ var objectproto = object.prototype; /** used to check objects for own properties. */ var hasownproperty = objectproto.hasownproperty; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /** * checks if `value` is a plain object, that is, an object created by the * `object` constructor or one with a `[[prototype]]` of `null`. * * **note:** this method assumes objects created by the `object` constructor * have no inherited enumerable properties. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is a plain object, else `false`. * @example * * function foo() { * this.a = 1; * } * * _.isplainobject(new foo); * // => false * * _.isplainobject([1, 2, 3]); * // => false * * _.isplainobject({ 'x': 0, 'y': 0 }); * // => true * * _.isplainobject(object.create(null)); * // => true */ function isplainobject(value) { var ctor; // exit early for non `object` objects. if (!(isobjectlike(value) && objtostring.call(value) == objecttag && !ishostobject(value) && !isarguments(value)) || (!hasownproperty.call(value, 'constructor') && (ctor = value.constructor, typeof ctor == 'function' && !(ctor instanceof ctor)))) { return false; } // ie < 9 iterates inherited properties before own properties. if the first // iterated property is an object's own property then there are no inherited // enumerable properties. var result; if (support.ownlast) { baseforin(value, function(subvalue, key, object) { result = hasownproperty.call(object, key); return false; }); return result !== false; } // in most environments an object's own properties are iterated before // its inherited properties. if the last iterated property is an object's // own property then there are no inherited enumerable properties. baseforin(value, function(subvalue, key) { result = key; }); return result === undefined || hasownproperty.call(value, result); } module.exports = isplainobject; },{"../internal/baseforin":12,"../internal/ishostobject":22,"../internal/isobjectlike":26,"../support":41,"./isarguments":29}],35:[function(_dereq_,module,exports){ var isobjectlike = _dereq_('../internal/isobjectlike'); /** `object#tostring` result references. */ var stringtag = '[object string]'; /** used for native method references. */ var objectproto = object.prototype; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /** * checks if `value` is classified as a `string` primitive or object. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is correctly classified, else `false`. * @example * * _.isstring('abc'); * // => true * * _.isstring(1); * // => false */ function isstring(value) { return typeof value == 'string' || (isobjectlike(value) && objtostring.call(value) == stringtag); } module.exports = isstring; },{"../internal/isobjectlike":26}],36:[function(_dereq_,module,exports){ var islength = _dereq_('../internal/islength'), isobjectlike = _dereq_('../internal/isobjectlike'); /** `object#tostring` result references. */ var argstag = '[object arguments]', arraytag = '[object array]', booltag = '[object boolean]', datetag = '[object date]', errortag = '[object error]', functag = '[object function]', maptag = '[object map]', numbertag = '[object number]', objecttag = '[object object]', regexptag = '[object regexp]', settag = '[object set]', stringtag = '[object string]', weakmaptag = '[object weakmap]'; var arraybuffertag = '[object arraybuffer]', float32tag = '[object float32array]', float64tag = '[object float64array]', int8tag = '[object int8array]', int16tag = '[object int16array]', int32tag = '[object int32array]', uint8tag = '[object uint8array]', uint8clampedtag = '[object uint8clampedarray]', uint16tag = '[object uint16array]', uint32tag = '[object uint32array]'; /** used to identify `tostringtag` values of typed arrays. */ var typedarraytags = {}; typedarraytags[float32tag] = typedarraytags[float64tag] = typedarraytags[int8tag] = typedarraytags[int16tag] = typedarraytags[int32tag] = typedarraytags[uint8tag] = typedarraytags[uint8clampedtag] = typedarraytags[uint16tag] = typedarraytags[uint32tag] = true; typedarraytags[argstag] = typedarraytags[arraytag] = typedarraytags[arraybuffertag] = typedarraytags[booltag] = typedarraytags[datetag] = typedarraytags[errortag] = typedarraytags[functag] = typedarraytags[maptag] = typedarraytags[numbertag] = typedarraytags[objecttag] = typedarraytags[regexptag] = typedarraytags[settag] = typedarraytags[stringtag] = typedarraytags[weakmaptag] = false; /** used for native method references. */ var objectproto = object.prototype; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /** * checks if `value` is classified as a typed array. * * @static * @memberof _ * @category lang * @param {*} value the value to check. * @returns {boolean} returns `true` if `value` is correctly classified, else `false`. * @example * * _.istypedarray(new uint8array); * // => true * * _.istypedarray([]); * // => false */ function istypedarray(value) { return isobjectlike(value) && islength(value.length) && !!typedarraytags[objtostring.call(value)]; } module.exports = istypedarray; },{"../internal/islength":25,"../internal/isobjectlike":26}],37:[function(_dereq_,module,exports){ var basecopy = _dereq_('../internal/basecopy'), keysin = _dereq_('../object/keysin'); /** * converts `value` to a plain object flattening inherited enumerable * properties of `value` to own properties of the plain object. * * @static * @memberof _ * @category lang * @param {*} value the value to convert. * @returns {object} returns the converted plain object. * @example * * function foo() { * this.b = 2; * } * * foo.prototype.c = 3; * * _.assign({ 'a': 1 }, new foo); * // => { 'a': 1, 'b': 2 } * * _.assign({ 'a': 1 }, _.toplainobject(new foo)); * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toplainobject(value) { return basecopy(value, keysin(value)); } module.exports = toplainobject; },{"../internal/basecopy":10,"../object/keysin":39}],38:[function(_dereq_,module,exports){ var getnative = _dereq_('../internal/getnative'), isarraylike = _dereq_('../internal/isarraylike'), isobject = _dereq_('../lang/isobject'), shimkeys = _dereq_('../internal/shimkeys'), support = _dereq_('../support'); /* native method references for those with the same name as other `lodash` methods. */ var nativekeys = getnative(object, 'keys'); /** * creates an array of the own enumerable property names of `object`. * * **note:** non-object values are coerced to objects. see the * [es spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) * for more details. * * @static * @memberof _ * @category object * @param {object} object the object to query. * @returns {array} returns the array of property names. * @example * * function foo() { * this.a = 1; * this.b = 2; * } * * foo.prototype.c = 3; * * _.keys(new foo); * // => ['a', 'b'] (iteration order is not guaranteed) * * _.keys('hi'); * // => ['0', '1'] */ var keys = !nativekeys ? shimkeys : function(object) { var ctor = object == null ? undefined : object.constructor; if ((typeof ctor == 'function' && ctor.prototype === object) || (typeof object == 'function' ? support.enumprototypes : isarraylike(object))) { return shimkeys(object); } return isobject(object) ? nativekeys(object) : []; }; module.exports = keys; },{"../internal/getnative":20,"../internal/isarraylike":21,"../internal/shimkeys":27,"../lang/isobject":33,"../support":41}],39:[function(_dereq_,module,exports){ var arrayeach = _dereq_('../internal/arrayeach'), isarguments = _dereq_('../lang/isarguments'), isarray = _dereq_('../lang/isarray'), isfunction = _dereq_('../lang/isfunction'), isindex = _dereq_('../internal/isindex'), islength = _dereq_('../internal/islength'), isobject = _dereq_('../lang/isobject'), isstring = _dereq_('../lang/isstring'), support = _dereq_('../support'); /** `object#tostring` result references. */ var arraytag = '[object array]', booltag = '[object boolean]', datetag = '[object date]', errortag = '[object error]', functag = '[object function]', numbertag = '[object number]', objecttag = '[object object]', regexptag = '[object regexp]', stringtag = '[object string]'; /** used to fix the jscript `[[dontenum]]` bug. */ var shadowprops = [ 'constructor', 'hasownproperty', 'isprototypeof', 'propertyisenumerable', 'tolocalestring', 'tostring', 'valueof' ]; /** used for native method references. */ var errorproto = error.prototype, objectproto = object.prototype, stringproto = string.prototype; /** used to check objects for own properties. */ var hasownproperty = objectproto.hasownproperty; /** * used to resolve the [`tostringtag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objtostring = objectproto.tostring; /** used to avoid iterating over non-enumerable properties in ie < 9. */ var nonenumprops = {}; nonenumprops[arraytag] = nonenumprops[datetag] = nonenumprops[numbertag] = { 'constructor': true, 'tolocalestring': true, 'tostring': true, 'valueof': true }; nonenumprops[booltag] = nonenumprops[stringtag] = { 'constructor': true, 'tostring': true, 'valueof': true }; nonenumprops[errortag] = nonenumprops[functag] = nonenumprops[regexptag] = { 'constructor': true, 'tostring': true }; nonenumprops[objecttag] = { 'constructor': true }; arrayeach(shadowprops, function(key) { for (var tag in nonenumprops) { if (hasownproperty.call(nonenumprops, tag)) { var props = nonenumprops[tag]; props[key] = hasownproperty.call(props, key); } } }); /** * creates an array of the own and inherited enumerable property names of `object`. * * **note:** non-object values are coerced to objects. * * @static * @memberof _ * @category object * @param {object} object the object to query. * @returns {array} returns the array of property names. * @example * * function foo() { * this.a = 1; * this.b = 2; * } * * foo.prototype.c = 3; * * _.keysin(new foo); * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysin(object) { if (object == null) { return []; } if (!isobject(object)) { object = object(object); } var length = object.length; length = (length && islength(length) && (isarray(object) || isarguments(object) || isstring(object)) && length) || 0; var ctor = object.constructor, index = -1, proto = (isfunction(ctor) && ctor.prototype) || objectproto, isproto = proto === object, result = array(length), skipindexes = length > 0, skiperrorprops = support.enumerrorprops && (object === errorproto || object instanceof error), skipproto = support.enumprototypes && isfunction(object); while (++index < length) { result[index] = (index + ''); } // lodash skips the `constructor` property when it infers it's iterating // over a `prototype` object because ie < 9 can't set the `[[enumerable]]` // attribute of an existing property and the `constructor` property of a // prototype defaults to non-enumerable. for (var key in object) { if (!(skipproto && key == 'prototype') && !(skiperrorprops && (key == 'message' || key == 'name')) && !(skipindexes && isindex(key, length)) && !(key == 'constructor' && (isproto || !hasownproperty.call(object, key)))) { result.push(key); } } if (support.nonenumshadows && object !== objectproto) { var tag = object === stringproto ? stringtag : (object === errorproto ? errortag : objtostring.call(object)), nonenums = nonenumprops[tag] || nonenumprops[objecttag]; if (tag == objecttag) { proto = objectproto; } length = shadowprops.length; while (length--) { key = shadowprops[length]; var nonenum = nonenums[key]; if (!(isproto && nonenum) && (nonenum ? hasownproperty.call(object, key) : object[key] !== proto[key])) { result.push(key); } } } return result; } module.exports = keysin; },{"../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){ var basemerge = _dereq_('../internal/basemerge'), createassigner = _dereq_('../internal/createassigner'); /** * recursively merges own enumerable properties of the source object(s), that * don't resolve to `undefined` into the destination object. subsequent sources * overwrite property assignments of previous sources. if `customizer` is * provided it's invoked to produce the merged values of the destination and * source properties. if `customizer` returns `undefined` merging is handled * by the method instead. the `customizer` is bound to `thisarg` and invoked * with five arguments: (objectvalue, sourcevalue, key, object, source). * * @static * @memberof _ * @category object * @param {object} object the destination object. * @param {...object} [sources] the source objects. * @param {function} [customizer] the function to customize assigned values. * @param {*} [thisarg] the `this` binding of `customizer`. * @returns {object} returns `object`. * @example * * var users = { * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] * }; * * var ages = { * 'data': [{ 'age': 36 }, { 'age': 40 }] * }; * * _.merge(users, ages); * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } * * // using a customizer callback * var object = { * 'fruits': ['apple'], * 'vegetables': ['beet'] * }; * * var other = { * 'fruits': ['banana'], * 'vegetables': ['carrot'] * }; * * _.merge(object, other, function(a, b) { * if (_.isarray(a)) { * return a.concat(b); * } * }); * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } */ var merge = createassigner(basemerge); module.exports = merge; },{"../internal/basemerge":13,"../internal/createassigner":17}],41:[function(_dereq_,module,exports){ /** used for native method references. */ var arrayproto = array.prototype, errorproto = error.prototype, objectproto = object.prototype; /** native method references. */ var propertyisenumerable = objectproto.propertyisenumerable, splice = arrayproto.splice; /** * an object environment feature flags. * * @static * @memberof _ * @type object */ var support = {}; (function(x) { var ctor = function() { this.x = x; }, object = { '0': x, 'length': x }, props = []; ctor.prototype = { 'valueof': x, 'y': x }; for (var key in new ctor) { props.push(key); } /** * detect if `name` or `message` properties of `error.prototype` are * enumerable by default (ie < 9, safari < 5.1). * * @memberof _.support * @type boolean */ support.enumerrorprops = propertyisenumerable.call(errorproto, 'message') || propertyisenumerable.call(errorproto, 'name'); /** * detect if `prototype` properties are enumerable by default. * * firefox < 3.6, opera > 9.50 - opera < 11.60, and safari < 5.1 * (if the prototype or a property on the prototype has been set) * incorrectly set the `[[enumerable]]` value of a function's `prototype` * property to `true`. * * @memberof _.support * @type boolean */ support.enumprototypes = propertyisenumerable.call(ctor, 'prototype'); /** * detect if properties shadowing those on `object.prototype` are non-enumerable. * * in ie < 9 an object's own properties, shadowing non-enumerable ones, * are made non-enumerable as well (a.k.a the jscript `[[dontenum]]` bug). * * @memberof _.support * @type boolean */ support.nonenumshadows = !/valueof/.test(props); /** * detect if own properties are iterated after inherited properties (ie < 9). * * @memberof _.support * @type boolean */ support.ownlast = props[0] != 'x'; /** * detect if `array#shift` and `array#splice` augment array-like objects * correctly. * * firefox < 10, compatibility modes of ie 8, and ie < 9 have buggy array * `shift()` and `splice()` functions that fail to remove the last element, * `value[0]`, of array-like objects even though the "length" property is * set to `0`. the `shift()` method is buggy in compatibility modes of ie 8, * while `splice()` is buggy regardless of mode in ie < 9. * * @memberof _.support * @type boolean */ support.spliceobjects = (splice.call(object, 0, 1), !object[0]); /** * detect lack of support for accessing string characters by index. * * ie < 8 can't access characters by index. ie 8 can only access characters * by index on string literals, not string objects. * * @memberof _.support * @type boolean */ support.unindexedchars = ('x'[0] + object('x')[0]) != 'xx'; }(1, 0)); module.exports = support; },{}],42:[function(_dereq_,module,exports){ /** * this method returns the first argument provided to it. * * @static * @memberof _ * @category utility * @param {*} value any value. * @returns {*} returns `value`. * @example * * var object = { 'user': 'fred' }; * * _.identity(object) === object; * // => true */ function identity(value) { return value; } module.exports = identity; },{}],43:[function(_dereq_,module,exports){ 'use strict'; var keys = _dereq_('object-keys'); module.exports = function hassymbols() { if (typeof symbol !== 'function' || typeof object.getownpropertysymbols !== 'function') { return false; } if (typeof symbol.iterator === 'symbol') { return true; } var obj = {}; var sym = symbol('test'); if (typeof sym === 'string') { return false; } // temp disabled per https://github.com/ljharb/object.assign/issues/17 // if (sym instanceof symbol) { return false; } // temp disabled per https://github.com/webreflection/get-own-property-symbols/issues/4 // if (!(object(sym) instanceof symbol)) { return false; } var symval = 42; obj[sym] = symval; for (sym in obj) { return false; } if (keys(obj).length !== 0) { return false; } if (typeof object.keys === 'function' && object.keys(obj).length !== 0) { return false; } if (typeof object.getownpropertynames === 'function' && object.getownpropertynames(obj).length !== 0) { return false; } var syms = object.getownpropertysymbols(obj); if (syms.length !== 1 || syms[0] !== sym) { return false; } if (!object.prototype.propertyisenumerable.call(obj, sym)) { return false; } if (typeof object.getownpropertydescriptor === 'function') { var descriptor = object.getownpropertydescriptor(obj, sym); if (descriptor.value !== symval || descriptor.enumerable !== true) { return false; } } return true; }; },{"object-keys":50}],44:[function(_dereq_,module,exports){ 'use strict'; // modified from https://github.com/es-shims/es6-shim var keys = _dereq_('object-keys'); var bind = _dereq_('function-bind'); var canbeobject = function (obj) { return typeof obj !== 'undefined' && obj !== null; }; var hassymbols = _dereq_('./hassymbols')(); var toobject = object; var push = bind.call(function.call, array.prototype.push); var propisenumerable = bind.call(function.call, object.prototype.propertyisenumerable); module.exports = function assign(target, source1) { if (!canbeobject(target)) { throw new typeerror('target must be an object'); } var objtarget = toobject(target); var s, source, i, props, syms, value, key; for (s = 1; s < arguments.length; ++s) { source = toobject(arguments[s]); props = keys(source); if (hassymbols && object.getownpropertysymbols) { syms = object.getownpropertysymbols(source); for (i = 0; i < syms.length; ++i) { key = syms[i]; if (propisenumerable(source, key)) { push(props, key); } } } for (i = 0; i < props.length; ++i) { key = props[i]; value = source[key]; if (propisenumerable(source, key)) { objtarget[key] = value; } } } return objtarget; }; },{"./hassymbols":43,"function-bind":49,"object-keys":50}],45:[function(_dereq_,module,exports){ 'use strict'; var defineproperties = _dereq_('define-properties'); var implementation = _dereq_('./implementation'); var getpolyfill = _dereq_('./polyfill'); var shim = _dereq_('./shim'); defineproperties(implementation, { implementation: implementation, getpolyfill: getpolyfill, shim: shim }); module.exports = implementation; },{"./implementation":44,"./polyfill":52,"./shim":53,"define-properties":46}],46:[function(_dereq_,module,exports){ 'use strict'; var keys = _dereq_('object-keys'); var foreach = _dereq_('foreach'); var hassymbols = typeof symbol === 'function' && typeof symbol() === 'symbol'; var tostr = object.prototype.tostring; var isfunction = function (fn) { return typeof fn === 'function' && tostr.call(fn) === '[object function]'; }; var arepropertydescriptorssupported = function () { var obj = {}; try { object.defineproperty(obj, 'x', { enumerable: false, value: obj }); /* eslint-disable no-unused-vars, no-restricted-syntax */ for (var _ in obj) { return false; } /* eslint-enable no-unused-vars, no-restricted-syntax */ return obj.x === obj; } catch (e) { /* this is ie 8. */ return false; } }; var supportsdescriptors = object.defineproperty && arepropertydescriptorssupported(); var defineproperty = function (object, name, value, predicate) { if (name in object && (!isfunction(predicate) || !predicate())) { return; } if (supportsdescriptors) { object.defineproperty(object, name, { configurable: true, enumerable: false, value: value, writable: true }); } else { object[name] = value; } }; var defineproperties = function (object, map) { var predicates = arguments.length > 2 ? arguments[2] : {}; var props = keys(map); if (hassymbols) { props = props.concat(object.getownpropertysymbols(map)); } foreach(props, function (name) { defineproperty(object, name, map[name], predicates[name]); }); }; defineproperties.supportsdescriptors = !!supportsdescriptors; module.exports = defineproperties; },{"foreach":47,"object-keys":50}],47:[function(_dereq_,module,exports){ var hasown = object.prototype.hasownproperty; var tostring = object.prototype.tostring; module.exports = function foreach (obj, fn, ctx) { if (tostring.call(fn) !== '[object function]') { throw new typeerror('iterator must be a function'); } var l = obj.length; if (l === +l) { for (var i = 0; i < l; i++) { fn.call(ctx, obj[i], i, obj); } } else { for (var k in obj) { if (hasown.call(obj, k)) { fn.call(ctx, obj[k], k, obj); } } } }; },{}],48:[function(_dereq_,module,exports){ var error_message = 'function.prototype.bind called on incompatible '; var slice = array.prototype.slice; var tostr = object.prototype.tostring; var functype = '[object function]'; module.exports = function bind(that) { var target = this; if (typeof target !== 'function' || tostr.call(target) !== functype) { throw new typeerror(error_message + target); } var args = slice.call(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; var boundlength = math.max(0, target.length - args.length); var boundargs = []; for (var i = 0; i < boundlength; i++) { boundargs.push('$' + i); } bound = function('binder', 'return function (' + boundargs.join(',') + '){ return binder.apply(this,arguments); }')(binder); if (target.prototype) { var empty = function empty() {}; empty.prototype = target.prototype; bound.prototype = new empty(); empty.prototype = null; } return bound; }; },{}],49:[function(_dereq_,module,exports){ var implementation = _dereq_('./implementation'); module.exports = function.prototype.bind || implementation; },{"./implementation":48}],50:[function(_dereq_,module,exports){ 'use strict'; // modified from https://github.com/es-shims/es5-shim var has = object.prototype.hasownproperty; var tostr = object.prototype.tostring; var slice = array.prototype.slice; var isargs = _dereq_('./isarguments'); var hasdontenumbug = !({ tostring: null }).propertyisenumerable('tostring'); var hasprotoenumbug = function () {}.propertyisenumerable('prototype'); var dontenums = [ 'tostring', 'tolocalestring', 'valueof', 'hasownproperty', 'isprototypeof', 'propertyisenumerable', 'constructor' ]; var equalsconstructorprototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var blacklistedkeys = { $console: true, $frame: true, $frameelement: true, $frames: true, $parent: true, $self: true, $webkitindexeddb: true, $webkitstorageinfo: true, $window: true }; var hasautomationequalitybug = (function () { /* global window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!blacklistedkeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { try { equalsconstructorprototype(window[k]); } catch (e) { return true; } } } catch (e) { return true; } } return false; }()); var equalsconstructorprototypeifnotbuggy = function (o) { /* global window */ if (typeof window === 'undefined' || !hasautomationequalitybug) { return equalsconstructorprototype(o); } try { return equalsconstructorprototype(o); } catch (e) { return false; } }; var keysshim = function keys(object) { var isobject = object !== null && typeof object === 'object'; var isfunction = tostr.call(object) === '[object function]'; var isarguments = isargs(object); var isstring = isobject && tostr.call(object) === '[object string]'; var thekeys = []; if (!isobject && !isfunction && !isarguments) { throw new typeerror('object.keys called on a non-object'); } var skipproto = hasprotoenumbug && isfunction; if (isstring && object.length > 0 && !has.call(object, 0)) { for (var i = 0; i < object.length; ++i) { thekeys.push(string(i)); } } if (isarguments && object.length > 0) { for (var j = 0; j < object.length; ++j) { thekeys.push(string(j)); } } else { for (var name in object) { if (!(skipproto && name === 'prototype') && has.call(object, name)) { thekeys.push(string(name)); } } } if (hasdontenumbug) { var skipconstructor = equalsconstructorprototypeifnotbuggy(object); for (var k = 0; k < dontenums.length; ++k) { if (!(skipconstructor && dontenums[k] === 'constructor') && has.call(object, dontenums[k])) { thekeys.push(dontenums[k]); } } } return thekeys; }; keysshim.shim = function shimobjectkeys() { if (object.keys) { var keysworkswitharguments = (function () { // safari 5.0 bug return (object.keys(arguments) || '').length === 2; }(1, 2)); if (!keysworkswitharguments) { var originalkeys = object.keys; object.keys = function keys(object) { if (isargs(object)) { return originalkeys(slice.call(object)); } else { return originalkeys(object); } }; } } else { object.keys = keysshim; } return object.keys || keysshim; }; module.exports = keysshim; },{"./isarguments":51}],51:[function(_dereq_,module,exports){ 'use strict'; var tostr = object.prototype.tostring; module.exports = function isarguments(value) { var str = tostr.call(value); var isargs = str === '[object arguments]'; if (!isargs) { isargs = str !== '[object array]' && value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && tostr.call(value.callee) === '[object function]'; } return isargs; }; },{}],52:[function(_dereq_,module,exports){ 'use strict'; var implementation = _dereq_('./implementation'); var lacksproperenumerationorder = function () { if (!object.assign) { return false; } // v8, specifically in node 4.x, has a bug with incorrect property enumeration order // note: this does not detect the bug unless there's 20 characters var str = 'abcdefghijklmnopqrst'; var letters = str.split(''); var map = {}; for (var i = 0; i < letters.length; ++i) { map[letters[i]] = letters[i]; } var obj = object.assign({}, map); var actual = ''; for (var k in obj) { actual += k; } return str !== actual; }; var assignhaspendingexceptions = function () { if (!object.assign || !object.preventextensions) { return false; } // firefox 37 still has "pending exception" logic in its object.assign implementation, // which is 72% slower than our shim, and firefox 40's native implementation. var thrower = object.preventextensions({ 1: 2 }); try { object.assign(thrower, 'xy'); } catch (e) { return thrower[1] === 'y'; } }; module.exports = function getpolyfill() { if (!object.assign) { return implementation; } if (lacksproperenumerationorder()) { return implementation; } if (assignhaspendingexceptions()) { return implementation; } return object.assign; }; },{"./implementation":44}],53:[function(_dereq_,module,exports){ 'use strict'; var define = _dereq_('define-properties'); var getpolyfill = _dereq_('./polyfill'); module.exports = function shimassign() { var polyfill = getpolyfill(); define( object, { assign: polyfill }, { assign: function () { return object.assign !== polyfill; } } ); return polyfill; }; },{"./polyfill":52,"define-properties":46}],54:[function(_dereq_,module,exports){ module.exports = safeparsetuple function safeparsetuple(obj, reviver) { var json var error = null try { json = json.parse(obj, reviver) } catch (err) { error = err } return [error, json] } },{}],55:[function(_dereq_,module,exports){ function clean (s) { return s.replace(/\n\r?\s*/g, '') } module.exports = function tsml (sa) { var s = '' , i = 0 for (; i < arguments.length; i++) s += clean(sa[i]) + (arguments[i + 1] || '') return s } },{}],56:[function(_dereq_,module,exports){ "use strict"; var window = _dereq_("global/window") var once = _dereq_("once") var isfunction = _dereq_("is-function") var parseheaders = _dereq_("parse-headers") var xtend = _dereq_("xtend") module.exports = createxhr createxhr.xmlhttprequest = window.xmlhttprequest || noop createxhr.xdomainrequest = "withcredentials" in (new createxhr.xmlhttprequest()) ? createxhr.xmlhttprequest : window.xdomainrequest foreacharray(["get", "put", "post", "patch", "head", "delete"], function(method) { createxhr[method === "delete" ? "del" : method] = function(uri, options, callback) { options = initparams(uri, options, callback) options.method = method.touppercase() return _createxhr(options) } }) function foreacharray(array, iterator) { for (var i = 0; i < array.length; i++) { iterator(array[i]) } } function isempty(obj){ for(var i in obj){ if(obj.hasownproperty(i)) return false } return true } function initparams(uri, options, callback) { var params = uri if (isfunction(options)) { callback = options if (typeof uri === "string") { params = {uri:uri} } } else { params = xtend(options, {uri: uri}) } params.callback = callback return params } function createxhr(uri, options, callback) { options = initparams(uri, options, callback) return _createxhr(options) } function _createxhr(options) { var callback = options.callback if(typeof callback === "undefined"){ throw new error("callback argument missing") } callback = once(callback) function readystatechange() { if (xhr.readystate === 4) { loadfunc() } } function getbody() { // chrome with requesttype=blob throws errors arround when even testing access to responsetext var body = undefined if (xhr.response) { body = xhr.response } else if (xhr.responsetype === "text" || !xhr.responsetype) { body = xhr.responsetext || xhr.responsexml } if (isjson) { try { body = json.parse(body) } catch (e) {} } return body } var failureresponse = { body: undefined, headers: {}, statuscode: 0, method: method, url: uri, rawrequest: xhr } function errorfunc(evt) { cleartimeout(timeouttimer) if(!(evt instanceof error)){ evt = new error("" + (evt || "unknown xmlhttprequest error") ) } evt.statuscode = 0 callback(evt, failureresponse) } // will load the data & process the response in a special response object function loadfunc() { if (aborted) return var status cleartimeout(timeouttimer) if(options.usexdr && xhr.status===undefined) { //ie8 cors get successful response doesn't have a status field, but body is fine status = 200 } else { status = (xhr.status === 1223 ? 204 : xhr.status) } var response = failureresponse var err = null if (status !== 0){ response = { body: getbody(), statuscode: status, method: method, headers: {}, url: uri, rawrequest: xhr } if(xhr.getallresponseheaders){ //remember xhr can in fact be xdr for cors in ie response.headers = parseheaders(xhr.getallresponseheaders()) } } else { err = new error("internal xmlhttprequest error") } callback(err, response, response.body) } var xhr = options.xhr || null if (!xhr) { if (options.cors || options.usexdr) { xhr = new createxhr.xdomainrequest() }else{ xhr = new createxhr.xmlhttprequest() } } var key var aborted var uri = xhr.url = options.uri || options.url var method = xhr.method = options.method || "get" var body = options.body || options.data || null var headers = xhr.headers = options.headers || {} var sync = !!options.sync var isjson = false var timeouttimer if ("json" in options) { isjson = true headers["accept"] || headers["accept"] || (headers["accept"] = "application/json") //don't override existing accept header declared by user if (method !== "get" && method !== "head") { headers["content-type"] || headers["content-type"] || (headers["content-type"] = "application/json") //don't override existing accept header declared by user body = json.stringify(options.json) } } xhr.onreadystatechange = readystatechange xhr.onload = loadfunc xhr.onerror = errorfunc // ie9 must have onprogress be set to a unique function. xhr.onprogress = function () { // ie must die } xhr.ontimeout = errorfunc xhr.open(method, uri, !sync, options.username, options.password) //has to be after open if(!sync) { xhr.withcredentials = !!options.withcredentials } // cannot set timeout with sync request // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent if (!sync && options.timeout > 0 ) { timeouttimer = settimeout(function(){ aborted=true//ie9 may still call readystatechange xhr.abort("timeout") var e = new error("xmlhttprequest timeout") e.code = "etimedout" errorfunc(e) }, options.timeout ) } if (xhr.setrequestheader) { for(key in headers){ if(headers.hasownproperty(key)){ xhr.setrequestheader(key, headers[key]) } } } else if (options.headers && !isempty(options.headers)) { throw new error("headers cannot be set on an xdomainrequest object") } if ("responsetype" in options) { xhr.responsetype = options.responsetype } if ("beforesend" in options && typeof options.beforesend === "function" ) { options.beforesend(xhr) } xhr.send(body) return xhr } function noop() {} },{"global/window":2,"is-function":57,"once":58,"parse-headers":61,"xtend":62}],57:[function(_dereq_,module,exports){ module.exports = isfunction var tostring = object.prototype.tostring function isfunction (fn) { var string = tostring.call(fn) return string === '[object function]' || (typeof fn === 'function' && string !== '[object regexp]') || (typeof window !== 'undefined' && // ie8 and below (fn === window.settimeout || fn === window.alert || fn === window.confirm || fn === window.prompt)) }; },{}],58:[function(_dereq_,module,exports){ module.exports = once once.proto = once(function () { object.defineproperty(function.prototype, 'once', { value: function () { return once(this) }, configurable: true }) }) function once (fn) { var called = false return function () { if (called) return called = true return fn.apply(this, arguments) } } },{}],59:[function(_dereq_,module,exports){ var isfunction = _dereq_('is-function') module.exports = foreach var tostring = object.prototype.tostring var hasownproperty = object.prototype.hasownproperty function foreach(list, iterator, context) { if (!isfunction(iterator)) { throw new typeerror('iterator must be a function') } if (arguments.length < 3) { context = this } if (tostring.call(list) === '[object array]') foreacharray(list, iterator, context) else if (typeof list === 'string') foreachstring(list, iterator, context) else foreachobject(list, iterator, context) } function foreacharray(array, iterator, context) { for (var i = 0, len = array.length; i < len; i++) { if (hasownproperty.call(array, i)) { iterator.call(context, array[i], i, array) } } } function foreachstring(string, iterator, context) { for (var i = 0, len = string.length; i < len; i++) { // no such thing as a sparse string. iterator.call(context, string.charat(i), i, string) } } function foreachobject(object, iterator, context) { for (var k in object) { if (hasownproperty.call(object, k)) { iterator.call(context, object[k], k, object) } } } },{"is-function":57}],60:[function(_dereq_,module,exports){ exports = module.exports = trim; function trim(str){ return str.replace(/^\s*|\s*$/g, ''); } exports.left = function(str){ return str.replace(/^\s*/, ''); }; exports.right = function(str){ return str.replace(/\s*$/, ''); }; },{}],61:[function(_dereq_,module,exports){ var trim = _dereq_('trim') , foreach = _dereq_('for-each') , isarray = function(arg) { return object.prototype.tostring.call(arg) === '[object array]'; } module.exports = function (headers) { if (!headers) return {} var result = {} foreach( trim(headers).split('\n') , function (row) { var index = row.indexof(':') , key = trim(row.slice(0, index)).tolowercase() , value = trim(row.slice(index + 1)) if (typeof(result[key]) === 'undefined') { result[key] = value } else if (isarray(result[key])) { result[key].push(value) } else { result[key] = [ result[key], value ] } } ) return result } },{"for-each":59,"trim":60}],62:[function(_dereq_,module,exports){ module.exports = extend var hasownproperty = object.prototype.hasownproperty; function extend() { var target = {} for (var i = 0; i < arguments.length; i++) { var source = arguments[i] for (var key in source) { if (hasownproperty.call(source, key)) { target[key] = source[key] } } } return target } },{}],63:[function(_dereq_,module,exports){ /** * @file big-play-button.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _buttonjs = _dereq_('./button.js'); var _buttonjs2 = _interoprequiredefault(_buttonjs); var _componentjs = _dereq_('./component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * initial play button. shows before the video has played. the hiding of the * big play button is done via css and player states. * * @param {object} player main player * @param {object=} options object of option names and values * @extends button * @class bigplaybutton */ var bigplaybutton = (function (_button) { _inherits(bigplaybutton, _button); function bigplaybutton(player, options) { _classcallcheck(this, bigplaybutton); _button.call(this, player, options); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ bigplaybutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-big-play-button'; }; /** * handles click for play * * @method handleclick */ bigplaybutton.prototype.handleclick = function handleclick() { this.player_.play(); }; return bigplaybutton; })(_buttonjs2['default']); bigplaybutton.prototype.controltext_ = 'play video'; _componentjs2['default'].registercomponent('bigplaybutton', bigplaybutton); exports['default'] = bigplaybutton; module.exports = exports['default']; },{"./button.js":64,"./component.js":67}],64:[function(_dereq_,module,exports){ /** * @file button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _clickablecomponentjs = _dereq_('./clickable-component.js'); var _clickablecomponentjs2 = _interoprequiredefault(_clickablecomponentjs); var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilslogjs = _dereq_('./utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /** * base class for all buttons * * @param {object} player main player * @param {object=} options object of option names and values * @extends clickablecomponent * @class button */ var button = (function (_clickablecomponent) { _inherits(button, _clickablecomponent); function button(player, options) { _classcallcheck(this, button); _clickablecomponent.call(this, player, options); } /** * create the component's dom element * * @param {string=} type element's node type. e.g. 'div' * @param {object=} props an object of properties that should be set on the element * @param {object=} attributes an object of attributes that should be set on the element * @return {element} * @method createel */ button.prototype.createel = function createel() { var tag = arguments.length <= 0 || arguments[0] === undefined ? 'button' : arguments[0]; var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; props = _objectassign2['default']({ classname: this.buildcssclass() }, props); if (tag !== 'button') { _utilslogjs2['default'].warn('creating a button with an html element of ' + tag + ' is deprecated; use clickablecomponent instead.'); // add properties for clickable element which is not a native html button props = _objectassign2['default']({ tabindex: 0 }, props); // add aria attributes for clickable element which is not a native html button attributes = _objectassign2['default']({ role: 'button' }, attributes); } // add attributes for button element attributes = _objectassign2['default']({ type: 'button', // necessary since the default button type is "submit" 'aria-live': 'polite' // let the screen reader user know that the text of the button may change }, attributes); var el = _component2['default'].prototype.createel.call(this, tag, props, attributes); this.createcontroltextel(el); return el; }; /** * adds a child component inside this button * * @param {string|component} child the class name or instance of a child to add * @param {object=} options options, including options to be passed to children of the child. * @return {component} the child component (created by this process if a string was used) * @deprecated * @method addchild */ button.prototype.addchild = function addchild(child) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var classname = this.constructor.name; _utilslogjs2['default'].warn('adding an actionable (user controllable) child to a button (' + classname + ') is not supported; use a clickablecomponent instead.'); // avoid the error message generated by clickablecomponent's addchild method return _component2['default'].prototype.addchild.call(this, child, options); }; /** * handle keypress (document level) - extend with specific functionality for button * * @method handlekeypress */ button.prototype.handlekeypress = function handlekeypress(event) { // ignore space (32) or enter (13) key operation, which is handled by the browser for a button. if (event.which === 32 || event.which === 13) {} else { _clickablecomponent.prototype.handlekeypress.call(this, event); // pass keypress handling up for unsupported keys } }; return button; })(_clickablecomponentjs2['default']); _component2['default'].registercomponent('button', button); exports['default'] = button; module.exports = exports['default']; },{"./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){ /** * @file button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); var _utilsdomjs = _dereq_('./utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilslogjs = _dereq_('./utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /** * clickable component which is clickable or keyboard actionable, but is not a native html button * * @param {object} player main player * @param {object=} options object of option names and values * @extends component * @class clickablecomponent */ var clickablecomponent = (function (_component) { _inherits(clickablecomponent, _component); function clickablecomponent(player, options) { _classcallcheck(this, clickablecomponent); _component.call(this, player, options); this.emittapevents(); this.on('tap', this.handleclick); this.on('click', this.handleclick); this.on('focus', this.handlefocus); this.on('blur', this.handleblur); } /** * create the component's dom element * * @param {string=} type element's node type. e.g. 'div' * @param {object=} props an object of properties that should be set on the element * @param {object=} attributes an object of attributes that should be set on the element * @return {element} * @method createel */ clickablecomponent.prototype.createel = function createel() { var tag = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; props = _objectassign2['default']({ classname: this.buildcssclass(), tabindex: 0 }, props); if (tag === 'button') { _utilslogjs2['default'].error('creating a clickablecomponent with an html element of ' + tag + ' is not supported; use a button instead.'); } // add aria attributes for clickable element which is not a native html button attributes = _objectassign2['default']({ role: 'button', 'aria-live': 'polite' // let the screen reader user know that the text of the element may change }, attributes); var el = _component.prototype.createel.call(this, tag, props, attributes); this.createcontroltextel(el); return el; }; /** * create control text * * @param {element} el parent element for the control text * @return {element} * @method controltext */ clickablecomponent.prototype.createcontroltextel = function createcontroltextel(el) { this.controltextel_ = dom.createel('span', { classname: 'vjs-control-text' }); if (el) { el.appendchild(this.controltextel_); } this.controltext(this.controltext_); return this.controltextel_; }; /** * controls text - both request and localize * * @param {string} text text for element * @return {string} * @method controltext */ clickablecomponent.prototype.controltext = function controltext(text) { if (!text) return this.controltext_ || 'need text'; this.controltext_ = text; this.controltextel_.innerhtml = this.localize(this.controltext_); return this; }; /** * allows sub components to stack css class names * * @return {string} * @method buildcssclass */ clickablecomponent.prototype.buildcssclass = function buildcssclass() { return 'vjs-control vjs-button ' + _component.prototype.buildcssclass.call(this); }; /** * adds a child component inside this clickable-component * * @param {string|component} child the class name or instance of a child to add * @param {object=} options options, including options to be passed to children of the child. * @return {component} the child component (created by this process if a string was used) * @method addchild */ clickablecomponent.prototype.addchild = function addchild(child) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; // todo: fix adding an actionable child to a clickablecomponent; currently // it will cause issues with assistive technology (e.g. screen readers) // which support aria, since an element with role="button" cannot have // actionable child elements. //let classname = this.constructor.name; //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.`); return _component.prototype.addchild.call(this, child, options); }; /** * enable the component element * * @return {component} * @method enable */ clickablecomponent.prototype.enable = function enable() { this.removeclass('vjs-disabled'); this.el_.setattribute('aria-disabled', 'false'); return this; }; /** * disable the component element * * @return {component} * @method disable */ clickablecomponent.prototype.disable = function disable() { this.addclass('vjs-disabled'); this.el_.setattribute('aria-disabled', 'true'); return this; }; /** * handle click - override with specific functionality for component * * @method handleclick */ clickablecomponent.prototype.handleclick = function handleclick() {}; /** * handle focus - add keyboard functionality to element * * @method handlefocus */ clickablecomponent.prototype.handlefocus = function handlefocus() { events.on(_globaldocument2['default'], 'keydown', fn.bind(this, this.handlekeypress)); }; /** * handle keypress (document level) - trigger click when space or enter key is pressed * * @method handlekeypress */ clickablecomponent.prototype.handlekeypress = function handlekeypress(event) { // support space (32) or enter (13) key operation to fire a click event if (event.which === 32 || event.which === 13) { event.preventdefault(); this.handleclick(event); } else if (_component.prototype.handlekeypress) { _component.prototype.handlekeypress.call(this, event); // pass keypress handling up for unsupported keys } }; /** * handle blur - remove keyboard triggers * * @method handleblur */ clickablecomponent.prototype.handleblur = function handleblur() { events.off(_globaldocument2['default'], 'keydown', fn.bind(this, this.handlekeypress)); }; return clickablecomponent; })(_component2['default']); _component2['default'].registercomponent('clickablecomponent', clickablecomponent); exports['default'] = clickablecomponent; module.exports = exports['default']; },{"./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){ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _button = _dereq_('./button'); var _button2 = _interoprequiredefault(_button); var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); /** * the `closebutton` component is a button which fires a "close" event * when it is activated. * * @extends button * @class closebutton */ var closebutton = (function (_button) { _inherits(closebutton, _button); function closebutton(player, options) { _classcallcheck(this, closebutton); _button.call(this, player, options); this.controltext(options && options.controltext || this.localize('close')); } closebutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-close-button ' + _button.prototype.buildcssclass.call(this); }; closebutton.prototype.handleclick = function handleclick() { this.trigger({ type: 'close', bubbles: false }); }; return closebutton; })(_button2['default']); _component2['default'].registercomponent('closebutton', closebutton); exports['default'] = closebutton; module.exports = exports['default']; },{"./button":64,"./component":67}],67:[function(_dereq_,module,exports){ /** * @file component.js * * player component - base class for all ui objects */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _utilsdomjs = _dereq_('./utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsguidjs = _dereq_('./utils/guid.js'); var guid = _interoprequirewildcard(_utilsguidjs); var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _utilslogjs = _dereq_('./utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _utilstotitlecasejs = _dereq_('./utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); var _utilsmergeoptionsjs = _dereq_('./utils/merge-options.js'); var _utilsmergeoptionsjs2 = _interoprequiredefault(_utilsmergeoptionsjs); /** * base ui component class * components are embeddable ui objects that are represented by both a * javascript object and an element in the dom. they can be children of other * components, and can have many children themselves. * ```js * // adding a button to the player * var button = player.addchild('button'); * button.el(); // -> button element * ``` * ```html *
*
button
*
* ``` * components are also event targets. * ```js * button.on('click', function(){ * console.log('button clicked!'); * }); * button.trigger('customevent'); * ``` * * @param {object} player main player * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @class component */ var component = (function () { function component(player, options, ready) { _classcallcheck(this, component); // the component might be the player itself and we can't pass `this` to super if (!player && this.play) { this.player_ = player = this; // eslint-disable-line } else { this.player_ = player; } // make a copy of prototype.options_ to protect against overriding defaults this.options_ = _utilsmergeoptionsjs2['default']({}, this.options_); // updated options with supplied options options = this.options_ = _utilsmergeoptionsjs2['default'](this.options_, options); // get id from options or options element if one is supplied this.id_ = options.id || options.el && options.el.id; // if there was no id from the options, generate one if (!this.id_) { // don't require the player id function in the case of mock players var id = player && player.id && player.id() || 'no_player'; this.id_ = id + '_component_' + guid.newguid(); } this.name_ = options.name || null; // create element if one wasn't provided in options if (options.el) { this.el_ = options.el; } else if (options.createel !== false) { this.el_ = this.createel(); } this.children_ = []; this.childindex_ = {}; this.childnameindex_ = {}; // add any child components in options if (options.initchildren !== false) { this.initchildren(); } this.ready(ready); // don't want to trigger ready here or it will before init is actually // finished for all children that run this constructor if (options.reporttouchactivity !== false) { this.enabletouchactivity(); } } /** * dispose of the component and all child components * * @method dispose */ component.prototype.dispose = function dispose() { this.trigger({ type: 'dispose', bubbles: false }); // dispose all children. if (this.children_) { for (var i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i].dispose) { this.children_[i].dispose(); } } } // delete child references this.children_ = null; this.childindex_ = null; this.childnameindex_ = null; // remove all event listeners. this.off(); // remove element from dom if (this.el_.parentnode) { this.el_.parentnode.removechild(this.el_); } dom.removeeldata(this.el_); this.el_ = null; }; /** * return the component's player * * @return {player} * @method player */ component.prototype.player = function player() { return this.player_; }; /** * deep merge of options objects * whenever a property is an object on both options objects * the two properties will be merged using mergeoptions. * * ```js * parent.prototype.options_ = { * optionset: { * 'childone': { 'foo': 'bar', 'asdf': 'fdsa' }, * 'childtwo': {}, * 'childthree': {} * } * } * newoptions = { * optionset: { * 'childone': { 'foo': 'baz', 'abc': '123' } * 'childtwo': null, * 'childfour': {} * } * } * * this.options(newoptions); * ``` * result * ```js * { * optionset: { * 'childone': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' }, * 'childtwo': null, // disabled. won't be initialized. * 'childthree': {}, * 'childfour': {} * } * } * ``` * * @param {object} obj object of new option values * @return {object} a new object of this.options_ and obj merged * @method options */ component.prototype.options = function options(obj) { _utilslogjs2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); if (!obj) { return this.options_; } this.options_ = _utilsmergeoptionsjs2['default'](this.options_, obj); return this.options_; }; /** * get the component's dom element * ```js * var domel = mycomponent.el(); * ``` * * @return {element} * @method el */ component.prototype.el = function el() { return this.el_; }; /** * create the component's dom element * * @param {string=} tagname element's node type. e.g. 'div' * @param {object=} properties an object of properties that should be set * @param {object=} attributes an object of attributes that should be set * @return {element} * @method createel */ component.prototype.createel = function createel(tagname, properties, attributes) { return dom.createel(tagname, properties, attributes); }; component.prototype.localize = function localize(string) { var code = this.player_.language && this.player_.language(); var languages = this.player_.languages && this.player_.languages(); if (!code || !languages) { return string; } var language = languages[code]; if (language && language[string]) { return language[string]; } var primarycode = code.split('-')[0]; var primarylang = languages[primarycode]; if (primarylang && primarylang[string]) { return primarylang[string]; } return string; }; /** * return the component's dom element where children are inserted. * will either be the same as el() or a new element defined in createel(). * * @return {element} * @method contentel */ component.prototype.contentel = function contentel() { return this.contentel_ || this.el_; }; /** * get the component's id * ```js * var id = mycomponent.id(); * ``` * * @return {string} * @method id */ component.prototype.id = function id() { return this.id_; }; /** * get the component's name. the name is often used to reference the component. * ```js * var name = mycomponent.name(); * ``` * * @return {string} * @method name */ component.prototype.name = function name() { return this.name_; }; /** * get an array of all child components * ```js * var kids = mycomponent.children(); * ``` * * @return {array} the children * @method children */ component.prototype.children = function children() { return this.children_; }; /** * returns a child component with the provided id * * @return {component} * @method getchildbyid */ component.prototype.getchildbyid = function getchildbyid(id) { return this.childindex_[id]; }; /** * returns a child component with the provided name * * @return {component} * @method getchild */ component.prototype.getchild = function getchild(name) { return this.childnameindex_[name]; }; /** * adds a child component inside this component * ```js * mycomponent.el(); * // ->
* mycomponent.children(); * // [empty array] * * var mybutton = mycomponent.addchild('mybutton'); * // ->
mybutton
* // -> mybutton === mycomponent.children()[0]; * ``` * pass in options for child constructors and options for children of the child * ```js * var mybutton = mycomponent.addchild('mybutton', { * text: 'press me', * buttonchildexample: { * buttonchildoption: true * } * }); * ``` * * @param {string|component} child the class name or instance of a child to add * @param {object=} options options, including options to be passed to children of the child. * @param {number} index into our children array to attempt to add the child * @return {component} the child component (created by this process if a string was used) * @method addchild */ component.prototype.addchild = function addchild(child) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var index = arguments.length <= 2 || arguments[2] === undefined ? this.children_.length : arguments[2]; var component = undefined; var componentname = undefined; // if child is a string, create nt with options if (typeof child === 'string') { componentname = child; // options can also be specified as a boolean, so convert to an empty object if false. if (!options) { options = {}; } // same as above, but true is deprecated so show a warning. if (options === true) { _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`.'); options = {}; } // if no componentclass in options, assume componentclass is the name lowercased // (e.g. playbutton) var componentclassname = options.componentclass || _utilstotitlecasejs2['default'](componentname); // set name through options options.name = componentname; // create a new object & element for this controls set // if there's no .player_, this is a player var componentclass = component.getcomponent(componentclassname); if (!componentclass) { throw new error('component ' + componentclassname + ' does not exist'); } // data stored directly on the videojs object may be // misidentified as a component to retain // backwards-compatibility with 4.x. check to make sure the // component class can be instantiated. if (typeof componentclass !== 'function') { return null; } component = new componentclass(this.player_ || this, options); // child is a component instance } else { component = child; } this.children_.splice(index, 0, component); if (typeof component.id === 'function') { this.childindex_[component.id()] = component; } // if a name wasn't used to create the component, check if we can use the // name function of the component componentname = componentname || component.name && component.name(); if (componentname) { this.childnameindex_[componentname] = component; } // add the ui object's element to the container div (box) // having an element is not required if (typeof component.el === 'function' && component.el()) { var childnodes = this.contentel().children; var refnode = childnodes[index] || null; this.contentel().insertbefore(component.el(), refnode); } // return so it can stored on parent object if desired. return component; }; /** * remove a child component from this component's list of children, and the * child component's element from this component's element * * @param {component} component component to remove * @method removechild */ component.prototype.removechild = function removechild(component) { if (typeof component === 'string') { component = this.getchild(component); } if (!component || !this.children_) { return; } var childfound = false; for (var i = this.children_.length - 1; i >= 0; i--) { if (this.children_[i] === component) { childfound = true; this.children_.splice(i, 1); break; } } if (!childfound) { return; } this.childindex_[component.id()] = null; this.childnameindex_[component.name()] = null; var compel = component.el(); if (compel && compel.parentnode === this.contentel()) { this.contentel().removechild(component.el()); } }; /** * add and initialize default child components from options * ```js * // when an instance of mycomponent is created, all children in options * // will be added to the instance by their name strings and options * mycomponent.prototype.options_ = { * children: [ * 'mychildcomponent' * ], * mychildcomponent: { * mychildoption: true * } * }; * * // or when creating the component * var mycomp = new mycomponent(player, { * children: [ * 'mychildcomponent' * ], * mychildcomponent: { * mychildoption: true * } * }); * ``` * the children option can also be an array of * child options objects (that also include a 'name' key). * this can be used if you have two child components of the * same type that need different options. * ```js * var mycomp = new mycomponent(player, { * children: [ * 'button', * { * name: 'button', * someotheroption: true * }, * { * name: 'button', * someotheroption: false * } * ] * }); * ``` * * @method initchildren */ component.prototype.initchildren = function initchildren() { var _this = this; var children = this.options_.children; if (children) { (function () { // `this` is `parent` var parentoptions = _this.options_; var handleadd = function handleadd(child) { var name = child.name; var opts = child.opts; // allow options for children to be set at the parent options // e.g. videojs(id, { controlbar: false }); // instead of videojs(id, { children: { controlbar: false }); if (parentoptions[name] !== undefined) { opts = parentoptions[name]; } // allow for disabling default components // e.g. options['children']['posterimage'] = false if (opts === false) { return; } // allow options to be passed as a simple boolean if no configuration // is necessary. if (opts === true) { opts = {}; } // we also want to pass the original player options to each component as well so they don't need to // reach back into the player for options later. opts.playeroptions = _this.options_.playeroptions; // create and add the child component. // add a direct reference to the child by name on the parent instance. // if two of the same component are used, different names should be supplied // for each var newchild = _this.addchild(name, opts); if (newchild) { _this[name] = newchild; } }; // allow for an array of children details to passed in the options var workingchildren = undefined; var tech = component.getcomponent('tech'); if (array.isarray(children)) { workingchildren = children; } else { workingchildren = object.keys(children); } workingchildren // children that are in this.options_ but also in workingchildren would // give us extra children we do not want. so, we want to filter them out. .concat(object.keys(_this.options_).filter(function (child) { return !workingchildren.some(function (wchild) { if (typeof wchild === 'string') { return child === wchild; } else { return child === wchild.name; } }); })).map(function (child) { var name = undefined, opts = undefined; if (typeof child === 'string') { name = child; opts = children[name] || _this.options_[name] || {}; } else { name = child.name; opts = child; } return { name: name, opts: opts }; }).filter(function (child) { // we have to make sure that child.name isn't in the techorder since // techs are registerd as components but can't aren't compatible // see https://github.com/videojs/video.js/issues/2772 var c = component.getcomponent(child.opts.componentclass || _utilstotitlecasejs2['default'](child.name)); return c && !tech.istech(c); }).foreach(handleadd); })(); } }; /** * allows sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ component.prototype.buildcssclass = function buildcssclass() { // child classes can include a function that does: // return 'class name' + this._super(); return ''; }; /** * add an event listener to this component's element * ```js * var myfunc = function(){ * var mycomponent = this; * // do something when the event is fired * }; * * mycomponent.on('eventtype', myfunc); * ``` * the context of myfunc will be mycomponent unless previously bound. * alternatively, you can add a listener to another element or component. * ```js * mycomponent.on(otherelement, 'eventname', myfunc); * mycomponent.on(othercomponent, 'eventname', myfunc); * ``` * the benefit of using this over `vjsevents.on(otherelement, 'eventname', myfunc)` * and `othercomponent.on('eventname', myfunc)` is that this way the listeners * will be automatically cleaned up when either component is disposed. * it will also bind mycomponent as the context of myfunc. * **note**: when using this on elements in the page other than window * and document (both permanent), if you remove the element from the dom * you need to call `mycomponent.trigger(el, 'dispose')` on it to clean up * references to it and allow the browser to garbage collect it. * * @param {string|component} first the event type or other component * @param {function|string} second the event handler or event type * @param {function} third the event handler * @return {component} * @method on */ component.prototype.on = function on(first, second, third) { var _this2 = this; if (typeof first === 'string' || array.isarray(first)) { events.on(this.el_, first, fn.bind(this, second)); // targeting another component or element } else { (function () { var target = first; var type = second; var fn = fn.bind(_this2, third); // when this component is disposed, remove the listener from the other component var removeondispose = function removeondispose() { return _this2.off(target, type, fn); }; // use the same function id so we can remove it later it using the id // of the original listener removeondispose.guid = fn.guid; _this2.on('dispose', removeondispose); // if the other component is disposed first we need to clean the reference // to the other component in this component's removeondispose listener // otherwise we create a memory leak. var cleanremover = function cleanremover() { return _this2.off('dispose', removeondispose); }; // add the same function id so we can easily remove it later cleanremover.guid = fn.guid; // check if this is a dom node if (first.nodename) { // add the listener to the other element events.on(target, type, fn); events.on(target, 'dispose', cleanremover); // should be a component // not using `instanceof component` because it makes mock players difficult } else if (typeof first.on === 'function') { // add the listener to the other component target.on(type, fn); target.on('dispose', cleanremover); } })(); } return this; }; /** * remove an event listener from this component's element * ```js * mycomponent.off('eventtype', myfunc); * ``` * if myfunc is excluded, all listeners for the event type will be removed. * if eventtype is excluded, all listeners will be removed from the component. * alternatively you can use `off` to remove listeners that were added to other * elements or components using `mycomponent.on(othercomponent...`. * in this case both the event type and listener function are required. * ```js * mycomponent.off(otherelement, 'eventtype', myfunc); * mycomponent.off(othercomponent, 'eventtype', myfunc); * ``` * * @param {string=|component} first the event type or other component * @param {function=|string} second the listener function or event type * @param {function=} third the listener for other component * @return {component} * @method off */ component.prototype.off = function off(first, second, third) { if (!first || typeof first === 'string' || array.isarray(first)) { events.off(this.el_, first, second); } else { var target = first; var type = second; // ensure there's at least a guid, even if the function hasn't been used var fn = fn.bind(this, third); // remove the dispose listener on this component, // which was given the same guid as the event listener this.off('dispose', fn); if (first.nodename) { // remove the listener events.off(target, type, fn); // remove the listener for cleaning the dispose listener events.off(target, 'dispose', fn); } else { target.off(type, fn); target.off('dispose', fn); } } return this; }; /** * add an event listener to be triggered only once and then removed * ```js * mycomponent.one('eventname', myfunc); * ``` * alternatively you can add a listener to another element or component * that will be triggered only once. * ```js * mycomponent.one(otherelement, 'eventname', myfunc); * mycomponent.one(othercomponent, 'eventname', myfunc); * ``` * * @param {string|component} first the event type or other component * @param {function|string} second the listener function or event type * @param {function=} third the listener function for other component * @return {component} * @method one */ component.prototype.one = function one(first, second, third) { var _this3 = this, _arguments = arguments; if (typeof first === 'string' || array.isarray(first)) { events.one(this.el_, first, fn.bind(this, second)); } else { (function () { var target = first; var type = second; var fn = fn.bind(_this3, third); var newfunc = function newfunc() { _this3.off(target, type, newfunc); fn.apply(null, _arguments); }; // keep the same function id so we can remove it later newfunc.guid = fn.guid; _this3.on(target, type, newfunc); })(); } return this; }; /** * trigger an event on an element * ```js * mycomponent.trigger('eventname'); * mycomponent.trigger({'type':'eventname'}); * mycomponent.trigger('eventname', {data: 'some data'}); * mycomponent.trigger({'type':'eventname'}, {data: 'some data'}); * ``` * * @param {event|object|string} event a string (the type) or an event object with a type attribute * @param {object} [hash] data hash to pass along with the event * @return {component} self * @method trigger */ component.prototype.trigger = function trigger(event, hash) { events.trigger(this.el_, event, hash); return this; }; /** * bind a listener to the component's ready state. * different from event listeners in that if the ready event has already happened * it will trigger the function immediately. * * @param {function} fn ready listener * @param {boolean} sync exec the listener synchronously if component is ready * @return {component} * @method ready */ component.prototype.ready = function ready(fn) { var sync = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; if (fn) { if (this.isready_) { if (sync) { fn.call(this); } else { // call the function asynchronously by default for consistency this.settimeout(fn, 1); } } else { this.readyqueue_ = this.readyqueue_ || []; this.readyqueue_.push(fn); } } return this; }; /** * trigger the ready listeners * * @return {component} * @method triggerready */ component.prototype.triggerready = function triggerready() { this.isready_ = true; // ensure ready is triggerd asynchronously this.settimeout(function () { var readyqueue = this.readyqueue_; // reset ready queue this.readyqueue_ = []; if (readyqueue && readyqueue.length > 0) { readyqueue.foreach(function (fn) { fn.call(this); }, this); } // allow for using event listeners also this.trigger('ready'); }, 1); }; /** * finds a single dom element matching `selector` within the component's * `contentel` or another custom context. * * @method $ * @param {string} selector * a valid css selector, which will be passed to `queryselector`. * * @param {element|string} [context=document] * a dom element within which to query. can also be a selector * string in which case the first matching element will be used * as context. if missing (or no element matches selector), falls * back to `document`. * * @return {element|null} */ component.prototype.$ = function $(selector, context) { return dom.$(selector, context || this.contentel()); }; /** * finds a all dom elements matching `selector` within the component's * `contentel` or another custom context. * * @method $$ * @param {string} selector * a valid css selector, which will be passed to `queryselectorall`. * * @param {element|string} [context=document] * a dom element within which to query. can also be a selector * string in which case the first matching element will be used * as context. if missing (or no element matches selector), falls * back to `document`. * * @return {nodelist} */ component.prototype.$$ = function $$(selector, context) { return dom.$$(selector, context || this.contentel()); }; /** * check if a component's element has a css class name * * @param {string} classtocheck classname to check * @return {component} * @method hasclass */ component.prototype.hasclass = function hasclass(classtocheck) { return dom.haselclass(this.el_, classtocheck); }; /** * add a css class name to the component's element * * @param {string} classtoadd classname to add * @return {component} * @method addclass */ component.prototype.addclass = function addclass(classtoadd) { dom.addelclass(this.el_, classtoadd); return this; }; /** * remove a css class name from the component's element * * @param {string} classtoremove classname to remove * @return {component} * @method removeclass */ component.prototype.removeclass = function removeclass(classtoremove) { dom.removeelclass(this.el_, classtoremove); return this; }; /** * add or remove a css class name from the component's element * * @param {string} classtotoggle * @param {boolean|function} [predicate] * can be a function that returns a boolean. if `true`, the class * will be added; if `false`, the class will be removed. if not * given, the class will be added if not present and vice versa. * * @return {component} * @method toggleclass */ component.prototype.toggleclass = function toggleclass(classtotoggle, predicate) { dom.toggleelclass(this.el_, classtotoggle, predicate); return this; }; /** * show the component element if hidden * * @return {component} * @method show */ component.prototype.show = function show() { this.removeclass('vjs-hidden'); return this; }; /** * hide the component element if currently showing * * @return {component} * @method hide */ component.prototype.hide = function hide() { this.addclass('vjs-hidden'); return this; }; /** * lock an item in its visible state * to be used with fadein/fadeout. * * @return {component} * @private * @method lockshowing */ component.prototype.lockshowing = function lockshowing() { this.addclass('vjs-lock-showing'); return this; }; /** * unlock an item to be hidden * to be used with fadein/fadeout. * * @return {component} * @private * @method unlockshowing */ component.prototype.unlockshowing = function unlockshowing() { this.removeclass('vjs-lock-showing'); return this; }; /** * set or get the width of the component (css values) * setting the video tag dimension values only works with values in pixels. * percent values will not work. * some percents can be used, but width()/height() will return the number + %, * not the actual computed width/height. * * @param {number|string=} num optional width number * @param {boolean} skiplisteners skip the 'resize' event trigger * @return {component} this component, when setting the width * @return {number|string} the width, when getting * @method width */ component.prototype.width = function width(num, skiplisteners) { return this.dimension('width', num, skiplisteners); }; /** * get or set the height of the component (css values) * setting the video tag dimension values only works with values in pixels. * percent values will not work. * some percents can be used, but width()/height() will return the number + %, * not the actual computed width/height. * * @param {number|string=} num new component height * @param {boolean=} skiplisteners skip the resize event trigger * @return {component} this component, when setting the height * @return {number|string} the height, when getting * @method height */ component.prototype.height = function height(num, skiplisteners) { return this.dimension('height', num, skiplisteners); }; /** * set both width and height at the same time * * @param {number|string} width width of player * @param {number|string} height height of player * @return {component} the component * @method dimensions */ component.prototype.dimensions = function dimensions(width, height) { // skip resize listeners on width for optimization return this.width(width, true).height(height); }; /** * get or set width or height * this is the shared code for the width() and height() methods. * all for an integer, integer + 'px' or integer + '%'; * known issue: hidden elements officially have a width of 0. we're defaulting * to the style.width value and falling back to computedstyle which has the * hidden element issue. info, but probably not an efficient fix: * http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/ * * @param {string} widthorheight 'width' or 'height' * @param {number|string=} num new dimension * @param {boolean=} skiplisteners skip resize event trigger * @return {component} the component if a dimension was set * @return {number|string} the dimension if nothing was set * @private * @method dimension */ component.prototype.dimension = function dimension(widthorheight, num, skiplisteners) { if (num !== undefined) { // set to zero if null or literally nan (nan !== nan) if (num === null || num !== num) { num = 0; } // check if using css width/height (% or px) and adjust if (('' + num).indexof('%') !== -1 || ('' + num).indexof('px') !== -1) { this.el_.style[widthorheight] = num; } else if (num === 'auto') { this.el_.style[widthorheight] = ''; } else { this.el_.style[widthorheight] = num + 'px'; } // skiplisteners allows us to avoid triggering the resize event when setting both width and height if (!skiplisteners) { this.trigger('resize'); } // return component return this; } // not setting a value, so getting it // make sure element exists if (!this.el_) { return 0; } // get dimension value from style var val = this.el_.style[widthorheight]; var pxindex = val.indexof('px'); if (pxindex !== -1) { // return the pixel value with no 'px' return parseint(val.slice(0, pxindex), 10); } // no px so using % or no style was set, so falling back to offsetwidth/height // if component has display:none, offset will return 0 // todo: handle display:none and no dimension style using px return parseint(this.el_['offset' + _utilstotitlecasejs2['default'](widthorheight)], 10); }; /** * get width or height of computed style * @param {string} widthorheight 'width' or 'height' * @return {number|boolean} the bolean false if nothing was set * @method currentdimension */ component.prototype.currentdimension = function currentdimension(widthorheight) { var computedwidthorheight = 0; if (widthorheight !== 'width' && widthorheight !== 'height') { throw new error('currentdimension only accepts width or height value'); } if (typeof _globalwindow2['default'].getcomputedstyle === 'function') { var computedstyle = _globalwindow2['default'].getcomputedstyle(this.el_); computedwidthorheight = computedstyle.getpropertyvalue(widthorheight) || computedstyle[widthorheight]; } else if (this.el_.currentstyle) { // ie 8 doesn't support computed style, shim it // return clientwidth or clientheight instead for better accuracy var rule = 'offset' + _utilstotitlecasejs2['default'](widthorheight); computedwidthorheight = this.el_[rule]; } // remove 'px' from variable and parse as integer computedwidthorheight = parsefloat(computedwidthorheight); return computedwidthorheight; }; /** * get an object which contains width and height values of computed style * @return {object} the dimensions of element * @method currentdimensions */ component.prototype.currentdimensions = function currentdimensions() { return { width: this.currentdimension('width'), height: this.currentdimension('height') }; }; /** * get width of computed style * @return {integer} * @method currentwidth */ component.prototype.currentwidth = function currentwidth() { return this.currentdimension('width'); }; /** * get height of computed style * @return {integer} * @method currentheight */ component.prototype.currentheight = function currentheight() { return this.currentdimension('height'); }; /** * emit 'tap' events when touch events are supported * this is used to support toggling the controls through a tap on the video. * we're requiring them to be enabled because otherwise every component would * have this extra overhead unnecessarily, on mobile devices where extra * overhead is especially bad. * * @private * @method emittapevents */ component.prototype.emittapevents = function emittapevents() { // track the start time so we can determine how long the touch lasted var touchstart = 0; var firsttouch = null; // maximum movement allowed during a touch event to still be considered a tap // other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number. var tapmovementthreshold = 10; // the maximum length a touch can be while still being considered a tap var touchtimethreshold = 200; var couldbetap = undefined; this.on('touchstart', function (event) { // if more than one finger, don't consider treating this as a click if (event.touches.length === 1) { // copy the touches object to prevent modifying the original firsttouch = _objectassign2['default']({}, event.touches[0]); // record start time so we can detect a tap vs. "touch and hold" touchstart = new date().gettime(); // reset couldbetap tracking couldbetap = true; } }); this.on('touchmove', function (event) { // if more than one finger, don't consider treating this as a click if (event.touches.length > 1) { couldbetap = false; } else if (firsttouch) { // some devices will throw touchmoves for all but the slightest of taps. // so, if we moved only a small distance, this could still be a tap var xdiff = event.touches[0].pagex - firsttouch.pagex; var ydiff = event.touches[0].pagey - firsttouch.pagey; var touchdistance = math.sqrt(xdiff * xdiff + ydiff * ydiff); if (touchdistance > tapmovementthreshold) { couldbetap = false; } } }); var notap = function notap() { couldbetap = false; }; // todo: listen to the original target. http://youtu.be/dujfpxokup8?t=13m8s this.on('touchleave', notap); this.on('touchcancel', notap); // when the touch ends, measure how long it took and trigger the appropriate // event this.on('touchend', function (event) { firsttouch = null; // proceed only if the touchmove/leave/cancel event didn't happen if (couldbetap === true) { // measure how long the touch lasted var touchtime = new date().gettime() - touchstart; // make sure the touch was less than the threshold to be considered a tap if (touchtime < touchtimethreshold) { // don't let browser turn this into a click event.preventdefault(); this.trigger('tap'); // it may be good to copy the touchend event object and change the // type to tap, if the other event properties aren't exact after // events.fixevent runs (e.g. event.target) } } }); }; /** * report user touch activity when touch events occur * user activity is used to determine when controls should show/hide. it's * relatively simple when it comes to mouse events, because any mouse event * should show the controls. so we capture mouse events that bubble up to the * player and report activity when that happens. * with touch events it isn't as easy. we can't rely on touch events at the * player level, because a tap (touchstart + touchend) on the video itself on * mobile devices is meant to turn controls off (and on). user activity is * checked asynchronously, so what could happen is a tap event on the video * turns the controls off, then the touchend event bubbles up to the player, * which if it reported user activity, would turn the controls right back on. * (we also don't want to completely block touch events from bubbling up) * also a touchmove, touch+hold, and anything other than a tap is not supposed * to turn the controls back on on a mobile device. * here we're setting the default component behavior to report user activity * whenever touch events happen, and this can be turned off by components that * want touch events to act differently. * * @method enabletouchactivity */ component.prototype.enabletouchactivity = function enabletouchactivity() { // don't continue if the root player doesn't support reporting user activity if (!this.player() || !this.player().reportuseractivity) { return; } // listener for reporting that the user is active var report = fn.bind(this.player(), this.player().reportuseractivity); var touchholding = undefined; this.on('touchstart', function () { report(); // for as long as the they are touching the device or have their mouse down, // we consider them active even if they're not moving their finger or mouse. // so we want to continue to update that they are active this.clearinterval(touchholding); // report at the same interval as activitycheck touchholding = this.setinterval(report, 250); }); var touchend = function touchend(event) { report(); // stop the interval that maintains activity if the touch is holding this.clearinterval(touchholding); }; this.on('touchmove', report); this.on('touchend', touchend); this.on('touchcancel', touchend); }; /** * creates timeout and sets up disposal automatically. * * @param {function} fn the function to run after the timeout. * @param {number} timeout number of ms to delay before executing specified function. * @return {number} returns the timeout id * @method settimeout */ component.prototype.settimeout = function settimeout(fn, timeout) { fn = fn.bind(this, fn); // window.settimeout would be preferable here, but due to some bizarre issue with sinon and/or phantomjs, we can't. var timeoutid = _globalwindow2['default'].settimeout(fn, timeout); var disposefn = function disposefn() { this.cleartimeout(timeoutid); }; disposefn.guid = 'vjs-timeout-' + timeoutid; this.on('dispose', disposefn); return timeoutid; }; /** * clears a timeout and removes the associated dispose listener * * @param {number} timeoutid the id of the timeout to clear * @return {number} returns the timeout id * @method cleartimeout */ component.prototype.cleartimeout = function cleartimeout(timeoutid) { _globalwindow2['default'].cleartimeout(timeoutid); var disposefn = function disposefn() {}; disposefn.guid = 'vjs-timeout-' + timeoutid; this.off('dispose', disposefn); return timeoutid; }; /** * creates an interval and sets up disposal automatically. * * @param {function} fn the function to run every n seconds. * @param {number} interval number of ms to delay before executing specified function. * @return {number} returns the interval id * @method setinterval */ component.prototype.setinterval = function setinterval(fn, interval) { fn = fn.bind(this, fn); var intervalid = _globalwindow2['default'].setinterval(fn, interval); var disposefn = function disposefn() { this.clearinterval(intervalid); }; disposefn.guid = 'vjs-interval-' + intervalid; this.on('dispose', disposefn); return intervalid; }; /** * clears an interval and removes the associated dispose listener * * @param {number} intervalid the id of the interval to clear * @return {number} returns the interval id * @method clearinterval */ component.prototype.clearinterval = function clearinterval(intervalid) { _globalwindow2['default'].clearinterval(intervalid); var disposefn = function disposefn() {}; disposefn.guid = 'vjs-interval-' + intervalid; this.off('dispose', disposefn); return intervalid; }; /** * registers a component * * @param {string} name name of the component to register * @param {object} comp the component to register * @static * @method registercomponent */ component.registercomponent = function registercomponent(name, comp) { if (!component.components_) { component.components_ = {}; } component.components_[name] = comp; return comp; }; /** * gets a component by name * * @param {string} name name of the component to get * @return {component} * @static * @method getcomponent */ component.getcomponent = function getcomponent(name) { if (component.components_ && component.components_[name]) { return component.components_[name]; } if (_globalwindow2['default'] && _globalwindow2['default'].videojs && _globalwindow2['default'].videojs[name]) { _utilslogjs2['default'].warn('the ' + name + ' component was added to the videojs object when it should be registered using videojs.registercomponent(name, component)'); return _globalwindow2['default'].videojs[name]; } }; /** * sets up the constructor using the supplied init method * or uses the init of the parent object * * @param {object} props an object of properties * @static * @deprecated * @method extend */ component.extend = function extend(props) { props = props || {}; _utilslogjs2['default'].warn('component.extend({}) has been deprecated, use videojs.extend(component, {}) instead'); // set up the constructor using the supplied init method // or using the init of the parent object // make sure to check the unobfuscated version for external libs var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {}; // in resig's simple class inheritance (previously used) the constructor // is a function that calls `this.init.apply(arguments)` // however that would prevent us from using `parentobject.call(this);` // in a child constructor because the `this` in `this.init` // would still refer to the child and cause an infinite loop. // we would instead have to do // `parentobject.prototype.init.apply(this, arguments);` // bleh. we're not creating a _super() function, so it's good to keep // the parent constructor reference simple. var subobj = function subobj() { init.apply(this, arguments); }; // inherit from this object's prototype subobj.prototype = object.create(this.prototype); // reset the constructor property for subobj otherwise // instances of subobj would have the constructor of the parent object subobj.prototype.constructor = subobj; // make the class extendable subobj.extend = component.extend; // extend subobj's prototype with functions and other properties from props for (var _name in props) { if (props.hasownproperty(_name)) { subobj.prototype[_name] = props[_name]; } } return subobj; }; return component; })(); component.registercomponent('component', component); exports['default'] = component; module.exports = exports['default']; },{"./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){ /** * @file control-bar.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); // required children var _playtogglejs = _dereq_('./play-toggle.js'); var _playtogglejs2 = _interoprequiredefault(_playtogglejs); var _timecontrolscurrenttimedisplayjs = _dereq_('./time-controls/current-time-display.js'); var _timecontrolscurrenttimedisplayjs2 = _interoprequiredefault(_timecontrolscurrenttimedisplayjs); var _timecontrolsdurationdisplayjs = _dereq_('./time-controls/duration-display.js'); var _timecontrolsdurationdisplayjs2 = _interoprequiredefault(_timecontrolsdurationdisplayjs); var _timecontrolstimedividerjs = _dereq_('./time-controls/time-divider.js'); var _timecontrolstimedividerjs2 = _interoprequiredefault(_timecontrolstimedividerjs); var _timecontrolsremainingtimedisplayjs = _dereq_('./time-controls/remaining-time-display.js'); var _timecontrolsremainingtimedisplayjs2 = _interoprequiredefault(_timecontrolsremainingtimedisplayjs); var _livedisplayjs = _dereq_('./live-display.js'); var _livedisplayjs2 = _interoprequiredefault(_livedisplayjs); var _progresscontrolprogresscontroljs = _dereq_('./progress-control/progress-control.js'); var _progresscontrolprogresscontroljs2 = _interoprequiredefault(_progresscontrolprogresscontroljs); var _fullscreentogglejs = _dereq_('./fullscreen-toggle.js'); var _fullscreentogglejs2 = _interoprequiredefault(_fullscreentogglejs); var _volumecontrolvolumecontroljs = _dereq_('./volume-control/volume-control.js'); var _volumecontrolvolumecontroljs2 = _interoprequiredefault(_volumecontrolvolumecontroljs); var _volumemenubuttonjs = _dereq_('./volume-menu-button.js'); var _volumemenubuttonjs2 = _interoprequiredefault(_volumemenubuttonjs); var _mutetogglejs = _dereq_('./mute-toggle.js'); var _mutetogglejs2 = _interoprequiredefault(_mutetogglejs); var _texttrackcontrolschaptersbuttonjs = _dereq_('./text-track-controls/chapters-button.js'); var _texttrackcontrolschaptersbuttonjs2 = _interoprequiredefault(_texttrackcontrolschaptersbuttonjs); var _texttrackcontrolsdescriptionsbuttonjs = _dereq_('./text-track-controls/descriptions-button.js'); var _texttrackcontrolsdescriptionsbuttonjs2 = _interoprequiredefault(_texttrackcontrolsdescriptionsbuttonjs); var _texttrackcontrolssubtitlesbuttonjs = _dereq_('./text-track-controls/subtitles-button.js'); var _texttrackcontrolssubtitlesbuttonjs2 = _interoprequiredefault(_texttrackcontrolssubtitlesbuttonjs); var _texttrackcontrolscaptionsbuttonjs = _dereq_('./text-track-controls/captions-button.js'); var _texttrackcontrolscaptionsbuttonjs2 = _interoprequiredefault(_texttrackcontrolscaptionsbuttonjs); var _playbackratemenuplaybackratemenubuttonjs = _dereq_('./playback-rate-menu/playback-rate-menu-button.js'); var _playbackratemenuplaybackratemenubuttonjs2 = _interoprequiredefault(_playbackratemenuplaybackratemenubuttonjs); var _spacercontrolscustomcontrolspacerjs = _dereq_('./spacer-controls/custom-control-spacer.js'); var _spacercontrolscustomcontrolspacerjs2 = _interoprequiredefault(_spacercontrolscustomcontrolspacerjs); /** * container of main controls * * @extends component * @class controlbar */ var controlbar = (function (_component) { _inherits(controlbar, _component); function controlbar() { _classcallcheck(this, controlbar); _component.apply(this, arguments); } /** * create the component's dom element * * @return {element} * @method createel */ controlbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-control-bar', dir: 'ltr' }, { 'role': 'group' // the control bar is a group, so it can contain menuitems }); }; return controlbar; })(_componentjs2['default']); controlbar.prototype.options_ = { loadevent: 'play', children: ['playtoggle', 'volumemenubutton', 'currenttimedisplay', 'timedivider', 'durationdisplay', 'progresscontrol', 'livedisplay', 'remainingtimedisplay', 'customcontrolspacer', 'playbackratemenubutton', 'chaptersbutton', 'descriptionsbutton', 'subtitlesbutton', 'captionsbutton', 'fullscreentoggle'] }; _componentjs2['default'].registercomponent('controlbar', controlbar); exports['default'] = controlbar; module.exports = exports['default']; },{"../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){ /** * @file fullscreen-toggle.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _buttonjs = _dereq_('../button.js'); var _buttonjs2 = _interoprequiredefault(_buttonjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * toggle fullscreen video * * @extends button * @class fullscreentoggle */ var fullscreentoggle = (function (_button) { _inherits(fullscreentoggle, _button); function fullscreentoggle() { _classcallcheck(this, fullscreentoggle); _button.apply(this, arguments); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ fullscreentoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-fullscreen-control ' + _button.prototype.buildcssclass.call(this); }; /** * handles click for full screen * * @method handleclick */ fullscreentoggle.prototype.handleclick = function handleclick() { if (!this.player_.isfullscreen()) { this.player_.requestfullscreen(); this.controltext('non-fullscreen'); } else { this.player_.exitfullscreen(); this.controltext('fullscreen'); } }; return fullscreentoggle; })(_buttonjs2['default']); fullscreentoggle.prototype.controltext_ = 'fullscreen'; _componentjs2['default'].registercomponent('fullscreentoggle', fullscreentoggle); exports['default'] = fullscreentoggle; module.exports = exports['default']; },{"../button.js":64,"../component.js":67}],70:[function(_dereq_,module,exports){ /** * @file live-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); /** * displays the live indicator * todo - future make it click to snap to live * * @extends component * @class livedisplay */ var livedisplay = (function (_component) { _inherits(livedisplay, _component); function livedisplay(player, options) { _classcallcheck(this, livedisplay); _component.call(this, player, options); this.updateshowing(); this.on(this.player(), 'durationchange', this.updateshowing); } /** * create the component's dom element * * @return {element} * @method createel */ livedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-live-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-live-display', innerhtml: '' + this.localize('stream type') + '' + this.localize('live') }, { 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; livedisplay.prototype.updateshowing = function updateshowing() { if (this.player().duration() === infinity) { this.show(); } else { this.hide(); } }; return livedisplay; })(_component2['default']); _component2['default'].registercomponent('livedisplay', livedisplay); exports['default'] = livedisplay; module.exports = exports['default']; },{"../component":67,"../utils/dom.js":134}],71:[function(_dereq_,module,exports){ /** * @file mute-toggle.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _button = _dereq_('../button'); var _button2 = _interoprequiredefault(_button); var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); /** * a button component for muting the audio * * @param {player|object} player * @param {object=} options * @extends button * @class mutetoggle */ var mutetoggle = (function (_button) { _inherits(mutetoggle, _button); function mutetoggle(player, options) { _classcallcheck(this, mutetoggle); _button.call(this, player, options); this.on(player, 'volumechange', this.update); // hide mute toggle if the current tech doesn't support volume control if (player.tech_ && player.tech_['featuresvolumecontrol'] === false) { this.addclass('vjs-hidden'); } this.on(player, 'loadstart', function () { this.update(); // we need to update the button to account for a default muted state. if (player.tech_['featuresvolumecontrol'] === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } }); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ mutetoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-mute-control ' + _button.prototype.buildcssclass.call(this); }; /** * handle click on mute * * @method handleclick */ mutetoggle.prototype.handleclick = function handleclick() { this.player_.muted(this.player_.muted() ? false : true); }; /** * update volume * * @method update */ mutetoggle.prototype.update = function update() { var vol = this.player_.volume(), level = 3; if (vol === 0 || this.player_.muted()) { level = 0; } else if (vol < 0.33) { level = 1; } else if (vol < 0.67) { level = 2; } // don't rewrite the button text if the actual text doesn't change. // this causes unnecessary and confusing information for screen reader users. // this check is needed because this function gets called every time the volume level is changed. var tomute = this.player_.muted() ? 'unmute' : 'mute'; if (this.controltext() !== tomute) { this.controltext(tomute); } /* todo improve muted icon classes */ for (var i = 0; i < 4; i++) { dom.removeelclass(this.el_, 'vjs-vol-' + i); } dom.addelclass(this.el_, 'vjs-vol-' + level); }; return mutetoggle; })(_button2['default']); mutetoggle.prototype.controltext_ = 'mute'; _component2['default'].registercomponent('mutetoggle', mutetoggle); exports['default'] = mutetoggle; module.exports = exports['default']; },{"../button":64,"../component":67,"../utils/dom.js":134}],72:[function(_dereq_,module,exports){ /** * @file play-toggle.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _buttonjs = _dereq_('../button.js'); var _buttonjs2 = _interoprequiredefault(_buttonjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * button to toggle between play and pause * * @param {player|object} player * @param {object=} options * @extends button * @class playtoggle */ var playtoggle = (function (_button) { _inherits(playtoggle, _button); function playtoggle(player, options) { _classcallcheck(this, playtoggle); _button.call(this, player, options); this.on(player, 'play', this.handleplay); this.on(player, 'pause', this.handlepause); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ playtoggle.prototype.buildcssclass = function buildcssclass() { return 'vjs-play-control ' + _button.prototype.buildcssclass.call(this); }; /** * handle click to toggle between play and pause * * @method handleclick */ playtoggle.prototype.handleclick = function handleclick() { if (this.player_.paused()) { this.player_.play(); } else { this.player_.pause(); } }; /** * add the vjs-playing class to the element so it can change appearance * * @method handleplay */ playtoggle.prototype.handleplay = function handleplay() { this.removeclass('vjs-paused'); this.addclass('vjs-playing'); this.controltext('pause'); // change the button text to "pause" }; /** * add the vjs-paused class to the element so it can change appearance * * @method handlepause */ playtoggle.prototype.handlepause = function handlepause() { this.removeclass('vjs-playing'); this.addclass('vjs-paused'); this.controltext('play'); // change the button text to "play" }; return playtoggle; })(_buttonjs2['default']); playtoggle.prototype.controltext_ = 'play'; _componentjs2['default'].registercomponent('playtoggle', playtoggle); exports['default'] = playtoggle; module.exports = exports['default']; },{"../button.js":64,"../component.js":67}],73:[function(_dereq_,module,exports){ /** * @file playback-rate-menu-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _menumenubuttonjs = _dereq_('../../menu/menu-button.js'); var _menumenubuttonjs2 = _interoprequiredefault(_menumenubuttonjs); var _menumenujs = _dereq_('../../menu/menu.js'); var _menumenujs2 = _interoprequiredefault(_menumenujs); var _playbackratemenuitemjs = _dereq_('./playback-rate-menu-item.js'); var _playbackratemenuitemjs2 = _interoprequiredefault(_playbackratemenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); /** * the component for controlling the playback rate * * @param {player|object} player * @param {object=} options * @extends menubutton * @class playbackratemenubutton */ var playbackratemenubutton = (function (_menubutton) { _inherits(playbackratemenubutton, _menubutton); function playbackratemenubutton(player, options) { _classcallcheck(this, playbackratemenubutton); _menubutton.call(this, player, options); this.updatevisibility(); this.updatelabel(); this.on(player, 'loadstart', this.updatevisibility); this.on(player, 'ratechange', this.updatelabel); } /** * create the component's dom element * * @return {element} * @method createel */ playbackratemenubutton.prototype.createel = function createel() { var el = _menubutton.prototype.createel.call(this); this.labelel_ = dom.createel('div', { classname: 'vjs-playback-rate-value', innerhtml: 1.0 }); el.appendchild(this.labelel_); return el; }; /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ playbackratemenubutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-playback-rate ' + _menubutton.prototype.buildcssclass.call(this); }; /** * create the playback rate menu * * @return {menu} menu object populated with items * @method createmenu */ playbackratemenubutton.prototype.createmenu = function createmenu() { var menu = new _menumenujs2['default'](this.player()); var rates = this.playbackrates(); if (rates) { for (var i = rates.length - 1; i >= 0; i--) { menu.addchild(new _playbackratemenuitemjs2['default'](this.player(), { 'rate': rates[i] + 'x' })); } } return menu; }; /** * updates aria accessibility attributes * * @method updateariaattributes */ playbackratemenubutton.prototype.updateariaattributes = function updateariaattributes() { // current playback rate this.el().setattribute('aria-valuenow', this.player().playbackrate()); }; /** * handle menu item click * * @method handleclick */ playbackratemenubutton.prototype.handleclick = function handleclick() { // select next rate option var currentrate = this.player().playbackrate(); var rates = this.playbackrates(); // this will select first one if the last one currently selected var newrate = rates[0]; for (var i = 0; i < rates.length; i++) { if (rates[i] > currentrate) { newrate = rates[i]; break; } } this.player().playbackrate(newrate); }; /** * get possible playback rates * * @return {array} possible playback rates * @method playbackrates */ playbackratemenubutton.prototype.playbackrates = function playbackrates() { return this.options_['playbackrates'] || this.options_.playeroptions && this.options_.playeroptions['playbackrates']; }; /** * get whether playback rates is supported by the tech * and an array of playback rates exists * * @return {boolean} whether changing playback rate is supported * @method playbackratesupported */ playbackratemenubutton.prototype.playbackratesupported = function playbackratesupported() { return this.player().tech_ && this.player().tech_['featuresplaybackrate'] && this.playbackrates() && this.playbackrates().length > 0; }; /** * hide playback rate controls when they're no playback rate options to select * * @method updatevisibility */ playbackratemenubutton.prototype.updatevisibility = function updatevisibility() { if (this.playbackratesupported()) { this.removeclass('vjs-hidden'); } else { this.addclass('vjs-hidden'); } }; /** * update button label when rate changed * * @method updatelabel */ playbackratemenubutton.prototype.updatelabel = function updatelabel() { if (this.playbackratesupported()) { this.labelel_.innerhtml = this.player().playbackrate() + 'x'; } }; return playbackratemenubutton; })(_menumenubuttonjs2['default']); playbackratemenubutton.prototype.controltext_ = 'playback rate'; _componentjs2['default'].registercomponent('playbackratemenubutton', playbackratemenubutton); exports['default'] = playbackratemenubutton; module.exports = exports['default']; },{"../../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){ /** * @file playback-rate-menu-item.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _menumenuitemjs = _dereq_('../../menu/menu-item.js'); var _menumenuitemjs2 = _interoprequiredefault(_menumenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * the specific menu item type for selecting a playback rate * * @param {player|object} player * @param {object=} options * @extends menuitem * @class playbackratemenuitem */ var playbackratemenuitem = (function (_menuitem) { _inherits(playbackratemenuitem, _menuitem); function playbackratemenuitem(player, options) { _classcallcheck(this, playbackratemenuitem); var label = options['rate']; var rate = parsefloat(label, 10); // modify options for parent menuitem class's init. options['label'] = label; options['selected'] = rate === 1; _menuitem.call(this, player, options); this.label = label; this.rate = rate; this.on(player, 'ratechange', this.update); } /** * handle click on menu item * * @method handleclick */ playbackratemenuitem.prototype.handleclick = function handleclick() { _menuitem.prototype.handleclick.call(this); this.player().playbackrate(this.rate); }; /** * update playback rate with selected rate * * @method update */ playbackratemenuitem.prototype.update = function update() { this.selected(this.player().playbackrate() === this.rate); }; return playbackratemenuitem; })(_menumenuitemjs2['default']); playbackratemenuitem.prototype.contenteltype = 'button'; _componentjs2['default'].registercomponent('playbackratemenuitem', playbackratemenuitem); exports['default'] = playbackratemenuitem; module.exports = exports['default']; },{"../../component.js":67,"../../menu/menu-item.js":107}],75:[function(_dereq_,module,exports){ /** * @file load-progress-bar.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); /** * shows load progress * * @param {player|object} player * @param {object=} options * @extends component * @class loadprogressbar */ var loadprogressbar = (function (_component) { _inherits(loadprogressbar, _component); function loadprogressbar(player, options) { _classcallcheck(this, loadprogressbar); _component.call(this, player, options); this.on(player, 'progress', this.update); } /** * create the component's dom element * * @return {element} * @method createel */ loadprogressbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-load-progress', innerhtml: '' + this.localize('loaded') + ': 0%' }); }; /** * update progress bar * * @method update */ loadprogressbar.prototype.update = function update() { var buffered = this.player_.buffered(); var duration = this.player_.duration(); var bufferedend = this.player_.bufferedend(); var children = this.el_.children; // get the percent width of a time compared to the total end var percentify = function percentify(time, end) { var percent = time / end || 0; // no nan return (percent >= 1 ? 1 : percent) * 100 + '%'; }; // update the width of the progress bar this.el_.style.width = percentify(bufferedend, duration); // add child elements to represent the individual buffered time ranges for (var i = 0; i < buffered.length; i++) { var start = buffered.start(i); var end = buffered.end(i); var part = children[i]; if (!part) { part = this.el_.appendchild(dom.createel()); } // set the percent based on the width of the progress bar (bufferedend) part.style.left = percentify(start, bufferedend); part.style.width = percentify(end - start, bufferedend); } // remove unused buffered range elements for (var i = children.length; i > buffered.length; i--) { this.el_.removechild(children[i - 1]); } }; return loadprogressbar; })(_componentjs2['default']); _componentjs2['default'].registercomponent('loadprogressbar', loadprogressbar); exports['default'] = loadprogressbar; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134}],76:[function(_dereq_,module,exports){ /** * @file mouse-time-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); var _lodashcompatfunctionthrottle = _dereq_('lodash-compat/function/throttle'); var _lodashcompatfunctionthrottle2 = _interoprequiredefault(_lodashcompatfunctionthrottle); /** * the mouse time display component shows the time you will seek to * when hovering over the progress bar * * @param {player|object} player * @param {object=} options * @extends component * @class mousetimedisplay */ var mousetimedisplay = (function (_component) { _inherits(mousetimedisplay, _component); function mousetimedisplay(player, options) { var _this = this; _classcallcheck(this, mousetimedisplay); _component.call(this, player, options); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (this.keeptooltipsinside) { this.tooltip = dom.createel('div', { classname: 'vjs-time-tooltip' }); this.el().appendchild(this.tooltip); this.addclass('vjs-keep-tooltips-inside'); } this.update(0, 0); player.on('ready', function () { _this.on(player.controlbar.progresscontrol.el(), 'mousemove', _lodashcompatfunctionthrottle2['default'](fn.bind(_this, _this.handlemousemove), 25)); }); } /** * create the component's dom element * * @return {element} * @method createel */ mousetimedisplay.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-mouse-display' }); }; mousetimedisplay.prototype.handlemousemove = function handlemousemove(event) { var duration = this.player_.duration(); var newtime = this.calculatedistance(event) * duration; var position = event.pagex - dom.findelposition(this.el().parentnode).left; this.update(newtime, position); }; mousetimedisplay.prototype.update = function update(newtime, position) { var time = _utilsformattimejs2['default'](newtime, this.player_.duration()); this.el().style.left = position + 'px'; this.el().setattribute('data-current-time', time); if (this.keeptooltipsinside) { var clampedposition = this.clampposition_(position); var difference = position - clampedposition + 1; var tooltipwidth = parsefloat(_globalwindow2['default'].getcomputedstyle(this.tooltip).width); var tooltipwidthhalf = tooltipwidth / 2; this.tooltip.innerhtml = time; this.tooltip.style.right = '-' + (tooltipwidthhalf - difference) + 'px'; } }; mousetimedisplay.prototype.calculatedistance = function calculatedistance(event) { return dom.getpointerposition(this.el().parentnode, event).x; }; /** * this takes in a horizontal position for the bar and returns a clamped position. * clamped position means that it will keep the position greater than half the width * of the tooltip and smaller than the player width minus half the width o the tooltip. * it will only clamp the position if `keeptooltipsinside` option is set. * * @param {number} position the position the bar wants to be * @return {number} newposition the (potentially) clamped position * @method clampposition_ */ mousetimedisplay.prototype.clampposition_ = function clampposition_(position) { if (!this.keeptooltipsinside) { return position; } var playerwidth = parsefloat(_globalwindow2['default'].getcomputedstyle(this.player().el()).width); var tooltipwidth = parsefloat(_globalwindow2['default'].getcomputedstyle(this.tooltip).width); var tooltipwidthhalf = tooltipwidth / 2; var actualposition = position; if (position < tooltipwidthhalf) { actualposition = math.ceil(tooltipwidthhalf); } else if (position > playerwidth - tooltipwidthhalf) { actualposition = math.floor(playerwidth - tooltipwidthhalf); } return actualposition; }; return mousetimedisplay; })(_componentjs2['default']); _componentjs2['default'].registercomponent('mousetimedisplay', mousetimedisplay); exports['default'] = mousetimedisplay; module.exports = exports['default']; },{"../../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){ /** * @file play-progress-bar.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); /** * shows play progress * * @param {player|object} player * @param {object=} options * @extends component * @class playprogressbar */ var playprogressbar = (function (_component) { _inherits(playprogressbar, _component); function playprogressbar(player, options) { _classcallcheck(this, playprogressbar); _component.call(this, player, options); this.updatedataattr(); this.on(player, 'timeupdate', this.updatedataattr); player.ready(fn.bind(this, this.updatedataattr)); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (this.keeptooltipsinside) { this.addclass('vjs-keep-tooltips-inside'); } } /** * create the component's dom element * * @return {element} * @method createel */ playprogressbar.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-play-progress vjs-slider-bar', innerhtml: '' + this.localize('progress') + ': 0%' }); }; playprogressbar.prototype.updatedataattr = function updatedataattr() { var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); this.el_.setattribute('data-current-time', _utilsformattimejs2['default'](time, this.player_.duration())); }; return playprogressbar; })(_componentjs2['default']); _componentjs2['default'].registercomponent('playprogressbar', playprogressbar); exports['default'] = playprogressbar; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/format-time.js":137}],78:[function(_dereq_,module,exports){ /** * @file progress-control.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _seekbarjs = _dereq_('./seek-bar.js'); var _seekbarjs2 = _interoprequiredefault(_seekbarjs); var _mousetimedisplayjs = _dereq_('./mouse-time-display.js'); var _mousetimedisplayjs2 = _interoprequiredefault(_mousetimedisplayjs); /** * the progress control component contains the seek bar, load progress, * and play progress * * @param {player|object} player * @param {object=} options * @extends component * @class progresscontrol */ var progresscontrol = (function (_component) { _inherits(progresscontrol, _component); function progresscontrol() { _classcallcheck(this, progresscontrol); _component.apply(this, arguments); } /** * create the component's dom element * * @return {element} * @method createel */ progresscontrol.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-progress-control vjs-control' }); }; return progresscontrol; })(_componentjs2['default']); progresscontrol.prototype.options_ = { children: ['seekbar'] }; _componentjs2['default'].registercomponent('progresscontrol', progresscontrol); exports['default'] = progresscontrol; module.exports = exports['default']; },{"../../component.js":67,"./mouse-time-display.js":76,"./seek-bar.js":79}],79:[function(_dereq_,module,exports){ /** * @file seek-bar.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _slidersliderjs = _dereq_('../../slider/slider.js'); var _slidersliderjs2 = _interoprequiredefault(_slidersliderjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _loadprogressbarjs = _dereq_('./load-progress-bar.js'); var _loadprogressbarjs2 = _interoprequiredefault(_loadprogressbarjs); var _playprogressbarjs = _dereq_('./play-progress-bar.js'); var _playprogressbarjs2 = _interoprequiredefault(_playprogressbarjs); var _tooltipprogressbarjs = _dereq_('./tooltip-progress-bar.js'); var _tooltipprogressbarjs2 = _interoprequiredefault(_tooltipprogressbarjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /** * seek bar and holder for the progress bars * * @param {player|object} player * @param {object=} options * @extends slider * @class seekbar */ var seekbar = (function (_slider) { _inherits(seekbar, _slider); function seekbar(player, options) { _classcallcheck(this, seekbar); _slider.call(this, player, options); this.on(player, 'timeupdate', this.updateprogress); this.on(player, 'ended', this.updateprogress); player.ready(fn.bind(this, this.updateprogress)); if (options.playeroptions && options.playeroptions.controlbar && options.playeroptions.controlbar.progresscontrol && options.playeroptions.controlbar.progresscontrol.keeptooltipsinside) { this.keeptooltipsinside = options.playeroptions.controlbar.progresscontrol.keeptooltipsinside; } if (this.keeptooltipsinside) { this.tooltipprogressbar = this.addchild('tooltipprogressbar'); } } /** * create the component's dom element * * @return {element} * @method createel */ seekbar.prototype.createel = function createel() { return _slider.prototype.createel.call(this, 'div', { classname: 'vjs-progress-holder' }, { 'aria-label': 'progress bar' }); }; /** * update aria accessibility attributes * * @method updateariaattributes */ seekbar.prototype.updateprogress = function updateprogress() { this.updateariaattributes(this.el_); if (this.keeptooltipsinside) { this.updateariaattributes(this.tooltipprogressbar.el_); this.tooltipprogressbar.el_.style.width = this.bar.el_.style.width; var playerwidth = parsefloat(_globalwindow2['default'].getcomputedstyle(this.player().el()).width); var tooltipwidth = parsefloat(_globalwindow2['default'].getcomputedstyle(this.tooltipprogressbar.tooltip).width); var tooltipstyle = this.tooltipprogressbar.el().style; tooltipstyle.maxwidth = math.floor(playerwidth - tooltipwidth / 2) + 'px'; tooltipstyle.minwidth = math.ceil(tooltipwidth / 2) + 'px'; tooltipstyle.right = '-' + tooltipwidth / 2 + 'px'; } }; seekbar.prototype.updateariaattributes = function updateariaattributes(el) { // allows for smooth scrubbing, when player can't keep up. var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); el.setattribute('aria-valuenow', (this.getpercent() * 100).tofixed(2)); // machine readable value of progress bar (percentage complete) el.setattribute('aria-valuetext', _utilsformattimejs2['default'](time, this.player_.duration())); // human readable value of progress bar (time complete) }; /** * get percentage of video played * * @return {number} percentage played * @method getpercent */ seekbar.prototype.getpercent = function getpercent() { var percent = this.player_.currenttime() / this.player_.duration(); return percent >= 1 ? 1 : percent; }; /** * handle mouse down on seek bar * * @method handlemousedown */ seekbar.prototype.handlemousedown = function handlemousedown(event) { _slider.prototype.handlemousedown.call(this, event); this.player_.scrubbing(true); this.videowasplaying = !this.player_.paused(); this.player_.pause(); }; /** * handle mouse move on seek bar * * @method handlemousemove */ seekbar.prototype.handlemousemove = function handlemousemove(event) { var newtime = this.calculatedistance(event) * this.player_.duration(); // don't let video end while scrubbing. if (newtime === this.player_.duration()) { newtime = newtime - 0.1; } // set new time (tell player to seek to new time) this.player_.currenttime(newtime); }; /** * handle mouse up on seek bar * * @method handlemouseup */ seekbar.prototype.handlemouseup = function handlemouseup(event) { _slider.prototype.handlemouseup.call(this, event); this.player_.scrubbing(false); if (this.videowasplaying) { this.player_.play(); } }; /** * move more quickly fast forward for keyboard-only users * * @method stepforward */ seekbar.prototype.stepforward = function stepforward() { this.player_.currenttime(this.player_.currenttime() + 5); // more quickly fast forward for keyboard-only users }; /** * move more quickly rewind for keyboard-only users * * @method stepback */ seekbar.prototype.stepback = function stepback() { this.player_.currenttime(this.player_.currenttime() - 5); // more quickly rewind for keyboard-only users }; return seekbar; })(_slidersliderjs2['default']); seekbar.prototype.options_ = { children: ['loadprogressbar', 'mousetimedisplay', 'playprogressbar'], 'barname': 'playprogressbar' }; seekbar.prototype.playerevent = 'timeupdate'; _componentjs2['default'].registercomponent('seekbar', seekbar); exports['default'] = seekbar; module.exports = exports['default']; },{"../../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){ /** * @file play-progress-bar.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); /** * shows play progress * * @param {player|object} player * @param {object=} options * @extends component * @class playprogressbar */ var tooltipprogressbar = (function (_component) { _inherits(tooltipprogressbar, _component); function tooltipprogressbar(player, options) { _classcallcheck(this, tooltipprogressbar); _component.call(this, player, options); this.updatedataattr(); this.on(player, 'timeupdate', this.updatedataattr); player.ready(fn.bind(this, this.updatedataattr)); } /** * create the component's dom element * * @return {element} * @method createel */ tooltipprogressbar.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-tooltip-progress-bar vjs-slider-bar', innerhtml: '
\n ' + this.localize('progress') + ': 0%' }); this.tooltip = el.queryselector('.vjs-time-tooltip'); return el; }; tooltipprogressbar.prototype.updatedataattr = function updatedataattr() { var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); var formattedtime = _utilsformattimejs2['default'](time, this.player_.duration()); this.el_.setattribute('data-current-time', formattedtime); this.tooltip.innerhtml = formattedtime; }; return tooltipprogressbar; })(_componentjs2['default']); _componentjs2['default'].registercomponent('tooltipprogressbar', tooltipprogressbar); exports['default'] = tooltipprogressbar; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/fn.js":136,"../../utils/format-time.js":137}],81:[function(_dereq_,module,exports){ /** * @file custom-control-spacer.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _spacerjs = _dereq_('./spacer.js'); var _spacerjs2 = _interoprequiredefault(_spacerjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * spacer specifically meant to be used as an insertion point for new plugins, etc. * * @extends spacer * @class customcontrolspacer */ var customcontrolspacer = (function (_spacer) { _inherits(customcontrolspacer, _spacer); function customcontrolspacer() { _classcallcheck(this, customcontrolspacer); _spacer.apply(this, arguments); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ customcontrolspacer.prototype.buildcssclass = function buildcssclass() { return 'vjs-custom-control-spacer ' + _spacer.prototype.buildcssclass.call(this); }; /** * create the component's dom element * * @return {element} * @method createel */ customcontrolspacer.prototype.createel = function createel() { var el = _spacer.prototype.createel.call(this, { classname: this.buildcssclass() }); // no-flex/table-cell mode requires there be some content // in the cell to fill the remaining space of the table. el.innerhtml = ' '; return el; }; return customcontrolspacer; })(_spacerjs2['default']); _componentjs2['default'].registercomponent('customcontrolspacer', customcontrolspacer); exports['default'] = customcontrolspacer; module.exports = exports['default']; },{"../../component.js":67,"./spacer.js":82}],82:[function(_dereq_,module,exports){ /** * @file spacer.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * just an empty spacer element that can be used as an append point for plugins, etc. * also can be used to create space between elements when necessary. * * @extends component * @class spacer */ var spacer = (function (_component) { _inherits(spacer, _component); function spacer() { _classcallcheck(this, spacer); _component.apply(this, arguments); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ spacer.prototype.buildcssclass = function buildcssclass() { return 'vjs-spacer ' + _component.prototype.buildcssclass.call(this); }; /** * create the component's dom element * * @return {element} * @method createel */ spacer.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; return spacer; })(_componentjs2['default']); _componentjs2['default'].registercomponent('spacer', spacer); exports['default'] = spacer; module.exports = exports['default']; },{"../../component.js":67}],83:[function(_dereq_,module,exports){ /** * @file caption-settings-menu-item.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackmenuitemjs = _dereq_('./text-track-menu-item.js'); var _texttrackmenuitemjs2 = _interoprequiredefault(_texttrackmenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * the menu item for caption track settings menu * * @param {player|object} player * @param {object=} options * @extends texttrackmenuitem * @class captionsettingsmenuitem */ var captionsettingsmenuitem = (function (_texttrackmenuitem) { _inherits(captionsettingsmenuitem, _texttrackmenuitem); function captionsettingsmenuitem(player, options) { _classcallcheck(this, captionsettingsmenuitem); options['track'] = { 'kind': options['kind'], 'player': player, 'label': options['kind'] + ' settings', 'selectable': false, 'default': false, mode: 'disabled' }; // captionsettingsmenuitem has no concept of 'selected' options['selectable'] = false; _texttrackmenuitem.call(this, player, options); this.addclass('vjs-texttrack-settings'); this.controltext(', opens ' + options['kind'] + ' settings dialog'); } /** * handle click on menu item * * @method handleclick */ captionsettingsmenuitem.prototype.handleclick = function handleclick() { this.player().getchild('texttracksettings').show(); this.player().getchild('texttracksettings').el_.focus(); }; return captionsettingsmenuitem; })(_texttrackmenuitemjs2['default']); _componentjs2['default'].registercomponent('captionsettingsmenuitem', captionsettingsmenuitem); exports['default'] = captionsettingsmenuitem; module.exports = exports['default']; },{"../../component.js":67,"./text-track-menu-item.js":91}],84:[function(_dereq_,module,exports){ /** * @file captions-button.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackbuttonjs = _dereq_('./text-track-button.js'); var _texttrackbuttonjs2 = _interoprequiredefault(_texttrackbuttonjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _captionsettingsmenuitemjs = _dereq_('./caption-settings-menu-item.js'); var _captionsettingsmenuitemjs2 = _interoprequiredefault(_captionsettingsmenuitemjs); /** * the button component for toggling and selecting captions * * @param {object} player player object * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends texttrackbutton * @class captionsbutton */ var captionsbutton = (function (_texttrackbutton) { _inherits(captionsbutton, _texttrackbutton); function captionsbutton(player, options, ready) { _classcallcheck(this, captionsbutton); _texttrackbutton.call(this, player, options, ready); this.el_.setattribute('aria-label', 'captions menu'); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ captionsbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-captions-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; /** * update caption menu items * * @method update */ captionsbutton.prototype.update = function update() { var threshold = 2; _texttrackbutton.prototype.update.call(this); // if native, then threshold is 1 because no settings button if (this.player().tech_ && this.player().tech_['featuresnativetexttracks']) { threshold = 1; } if (this.items && this.items.length > threshold) { this.show(); } else { this.hide(); } }; /** * create caption menu items * * @return {array} array of menu items * @method createitems */ captionsbutton.prototype.createitems = function createitems() { var items = []; if (!(this.player().tech_ && this.player().tech_['featuresnativetexttracks'])) { items.push(new _captionsettingsmenuitemjs2['default'](this.player_, { 'kind': this.kind_ })); } return _texttrackbutton.prototype.createitems.call(this, items); }; return captionsbutton; })(_texttrackbuttonjs2['default']); captionsbutton.prototype.kind_ = 'captions'; captionsbutton.prototype.controltext_ = 'captions'; _componentjs2['default'].registercomponent('captionsbutton', captionsbutton); exports['default'] = captionsbutton; module.exports = exports['default']; },{"../../component.js":67,"./caption-settings-menu-item.js":83,"./text-track-button.js":90}],85:[function(_dereq_,module,exports){ /** * @file chapters-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackbuttonjs = _dereq_('./text-track-button.js'); var _texttrackbuttonjs2 = _interoprequiredefault(_texttrackbuttonjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _texttrackmenuitemjs = _dereq_('./text-track-menu-item.js'); var _texttrackmenuitemjs2 = _interoprequiredefault(_texttrackmenuitemjs); var _chapterstrackmenuitemjs = _dereq_('./chapters-track-menu-item.js'); var _chapterstrackmenuitemjs2 = _interoprequiredefault(_chapterstrackmenuitemjs); var _menumenujs = _dereq_('../../menu/menu.js'); var _menumenujs2 = _interoprequiredefault(_menumenujs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilstotitlecasejs = _dereq_('../../utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); /** * the button component for toggling and selecting chapters * chapters act much differently than other text tracks * cues are navigation vs. other tracks of alternative languages * * @param {object} player player object * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends texttrackbutton * @class chaptersbutton */ var chaptersbutton = (function (_texttrackbutton) { _inherits(chaptersbutton, _texttrackbutton); function chaptersbutton(player, options, ready) { _classcallcheck(this, chaptersbutton); _texttrackbutton.call(this, player, options, ready); this.el_.setattribute('aria-label', 'chapters menu'); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ chaptersbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-chapters-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; /** * create a menu item for each text track * * @return {array} array of menu items * @method createitems */ chaptersbutton.prototype.createitems = function createitems() { var items = []; var tracks = this.player_.texttracks(); if (!tracks) { return items; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; if (track['kind'] === this.kind_) { items.push(new _texttrackmenuitemjs2['default'](this.player_, { 'track': track })); } } return items; }; /** * create menu from chapter buttons * * @return {menu} menu of chapter buttons * @method createmenu */ chaptersbutton.prototype.createmenu = function createmenu() { var _this = this; var tracks = this.player_.texttracks() || []; var chapterstrack = undefined; var items = this.items = []; for (var i = 0, _length = tracks.length; i < _length; i++) { var track = tracks[i]; if (track['kind'] === this.kind_) { chapterstrack = track; break; } } var menu = this.menu; if (menu === undefined) { menu = new _menumenujs2['default'](this.player_); var title = dom.createel('li', { classname: 'vjs-menu-title', innerhtml: _utilstotitlecasejs2['default'](this.kind_), tabindex: -1 }); menu.children_.unshift(title); dom.insertelfirst(title, menu.contentel()); } if (chapterstrack && chapterstrack.cues == null) { chapterstrack['mode'] = 'hidden'; var remotetexttrackel = this.player_.remotetexttrackels().gettrackelementbytrack_(chapterstrack); if (remotetexttrackel) { remotetexttrackel.addeventlistener('load', function (event) { return _this.update(); }); } } if (chapterstrack && chapterstrack.cues && chapterstrack.cues.length > 0) { var cues = chapterstrack['cues'], cue = undefined; for (var i = 0, l = cues.length; i < l; i++) { cue = cues[i]; var mi = new _chapterstrackmenuitemjs2['default'](this.player_, { 'track': chapterstrack, 'cue': cue }); items.push(mi); menu.addchild(mi); } this.addchild(menu); } if (this.items.length > 0) { this.show(); } return menu; }; return chaptersbutton; })(_texttrackbuttonjs2['default']); chaptersbutton.prototype.kind_ = 'chapters'; chaptersbutton.prototype.controltext_ = 'chapters'; _componentjs2['default'].registercomponent('chaptersbutton', chaptersbutton); exports['default'] = chaptersbutton; module.exports = exports['default']; },{"../../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){ /** * @file chapters-track-menu-item.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _menumenuitemjs = _dereq_('../../menu/menu-item.js'); var _menumenuitemjs2 = _interoprequiredefault(_menumenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); /** * the chapter track menu item * * @param {player|object} player * @param {object=} options * @extends menuitem * @class chapterstrackmenuitem */ var chapterstrackmenuitem = (function (_menuitem) { _inherits(chapterstrackmenuitem, _menuitem); function chapterstrackmenuitem(player, options) { _classcallcheck(this, chapterstrackmenuitem); var track = options['track']; var cue = options['cue']; var currenttime = player.currenttime(); // modify options for parent menuitem class's init. options['label'] = cue.text; options['selected'] = cue['starttime'] <= currenttime && currenttime < cue['endtime']; _menuitem.call(this, player, options); this.track = track; this.cue = cue; track.addeventlistener('cuechange', fn.bind(this, this.update)); } /** * handle click on menu item * * @method handleclick */ chapterstrackmenuitem.prototype.handleclick = function handleclick() { _menuitem.prototype.handleclick.call(this); this.player_.currenttime(this.cue.starttime); this.update(this.cue.starttime); }; /** * update chapter menu item * * @method update */ chapterstrackmenuitem.prototype.update = function update() { var cue = this.cue; var currenttime = this.player_.currenttime(); // vjs.log(currenttime, cue.starttime); this.selected(cue['starttime'] <= currenttime && currenttime < cue['endtime']); }; return chapterstrackmenuitem; })(_menumenuitemjs2['default']); _componentjs2['default'].registercomponent('chapterstrackmenuitem', chapterstrackmenuitem); exports['default'] = chapterstrackmenuitem; module.exports = exports['default']; },{"../../component.js":67,"../../menu/menu-item.js":107,"../../utils/fn.js":136}],87:[function(_dereq_,module,exports){ /** * @file descriptions-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackbuttonjs = _dereq_('./text-track-button.js'); var _texttrackbuttonjs2 = _interoprequiredefault(_texttrackbuttonjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); /** * the button component for toggling and selecting descriptions * * @param {object} player player object * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends texttrackbutton * @class descriptionsbutton */ var descriptionsbutton = (function (_texttrackbutton) { _inherits(descriptionsbutton, _texttrackbutton); function descriptionsbutton(player, options, ready) { var _this = this; _classcallcheck(this, descriptionsbutton); _texttrackbutton.call(this, player, options, ready); this.el_.setattribute('aria-label', 'descriptions menu'); var tracks = player.texttracks(); if (tracks) { (function () { var changehandler = fn.bind(_this, _this.handletrackschange); tracks.addeventlistener('change', changehandler); _this.on('dispose', function () { tracks.removeeventlistener('change', changehandler); }); })(); } } /** * handle text track change * * @method handletrackschange */ descriptionsbutton.prototype.handletrackschange = function handletrackschange(event) { var tracks = this.player().texttracks(); var disabled = false; // check whether a track of a different kind is showing for (var i = 0, l = tracks.length; i < l; i++) { var track = tracks[i]; if (track['kind'] !== this.kind_ && track['mode'] === 'showing') { disabled = true; break; } } // if another track is showing, disable this menu button if (disabled) { this.disable(); } else { this.enable(); } }; /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ descriptionsbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-descriptions-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; return descriptionsbutton; })(_texttrackbuttonjs2['default']); descriptionsbutton.prototype.kind_ = 'descriptions'; descriptionsbutton.prototype.controltext_ = 'descriptions'; _componentjs2['default'].registercomponent('descriptionsbutton', descriptionsbutton); exports['default'] = descriptionsbutton; module.exports = exports['default']; },{"../../component.js":67,"../../utils/fn.js":136,"./text-track-button.js":90}],88:[function(_dereq_,module,exports){ /** * @file off-text-track-menu-item.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackmenuitemjs = _dereq_('./text-track-menu-item.js'); var _texttrackmenuitemjs2 = _interoprequiredefault(_texttrackmenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * a special menu item for turning of a specific type of text track * * @param {player|object} player * @param {object=} options * @extends texttrackmenuitem * @class offtexttrackmenuitem */ var offtexttrackmenuitem = (function (_texttrackmenuitem) { _inherits(offtexttrackmenuitem, _texttrackmenuitem); function offtexttrackmenuitem(player, options) { _classcallcheck(this, offtexttrackmenuitem); // create pseudo track info // requires options['kind'] options['track'] = { 'kind': options['kind'], 'player': player, 'label': options['kind'] + ' off', 'default': false, 'mode': 'disabled' }; // menuitem is selectable options['selectable'] = true; _texttrackmenuitem.call(this, player, options); this.selected(true); } /** * handle text track change * * @param {object} event event object * @method handletrackschange */ offtexttrackmenuitem.prototype.handletrackschange = function handletrackschange(event) { var tracks = this.player().texttracks(); var selected = true; for (var i = 0, l = tracks.length; i < l; i++) { var track = tracks[i]; if (track['kind'] === this.track['kind'] && track['mode'] === 'showing') { selected = false; break; } } this.selected(selected); }; return offtexttrackmenuitem; })(_texttrackmenuitemjs2['default']); _componentjs2['default'].registercomponent('offtexttrackmenuitem', offtexttrackmenuitem); exports['default'] = offtexttrackmenuitem; module.exports = exports['default']; },{"../../component.js":67,"./text-track-menu-item.js":91}],89:[function(_dereq_,module,exports){ /** * @file subtitles-button.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackbuttonjs = _dereq_('./text-track-button.js'); var _texttrackbuttonjs2 = _interoprequiredefault(_texttrackbuttonjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * the button component for toggling and selecting subtitles * * @param {object} player player object * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends texttrackbutton * @class subtitlesbutton */ var subtitlesbutton = (function (_texttrackbutton) { _inherits(subtitlesbutton, _texttrackbutton); function subtitlesbutton(player, options, ready) { _classcallcheck(this, subtitlesbutton); _texttrackbutton.call(this, player, options, ready); this.el_.setattribute('aria-label', 'subtitles menu'); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ subtitlesbutton.prototype.buildcssclass = function buildcssclass() { return 'vjs-subtitles-button ' + _texttrackbutton.prototype.buildcssclass.call(this); }; return subtitlesbutton; })(_texttrackbuttonjs2['default']); subtitlesbutton.prototype.kind_ = 'subtitles'; subtitlesbutton.prototype.controltext_ = 'subtitles'; _componentjs2['default'].registercomponent('subtitlesbutton', subtitlesbutton); exports['default'] = subtitlesbutton; module.exports = exports['default']; },{"../../component.js":67,"./text-track-button.js":90}],90:[function(_dereq_,module,exports){ /** * @file text-track-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _menumenubuttonjs = _dereq_('../../menu/menu-button.js'); var _menumenubuttonjs2 = _interoprequiredefault(_menumenubuttonjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _texttrackmenuitemjs = _dereq_('./text-track-menu-item.js'); var _texttrackmenuitemjs2 = _interoprequiredefault(_texttrackmenuitemjs); var _offtexttrackmenuitemjs = _dereq_('./off-text-track-menu-item.js'); var _offtexttrackmenuitemjs2 = _interoprequiredefault(_offtexttrackmenuitemjs); /** * the base class for buttons that toggle specific text track types (e.g. subtitles) * * @param {player|object} player * @param {object=} options * @extends menubutton * @class texttrackbutton */ var texttrackbutton = (function (_menubutton) { _inherits(texttrackbutton, _menubutton); function texttrackbutton(player, options) { _classcallcheck(this, texttrackbutton); _menubutton.call(this, player, options); var tracks = this.player_.texttracks(); if (this.items.length <= 1) { this.hide(); } if (!tracks) { return; } var updatehandler = fn.bind(this, this.update); tracks.addeventlistener('removetrack', updatehandler); tracks.addeventlistener('addtrack', updatehandler); this.player_.on('dispose', function () { tracks.removeeventlistener('removetrack', updatehandler); tracks.removeeventlistener('addtrack', updatehandler); }); } // create a menu item for each text track texttrackbutton.prototype.createitems = function createitems() { var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; // add an off menu item to turn all tracks off items.push(new _offtexttrackmenuitemjs2['default'](this.player_, { 'kind': this.kind_ })); var tracks = this.player_.texttracks(); if (!tracks) { return items; } for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; // only add tracks that are of the appropriate kind and have a label if (track['kind'] === this.kind_) { items.push(new _texttrackmenuitemjs2['default'](this.player_, { // menuitem is selectable 'selectable': true, 'track': track })); } } return items; }; return texttrackbutton; })(_menumenubuttonjs2['default']); _componentjs2['default'].registercomponent('texttrackbutton', texttrackbutton); exports['default'] = texttrackbutton; module.exports = exports['default']; },{"../../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){ /** * @file text-track-menu-item.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _menumenuitemjs = _dereq_('../../menu/menu-item.js'); var _menumenuitemjs2 = _interoprequiredefault(_menumenuitemjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /** * the specific menu item type for selecting a language within a text track kind * * @param {player|object} player * @param {object=} options * @extends menuitem * @class texttrackmenuitem */ var texttrackmenuitem = (function (_menuitem) { _inherits(texttrackmenuitem, _menuitem); function texttrackmenuitem(player, options) { var _this = this; _classcallcheck(this, texttrackmenuitem); var track = options['track']; var tracks = player.texttracks(); // modify options for parent menuitem class's init. options['label'] = track['label'] || track['language'] || 'unknown'; options['selected'] = track['default'] || track['mode'] === 'showing'; _menuitem.call(this, player, options); this.track = track; if (tracks) { (function () { var changehandler = fn.bind(_this, _this.handletrackschange); tracks.addeventlistener('change', changehandler); _this.on('dispose', function () { tracks.removeeventlistener('change', changehandler); }); })(); } // ios7 doesn't dispatch change events to texttracklists when an // associated track's mode changes. without something like // object.observe() (also not present on ios7), it's not // possible to detect changes to the mode attribute and polyfill // the change event. as a poor substitute, we manually dispatch // change events whenever the controls modify the mode. if (tracks && tracks.onchange === undefined) { (function () { var event = undefined; _this.on(['tap', 'click'], function () { if (typeof _globalwindow2['default'].event !== 'object') { // android 2.3 throws an illegal constructor error for window.event try { event = new _globalwindow2['default'].event('change'); } catch (err) {} } if (!event) { event = _globaldocument2['default'].createevent('event'); event.initevent('change', true, true); } tracks.dispatchevent(event); }); })(); } } /** * handle click on text track * * @method handleclick */ texttrackmenuitem.prototype.handleclick = function handleclick(event) { var kind = this.track['kind']; var tracks = this.player_.texttracks(); _menuitem.prototype.handleclick.call(this, event); if (!tracks) return; for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; if (track['kind'] !== kind) { continue; } if (track === this.track) { track['mode'] = 'showing'; } else { track['mode'] = 'disabled'; } } }; /** * handle text track change * * @method handletrackschange */ texttrackmenuitem.prototype.handletrackschange = function handletrackschange(event) { this.selected(this.track['mode'] === 'showing'); }; return texttrackmenuitem; })(_menumenuitemjs2['default']); _componentjs2['default'].registercomponent('texttrackmenuitem', texttrackmenuitem); exports['default'] = texttrackmenuitem; module.exports = exports['default']; },{"../../component.js":67,"../../menu/menu-item.js":107,"../../utils/fn.js":136,"global/document":1,"global/window":2}],92:[function(_dereq_,module,exports){ /** * @file current-time-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); /** * displays the current time * * @param {player|object} player * @param {object=} options * @extends component * @class currenttimedisplay */ var currenttimedisplay = (function (_component) { _inherits(currenttimedisplay, _component); function currenttimedisplay(player, options) { _classcallcheck(this, currenttimedisplay); _component.call(this, player, options); this.on(player, 'timeupdate', this.updatecontent); } /** * create the component's dom element * * @return {element} * @method createel */ currenttimedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-current-time vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-current-time-display', // label the current time for screen reader users innerhtml: 'current time ' + '0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update current time display * * @method updatecontent */ currenttimedisplay.prototype.updatecontent = function updatecontent() { // allows for smooth scrubbing, when player can't keep up. var time = this.player_.scrubbing() ? this.player_.getcache().currenttime : this.player_.currenttime(); var localizedtext = this.localize('current time'); var formattedtime = _utilsformattimejs2['default'](time, this.player_.duration()); if (formattedtime !== this.formattedtime_) { this.formattedtime_ = formattedtime; this.contentel_.innerhtml = '' + localizedtext + ' ' + formattedtime; } }; return currenttimedisplay; })(_componentjs2['default']); _componentjs2['default'].registercomponent('currenttimedisplay', currenttimedisplay); exports['default'] = currenttimedisplay; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],93:[function(_dereq_,module,exports){ /** * @file duration-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); /** * displays the duration * * @param {player|object} player * @param {object=} options * @extends component * @class durationdisplay */ var durationdisplay = (function (_component) { _inherits(durationdisplay, _component); function durationdisplay(player, options) { _classcallcheck(this, durationdisplay); _component.call(this, player, options); // this might need to be changed to 'durationchange' instead of 'timeupdate' eventually, // however the durationchange event fires before this.player_.duration() is set, // so the value cannot be written out using this method. // once the order of durationchange and this.player_.duration() being set is figured out, // this can be updated. this.on(player, 'timeupdate', this.updatecontent); this.on(player, 'loadedmetadata', this.updatecontent); } /** * create the component's dom element * * @return {element} * @method createel */ durationdisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-duration vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-duration-display', // label the duration time for screen reader users innerhtml: '' + this.localize('duration time') + ' 0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update duration time display * * @method updatecontent */ durationdisplay.prototype.updatecontent = function updatecontent() { var duration = this.player_.duration(); if (duration && this.duration_ !== duration) { this.duration_ = duration; var localizedtext = this.localize('duration time'); var formattedtime = _utilsformattimejs2['default'](duration); this.contentel_.innerhtml = '' + localizedtext + ' ' + formattedtime; // label the duration time for screen reader users } }; return durationdisplay; })(_componentjs2['default']); _componentjs2['default'].registercomponent('durationdisplay', durationdisplay); exports['default'] = durationdisplay; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],94:[function(_dereq_,module,exports){ /** * @file remaining-time-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsformattimejs = _dereq_('../../utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); /** * displays the time left in the video * * @param {player|object} player * @param {object=} options * @extends component * @class remainingtimedisplay */ var remainingtimedisplay = (function (_component) { _inherits(remainingtimedisplay, _component); function remainingtimedisplay(player, options) { _classcallcheck(this, remainingtimedisplay); _component.call(this, player, options); this.on(player, 'timeupdate', this.updatecontent); } /** * create the component's dom element * * @return {element} * @method createel */ remainingtimedisplay.prototype.createel = function createel() { var el = _component.prototype.createel.call(this, 'div', { classname: 'vjs-remaining-time vjs-time-control vjs-control' }); this.contentel_ = dom.createel('div', { classname: 'vjs-remaining-time-display', // label the remaining time for screen reader users innerhtml: '' + this.localize('remaining time') + ' -0:00' }, { // tell screen readers not to automatically read the time as it changes 'aria-live': 'off' }); el.appendchild(this.contentel_); return el; }; /** * update remaining time display * * @method updatecontent */ remainingtimedisplay.prototype.updatecontent = function updatecontent() { if (this.player_.duration()) { var localizedtext = this.localize('remaining time'); var formattedtime = _utilsformattimejs2['default'](this.player_.remainingtime()); if (formattedtime !== this.formattedtime_) { this.formattedtime_ = formattedtime; this.contentel_.innerhtml = '' + localizedtext + ' -' + formattedtime; } } // allows for smooth scrubbing, when player can't keep up. // var time = (this.player_.scrubbing()) ? this.player_.getcache().currenttime : this.player_.currenttime(); // this.contentel_.innerhtml = vjs.formattime(time, this.player_.duration()); }; return remainingtimedisplay; })(_componentjs2['default']); _componentjs2['default'].registercomponent('remainingtimedisplay', remainingtimedisplay); exports['default'] = remainingtimedisplay; module.exports = exports['default']; },{"../../component.js":67,"../../utils/dom.js":134,"../../utils/format-time.js":137}],95:[function(_dereq_,module,exports){ /** * @file time-divider.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * the separator between the current time and duration. * can be hidden if it's not needed in the design. * * @param {player|object} player * @param {object=} options * @extends component * @class timedivider */ var timedivider = (function (_component) { _inherits(timedivider, _component); function timedivider() { _classcallcheck(this, timedivider); _component.apply(this, arguments); } /** * create the component's dom element * * @return {element} * @method createel */ timedivider.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-time-control vjs-time-divider', innerhtml: '
/
' }); }; return timedivider; })(_componentjs2['default']); _componentjs2['default'].registercomponent('timedivider', timedivider); exports['default'] = timedivider; module.exports = exports['default']; },{"../../component.js":67}],96:[function(_dereq_,module,exports){ /** * @file volume-bar.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _slidersliderjs = _dereq_('../../slider/slider.js'); var _slidersliderjs2 = _interoprequiredefault(_slidersliderjs); var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('../../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); // required children var _volumeleveljs = _dereq_('./volume-level.js'); var _volumeleveljs2 = _interoprequiredefault(_volumeleveljs); /** * the bar that contains the volume level and can be clicked on to adjust the level * * @param {player|object} player * @param {object=} options * @extends slider * @class volumebar */ var volumebar = (function (_slider) { _inherits(volumebar, _slider); function volumebar(player, options) { _classcallcheck(this, volumebar); _slider.call(this, player, options); this.on(player, 'volumechange', this.updateariaattributes); player.ready(fn.bind(this, this.updateariaattributes)); } /** * create the component's dom element * * @return {element} * @method createel */ volumebar.prototype.createel = function createel() { return _slider.prototype.createel.call(this, 'div', { classname: 'vjs-volume-bar vjs-slider-bar' }, { 'aria-label': 'volume level' }); }; /** * handle mouse move on volume bar * * @method handlemousemove */ volumebar.prototype.handlemousemove = function handlemousemove(event) { this.checkmuted(); this.player_.volume(this.calculatedistance(event)); }; volumebar.prototype.checkmuted = function checkmuted() { if (this.player_.muted()) { this.player_.muted(false); } }; /** * get percent of volume level * * @retun {number} volume level percent * @method getpercent */ volumebar.prototype.getpercent = function getpercent() { if (this.player_.muted()) { return 0; } else { return this.player_.volume(); } }; /** * increase volume level for keyboard users * * @method stepforward */ volumebar.prototype.stepforward = function stepforward() { this.checkmuted(); this.player_.volume(this.player_.volume() + 0.1); }; /** * decrease volume level for keyboard users * * @method stepback */ volumebar.prototype.stepback = function stepback() { this.checkmuted(); this.player_.volume(this.player_.volume() - 0.1); }; /** * update aria accessibility attributes * * @method updateariaattributes */ volumebar.prototype.updateariaattributes = function updateariaattributes() { // current value of volume bar as a percentage var volume = (this.player_.volume() * 100).tofixed(2); this.el_.setattribute('aria-valuenow', volume); this.el_.setattribute('aria-valuetext', volume + '%'); }; return volumebar; })(_slidersliderjs2['default']); volumebar.prototype.options_ = { children: ['volumelevel'], 'barname': 'volumelevel' }; volumebar.prototype.playerevent = 'volumechange'; _componentjs2['default'].registercomponent('volumebar', volumebar); exports['default'] = volumebar; module.exports = exports['default']; },{"../../component.js":67,"../../slider/slider.js":116,"../../utils/fn.js":136,"./volume-level.js":98}],97:[function(_dereq_,module,exports){ /** * @file volume-control.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); // required children var _volumebarjs = _dereq_('./volume-bar.js'); var _volumebarjs2 = _interoprequiredefault(_volumebarjs); /** * the component for controlling the volume level * * @param {player|object} player * @param {object=} options * @extends component * @class volumecontrol */ var volumecontrol = (function (_component) { _inherits(volumecontrol, _component); function volumecontrol(player, options) { _classcallcheck(this, volumecontrol); _component.call(this, player, options); // hide volume controls when they're not supported by the current tech if (player.tech_ && player.tech_['featuresvolumecontrol'] === false) { this.addclass('vjs-hidden'); } this.on(player, 'loadstart', function () { if (player.tech_['featuresvolumecontrol'] === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } }); } /** * create the component's dom element * * @return {element} * @method createel */ volumecontrol.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-volume-control vjs-control' }); }; return volumecontrol; })(_componentjs2['default']); volumecontrol.prototype.options_ = { children: ['volumebar'] }; _componentjs2['default'].registercomponent('volumecontrol', volumecontrol); exports['default'] = volumecontrol; module.exports = exports['default']; },{"../../component.js":67,"./volume-bar.js":96}],98:[function(_dereq_,module,exports){ /** * @file volume-level.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); /** * shows volume level * * @param {player|object} player * @param {object=} options * @extends component * @class volumelevel */ var volumelevel = (function (_component) { _inherits(volumelevel, _component); function volumelevel() { _classcallcheck(this, volumelevel); _component.apply(this, arguments); } /** * create the component's dom element * * @return {element} * @method createel */ volumelevel.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-volume-level', innerhtml: '' }); }; return volumelevel; })(_componentjs2['default']); _componentjs2['default'].registercomponent('volumelevel', volumelevel); exports['default'] = volumelevel; module.exports = exports['default']; },{"../../component.js":67}],99:[function(_dereq_,module,exports){ /** * @file volume-menu-button.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _popuppopupjs = _dereq_('../popup/popup.js'); var _popuppopupjs2 = _interoprequiredefault(_popuppopupjs); var _popuppopupbuttonjs = _dereq_('../popup/popup-button.js'); var _popuppopupbuttonjs2 = _interoprequiredefault(_popuppopupbuttonjs); var _mutetogglejs = _dereq_('./mute-toggle.js'); var _mutetogglejs2 = _interoprequiredefault(_mutetogglejs); var _volumecontrolvolumebarjs = _dereq_('./volume-control/volume-bar.js'); var _volumecontrolvolumebarjs2 = _interoprequiredefault(_volumecontrolvolumebarjs); /** * button for volume popup * * @param {player|object} player * @param {object=} options * @extends popupbutton * @class volumemenubutton */ var volumemenubutton = (function (_popupbutton) { _inherits(volumemenubutton, _popupbutton); function volumemenubutton(player) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classcallcheck(this, volumemenubutton); // default to inline if (options.inline === undefined) { options.inline = true; } // if the vertical option isn't passed at all, default to true. if (options.vertical === undefined) { // if an inline volumemenubutton is used, we should default to using // a horizontal slider for obvious reasons. if (options.inline) { options.vertical = false; } else { options.vertical = true; } } // the vertical option needs to be set on the volumebar as well, // since that will need to be passed along to the volumebar constructor options.volumebar = options.volumebar || {}; options.volumebar.vertical = !!options.vertical; _popupbutton.call(this, player, options); // same listeners as mutetoggle this.on(player, 'volumechange', this.volumeupdate); this.on(player, 'loadstart', this.volumeupdate); // hide mute toggle if the current tech doesn't support volume control function updatevisibility() { if (player.tech_ && player.tech_['featuresvolumecontrol'] === false) { this.addclass('vjs-hidden'); } else { this.removeclass('vjs-hidden'); } } updatevisibility.call(this); this.on(player, 'loadstart', updatevisibility); this.on(this.volumebar, ['slideractive', 'focus'], function () { this.addclass('vjs-slider-active'); }); this.on(this.volumebar, ['sliderinactive', 'blur'], function () { this.removeclass('vjs-slider-active'); }); this.on(this.volumebar, ['focus'], function () { this.addclass('vjs-lock-showing'); }); this.on(this.volumebar, ['blur'], function () { this.removeclass('vjs-lock-showing'); }); } /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ volumemenubutton.prototype.buildcssclass = function buildcssclass() { var orientationclass = ''; if (!!this.options_.vertical) { orientationclass = 'vjs-volume-menu-button-vertical'; } else { orientationclass = 'vjs-volume-menu-button-horizontal'; } return 'vjs-volume-menu-button ' + _popupbutton.prototype.buildcssclass.call(this) + ' ' + orientationclass; }; /** * allow sub components to stack css class names * * @return {popup} the volume popup button * @method createpopup */ volumemenubutton.prototype.createpopup = function createpopup() { var popup = new _popuppopupjs2['default'](this.player_, { contenteltype: 'div' }); var vb = new _volumecontrolvolumebarjs2['default'](this.player_, this.options_.volumebar); popup.addchild(vb); this.menucontent = popup; this.volumebar = vb; this.attachvolumebarevents(); return popup; }; /** * handle click on volume popup and calls super * * @method handleclick */ volumemenubutton.prototype.handleclick = function handleclick() { _mutetogglejs2['default'].prototype.handleclick.call(this); _popupbutton.prototype.handleclick.call(this); }; volumemenubutton.prototype.attachvolumebarevents = function attachvolumebarevents() { this.menucontent.on(['mousedown', 'touchdown'], fn.bind(this, this.handlemousedown)); }; volumemenubutton.prototype.handlemousedown = function handlemousedown(event) { this.on(['mousemove', 'touchmove'], fn.bind(this.volumebar, this.volumebar.handlemousemove)); this.on(this.el_.ownerdocument, ['mouseup', 'touchend'], this.handlemouseup); }; volumemenubutton.prototype.handlemouseup = function handlemouseup(event) { this.off(['mousemove', 'touchmove'], fn.bind(this.volumebar, this.volumebar.handlemousemove)); }; return volumemenubutton; })(_popuppopupbuttonjs2['default']); volumemenubutton.prototype.volumeupdate = _mutetogglejs2['default'].prototype.update; volumemenubutton.prototype.controltext_ = 'mute'; _componentjs2['default'].registercomponent('volumemenubutton', volumemenubutton); exports['default'] = volumemenubutton; module.exports = exports['default']; },{"../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){ /** * @file error-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); var _modaldialog = _dereq_('./modal-dialog'); var _modaldialog2 = _interoprequiredefault(_modaldialog); var _utilsdom = _dereq_('./utils/dom'); var dom = _interoprequirewildcard(_utilsdom); var _utilsmergeoptions = _dereq_('./utils/merge-options'); var _utilsmergeoptions2 = _interoprequiredefault(_utilsmergeoptions); /** * display that an error has occurred making the video unplayable. * * @extends modaldialog * @class errordisplay */ var errordisplay = (function (_modaldialog) { _inherits(errordisplay, _modaldialog); /** * constructor for error display modal. * * @param {player} player * @param {object} [options] */ function errordisplay(player, options) { _classcallcheck(this, errordisplay); _modaldialog.call(this, player, options); this.on(player, 'error', this.open); } /** * include the old class for backward-compatibility. * * this can be removed in 6.0. * * @method buildcssclass * @deprecated * @return {string} */ errordisplay.prototype.buildcssclass = function buildcssclass() { return 'vjs-error-display ' + _modaldialog.prototype.buildcssclass.call(this); }; /** * generates the modal content based on the player error. * * @return {string|null} */ errordisplay.prototype.content = function content() { var error = this.player().error(); return error ? this.localize(error.message) : ''; }; return errordisplay; })(_modaldialog2['default']); errordisplay.prototype.options_ = _utilsmergeoptions2['default'](_modaldialog2['default'].prototype.options_, { fillalways: true, temporary: false, uncloseable: true }); _component2['default'].registercomponent('errordisplay', errordisplay); exports['default'] = errordisplay; module.exports = exports['default']; },{"./component":67,"./modal-dialog":109,"./utils/dom":134,"./utils/merge-options":140}],101:[function(_dereq_,module,exports){ /** * @file event-target.js */ 'use strict'; exports.__esmodule = true; 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; } } var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var eventtarget = function eventtarget() {}; eventtarget.prototype.allowedevents_ = {}; eventtarget.prototype.on = function (type, fn) { // remove the addeventlistener alias before calling events.on // so we don't get into an infinite type loop var ael = this.addeventlistener; this.addeventlistener = function.prototype; events.on(this, type, fn); this.addeventlistener = ael; }; eventtarget.prototype.addeventlistener = eventtarget.prototype.on; eventtarget.prototype.off = function (type, fn) { events.off(this, type, fn); }; eventtarget.prototype.removeeventlistener = eventtarget.prototype.off; eventtarget.prototype.one = function (type, fn) { events.one(this, type, fn); }; eventtarget.prototype.trigger = function (event) { var type = event.type || event; if (typeof event === 'string') { event = { type: type }; } event = events.fixevent(event); if (this.allowedevents_[type] && this['on' + type]) { this['on' + type](event); } events.trigger(this, event); }; // the standard dom eventtarget.dispatchevent() is aliased to trigger() eventtarget.prototype.dispatchevent = eventtarget.prototype.trigger; exports['default'] = eventtarget; module.exports = exports['default']; },{"./utils/events.js":135}],102:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _utilslog = _dereq_('./utils/log'); var _utilslog2 = _interoprequiredefault(_utilslog); /* * @file extend.js * * a combination of node inherits and babel's inherits (after transpile). * both work the same but node adds `super_` to the subclass * and bable adds the superclass as __proto__. both seem useful. */ var _inherits = 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) { // node subclass.super_ = superclass; } }; /* * function for subclassing using the same inheritance that * videojs uses internally * ```js * var button = videojs.getcomponent('button'); * ``` * ```js * var mybutton = videojs.extend(button, { * constructor: function(player, options) { * button.call(this, player, options); * }, * onclick: function() { * // dosomething * } * }); * ``` */ var extendfn = function extendfn(superclass) { var subclassmethods = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var subclass = function subclass() { superclass.apply(this, arguments); }; var methods = {}; if (typeof subclassmethods === 'object') { if (typeof subclassmethods.init === 'function') { _utilslog2['default'].warn('constructor logic via init() is deprecated; please use constructor() instead.'); subclassmethods.constructor = subclassmethods.init; } if (subclassmethods.constructor !== object.prototype.constructor) { subclass = subclassmethods.constructor; } methods = subclassmethods; } else if (typeof subclassmethods === 'function') { subclass = subclassmethods; } _inherits(subclass, superclass); // extend subobj's prototype with functions and other properties from props for (var name in methods) { if (methods.hasownproperty(name)) { subclass.prototype[name] = methods[name]; } } return subclass; }; exports['default'] = extendfn; module.exports = exports['default']; },{"./utils/log":139}],103:[function(_dereq_,module,exports){ /** * @file fullscreen-api.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /* * store the browser-specific methods for the fullscreen api * @type {object|undefined} * @private */ var fullscreenapi = {}; // browser api methods // map approach from screenful.js - https://github.com/sindresorhus/screenfull.js var apimap = [ // spec: https://dvcs.w3.org/hg/fullscreen/raw-file/tip/overview.html ['requestfullscreen', 'exitfullscreen', 'fullscreenelement', 'fullscreenenabled', 'fullscreenchange', 'fullscreenerror'], // webkit ['webkitrequestfullscreen', 'webkitexitfullscreen', 'webkitfullscreenelement', 'webkitfullscreenenabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], // old webkit (safari 5.1) ['webkitrequestfullscreen', 'webkitcancelfullscreen', 'webkitcurrentfullscreenelement', 'webkitcancelfullscreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], // mozilla ['mozrequestfullscreen', 'mozcancelfullscreen', 'mozfullscreenelement', 'mozfullscreenenabled', 'mozfullscreenchange', 'mozfullscreenerror'], // microsoft ['msrequestfullscreen', 'msexitfullscreen', 'msfullscreenelement', 'msfullscreenenabled', 'msfullscreenchange', 'msfullscreenerror']]; var specapi = apimap[0]; var browserapi = undefined; // determine the supported set of functions for (var i = 0; i < apimap.length; i++) { // check for exitfullscreen function if (apimap[i][1] in _globaldocument2['default']) { browserapi = apimap[i]; break; } } // map the browser api names to the spec api names if (browserapi) { for (var i = 0; i < browserapi.length; i++) { fullscreenapi[specapi[i]] = browserapi[i]; } } exports['default'] = fullscreenapi; module.exports = exports['default']; },{"global/document":1}],104:[function(_dereq_,module,exports){ /** * @file loading-spinner.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); /* loading spinner ================================================================================ */ /** * loading spinner for waiting events * * @extends component * @class loadingspinner */ var loadingspinner = (function (_component) { _inherits(loadingspinner, _component); function loadingspinner() { _classcallcheck(this, loadingspinner); _component.apply(this, arguments); } /** * create the component's dom element * * @method createel */ loadingspinner.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-loading-spinner', dir: 'ltr' }); }; return loadingspinner; })(_component2['default']); _component2['default'].registercomponent('loadingspinner', loadingspinner); exports['default'] = loadingspinner; module.exports = exports['default']; },{"./component":67}],105:[function(_dereq_,module,exports){ /** * @file media-error.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /* * custom mediaerror to mimic the html5 mediaerror * * @param {number} code the media error code */ var mediaerror = function mediaerror(code) { if (typeof code === 'number') { this.code = code; } else if (typeof code === 'string') { // default code is zero, so this is a custom error this.message = code; } else if (typeof code === 'object') { // object _objectassign2['default'](this, code); } if (!this.message) { this.message = mediaerror.defaultmessages[this.code] || ''; } }; /* * the error code that refers two one of the defined * mediaerror types * * @type {number} */ mediaerror.prototype.code = 0; /* * an optional message to be shown with the error. * message is not part of the html5 video spec * but allows for more informative custom errors. * * @type {string} */ mediaerror.prototype.message = ''; /* * an optional status code that can be set by plugins * to allow even more detail about the error. * for example the hls plugin might provide the specific * http status code that was returned when the error * occurred, then allowing a custom error overlay * to display more information. * * @type {array} */ mediaerror.prototype.status = null; mediaerror.errortypes = ['media_err_custom', // = 0 'media_err_aborted', // = 1 'media_err_network', // = 2 'media_err_decode', // = 3 'media_err_src_not_supported', // = 4 'media_err_encrypted' // = 5 ]; mediaerror.defaultmessages = { 1: 'you aborted the media playback', 2: 'a network error caused the media download to fail part-way.', 3: 'the media playback was aborted due to a corruption problem or because the media used features your browser did not support.', 4: 'the media could not be loaded, either because the server or network failed or because the format is not supported.', 5: 'the media is encrypted and we do not have the keys to decrypt it.' }; // add types as properties on mediaerror // e.g. mediaerror.media_err_src_not_supported = 4; for (var errnum = 0; errnum < mediaerror.errortypes.length; errnum++) { mediaerror[mediaerror.errortypes[errnum]] = errnum; // values should be accessible on both the class and instance mediaerror.prototype[mediaerror.errortypes[errnum]] = errnum; } exports['default'] = mediaerror; module.exports = exports['default']; },{"object.assign":45}],106:[function(_dereq_,module,exports){ /** * @file menu-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _clickablecomponentjs = _dereq_('../clickable-component.js'); var _clickablecomponentjs2 = _interoprequiredefault(_clickablecomponentjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _menujs = _dereq_('./menu.js'); var _menujs2 = _interoprequiredefault(_menujs); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilstotitlecasejs = _dereq_('../utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); /** * a button class with a popup menu * * @param {player|object} player * @param {object=} options * @extends button * @class menubutton */ var menubutton = (function (_clickablecomponent) { _inherits(menubutton, _clickablecomponent); function menubutton(player) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classcallcheck(this, menubutton); _clickablecomponent.call(this, player, options); this.update(); this.enabled_ = true; this.el_.setattribute('aria-haspopup', 'true'); this.el_.setattribute('role', 'menuitem'); this.on('keydown', this.handlesubmenukeypress); } /** * update menu * * @method update */ menubutton.prototype.update = function update() { var menu = this.createmenu(); if (this.menu) { this.removechild(this.menu); } this.menu = menu; this.addchild(menu); /** * track the state of the menu button * * @type {boolean} * @private */ this.buttonpressed_ = false; this.el_.setattribute('aria-expanded', 'false'); if (this.items && this.items.length === 0) { this.hide(); } else if (this.items && this.items.length > 1) { this.show(); } }; /** * create menu * * @return {menu} the constructed menu * @method createmenu */ menubutton.prototype.createmenu = function createmenu() { var menu = new _menujs2['default'](this.player_); // add a title list item to the top if (this.options_.title) { var title = dom.createel('li', { classname: 'vjs-menu-title', innerhtml: _utilstotitlecasejs2['default'](this.options_.title), tabindex: -1 }); menu.children_.unshift(title); dom.insertelfirst(title, menu.contentel()); } this.items = this['createitems'](); if (this.items) { // add menu items to the menu for (var i = 0; i < this.items.length; i++) { menu.additem(this.items[i]); } } return menu; }; /** * create the list of menu items. specific to each subclass. * * @method createitems */ menubutton.prototype.createitems = function createitems() {}; /** * create the component's dom element * * @return {element} * @method createel */ menubutton.prototype.createel = function createel() { return _clickablecomponent.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ menubutton.prototype.buildcssclass = function buildcssclass() { var menubuttonclass = 'vjs-menu-button'; // if the inline option is passed, we want to use different styles altogether. if (this.options_.inline === true) { menubuttonclass += '-inline'; } else { menubuttonclass += '-popup'; } return 'vjs-menu-button ' + menubuttonclass + ' ' + _clickablecomponent.prototype.buildcssclass.call(this); }; /** * when you click the button it adds focus, which * will show the menu indefinitely. * so we'll remove focus when the mouse leaves the button. * focus is needed for tab navigation. * allow sub components to stack css class names * * @method handleclick */ menubutton.prototype.handleclick = function handleclick() { this.one('mouseout', fn.bind(this, function () { this.menu.unlockshowing(); this.el_.blur(); })); if (this.buttonpressed_) { this.unpressbutton(); } else { this.pressbutton(); } }; /** * handle key press on menu * * @param {object} event key press event * @method handlekeypress */ menubutton.prototype.handlekeypress = function handlekeypress(event) { // escape (27) key or tab (9) key unpress the 'button' if (event.which === 27 || event.which === 9) { if (this.buttonpressed_) { this.unpressbutton(); } // don't preventdefault for tab key - we still want to lose focus if (event.which !== 9) { event.preventdefault(); } // up (38) key or down (40) key press the 'button' } else if (event.which === 38 || event.which === 40) { if (!this.buttonpressed_) { this.pressbutton(); event.preventdefault(); } } else { _clickablecomponent.prototype.handlekeypress.call(this, event); } }; /** * handle key press on submenu * * @param {object} event key press event * @method handlesubmenukeypress */ menubutton.prototype.handlesubmenukeypress = function handlesubmenukeypress(event) { // escape (27) key or tab (9) key unpress the 'button' if (event.which === 27 || event.which === 9) { if (this.buttonpressed_) { this.unpressbutton(); } // don't preventdefault for tab key - we still want to lose focus if (event.which !== 9) { event.preventdefault(); } } }; /** * makes changes based on button pressed * * @method pressbutton */ menubutton.prototype.pressbutton = function pressbutton() { if (this.enabled_) { this.buttonpressed_ = true; this.menu.lockshowing(); this.el_.setattribute('aria-expanded', 'true'); this.menu.focus(); // set the focus into the submenu } }; /** * makes changes based on button unpressed * * @method unpressbutton */ menubutton.prototype.unpressbutton = function unpressbutton() { if (this.enabled_) { this.buttonpressed_ = false; this.menu.unlockshowing(); this.el_.setattribute('aria-expanded', 'false'); this.el_.focus(); // set focus back to this menu button } }; /** * disable the menu button * * @return {component} * @method disable */ menubutton.prototype.disable = function disable() { // unpress, but don't force focus on this button this.buttonpressed_ = false; this.menu.unlockshowing(); this.el_.setattribute('aria-expanded', 'false'); this.enabled_ = false; return _clickablecomponent.prototype.disable.call(this); }; /** * enable the menu button * * @return {component} * @method disable */ menubutton.prototype.enable = function enable() { this.enabled_ = true; return _clickablecomponent.prototype.enable.call(this); }; return menubutton; })(_clickablecomponentjs2['default']); _componentjs2['default'].registercomponent('menubutton', menubutton); exports['default'] = menubutton; module.exports = exports['default']; },{"../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){ /** * @file menu-item.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _clickablecomponentjs = _dereq_('../clickable-component.js'); var _clickablecomponentjs2 = _interoprequiredefault(_clickablecomponentjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /** * the component for a menu item. `
  • ` * * @param {player|object} player * @param {object=} options * @extends button * @class menuitem */ var menuitem = (function (_clickablecomponent) { _inherits(menuitem, _clickablecomponent); function menuitem(player, options) { _classcallcheck(this, menuitem); _clickablecomponent.call(this, player, options); this.selectable = options['selectable']; this.selected(options['selected']); if (this.selectable) { // todo: may need to be either menuitemcheckbox or menuitemradio, // and may need logical grouping of menu items. this.el_.setattribute('role', 'menuitemcheckbox'); } else { this.el_.setattribute('role', 'menuitem'); } } /** * create the component's dom element * * @param {string=} type desc * @param {object=} props desc * @return {element} * @method createel */ menuitem.prototype.createel = function createel(type, props, attrs) { return _clickablecomponent.prototype.createel.call(this, 'li', _objectassign2['default']({ classname: 'vjs-menu-item', innerhtml: this.localize(this.options_['label']), tabindex: -1 }, props), attrs); }; /** * handle a click on the menu item, and set it to selected * * @method handleclick */ menuitem.prototype.handleclick = function handleclick() { this.selected(true); }; /** * set this menu item as selected or not * * @param {boolean} selected * @method selected */ menuitem.prototype.selected = function selected(_selected) { if (this.selectable) { if (_selected) { this.addclass('vjs-selected'); this.el_.setattribute('aria-checked', 'true'); // aria-checked isn't fully supported by browsers/screen readers, // so indicate selected state to screen reader in the control text. this.controltext(', selected'); } else { this.removeclass('vjs-selected'); this.el_.setattribute('aria-checked', 'false'); // indicate un-selected state to screen reader // note that a space clears out the selected state text this.controltext(' '); } } }; return menuitem; })(_clickablecomponentjs2['default']); _componentjs2['default'].registercomponent('menuitem', menuitem); exports['default'] = menuitem; module.exports = exports['default']; },{"../clickable-component.js":65,"../component.js":67,"object.assign":45}],108:[function(_dereq_,module,exports){ /** * @file menu.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilseventsjs = _dereq_('../utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); /** * the menu component is used to build pop up menus, including subtitle and * captions selection menus. * * @extends component * @class menu */ var menu = (function (_component) { _inherits(menu, _component); function menu(player, options) { _classcallcheck(this, menu); _component.call(this, player, options); this.focusedchild_ = -1; this.on('keydown', this.handlekeypress); } /** * add a menu item to the menu * * @param {object|string} component component or component type to add * @method additem */ menu.prototype.additem = function additem(component) { this.addchild(component); component.on('click', fn.bind(this, function () { this.unlockshowing(); //todo: need to set keyboard focus back to the menubutton })); }; /** * create the component's dom element * * @return {element} * @method createel */ menu.prototype.createel = function createel() { var contenteltype = this.options_.contenteltype || 'ul'; this.contentel_ = dom.createel(contenteltype, { classname: 'vjs-menu-content' }); this.contentel_.setattribute('role', 'menu'); var el = _component.prototype.createel.call(this, 'div', { append: this.contentel_, classname: 'vjs-menu' }); el.setattribute('role', 'presentation'); el.appendchild(this.contentel_); // prevent clicks from bubbling up. needed for menu buttons, // where a click on the parent is significant events.on(el, 'click', function (event) { event.preventdefault(); event.stopimmediatepropagation(); }); return el; }; /** * handle key press for menu * * @param {object} event event object * @method handlekeypress */ menu.prototype.handlekeypress = function handlekeypress(event) { if (event.which === 37 || event.which === 40) { // left and down arrows event.preventdefault(); this.stepforward(); } else if (event.which === 38 || event.which === 39) { // up and right arrows event.preventdefault(); this.stepback(); } }; /** * move to next (lower) menu item for keyboard users * * @method stepforward */ menu.prototype.stepforward = function stepforward() { var stepchild = 0; if (this.focusedchild_ !== undefined) { stepchild = this.focusedchild_ + 1; } this.focus(stepchild); }; /** * move to previous (higher) menu item for keyboard users * * @method stepback */ menu.prototype.stepback = function stepback() { var stepchild = 0; if (this.focusedchild_ !== undefined) { stepchild = this.focusedchild_ - 1; } this.focus(stepchild); }; /** * set focus on a menu item in the menu * * @param {object|string} item index of child item set focus on * @method focus */ menu.prototype.focus = function focus() { var item = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0]; var children = this.children().slice(); var havetitle = children.length && children[0].classname && /vjs-menu-title/.test(children[0].classname); if (havetitle) { children.shift(); } if (children.length > 0) { if (item < 0) { item = 0; } else if (item >= children.length) { item = children.length - 1; } this.focusedchild_ = item; children[item].el_.focus(); } }; return menu; })(_componentjs2['default']); _componentjs2['default'].registercomponent('menu', menu); exports['default'] = menu; module.exports = exports['default']; },{"../component.js":67,"../utils/dom.js":134,"../utils/events.js":135,"../utils/fn.js":136}],109:[function(_dereq_,module,exports){ /** * @file modal-dialog.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _utilsdom = _dereq_('./utils/dom'); var dom = _interoprequirewildcard(_utilsdom); var _utilsfn = _dereq_('./utils/fn'); var fn = _interoprequirewildcard(_utilsfn); var _utilslog = _dereq_('./utils/log'); var _utilslog2 = _interoprequiredefault(_utilslog); var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); var _closebutton = _dereq_('./close-button'); var _closebutton2 = _interoprequiredefault(_closebutton); var modal_class_name = 'vjs-modal-dialog'; var esc = 27; /** * the `modaldialog` displays over the video and its controls, which blocks * interaction with the player until it is closed. * * modal dialogs include a "close" button and will close when that button * is activated - or when esc is pressed anywhere. * * @extends component * @class modaldialog */ var modaldialog = (function (_component) { _inherits(modaldialog, _component); /** * constructor for modals. * * @param {player} player * @param {object} [options] * @param {mixed} [options.content=undefined] * provide customized content for this modal. * * @param {string} [options.description] * a text description for the modal, primarily for accessibility. * * @param {boolean} [options.fillalways=false] * normally, modals are automatically filled only the first time * they open. this tells the modal to refresh its content * every time it opens. * * @param {string} [options.label] * a text label for the modal, primarily for accessibility. * * @param {boolean} [options.temporary=true] * if `true`, the modal can only be opened once; it will be * disposed as soon as it's closed. * * @param {boolean} [options.uncloseable=false] * if `true`, the user will not be able to close the modal * through the ui in the normal ways. programmatic closing is * still possible. * */ function modaldialog(player, options) { _classcallcheck(this, modaldialog); _component.call(this, player, options); this.opened_ = this.hasbeenopened_ = this.hasbeenfilled_ = false; this.closeable(!this.options_.uncloseable); this.content(this.options_.content); // make sure the contentel is defined after any children are initialized // because we only want the contents of the modal in the contentel // (not the ui elements like the close button). this.contentel_ = dom.createel('div', { classname: modal_class_name + '-content' }, { role: 'document' }); this.descel_ = dom.createel('p', { classname: modal_class_name + '-description vjs-offscreen', id: this.el().getattribute('aria-describedby') }); dom.textcontent(this.descel_, this.description()); this.el_.appendchild(this.descel_); this.el_.appendchild(this.contentel_); } /* * modal dialog default options. * * @type {object} * @private */ /** * create the modal's dom element * * @method createel * @return {element} */ modaldialog.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: this.buildcssclass(), tabindex: -1 }, { 'aria-describedby': this.id() + '_description', 'aria-hidden': 'true', 'aria-label': this.label(), role: 'dialog' }); }; /** * build the modal's css class. * * @method buildcssclass * @return {string} */ modaldialog.prototype.buildcssclass = function buildcssclass() { return modal_class_name + ' vjs-hidden ' + _component.prototype.buildcssclass.call(this); }; /** * handles key presses on the document, looking for esc, which closes * the modal. * * @method handlekeypress * @param {event} e */ modaldialog.prototype.handlekeypress = function handlekeypress(e) { if (e.which === esc && this.closeable()) { this.close(); } }; /** * returns the label string for this modal. primarily used for accessibility. * * @return {string} */ modaldialog.prototype.label = function label() { return this.options_.label || this.localize('modal window'); }; /** * returns the description string for this modal. primarily used for * accessibility. * * @return {string} */ modaldialog.prototype.description = function description() { var desc = this.options_.description || this.localize('this is a modal window.'); // append a universal closeability message if the modal is closeable. if (this.closeable()) { desc += ' ' + this.localize('this modal can be closed by pressing the escape key or activating the close button.'); } return desc; }; /** * opens the modal. * * @method open * @return {modaldialog} */ modaldialog.prototype.open = function open() { if (!this.opened_) { var player = this.player(); this.trigger('beforemodalopen'); this.opened_ = true; // fill content if the modal has never opened before and // never been filled. if (this.options_.fillalways || !this.hasbeenopened_ && !this.hasbeenfilled_) { this.fill(); } // if the player was playing, pause it and take note of its previously // playing state. this.wasplaying_ = !player.paused(); if (this.wasplaying_) { player.pause(); } if (this.closeable()) { this.on(this.el_.ownerdocument, 'keydown', fn.bind(this, this.handlekeypress)); } player.controls(false); this.show(); this.el().setattribute('aria-hidden', 'false'); this.trigger('modalopen'); this.hasbeenopened_ = true; } return this; }; /** * whether or not the modal is opened currently. * * @method opened * @param {boolean} [value] * if given, it will open (`true`) or close (`false`) the modal. * * @return {boolean} */ modaldialog.prototype.opened = function opened(value) { if (typeof value === 'boolean') { this[value ? 'open' : 'close'](); } return this.opened_; }; /** * closes the modal. * * @method close * @return {modaldialog} */ modaldialog.prototype.close = function close() { if (this.opened_) { var player = this.player(); this.trigger('beforemodalclose'); this.opened_ = false; if (this.wasplaying_) { player.play(); } if (this.closeable()) { this.off(this.el_.ownerdocument, 'keydown', fn.bind(this, this.handlekeypress)); } player.controls(true); this.hide(); this.el().setattribute('aria-hidden', 'true'); this.trigger('modalclose'); if (this.options_.temporary) { this.dispose(); } } return this; }; /** * whether or not the modal is closeable via the ui. * * @method closeable * @param {boolean} [value] * if given as a boolean, it will set the `closeable` option. * * @return {boolean} */ modaldialog.prototype.closeable = function closeable(value) { if (typeof value === 'boolean') { var closeable = this.closeable_ = !!value; var _close = this.getchild('closebutton'); // if this is being made closeable and has no close button, add one. if (closeable && !_close) { // the close button should be a child of the modal - not its // content element, so temporarily change the content element. var temp = this.contentel_; this.contentel_ = this.el_; _close = this.addchild('closebutton'); this.contentel_ = temp; this.on(_close, 'close', this.close); } // if this is being made uncloseable and has a close button, remove it. if (!closeable && _close) { this.off(_close, 'close', this.close); this.removechild(_close); _close.dispose(); } } return this.closeable_; }; /** * fill the modal's content element with the modal's "content" option. * * the content element will be emptied before this change takes place. * * @method fill * @return {modaldialog} */ modaldialog.prototype.fill = function fill() { return this.fillwith(this.content()); }; /** * fill the modal's content element with arbitrary content. * * the content element will be emptied before this change takes place. * * @method fillwith * @param {mixed} [content] * the same rules apply to this as apply to the `content` option. * * @return {modaldialog} */ modaldialog.prototype.fillwith = function fillwith(content) { var contentel = this.contentel(); var parentel = contentel.parentnode; var nextsiblingel = contentel.nextsibling; this.trigger('beforemodalfill'); this.hasbeenfilled_ = true; // detach the content element from the dom before performing // manipulation to avoid modifying the live dom multiple times. parentel.removechild(contentel); this.empty(); dom.insertcontent(contentel, content); this.trigger('modalfill'); // re-inject the re-filled content element. if (nextsiblingel) { parentel.insertbefore(contentel, nextsiblingel); } else { parentel.appendchild(contentel); } return this; }; /** * empties the content element. * * this happens automatically anytime the modal is filled. * * @method empty * @return {modaldialog} */ modaldialog.prototype.empty = function empty() { this.trigger('beforemodalempty'); dom.emptyel(this.contentel()); this.trigger('modalempty'); return this; }; /** * gets or sets the modal content, which gets normalized before being * rendered into the dom. * * this does not update the dom or fill the modal, but it is called during * that process. * * @method content * @param {mixed} [value] * if defined, sets the internal content value to be used on the * next call(s) to `fill`. this value is normalized before being * inserted. to "clear" the internal content value, pass `null`. * * @return {mixed} */ modaldialog.prototype.content = function content(value) { if (typeof value !== 'undefined') { this.content_ = value; } return this.content_; }; return modaldialog; })(_component2['default']); modaldialog.prototype.options_ = { temporary: true }; _component2['default'].registercomponent('modaldialog', modaldialog); exports['default'] = modaldialog; module.exports = exports['default']; },{"./close-button":66,"./component":67,"./utils/dom":134,"./utils/fn":136,"./utils/log":139}],110:[function(_dereq_,module,exports){ /** * @file player.js */ // subclasses component 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('./component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _utilsdomjs = _dereq_('./utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsguidjs = _dereq_('./utils/guid.js'); var guid = _interoprequirewildcard(_utilsguidjs); var _utilsbrowserjs = _dereq_('./utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _utilslogjs = _dereq_('./utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _utilstotitlecasejs = _dereq_('./utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); var _utilstimerangesjs = _dereq_('./utils/time-ranges.js'); var _utilsbufferjs = _dereq_('./utils/buffer.js'); var _utilsstylesheetjs = _dereq_('./utils/stylesheet.js'); var stylesheet = _interoprequirewildcard(_utilsstylesheetjs); var _fullscreenapijs = _dereq_('./fullscreen-api.js'); var _fullscreenapijs2 = _interoprequiredefault(_fullscreenapijs); var _mediaerrorjs = _dereq_('./media-error.js'); var _mediaerrorjs2 = _interoprequiredefault(_mediaerrorjs); var _safejsonparsetuple = _dereq_('safe-json-parse/tuple'); var _safejsonparsetuple2 = _interoprequiredefault(_safejsonparsetuple); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); var _utilsmergeoptionsjs = _dereq_('./utils/merge-options.js'); var _utilsmergeoptionsjs2 = _interoprequiredefault(_utilsmergeoptionsjs); var _trackstexttracklistconverterjs = _dereq_('./tracks/text-track-list-converter.js'); var _trackstexttracklistconverterjs2 = _interoprequiredefault(_trackstexttracklistconverterjs); // include required child components (importing also registers them) var _techloaderjs = _dereq_('./tech/loader.js'); var _techloaderjs2 = _interoprequiredefault(_techloaderjs); var _posterimagejs = _dereq_('./poster-image.js'); var _posterimagejs2 = _interoprequiredefault(_posterimagejs); var _trackstexttrackdisplayjs = _dereq_('./tracks/text-track-display.js'); var _trackstexttrackdisplayjs2 = _interoprequiredefault(_trackstexttrackdisplayjs); var _loadingspinnerjs = _dereq_('./loading-spinner.js'); var _loadingspinnerjs2 = _interoprequiredefault(_loadingspinnerjs); var _bigplaybuttonjs = _dereq_('./big-play-button.js'); var _bigplaybuttonjs2 = _interoprequiredefault(_bigplaybuttonjs); var _controlbarcontrolbarjs = _dereq_('./control-bar/control-bar.js'); var _controlbarcontrolbarjs2 = _interoprequiredefault(_controlbarcontrolbarjs); var _errordisplayjs = _dereq_('./error-display.js'); var _errordisplayjs2 = _interoprequiredefault(_errordisplayjs); var _trackstexttracksettingsjs = _dereq_('./tracks/text-track-settings.js'); var _trackstexttracksettingsjs2 = _interoprequiredefault(_trackstexttracksettingsjs); var _modaldialog = _dereq_('./modal-dialog'); var _modaldialog2 = _interoprequiredefault(_modaldialog); // require html5 tech, at least for disposing the original video tag var _techtechjs = _dereq_('./tech/tech.js'); var _techtechjs2 = _interoprequiredefault(_techtechjs); var _techhtml5js = _dereq_('./tech/html5.js'); var _techhtml5js2 = _interoprequiredefault(_techhtml5js); /** * an instance of the `player` class is created when any of the video.js setup methods are used to initialize a video. * ```js * var myplayer = videojs('example_video_1'); * ``` * in the following example, the `data-setup` attribute tells the video.js library to create a player instance when the library is ready. * ```html * * ``` * after an instance has been created it can be accessed globally using `video('example_video_1')`. * * @param {element} tag the original video tag used for configuring options * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends component * @class player */ var player = (function (_component) { _inherits(player, _component); /** * player's constructor function * * @constructs * @method init * @param {element} tag the original video tag used for configuring options * @param {object=} options player options * @param {function=} ready ready callback function */ function player(tag, options, ready) { var _this = this; _classcallcheck(this, player); // make sure tag id exists tag.id = tag.id || 'vjs_video_' + guid.newguid(); // set options // the options argument overrides options set in the video tag // which overrides globally set options. // this latter part coincides with the load order // (tag must exist before player) options = _objectassign2['default'](player.gettagsettings(tag), options); // delay the initialization of children because we need to set up // player properties first, and can't use `this` before `super()` options.initchildren = false; // same with creating the element options.createel = false; // we don't want the player to report touch activity on itself // see enabletouchactivity in component options.reporttouchactivity = false; // run base component initializing with new options _component.call(this, null, options, ready); // if the global option object was accidentally blown away by // someone, bail early with an informative error if (!this.options_ || !this.options_.techorder || !this.options_.techorder.length) { throw new error('no techorder specified. did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); } this.tag = tag; // store the original tag used to set options // store the tag attributes used to restore html5 element this.tagattributes = tag && dom.getelattributes(tag); // update current language this.language(this.options_.language); // update supported languages if (options.languages) { (function () { // normalise player option languages to lowercase var languagestolower = {}; object.getownpropertynames(options.languages).foreach(function (name) { languagestolower[name.tolowercase()] = options.languages[name]; }); _this.languages_ = languagestolower; })(); } else { this.languages_ = player.prototype.options_.languages; } // cache for video property values. this.cache_ = {}; // set poster this.poster_ = options.poster || ''; // set controls this.controls_ = !!options.controls; // original tag settings stored in options // now remove immediately so native controls don't flash. // may be turned back on by html5 tech if nativecontrolsfortouch is true tag.controls = false; /* * store the internal state of scrubbing * * @private * @return {boolean} true if the user is scrubbing */ this.scrubbing_ = false; this.el_ = this.createel(); // we also want to pass the original player options to each component and plugin // as well so they don't need to reach back into the player for options later. // we also need to do another copy of this.options_ so we don't end up with // an infinite loop. var playeroptionscopy = _utilsmergeoptionsjs2['default'](this.options_); // load plugins if (options.plugins) { (function () { var plugins = options.plugins; object.getownpropertynames(plugins).foreach(function (name) { if (typeof this[name] === 'function') { this[name](plugins[name]); } else { _utilslogjs2['default'].error('unable to find plugin:', name); } }, _this); })(); } this.options_.playeroptions = playeroptionscopy; this.initchildren(); // set isaudio based on whether or not an audio tag was used this.isaudio(tag.nodename.tolowercase() === 'audio'); // update controls classname. can't do this when the controls are initially // set because the element doesn't exist yet. if (this.controls()) { this.addclass('vjs-controls-enabled'); } else { this.addclass('vjs-controls-disabled'); } // set aria label and region role depending on player type this.el_.setattribute('role', 'region'); if (this.isaudio()) { this.el_.setattribute('aria-label', 'audio player'); } else { this.el_.setattribute('aria-label', 'video player'); } if (this.isaudio()) { this.addclass('vjs-audio'); } if (this.flexnotsupported_()) { this.addclass('vjs-no-flex'); } // todo: make this smarter. toggle user state between touching/mousing // using events, since devices can have both touch and mouse events. // if (browser.touch_enabled) { // this.addclass('vjs-touch-enabled'); // } // ios safari has broken hover handling if (!browser.is_ios) { this.addclass('vjs-workinghover'); } // make player easily findable by id player.players[this.id_] = this; // when the player is first initialized, trigger activity so components // like the control bar show themselves if needed this.useractive(true); this.reportuseractivity(); this.listenforuseractivity_(); this.on('fullscreenchange', this.handlefullscreenchange_); this.on('stageclick', this.handlestageclick_); } /* * global player list * * @type {object} */ /** * destroys the video player and does any necessary cleanup * ```js * myplayer.dispose(); * ``` * this is especially helpful if you are dynamically adding and removing videos * to/from the dom. * * @method dispose */ player.prototype.dispose = function dispose() { this.trigger('dispose'); // prevent dispose from being called twice this.off('dispose'); if (this.styleel_ && this.styleel_.parentnode) { this.styleel_.parentnode.removechild(this.styleel_); } // kill reference to this player player.players[this.id_] = null; if (this.tag && this.tag.player) { this.tag.player = null; } if (this.el_ && this.el_.player) { this.el_.player = null; } if (this.tech_) { this.tech_.dispose(); } _component.prototype.dispose.call(this); }; /** * create the component's dom element * * @return {element} * @method createel */ player.prototype.createel = function createel() { var el = this.el_ = _component.prototype.createel.call(this, 'div'); var tag = this.tag; // remove width/height attrs from tag so css can make it 100% width/height tag.removeattribute('width'); tag.removeattribute('height'); // copy over all the attributes from the tag, including id and class // id will now reference player box, not the video tag var attrs = dom.getelattributes(tag); object.getownpropertynames(attrs).foreach(function (attr) { // workaround so we don't totally break ie7 // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 if (attr === 'class') { el.classname = attrs[attr]; } else { el.setattribute(attr, attrs[attr]); } }); // update tag id/class for use as html5 playback tech // might think we should do this after embedding in container so .vjs-tech class // doesn't flash 100% width/height, but class only applies with .video-js parent tag.playerid = tag.id; tag.id += '_html5_api'; tag.classname = 'vjs-tech'; // make player findable on elements tag.player = el.player = this; // default state of video is paused this.addclass('vjs-paused'); // add a style element in the player that we'll use to set the width/height // of the player in a way that's still overrideable by css, just like the // video element if (_globalwindow2['default'].videojs_no_dynamic_style !== true) { this.styleel_ = stylesheet.createstyleelement('vjs-styles-dimensions'); var defaultsstyleel = dom.$('.vjs-styles-defaults'); var head = dom.$('head'); head.insertbefore(this.styleel_, defaultsstyleel ? defaultsstyleel.nextsibling : head.firstchild); } // pass in the width/height/aspectratio options which will update the style el this.width(this.options_.width); this.height(this.options_.height); this.fluid(this.options_.fluid); this.aspectratio(this.options_.aspectratio); // hide any links within the video/audio tag, because ie doesn't hide them completely. var links = tag.getelementsbytagname('a'); for (var i = 0; i < links.length; i++) { var linkel = links.item(i); dom.addelclass(linkel, 'vjs-hidden'); linkel.setattribute('hidden', 'hidden'); } // insertelfirst seems to cause the networkstate to flicker from 3 to 2, so // keep track of the original for later so we can know if the source originally failed tag.initnetworkstate_ = tag.networkstate; // wrap video tag in div (el/box) container if (tag.parentnode) { tag.parentnode.insertbefore(el, tag); } // insert the tag as the first child of the player element // then manually add it to the children array so that this.addchild // will work properly for other components dom.insertelfirst(tag, el); // breaks iphone, fixed in html5 setup. this.children_.unshift(tag); this.el_ = el; return el; }; /** * get/set player width * * @param {number=} value value for width * @return {number} width when getting * @method width */ player.prototype.width = function width(value) { return this.dimension('width', value); }; /** * get/set player height * * @param {number=} value value for height * @return {number} height when getting * @method height */ player.prototype.height = function height(value) { return this.dimension('height', value); }; /** * get/set dimension for player * * @param {string} dimension either width or height * @param {number=} value value for dimension * @return {component} * @method dimension */ player.prototype.dimension = function dimension(_dimension, value) { var privdimension = _dimension + '_'; if (value === undefined) { return this[privdimension] || 0; } if (value === '') { // if an empty string is given, reset the dimension to be automatic this[privdimension] = undefined; } else { var parsedval = parsefloat(value); if (isnan(parsedval)) { _utilslogjs2['default'].error('improper value "' + value + '" supplied for for ' + _dimension); return this; } this[privdimension] = parsedval; } this.updatestyleel_(); return this; }; /** * add/remove the vjs-fluid class * * @param {boolean} bool value of true adds the class, value of false removes the class * @method fluid */ player.prototype.fluid = function fluid(bool) { if (bool === undefined) { return !!this.fluid_; } this.fluid_ = !!bool; if (bool) { this.addclass('vjs-fluid'); } else { this.removeclass('vjs-fluid'); } }; /** * get/set the aspect ratio * * @param {string=} ratio aspect ratio for player * @return aspectratio * @method aspectratio */ player.prototype.aspectratio = function aspectratio(ratio) { if (ratio === undefined) { return this.aspectratio_; } // check for width:height format if (!/^\d+\:\d+$/.test(ratio)) { throw new error('improper value supplied for aspect ratio. the format should be width:height, for example 16:9.'); } this.aspectratio_ = ratio; // we're assuming if you set an aspect ratio you want fluid mode, // because in fixed mode you could calculate width and height yourself. this.fluid(true); this.updatestyleel_(); }; /** * update styles of the player element (height, width and aspect ratio) * * @method updatestyleel_ */ player.prototype.updatestyleel_ = function updatestyleel_() { if (_globalwindow2['default'].videojs_no_dynamic_style === true) { var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; var techel = this.tech_ && this.tech_.el(); if (techel) { if (_width >= 0) { techel.width = _width; } if (_height >= 0) { techel.height = _height; } } return; } var width = undefined; var height = undefined; var aspectratio = undefined; var idclass = undefined; // the aspect ratio is either used directly or to calculate width and height. if (this.aspectratio_ !== undefined && this.aspectratio_ !== 'auto') { // use any aspectratio that's been specifically set aspectratio = this.aspectratio_; } else if (this.videowidth()) { // otherwise try to get the aspect ratio from the video metadata aspectratio = this.videowidth() + ':' + this.videoheight(); } else { // or use a default. the video element's is 2:1, but 16:9 is more common. aspectratio = '16:9'; } // get the ratio as a decimal we can use to calculate dimensions var ratioparts = aspectratio.split(':'); var ratiomultiplier = ratioparts[1] / ratioparts[0]; if (this.width_ !== undefined) { // use any width that's been specifically set width = this.width_; } else if (this.height_ !== undefined) { // or calulate the width from the aspect ratio if a height has been set width = this.height_ / ratiomultiplier; } else { // or use the video's metadata, or use the video el's default of 300 width = this.videowidth() || 300; } if (this.height_ !== undefined) { // use any height that's been specifically set height = this.height_; } else { // otherwise calculate the height from the ratio and the width height = width * ratiomultiplier; } // ensure the css class is valid by starting with an alpha character if (/^[^a-za-z]/.test(this.id())) { idclass = 'dimensions-' + this.id(); } else { idclass = this.id() + '-dimensions'; } // ensure the right class is still on the player for the style element this.addclass(idclass); 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 '); }; /** * load the media playback technology (tech) * load/create an instance of playback technology including element and api methods * and append playback element in player div. * * @param {string} techname name of the playback technology * @param {string} source video source * @method loadtech_ * @private */ player.prototype.loadtech_ = function loadtech_(techname, source) { // pause and remove current playback technology if (this.tech_) { this.unloadtech_(); } // get rid of the html5 video tag as soon as we are using another tech if (techname !== 'html5' && this.tag) { _techtechjs2['default'].gettech('html5').disposemediaelement(this.tag); this.tag.player = null; this.tag = null; } this.techname_ = techname; // turn off api access because we're loading a new tech that might load asynchronously this.isready_ = false; // grab tech-specific options from player options and add source and parent element to use. var techoptions = _objectassign2['default']({ 'nativecontrolsfortouch': this.options_.nativecontrolsfortouch, 'source': source, 'playerid': this.id(), 'techid': this.id() + '_' + techname + '_api', 'texttracks': this.texttracks_, 'autoplay': this.options_.autoplay, 'preload': this.options_.preload, 'loop': this.options_.loop, 'muted': this.options_.muted, 'poster': this.poster(), 'language': this.language(), 'vtt.js': this.options_['vtt.js'] }, this.options_[techname.tolowercase()]); if (this.tag) { techoptions.tag = this.tag; } if (source) { this.currenttype_ = source.type; if (source.src === this.cache_.src && this.cache_.currenttime > 0) { techoptions.starttime = this.cache_.currenttime; } this.cache_.src = source.src; } // initialize tech instance var techcomponent = _techtechjs2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!techcomponent) { techcomponent = _componentjs2['default'].getcomponent(techname); } this.tech_ = new techcomponent(techoptions); // player.triggerready is always async, so don't need this to be async this.tech_.ready(fn.bind(this, this.handletechready_), true); _trackstexttracklistconverterjs2['default'].jsontotexttracks(this.texttracksjson_ || [], this.tech_); // listen to all html5-defined events and trigger them on the player this.on(this.tech_, 'loadstart', this.handletechloadstart_); this.on(this.tech_, 'waiting', this.handletechwaiting_); this.on(this.tech_, 'canplay', this.handletechcanplay_); this.on(this.tech_, 'canplaythrough', this.handletechcanplaythrough_); this.on(this.tech_, 'playing', this.handletechplaying_); this.on(this.tech_, 'ended', this.handletechended_); this.on(this.tech_, 'seeking', this.handletechseeking_); this.on(this.tech_, 'seeked', this.handletechseeked_); this.on(this.tech_, 'play', this.handletechplay_); this.on(this.tech_, 'firstplay', this.handletechfirstplay_); this.on(this.tech_, 'pause', this.handletechpause_); this.on(this.tech_, 'progress', this.handletechprogress_); this.on(this.tech_, 'durationchange', this.handletechdurationchange_); this.on(this.tech_, 'fullscreenchange', this.handletechfullscreenchange_); this.on(this.tech_, 'error', this.handletecherror_); this.on(this.tech_, 'suspend', this.handletechsuspend_); this.on(this.tech_, 'abort', this.handletechabort_); this.on(this.tech_, 'emptied', this.handletechemptied_); this.on(this.tech_, 'stalled', this.handletechstalled_); this.on(this.tech_, 'loadedmetadata', this.handletechloadedmetadata_); this.on(this.tech_, 'loadeddata', this.handletechloadeddata_); this.on(this.tech_, 'timeupdate', this.handletechtimeupdate_); this.on(this.tech_, 'ratechange', this.handletechratechange_); this.on(this.tech_, 'volumechange', this.handletechvolumechange_); this.on(this.tech_, 'texttrackchange', this.handletechtexttrackchange_); this.on(this.tech_, 'loadedmetadata', this.updatestyleel_); this.on(this.tech_, 'posterchange', this.handletechposterchange_); this.usingnativecontrols(this.techget_('controls')); if (this.controls() && !this.usingnativecontrols()) { this.addtechcontrolslisteners_(); } // add the tech element in the dom if it was not already there // make sure to not insert the original video element if using html5 if (this.tech_.el().parentnode !== this.el() && (techname !== 'html5' || !this.tag)) { dom.insertelfirst(this.tech_.el(), this.el()); } // get rid of the original video tag reference after the first tech is loaded if (this.tag) { this.tag.player = null; this.tag = null; } }; /** * unload playback technology * * @method unloadtech_ * @private */ player.prototype.unloadtech_ = function unloadtech_() { // save the current text tracks so that we can reuse the same text tracks with the next tech this.texttracks_ = this.texttracks(); this.texttracksjson_ = _trackstexttracklistconverterjs2['default'].texttrackstojson(this.tech_); this.isready_ = false; this.tech_.dispose(); this.tech_ = false; }; /** * return a reference to the current tech. * it will only return a reference to the tech if given an object with the * `iwillnotusethisinplugins` property on it. this is try and prevent misuse * of techs by plugins. * * @param {object} * @return {object} the tech * @method tech */ player.prototype.tech = function tech(safety) { if (safety && safety.iwillnotusethisinplugins) { return this.tech_; } 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 '; _globalwindow2['default'].alert(errortext); throw new error(errortext); }; /** * set up click and touch listeners for the playback element * * on desktops, a click on the video itself will toggle playback, * on a mobile device a click on the video toggles controls. * (toggling controls is done by toggling the user state between active and * inactive) * a tap can signal that a user has become active, or has become inactive * e.g. a quick tap on an iphone movie should reveal the controls. another * quick tap should hide them again (signaling the user is in an inactive * viewing state) * in addition to this, we still want the user to be considered inactive after * a few seconds of inactivity. * note: the only part of ios interaction we can't mimic with this setup * is a touch and hold on the video element counting as activity in order to * keep the controls showing, but that shouldn't be an issue. a touch and hold * on any controls will still keep the user active * * @private * @method addtechcontrolslisteners_ */ player.prototype.addtechcontrolslisteners_ = function addtechcontrolslisteners_() { // make sure to remove all the previous listeners in case we are called multiple times. this.removetechcontrolslisteners_(); // some browsers (chrome & ie) don't trigger a click on a flash swf, but do // trigger mousedown/up. // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object // any touch events are set to block the mousedown event from happening this.on(this.tech_, 'mousedown', this.handletechclick_); // if the controls were hidden we don't want that to change without a tap event // so we'll check if the controls were already showing before reporting user // activity this.on(this.tech_, 'touchstart', this.handletechtouchstart_); this.on(this.tech_, 'touchmove', this.handletechtouchmove_); this.on(this.tech_, 'touchend', this.handletechtouchend_); // the tap listener needs to come after the touchend listener because the tap // listener cancels out any reporteduseractivity when setting useractive(false) this.on(this.tech_, 'tap', this.handletechtap_); }; /** * remove the listeners used for click and tap controls. this is needed for * toggling to controls disabled, where a tap/touch should do nothing. * * @method removetechcontrolslisteners_ * @private */ player.prototype.removetechcontrolslisteners_ = function removetechcontrolslisteners_() { // we don't want to just use `this.off()` because there might be other needed // listeners added by techs that extend this. this.off(this.tech_, 'tap', this.handletechtap_); this.off(this.tech_, 'touchstart', this.handletechtouchstart_); this.off(this.tech_, 'touchmove', this.handletechtouchmove_); this.off(this.tech_, 'touchend', this.handletechtouchend_); this.off(this.tech_, 'mousedown', this.handletechclick_); }; /** * player waits for the tech to be ready * * @method handletechready_ * @private */ player.prototype.handletechready_ = function handletechready_() { this.triggerready(); // keep the same volume as before if (this.cache_.volume) { this.techcall_('setvolume', this.cache_.volume); } // look if the tech found a higher resolution poster while loading this.handletechposterchange_(); // update the duration if available this.handletechdurationchange_(); // chrome and safari both have issues with autoplay. // in safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. // in chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) // this fixes both issues. need to wait for api, so it updates displays correctly if (this.src() && this.tag && this.options_.autoplay && this.paused()) { delete this.tag.poster; // chrome fix. fixed in chrome v16. this.play(); } }; /** * fired when the user agent begins looking for media data * * @private * @method handletechloadstart_ */ player.prototype.handletechloadstart_ = function handletechloadstart_() { // todo: update to use `emptied` event instead. see #1277. this.removeclass('vjs-ended'); // reset the error state this.error(null); // if it's already playing we want to trigger a firstplay event now. // the firstplay event relies on both the play and loadstart events // which can happen in any order for a new source if (!this.paused()) { this.trigger('loadstart'); this.trigger('firstplay'); } else { // reset the hasstarted state this.hasstarted(false); this.trigger('loadstart'); } }; /** * add/remove the vjs-has-started class * * @param {boolean} hasstarted the value of true adds the class the value of false remove the class * @return {boolean} boolean value if has started * @private * @method hasstarted */ player.prototype.hasstarted = function hasstarted(_hasstarted) { if (_hasstarted !== undefined) { // only update if this is a new value if (this.hasstarted_ !== _hasstarted) { this.hasstarted_ = _hasstarted; if (_hasstarted) { this.addclass('vjs-has-started'); // trigger the firstplay event if this newly has played this.trigger('firstplay'); } else { this.removeclass('vjs-has-started'); } } return this; } return !!this.hasstarted_; }; /** * fired whenever the media begins or resumes playback * * @private * @method handletechplay_ */ player.prototype.handletechplay_ = function handletechplay_() { this.removeclass('vjs-ended'); this.removeclass('vjs-paused'); this.addclass('vjs-playing'); // hide the poster when the user hits play // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play this.hasstarted(true); this.trigger('play'); }; /** * fired whenever the media begins waiting * * @private * @method handletechwaiting_ */ player.prototype.handletechwaiting_ = function handletechwaiting_() { var _this2 = this; this.addclass('vjs-waiting'); this.trigger('waiting'); this.one('timeupdate', function () { return _this2.removeclass('vjs-waiting'); }); }; /** * a handler for events that signal that waiting has ended * which is not consistent between browsers. see #1351 * * @private * @method handletechcanplay_ */ player.prototype.handletechcanplay_ = function handletechcanplay_() { this.removeclass('vjs-waiting'); this.trigger('canplay'); }; /** * a handler for events that signal that waiting has ended * which is not consistent between browsers. see #1351 * * @private * @method handletechcanplaythrough_ */ player.prototype.handletechcanplaythrough_ = function handletechcanplaythrough_() { this.removeclass('vjs-waiting'); this.trigger('canplaythrough'); }; /** * a handler for events that signal that waiting has ended * which is not consistent between browsers. see #1351 * * @private * @method handletechplaying_ */ player.prototype.handletechplaying_ = function handletechplaying_() { this.removeclass('vjs-waiting'); this.trigger('playing'); }; /** * fired whenever the player is jumping to a new time * * @private * @method handletechseeking_ */ player.prototype.handletechseeking_ = function handletechseeking_() { this.addclass('vjs-seeking'); this.trigger('seeking'); }; /** * fired when the player has finished jumping to a new time * * @private * @method handletechseeked_ */ player.prototype.handletechseeked_ = function handletechseeked_() { this.removeclass('vjs-seeking'); this.trigger('seeked'); }; /** * fired the first time a video is played * not part of the hls spec, and we're not sure if this is the best * implementation yet, so use sparingly. if you don't have a reason to * prevent playback, use `myplayer.one('play');` instead. * * @private * @method handletechfirstplay_ */ player.prototype.handletechfirstplay_ = function handletechfirstplay_() { //if the first starttime attribute is specified //then we will start at the given offset in seconds if (this.options_.starttime) { this.currenttime(this.options_.starttime); } this.addclass('vjs-has-started'); this.trigger('firstplay'); }; /** * fired whenever the media has been paused * * @private * @method handletechpause_ */ player.prototype.handletechpause_ = function handletechpause_() { this.removeclass('vjs-playing'); this.addclass('vjs-paused'); this.trigger('pause'); }; /** * fired while the user agent is downloading media data * * @private * @method handletechprogress_ */ player.prototype.handletechprogress_ = function handletechprogress_() { this.trigger('progress'); }; /** * fired when the end of the media resource is reached (currenttime == duration) * * @private * @method handletechended_ */ player.prototype.handletechended_ = function handletechended_() { this.addclass('vjs-ended'); if (this.options_.loop) { this.currenttime(0); this.play(); } else if (!this.paused()) { this.pause(); } this.trigger('ended'); }; /** * fired when the duration of the media resource is first known or changed * * @private * @method handletechdurationchange_ */ player.prototype.handletechdurationchange_ = function handletechdurationchange_() { this.duration(this.techget_('duration')); }; /** * handle a click on the media element to play/pause * * @param {object=} event event object * @private * @method handletechclick_ */ player.prototype.handletechclick_ = function handletechclick_(event) { // we're using mousedown to detect clicks thanks to flash, but mousedown // will also be triggered with right-clicks, so we need to prevent that if (event.button !== 0) return; // when controls are disabled a click should not toggle playback because // the click is considered a control if (this.controls()) { if (this.paused()) { this.play(); } else { this.pause(); } } }; /** * handle a tap on the media element. it will toggle the user * activity state, which hides and shows the controls. * * @private * @method handletechtap_ */ player.prototype.handletechtap_ = function handletechtap_() { this.useractive(!this.useractive()); }; /** * handle touch to start * * @private * @method handletechtouchstart_ */ player.prototype.handletechtouchstart_ = function handletechtouchstart_() { this.userwasactive = this.useractive(); }; /** * handle touch to move * * @private * @method handletechtouchmove_ */ player.prototype.handletechtouchmove_ = function handletechtouchmove_() { if (this.userwasactive) { this.reportuseractivity(); } }; /** * handle touch to end * * @private * @method handletechtouchend_ */ player.prototype.handletechtouchend_ = function handletechtouchend_(event) { // stop the mouse events from also happening event.preventdefault(); }; /** * fired when the player switches in or out of fullscreen mode * * @private * @method handlefullscreenchange_ */ player.prototype.handlefullscreenchange_ = function handlefullscreenchange_() { if (this.isfullscreen()) { this.addclass('vjs-fullscreen'); } else { this.removeclass('vjs-fullscreen'); } }; /** * native click events on the swf aren't triggered on ie11, win8.1rt * use stageclick events triggered from inside the swf instead * * @private * @method handlestageclick_ */ player.prototype.handlestageclick_ = function handlestageclick_() { this.reportuseractivity(); }; /** * handle tech fullscreen change * * @private * @method handletechfullscreenchange_ */ player.prototype.handletechfullscreenchange_ = function handletechfullscreenchange_(event, data) { if (data) { this.isfullscreen(data.isfullscreen); } this.trigger('fullscreenchange'); }; /** * fires when an error occurred during the loading of an audio/video * * @private * @method handletecherror_ */ player.prototype.handletecherror_ = function handletecherror_() { var error = this.tech_.error(); this.error(error && error.code); }; /** * fires when the browser is intentionally not getting media data * * @private * @method handletechsuspend_ */ player.prototype.handletechsuspend_ = function handletechsuspend_() { this.trigger('suspend'); }; /** * fires when the loading of an audio/video is aborted * * @private * @method handletechabort_ */ player.prototype.handletechabort_ = function handletechabort_() { this.trigger('abort'); }; /** * fires when the current playlist is empty * * @private * @method handletechemptied_ */ player.prototype.handletechemptied_ = function handletechemptied_() { this.trigger('emptied'); }; /** * fires when the browser is trying to get media data, but data is not available * * @private * @method handletechstalled_ */ player.prototype.handletechstalled_ = function handletechstalled_() { this.trigger('stalled'); }; /** * fires when the browser has loaded meta data for the audio/video * * @private * @method handletechloadedmetadata_ */ player.prototype.handletechloadedmetadata_ = function handletechloadedmetadata_() { this.trigger('loadedmetadata'); }; /** * fires when the browser has loaded the current frame of the audio/video * * @private * @method handletechloadeddata_ */ player.prototype.handletechloadeddata_ = function handletechloadeddata_() { this.trigger('loadeddata'); }; /** * fires when the current playback position has changed * * @private * @method handletechtimeupdate_ */ player.prototype.handletechtimeupdate_ = function handletechtimeupdate_() { this.trigger('timeupdate'); }; /** * fires when the playing speed of the audio/video is changed * * @private * @method handletechratechange_ */ player.prototype.handletechratechange_ = function handletechratechange_() { this.trigger('ratechange'); }; /** * fires when the volume has been changed * * @private * @method handletechvolumechange_ */ player.prototype.handletechvolumechange_ = function handletechvolumechange_() { this.trigger('volumechange'); }; /** * fires when the text track has been changed * * @private * @method handletechtexttrackchange_ */ player.prototype.handletechtexttrackchange_ = function handletechtexttrackchange_() { this.trigger('texttrackchange'); }; /** * get object for cached values. * * @return {object} * @method getcache */ player.prototype.getcache = function getcache() { return this.cache_; }; /** * pass values to the playback tech * * @param {string=} method method * @param {object=} arg argument * @private * @method techcall_ */ player.prototype.techcall_ = function techcall_(method, arg) { // if it's not ready yet, call method when it is if (this.tech_ && !this.tech_.isready_) { this.tech_.ready(function () { this[method](arg); }, true); // otherwise call method now } else { try { this.tech_[method](arg); } catch (e) { _utilslogjs2['default'](e); throw e; } } }; /** * get calls can't wait for the tech, and sometimes don't need to. * * @param {string} method tech method * @return {method} * @private * @method techget_ */ player.prototype.techget_ = function techget_(method) { if (this.tech_ && this.tech_.isready_) { // flash likes to die and reload when you hide or reposition it. // in these cases the object methods go away and we get errors. // when that happens we'll catch the errors and inform tech that it's not ready any more. try { return this.tech_[method](); } catch (e) { // when building additional tech libs, an expected method may not be defined yet if (this.tech_[method] === undefined) { _utilslogjs2['default']('video.js: ' + method + ' method not defined for ' + this.techname_ + ' playback technology.', e); } else { // when a method isn't available on the object it throws a typeerror if (e.name === 'typeerror') { _utilslogjs2['default']('video.js: ' + method + ' unavailable on ' + this.techname_ + ' playback technology element.', e); this.tech_.isready_ = false; } else { _utilslogjs2['default'](e); } } throw e; } } return; }; /** * start media playback * ```js * myplayer.play(); * ``` * * @return {player} self * @method play */ player.prototype.play = function play() { this.techcall_('play'); return this; }; /** * pause the video playback * ```js * myplayer.pause(); * ``` * * @return {player} self * @method pause */ player.prototype.pause = function pause() { this.techcall_('pause'); return this; }; /** * check if the player is paused * ```js * var ispaused = myplayer.paused(); * var isplaying = !myplayer.paused(); * ``` * * @return {boolean} false if the media is currently playing, or true otherwise * @method paused */ player.prototype.paused = function paused() { // the initial state of paused should be true (in safari it's actually false) return this.techget_('paused') === false ? false : true; }; /** * returns whether or not the user is "scrubbing". scrubbing is when the user * has clicked the progress bar handle and is dragging it along the progress bar. * * @param {boolean} isscrubbing true/false the user is scrubbing * @return {boolean} the scrubbing status when getting * @return {object} the player when setting * @method scrubbing */ player.prototype.scrubbing = function scrubbing(isscrubbing) { if (isscrubbing !== undefined) { this.scrubbing_ = !!isscrubbing; if (isscrubbing) { this.addclass('vjs-scrubbing'); } else { this.removeclass('vjs-scrubbing'); } return this; } return this.scrubbing_; }; /** * get or set the current time (in seconds) * ```js * // get * var whereyouat = myplayer.currenttime(); * // set * myplayer.currenttime(120); // 2 minutes into the video * ``` * * @param {number|string=} seconds the time to seek to * @return {number} the time in seconds, when not setting * @return {player} self, when the current time is set * @method currenttime */ player.prototype.currenttime = function currenttime(seconds) { if (seconds !== undefined) { this.techcall_('setcurrenttime', seconds); return this; } // cache last currenttime and return. default to 0 seconds // // caching the currenttime is meant to prevent a massive amount of reads on the tech's // currenttime when scrubbing, but may not provide much performance benefit afterall. // should be tested. also something has to read the actual current time or the cache will // never get updated. return this.cache_.currenttime = this.techget_('currenttime') || 0; }; /** * get the length in time of the video in seconds * ```js * var lengthofvideo = myplayer.duration(); * ``` * **note**: the video must have started loading before the duration can be * known, and in the case of flash, may not be known until the video starts * playing. * * @param {number} seconds duration when setting * @return {number} the duration of the video in seconds when getting * @method duration */ player.prototype.duration = function duration(seconds) { if (seconds === undefined) { return this.cache_.duration || 0; } seconds = parsefloat(seconds) || 0; // standardize on inifity for signaling video is live if (seconds < 0) { seconds = infinity; } if (seconds !== this.cache_.duration) { // cache the last set value for optimized scrubbing (esp. flash) this.cache_.duration = seconds; if (seconds === infinity) { this.addclass('vjs-live'); } else { this.removeclass('vjs-live'); } this.trigger('durationchange'); } return this; }; /** * calculates how much time is left. * ```js * var timeleft = myplayer.remainingtime(); * ``` * not a native video element function, but useful * * @return {number} the time remaining in seconds * @method remainingtime */ player.prototype.remainingtime = function remainingtime() { return this.duration() - this.currenttime(); }; // http://dev.w3.org/html5/spec/video.html#dom-media-buffered // buffered returns a timerange object. // kind of like an array of portions of the video that have been downloaded. /** * get a timerange object with the times of the video that have been downloaded * if you just want the percent of the video that's been downloaded, * use bufferedpercent. * ```js * // number of different ranges of time have been buffered. usually 1. * numberofranges = bufferedtimerange.length, * // time in seconds when the first range starts. usually 0. * firstrangestart = bufferedtimerange.start(0), * // time in seconds when the first range ends * firstrangeend = bufferedtimerange.end(0), * // length in seconds of the first time range * firstrangelength = firstrangeend - firstrangestart; * ``` * * @return {object} a mock timerange object (following html spec) * @method buffered */ player.prototype.buffered = function buffered() { var buffered = this.techget_('buffered'); if (!buffered || !buffered.length) { buffered = _utilstimerangesjs.createtimerange(0, 0); } return buffered; }; /** * get the percent (as a decimal) of the video that's been downloaded * ```js * var howmuchisdownloaded = myplayer.bufferedpercent(); * ``` * 0 means none, 1 means all. * (this method isn't in the html5 spec, but it's very convenient) * * @return {number} a decimal between 0 and 1 representing the percent * @method bufferedpercent */ player.prototype.bufferedpercent = function bufferedpercent() { return _utilsbufferjs.bufferedpercent(this.buffered(), this.duration()); }; /** * get the ending time of the last buffered time range * this is used in the progress bar to encapsulate all time ranges. * * @return {number} the end of the last buffered time range * @method bufferedend */ player.prototype.bufferedend = function bufferedend() { var buffered = this.buffered(), duration = this.duration(), end = buffered.end(buffered.length - 1); if (end > duration) { end = duration; } return end; }; /** * get or set the current volume of the media * ```js * // get * var howloudisit = myplayer.volume(); * // set * myplayer.volume(0.5); // set volume to half * ``` * 0 is off (muted), 1.0 is all the way up, 0.5 is half way. * * @param {number} percentasdecimal the new volume as a decimal percent * @return {number} the current volume when getting * @return {player} self when setting * @method volume */ player.prototype.volume = function volume(percentasdecimal) { var vol = undefined; if (percentasdecimal !== undefined) { vol = math.max(0, math.min(1, parsefloat(percentasdecimal))); // force value to between 0 and 1 this.cache_.volume = vol; this.techcall_('setvolume', vol); return this; } // default to 1 when returning current volume. vol = parsefloat(this.techget_('volume')); return isnan(vol) ? 1 : vol; }; /** * get the current muted state, or turn mute on or off * ```js * // get * var isvolumemuted = myplayer.muted(); * // set * myplayer.muted(true); // mute the volume * ``` * * @param {boolean=} muted true to mute, false to unmute * @return {boolean} true if mute is on, false if not when getting * @return {player} self when setting mute * @method muted */ player.prototype.muted = function muted(_muted) { if (_muted !== undefined) { this.techcall_('setmuted', _muted); return this; } return this.techget_('muted') || false; // default to false }; // check if current tech can support native fullscreen // (e.g. with built in controls like ios, so not our flash swf) /** * check to see if fullscreen is supported * * @return {boolean} * @method supportsfullscreen */ player.prototype.supportsfullscreen = function supportsfullscreen() { return this.techget_('supportsfullscreen') || false; }; /** * check if the player is in fullscreen mode * ```js * // get * var fullscreenornot = myplayer.isfullscreen(); * // set * myplayer.isfullscreen(true); // tell the player it's in fullscreen * ``` * note: as of the latest html5 spec, isfullscreen is no longer an official * property and instead document.fullscreenelement is used. but isfullscreen is * still a valuable property for internal player workings. * * @param {boolean=} isfs update the player's fullscreen state * @return {boolean} true if fullscreen false if not when getting * @return {player} self when setting * @method isfullscreen */ player.prototype.isfullscreen = function isfullscreen(isfs) { if (isfs !== undefined) { this.isfullscreen_ = !!isfs; return this; } return !!this.isfullscreen_; }; /** * increase the size of the video to full screen * ```js * myplayer.requestfullscreen(); * ``` * in some browsers, full screen is not supported natively, so it enters * "full window mode", where the video fills the browser window. * in browsers and devices that support native full screen, sometimes the * browser's default controls will be shown, and not the video.js custom skin. * this includes most mobile devices (ios, android) and older versions of * safari. * * @return {player} self * @method requestfullscreen */ player.prototype.requestfullscreen = function requestfullscreen() { var fsapi = _fullscreenapijs2['default']; this.isfullscreen(true); if (fsapi.requestfullscreen) { // the browser supports going fullscreen at the element level so we can // take the controls fullscreen as well as the video // trigger fullscreenchange event after change // we have to specifically add this each time, and remove // when canceling fullscreen. otherwise if there's multiple // players on a page, they would all be reacting to the same fullscreen // events events.on(_globaldocument2['default'], fsapi.fullscreenchange, fn.bind(this, function documentfullscreenchange(e) { this.isfullscreen(_globaldocument2['default'][fsapi.fullscreenelement]); // if cancelling fullscreen, remove event listener. if (this.isfullscreen() === false) { events.off(_globaldocument2['default'], fsapi.fullscreenchange, documentfullscreenchange); } this.trigger('fullscreenchange'); })); this.el_[fsapi.requestfullscreen](); } else if (this.tech_.supportsfullscreen()) { // we can't take the video.js controls fullscreen but we can go fullscreen // with native controls this.techcall_('enterfullscreen'); } else { // fullscreen isn't supported so we'll just stretch the video element to // fill the viewport this.enterfullwindow(); this.trigger('fullscreenchange'); } return this; }; /** * return the video to its normal size after having been in full screen mode * ```js * myplayer.exitfullscreen(); * ``` * * @return {player} self * @method exitfullscreen */ player.prototype.exitfullscreen = function exitfullscreen() { var fsapi = _fullscreenapijs2['default']; this.isfullscreen(false); // check for browser element fullscreen support if (fsapi.requestfullscreen) { _globaldocument2['default'][fsapi.exitfullscreen](); } else if (this.tech_.supportsfullscreen()) { this.techcall_('exitfullscreen'); } else { this.exitfullwindow(); this.trigger('fullscreenchange'); } return this; }; /** * when fullscreen isn't supported we can stretch the video container to as wide as the browser will let us. * * @method enterfullwindow */ player.prototype.enterfullwindow = function enterfullwindow() { this.isfullwindow = true; // storing original doc overflow value to return to when fullscreen is off this.docorigoverflow = _globaldocument2['default'].documentelement.style.overflow; // add listener for esc key to exit fullscreen events.on(_globaldocument2['default'], 'keydown', fn.bind(this, this.fullwindowonesckey)); // hide any scroll bars _globaldocument2['default'].documentelement.style.overflow = 'hidden'; // apply fullscreen styles dom.addelclass(_globaldocument2['default'].body, 'vjs-full-window'); this.trigger('enterfullwindow'); }; /** * check for call to either exit full window or full screen on esc key * * @param {string} event event to check for key press * @method fullwindowonesckey */ player.prototype.fullwindowonesckey = function fullwindowonesckey(event) { if (event.keycode === 27) { if (this.isfullscreen() === true) { this.exitfullscreen(); } else { this.exitfullwindow(); } } }; /** * exit full window * * @method exitfullwindow */ player.prototype.exitfullwindow = function exitfullwindow() { this.isfullwindow = false; events.off(_globaldocument2['default'], 'keydown', this.fullwindowonesckey); // unhide scroll bars. _globaldocument2['default'].documentelement.style.overflow = this.docorigoverflow; // remove fullscreen styles dom.removeelclass(_globaldocument2['default'].body, 'vjs-full-window'); // resize the box, controller, and poster to original sizes // this.positionall(); this.trigger('exitfullwindow'); }; /** * check whether the player can play a given mimetype * * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) * @method canplaytype */ player.prototype.canplaytype = function canplaytype(type) { var can = undefined; // loop through each playback technology in the options order for (var i = 0, j = this.options_.techorder; i < j.length; i++) { var techname = _utilstotitlecasejs2['default'](j[i]); var tech = _techtechjs2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!tech) { tech = _componentjs2['default'].getcomponent(techname); } // check if the current tech is defined before continuing if (!tech) { _utilslogjs2['default'].error('the "' + techname + '" tech is undefined. skipped browser support check for that tech.'); continue; } // check if the browser supports this technology if (tech.issupported()) { can = tech.canplaytype(type); if (can) { return can; } } } return ''; }; /** * select source based on tech-order or source-order * uses source-order selection if `options.sourceorder` is truthy. otherwise, * defaults to tech-order selection * * @param {array} sources the sources for a media asset * @return {object|boolean} object of source and tech order, otherwise false * @method selectsource */ player.prototype.selectsource = function selectsource(sources) { // get only the techs specified in `techorder` that exist and are supported by the // current platform var techs = this.options_.techorder.map(_utilstotitlecasejs2['default']).map(function (techname) { // `component.getcomponent(...)` is for support of old behavior of techs // being registered as components. // remove once that deprecated behavior is removed. return [techname, _techtechjs2['default'].gettech(techname) || _componentjs2['default'].getcomponent(techname)]; }).filter(function (_ref) { var techname = _ref[0]; var tech = _ref[1]; // check if the current tech is defined before continuing if (tech) { // check if the browser supports this technology return tech.issupported(); } _utilslogjs2['default'].error('the "' + techname + '" tech is undefined. skipped browser support check for that tech.'); return false; }); // iterate over each `innerarray` element once per `outerarray` element and execute // `tester` with both. if `tester` returns a non-falsy value, exit early and return // that value. var findfirstpassingtechsourcepair = function findfirstpassingtechsourcepair(outerarray, innerarray, tester) { var found = undefined; outerarray.some(function (outerchoice) { return innerarray.some(function (innerchoice) { found = tester(outerchoice, innerchoice); if (found) { return true; } }); }); return found; }; var foundsourceandtech = undefined; var flip = function flip(fn) { return function (a, b) { return fn(b, a); }; }; var finder = function finder(_ref2, source) { var techname = _ref2[0]; var tech = _ref2[1]; if (tech.canplaysource(source)) { return { source: source, tech: techname }; } }; // depending on the truthiness of `options.sourceorder`, we swap the order of techs and sources // to select from them based on their priority. if (this.options_.sourceorder) { // source-first ordering foundsourceandtech = findfirstpassingtechsourcepair(sources, techs, flip(finder)); } else { // tech-first ordering foundsourceandtech = findfirstpassingtechsourcepair(techs, sources, finder); } return foundsourceandtech || false; }; /** * the source function updates the video source * there are three types of variables you can pass as the argument. * **url string**: a url to the the video file. use this method if you are sure * the current playback technology (html5/flash) can support the source you * provide. currently only mp4 files can be used in both html5 and flash. * ```js * myplayer.src("http://www.example.com/path/to/video.mp4"); * ``` * **source object (or element):* * a javascript object containing information * about the source file. use this method if you want the player to determine if * it can support the file using the type information. * ```js * myplayer.src({ type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }); * ``` * **array of source objects:* * to provide multiple versions of the source so * that it can be played using html5 across browsers you can use an array of * source objects. video.js will detect which version is supported and load that * file. * ```js * myplayer.src([ * { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4" }, * { type: "video/webm", src: "http://www.example.com/path/to/video.webm" }, * { type: "video/ogg", src: "http://www.example.com/path/to/video.ogv" } * ]); * ``` * * @param {string|object|array=} source the source url, object, or array of sources * @return {string} the current video source when getting * @return {string} the player when setting * @method src */ player.prototype.src = function src(source) { if (source === undefined) { return this.techget_('src'); } var currenttech = _techtechjs2['default'].gettech(this.techname_); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!currenttech) { currenttech = _componentjs2['default'].getcomponent(this.techname_); } // case: array of source objects to choose from and pick the best to play if (array.isarray(source)) { this.sourcelist_(source); // case: url string (http://myvideo...) } else if (typeof source === 'string') { // create a source object from the string this.src({ src: source }); // case: source object { src: '', type: '' ... } } else if (source instanceof object) { // check if the source has a type and the loaded tech cannot play the source // if there's no type we'll just try the current tech if (source.type && !currenttech.canplaysource(source)) { // create a source list with the current source and send through // the tech loop to check for a compatible technology this.sourcelist_([source]); } else { this.cache_.src = source.src; this.currenttype_ = source.type || ''; // wait until the tech is ready to set the source this.ready(function () { // the setsource tech method was added with source handlers // so older techs won't support it // we need to check the direct prototype for the case where subclasses // of the tech do not support source handlers if (currenttech.prototype.hasownproperty('setsource')) { this.techcall_('setsource', source); } else { this.techcall_('src', source.src); } if (this.options_.preload === 'auto') { this.load(); } if (this.options_.autoplay) { this.play(); } // set the source synchronously if possible (#2326) }, true); } } return this; }; /** * handle an array of source objects * * @param {array} sources array of source objects * @private * @method sourcelist_ */ player.prototype.sourcelist_ = function sourcelist_(sources) { var sourcetech = this.selectsource(sources); if (sourcetech) { if (sourcetech.tech === this.techname_) { // if this technology is already loaded, set the source this.src(sourcetech.source); } else { // load this technology with the chosen source this.loadtech_(sourcetech.tech, sourcetech.source); } } else { // we need to wrap this in a timeout to give folks a chance to add error event handlers this.settimeout(function () { this.error({ code: 4, message: this.localize(this.options_.notsupportedmessage) }); }, 0); // we could not find an appropriate tech, but let's still notify the delegate that this is it // this needs a better comment about why this is needed this.triggerready(); } }; /** * begin loading the src data. * * @return {player} returns the player * @method load */ player.prototype.load = function load() { this.techcall_('load'); return this; }; /** * reset the player. loads the first tech in the techorder, * and calls `reset` on the tech`. * * @return {player} returns the player * @method reset */ player.prototype.reset = function reset() { this.loadtech_(_utilstotitlecasejs2['default'](this.options_.techorder[0]), null); this.techcall_('reset'); return this; }; /** * returns the fully qualified url of the current source value e.g. http://mysite.com/video.mp4 * can be used in conjuction with `currenttype` to assist in rebuilding the current source object. * * @return {string} the current source * @method currentsrc */ player.prototype.currentsrc = function currentsrc() { return this.techget_('currentsrc') || this.cache_.src || ''; }; /** * get the current source type e.g. video/mp4 * this can allow you rebuild the current source object so that you could load the same * source and tech later * * @return {string} the source mime type * @method currenttype */ player.prototype.currenttype = function currenttype() { return this.currenttype_ || ''; }; /** * get or set the preload attribute * * @param {boolean} value boolean to determine if preload should be used * @return {string} the preload attribute value when getting * @return {player} returns the player when setting * @method preload */ player.prototype.preload = function preload(value) { if (value !== undefined) { this.techcall_('setpreload', value); this.options_.preload = value; return this; } return this.techget_('preload'); }; /** * get or set the autoplay attribute. * * @param {boolean} value boolean to determine if video should autoplay * @return {string} the autoplay attribute value when getting * @return {player} returns the player when setting * @method autoplay */ player.prototype.autoplay = function autoplay(value) { if (value !== undefined) { this.techcall_('setautoplay', value); this.options_.autoplay = value; return this; } return this.techget_('autoplay', value); }; /** * get or set the loop attribute on the video element. * * @param {boolean} value boolean to determine if video should loop * @return {string} the loop attribute value when getting * @return {player} returns the player when setting * @method loop */ player.prototype.loop = function loop(value) { if (value !== undefined) { this.techcall_('setloop', value); this.options_['loop'] = value; return this; } return this.techget_('loop'); }; /** * get or set the poster image source url * * ##### example: * ```js * // get * var currentposter = myplayer.poster(); * // set * myplayer.poster('http://example.com/myimage.jpg'); * ``` * * @param {string=} src poster image source url * @return {string} poster url when getting * @return {player} self when setting * @method poster */ player.prototype.poster = function poster(src) { if (src === undefined) { return this.poster_; } // the correct way to remove a poster is to set as an empty string // other falsey values will throw errors if (!src) { src = ''; } // update the internal poster variable this.poster_ = src; // update the tech's poster this.techcall_('setposter', src); // alert components that the poster has been set this.trigger('posterchange'); return this; }; /** * some techs (e.g. youtube) can provide a poster source in an * asynchronous way. we want the poster component to use this * poster source so that it covers up the tech's controls. * (youtube's play button). however we only want to use this * soruce if the player user hasn't set a poster through * the normal apis. * * @private * @method handletechposterchange_ */ player.prototype.handletechposterchange_ = function handletechposterchange_() { if (!this.poster_ && this.tech_ && this.tech_.poster) { this.poster_ = this.tech_.poster() || ''; // let components know the poster has changed this.trigger('posterchange'); } }; /** * get or set whether or not the controls are showing. * * @param {boolean} bool set controls to showing or not * @return {boolean} controls are showing * @method controls */ player.prototype.controls = function controls(bool) { if (bool !== undefined) { bool = !!bool; // force boolean // don't trigger a change event unless it actually changed if (this.controls_ !== bool) { this.controls_ = bool; if (this.usingnativecontrols()) { this.techcall_('setcontrols', bool); } if (bool) { this.removeclass('vjs-controls-disabled'); this.addclass('vjs-controls-enabled'); this.trigger('controlsenabled'); if (!this.usingnativecontrols()) { this.addtechcontrolslisteners_(); } } else { this.removeclass('vjs-controls-enabled'); this.addclass('vjs-controls-disabled'); this.trigger('controlsdisabled'); if (!this.usingnativecontrols()) { this.removetechcontrolslisteners_(); } } } return this; } return !!this.controls_; }; /** * toggle native controls on/off. native controls are the controls built into * devices (e.g. default iphone controls), flash, or other techs * (e.g. vimeo controls) * **this should only be set by the current tech, because only the tech knows * if it can support native controls** * * @param {boolean} bool true signals that native controls are on * @return {player} returns the player * @private * @method usingnativecontrols */ player.prototype.usingnativecontrols = function usingnativecontrols(bool) { if (bool !== undefined) { bool = !!bool; // force boolean // don't trigger a change event unless it actually changed if (this.usingnativecontrols_ !== bool) { this.usingnativecontrols_ = bool; if (bool) { this.addclass('vjs-using-native-controls'); /** * player is using the native device controls * * @event usingnativecontrols * @memberof player * @instance * @private */ this.trigger('usingnativecontrols'); } else { this.removeclass('vjs-using-native-controls'); /** * player is using the custom html controls * * @event usingcustomcontrols * @memberof player * @instance * @private */ this.trigger('usingcustomcontrols'); } } return this; } return !!this.usingnativecontrols_; }; /** * set or get the current mediaerror * * @param {*} err a mediaerror or a string/number to be turned into a mediaerror * @return {mediaerror|null} when getting * @return {player} when setting * @method error */ player.prototype.error = function error(err) { if (err === undefined) { return this.error_ || null; } // restoring to default if (err === null) { this.error_ = err; this.removeclass('vjs-error'); this.errordisplay.close(); return this; } // error instance if (err instanceof _mediaerrorjs2['default']) { this.error_ = err; } else { this.error_ = new _mediaerrorjs2['default'](err); } // add the vjs-error classname to the player this.addclass('vjs-error'); // log the name of the error type and any message // ie8 just logs "[object object]" if you just log the error object _utilslogjs2['default'].error('(code:' + this.error_.code + ' ' + _mediaerrorjs2['default'].errortypes[this.error_.code] + ')', this.error_.message, this.error_); // fire an error event on the player this.trigger('error'); return this; }; /** * returns whether or not the player is in the "ended" state. * * @return {boolean} true if the player is in the ended state, false if not. * @method ended */ player.prototype.ended = function ended() { return this.techget_('ended'); }; /** * returns whether or not the player is in the "seeking" state. * * @return {boolean} true if the player is in the seeking state, false if not. * @method seeking */ player.prototype.seeking = function seeking() { return this.techget_('seeking'); }; /** * returns the timeranges of the media that are currently available * for seeking to. * * @return {timeranges} the seekable intervals of the media timeline * @method seekable */ player.prototype.seekable = function seekable() { return this.techget_('seekable'); }; /** * report user activity * * @param {object} event event object * @method reportuseractivity */ player.prototype.reportuseractivity = function reportuseractivity(event) { this.useractivity_ = true; }; /** * get/set if user is active * * @param {boolean} bool value when setting * @return {boolean} value if user is active user when getting * @method useractive */ player.prototype.useractive = function useractive(bool) { if (bool !== undefined) { bool = !!bool; if (bool !== this.useractive_) { this.useractive_ = bool; if (bool) { // if the user was inactive and is now active we want to reset the // inactivity timer this.useractivity_ = true; this.removeclass('vjs-user-inactive'); this.addclass('vjs-user-active'); this.trigger('useractive'); } else { // we're switching the state to inactive manually, so erase any other // activity this.useractivity_ = false; // chrome/safari/ie have bugs where when you change the cursor it can // trigger a mousemove event. this causes an issue when you're hiding // the cursor when the user is inactive, and a mousemove signals user // activity. making it impossible to go into inactive mode. specifically // this happens in fullscreen when we really need to hide the cursor. // // when this gets resolved in all browsers it can be removed // https://code.google.com/p/chromium/issues/detail?id=103041 if (this.tech_) { this.tech_.one('mousemove', function (e) { e.stoppropagation(); e.preventdefault(); }); } this.removeclass('vjs-user-active'); this.addclass('vjs-user-inactive'); this.trigger('userinactive'); } } return this; } return this.useractive_; }; /** * listen for user activity based on timeout value * * @private * @method listenforuseractivity_ */ player.prototype.listenforuseractivity_ = function listenforuseractivity_() { var mouseinprogress = undefined, lastmovex = undefined, lastmovey = undefined; var handleactivity = fn.bind(this, this.reportuseractivity); var handlemousemove = function handlemousemove(e) { // #1068 - prevent mousemove spamming // chrome bug: https://code.google.com/p/chromium/issues/detail?id=366970 if (e.screenx !== lastmovex || e.screeny !== lastmovey) { lastmovex = e.screenx; lastmovey = e.screeny; handleactivity(); } }; var handlemousedown = function handlemousedown() { handleactivity(); // for as long as the they are touching the device or have their mouse down, // we consider them active even if they're not moving their finger or mouse. // so we want to continue to update that they are active this.clearinterval(mouseinprogress); // setting useractivity=true now and setting the interval to the same time // as the activitycheck interval (250) should ensure we never miss the // next activitycheck mouseinprogress = this.setinterval(handleactivity, 250); }; var handlemouseup = function handlemouseup(event) { handleactivity(); // stop the interval that maintains activity if the mouse/touch is down this.clearinterval(mouseinprogress); }; // any mouse movement will be considered user activity this.on('mousedown', handlemousedown); this.on('mousemove', handlemousemove); this.on('mouseup', handlemouseup); // listen for keyboard navigation // shouldn't need to use inprogress interval because of key repeat this.on('keydown', handleactivity); this.on('keyup', handleactivity); // run an interval every 250 milliseconds instead of stuffing everything into // the mousemove/touchmove function itself, to prevent performance degradation. // `this.reportuseractivity` simply sets this.useractivity_ to true, which // then gets picked up by this loop // http://ejohn.org/blog/learning-from-twitter/ var inactivitytimeout = undefined; var activitycheck = this.setinterval(function () { // check to see if mouse/touch activity has happened if (this.useractivity_) { // reset the activity tracker this.useractivity_ = false; // if the user state was inactive, set the state to active this.useractive(true); // clear any existing inactivity timeout to start the timer over this.cleartimeout(inactivitytimeout); var timeout = this.options_['inactivitytimeout']; if (timeout > 0) { // in milliseconds, if no more activity has occurred the // user will be considered inactive inactivitytimeout = this.settimeout(function () { // protect against the case where the inactivitytimeout can trigger just // before the next user activity is picked up by the activitycheck loop // causing a flicker if (!this.useractivity_) { this.useractive(false); } }, timeout); } } }, 250); }; /** * gets or sets the current playback rate. a playback rate of * 1.0 represents normal speed and 0.5 would indicate half-speed * playback, for instance. * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate * * @param {number} rate new playback rate to set. * @return {number} returns the new playback rate when setting * @return {number} returns the current playback rate when getting * @method playbackrate */ player.prototype.playbackrate = function playbackrate(rate) { if (rate !== undefined) { this.techcall_('setplaybackrate', rate); return this; } if (this.tech_ && this.tech_['featuresplaybackrate']) { return this.techget_('playbackrate'); } else { return 1.0; } }; /** * gets or sets the audio flag * * @param {boolean} bool true signals that this is an audio player. * @return {boolean} returns true if player is audio, false if not when getting * @return {player} returns the player if setting * @private * @method isaudio */ player.prototype.isaudio = function isaudio(bool) { if (bool !== undefined) { this.isaudio_ = !!bool; return this; } return !!this.isaudio_; }; /** * returns the current state of network activity for the element, from * the codes in the list below. * - network_empty (numeric value 0) * the element has not yet been initialised. all attributes are in * their initial states. * - network_idle (numeric value 1) * the element's resource selection algorithm is active and has * selected a resource, but it is not actually using the network at * this time. * - network_loading (numeric value 2) * the user agent is actively trying to download data. * - network_no_source (numeric value 3) * the element's resource selection algorithm is active, but it has * not yet found a resource to use. * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states * @return {number} the current network activity state * @method networkstate */ player.prototype.networkstate = function networkstate() { return this.techget_('networkstate'); }; /** * returns a value that expresses the current state of the element * with respect to rendering the current playback position, from the * codes in the list below. * - have_nothing (numeric value 0) * no information regarding the media resource is available. * - have_metadata (numeric value 1) * enough of the resource has been obtained that the duration of the * resource is available. * - have_current_data (numeric value 2) * data for the immediate current playback position is available. * - have_future_data (numeric value 3) * data for the immediate current playback position is available, as * well as enough data for the user agent to advance the current * playback position in the direction of playback. * - have_enough_data (numeric value 4) * the user agent estimates that enough data is available for * playback to proceed uninterrupted. * * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate * @return {number} the current playback rendering state * @method readystate */ player.prototype.readystate = function readystate() { return this.techget_('readystate'); }; /** * text tracks are tracks of timed text events. * captions - text displayed over the video for the hearing impaired * subtitles - text displayed over the video for those who don't understand language in the video * chapters - text displayed in a menu allowing the user to jump to particular points (chapters) in the video * descriptions - audio descriptions that are read back to the user by a screen reading device */ /** * get an array of associated text tracks. captions, subtitles, chapters, descriptions * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks * * @return {array} array of track objects * @method texttracks */ player.prototype.texttracks = function texttracks() { // cannot use techget_ directly because it checks to see whether the tech is ready. // flash is unlikely to be ready in time but texttracks should still work. return this.tech_ && this.tech_['texttracks'](); }; /** * get an array of remote text tracks * * @return {array} * @method remotetexttracks */ player.prototype.remotetexttracks = function remotetexttracks() { return this.tech_ && this.tech_['remotetexttracks'](); }; /** * get an array of remote html track elements * * @return {htmltrackelement[]} * @method remotetexttrackels */ player.prototype.remotetexttrackels = function remotetexttrackels() { return this.tech_ && this.tech_['remotetexttrackels'](); }; /** * add a text track * in addition to the w3c settings we allow adding additional info through options. * http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack * * @param {string} kind captions, subtitles, chapters, descriptions, or metadata * @param {string=} label optional label * @param {string=} language optional language * @method addtexttrack */ player.prototype.addtexttrack = function addtexttrack(kind, label, language) { return this.tech_ && this.tech_['addtexttrack'](kind, label, language); }; /** * add a remote text track * * @param {object} options options for remote text track * @method addremotetexttrack */ player.prototype.addremotetexttrack = function addremotetexttrack(options) { return this.tech_ && this.tech_['addremotetexttrack'](options); }; /** * remove a remote text track * * @param {object} track remote text track to remove * @method removeremotetexttrack */ // destructure the input into an object with a track argument, defaulting to arguments[0] // default the whole argument to an empty object if nothing was passed in player.prototype.removeremotetexttrack = function removeremotetexttrack() { var _ref3 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var _ref3$track = _ref3.track; var track = _ref3$track === undefined ? arguments[0] : _ref3$track; // jshint ignore:line this.tech_ && this.tech_['removeremotetexttrack'](track); }; /** * get video width * * @return {number} video width * @method videowidth */ player.prototype.videowidth = function videowidth() { return this.tech_ && this.tech_.videowidth && this.tech_.videowidth() || 0; }; /** * get video height * * @return {number} video height * @method videoheight */ player.prototype.videoheight = function videoheight() { return this.tech_ && this.tech_.videoheight && this.tech_.videoheight() || 0; }; // methods to add support for // initialtime: function(){ return this.techcall_('initialtime'); }, // startoffsettime: function(){ return this.techcall_('startoffsettime'); }, // played: function(){ return this.techcall_('played'); }, // videotracks: function(){ return this.techcall_('videotracks'); }, // audiotracks: function(){ return this.techcall_('audiotracks'); }, // defaultplaybackrate: function(){ return this.techcall_('defaultplaybackrate'); }, // defaultmuted: function(){ return this.techcall_('defaultmuted'); } /** * the player's language code * note: the language should be set in the player options if you want the * the controls to be built with a specific language. changing the lanugage * later will not update controls text. * * @param {string} code the locale string * @return {string} the locale string when getting * @return {player} self when setting * @method language */ player.prototype.language = function language(code) { if (code === undefined) { return this.language_; } this.language_ = ('' + code).tolowercase(); return this; }; /** * get the player's language dictionary * merge every time, because a newly added plugin might call videojs.addlanguage() at any time * languages specified directly in the player options have precedence * * @return {array} array of languages * @method languages */ player.prototype.languages = function languages() { return _utilsmergeoptionsjs2['default'](player.prototype.options_.languages, this.languages_); }; /** * converts track info to json * * @return {object} json object of options * @method tojson */ player.prototype.tojson = function tojson() { var options = _utilsmergeoptionsjs2['default'](this.options_); var tracks = options.tracks; options.tracks = []; for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; // deep merge tracks and null out player so no circular references track = _utilsmergeoptionsjs2['default'](track); track.player = undefined; options.tracks[i] = track; } return options; }; /** * creates a simple modal dialog (an instance of the `modaldialog` * component) that immediately overlays the player with arbitrary * content and removes itself when closed. * * @param {string|function|element|array|null} content * same as `modaldialog#content`'s param of the same name. * * the most straight-forward usage is to provide a string or dom * element. * * @param {object} [options] * extra options which will be passed on to the `modaldialog`. * * @return {modaldialog} */ player.prototype.createmodal = function createmodal(content, options) { var player = this; options = options || {}; options.content = content || ''; var modal = new _modaldialog2['default'](player, options); player.addchild(modal); modal.on('dispose', function () { player.removechild(modal); }); return modal.open(); }; /** * gets tag settings * * @param {element} tag the player tag * @return {array} an array of sources and track objects * @static * @method gettagsettings */ player.gettagsettings = function gettagsettings(tag) { var baseoptions = { 'sources': [], 'tracks': [] }; var tagoptions = dom.getelattributes(tag); var datasetup = tagoptions['data-setup']; // check if data-setup attr exists. if (datasetup !== null) { // parse options json var _safeparsetuple = _safejsonparsetuple2['default'](datasetup || '{}'); var err = _safeparsetuple[0]; var data = _safeparsetuple[1]; if (err) { _utilslogjs2['default'].error(err); } _objectassign2['default'](tagoptions, data); } _objectassign2['default'](baseoptions, tagoptions); // get tag children settings if (tag.haschildnodes()) { var children = tag.childnodes; for (var i = 0, j = children.length; i < j; i++) { var child = children[i]; // change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ var childname = child.nodename.tolowercase(); if (childname === 'source') { baseoptions.sources.push(dom.getelattributes(child)); } else if (childname === 'track') { baseoptions.tracks.push(dom.getelattributes(child)); } } } return baseoptions; }; return player; })(_componentjs2['default']); player.players = {}; var navigator = _globalwindow2['default'].navigator; /* * player instance options, surfaced using options * options = player.prototype.options_ * make changes in options, not here. * * @type {object} * @private */ player.prototype.options_ = { // default order of fallback technology techorder: ['html5', 'flash'], // techorder: ['flash','html5'], html5: {}, flash: {}, // defaultvolume: 0.85, defaultvolume: 0.00, // the freakin seaguls are driving me crazy! // default inactivity timeout inactivitytimeout: 2000, // default playback rates playbackrates: [], // add playback rate selection by adding rates // 'playbackrates': [0.5, 1, 1.5, 2], // included control sets children: ['medialoader', 'posterimage', 'texttrackdisplay', 'loadingspinner', 'bigplaybutton', 'controlbar', 'errordisplay', 'texttracksettings'], language: _globaldocument2['default'].getelementsbytagname('html')[0].getattribute('lang') || navigator.languages && navigator.languages[0] || navigator.userlanguage || navigator.language || 'en', // locales and their language translations languages: {}, // default message to show when a video cannot be played. notsupportedmessage: 'no compatible source was found for this media.' }; /** * fired when the player has initial duration and dimension information * * @event loadedmetadata */ player.prototype.handleloadedmetadata_; /** * fired when the player has downloaded data at the current playback position * * @event loadeddata */ player.prototype.handleloadeddata_; /** * fired when the user is active, e.g. moves the mouse over the player * * @event useractive */ player.prototype.handleuseractive_; /** * fired when the user is inactive, e.g. a short delay after the last mouse move or control interaction * * @event userinactive */ player.prototype.handleuserinactive_; /** * fired when the current playback position has changed * * during playback this is fired every 15-250 milliseconds, depending on the * playback technology in use. * * @event timeupdate */ player.prototype.handletimeupdate_; /** * fired when video playback ends * * @event ended */ player.prototype.handletechended_; /** * fired when the volume changes * * @event volumechange */ player.prototype.handlevolumechange_; /** * fired when an error occurs * * @event error */ player.prototype.handleerror_; player.prototype.flexnotsupported_ = function () { var elem = _globaldocument2['default'].createelement('i'); // note: we don't actually use flexbasis (or flexorder), but it's one of the more // common flex features that we can rely on when checking for flex support. 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) */; }; _componentjs2['default'].registercomponent('player', player); exports['default'] = player; module.exports = exports['default']; // if empty string, make it a parsable json object. },{"./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){ /** * @file plugins.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _playerjs = _dereq_('./player.js'); var _playerjs2 = _interoprequiredefault(_playerjs); /** * the method for registering a video.js plugin * * @param {string} name the name of the plugin * @param {function} init the function that is run when the player inits * @method plugin */ var plugin = function plugin(name, init) { _playerjs2['default'].prototype[name] = init; }; exports['default'] = plugin; module.exports = exports['default']; },{"./player.js":110}],112:[function(_dereq_,module,exports){ /** * @file popup-button.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _clickablecomponentjs = _dereq_('../clickable-component.js'); var _clickablecomponentjs2 = _interoprequiredefault(_clickablecomponentjs); var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _popupjs = _dereq_('./popup.js'); var _popupjs2 = _interoprequiredefault(_popupjs); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilstotitlecasejs = _dereq_('../utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); /** * a button class with a popup control * * @param {player|object} player * @param {object=} options * @extends clickablecomponent * @class popupbutton */ var popupbutton = (function (_clickablecomponent) { _inherits(popupbutton, _clickablecomponent); function popupbutton(player) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classcallcheck(this, popupbutton); _clickablecomponent.call(this, player, options); this.update(); } /** * update popup * * @method update */ popupbutton.prototype.update = function update() { var popup = this.createpopup(); if (this.popup) { this.removechild(this.popup); } this.popup = popup; this.addchild(popup); if (this.items && this.items.length === 0) { this.hide(); } else if (this.items && this.items.length > 1) { this.show(); } }; /** * create popup - override with specific functionality for component * * @return {popup} the constructed popup * @method createpopup */ popupbutton.prototype.createpopup = function createpopup() {}; /** * create the component's dom element * * @return {element} * @method createel */ popupbutton.prototype.createel = function createel() { return _clickablecomponent.prototype.createel.call(this, 'div', { classname: this.buildcssclass() }); }; /** * allow sub components to stack css class names * * @return {string} the constructed class name * @method buildcssclass */ popupbutton.prototype.buildcssclass = function buildcssclass() { var menubuttonclass = 'vjs-menu-button'; // if the inline option is passed, we want to use different styles altogether. if (this.options_.inline === true) { menubuttonclass += '-inline'; } else { menubuttonclass += '-popup'; } return 'vjs-menu-button ' + menubuttonclass + ' ' + _clickablecomponent.prototype.buildcssclass.call(this); }; return popupbutton; })(_clickablecomponentjs2['default']); _componentjs2['default'].registercomponent('popupbutton', popupbutton); exports['default'] = popupbutton; module.exports = exports['default']; },{"../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){ /** * @file popup.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilseventsjs = _dereq_('../utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); /** * the popup component is used to build pop up controls. * * @extends component * @class popup */ var popup = (function (_component) { _inherits(popup, _component); function popup() { _classcallcheck(this, popup); _component.apply(this, arguments); } /** * add a popup item to the popup * * @param {object|string} component component or component type to add * @method additem */ popup.prototype.additem = function additem(component) { this.addchild(component); component.on('click', fn.bind(this, function () { this.unlockshowing(); })); }; /** * create the component's dom element * * @return {element} * @method createel */ popup.prototype.createel = function createel() { var contenteltype = this.options_.contenteltype || 'ul'; this.contentel_ = dom.createel(contenteltype, { classname: 'vjs-menu-content' }); var el = _component.prototype.createel.call(this, 'div', { append: this.contentel_, classname: 'vjs-menu' }); el.appendchild(this.contentel_); // prevent clicks from bubbling up. needed for popup buttons, // where a click on the parent is significant events.on(el, 'click', function (event) { event.preventdefault(); event.stopimmediatepropagation(); }); return el; }; return popup; })(_componentjs2['default']); _componentjs2['default'].registercomponent('popup', popup); exports['default'] = popup; module.exports = exports['default']; },{"../component.js":67,"../utils/dom.js":134,"../utils/events.js":135,"../utils/fn.js":136}],114:[function(_dereq_,module,exports){ /** * @file poster-image.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _clickablecomponentjs = _dereq_('./clickable-component.js'); var _clickablecomponentjs2 = _interoprequiredefault(_clickablecomponentjs); var _componentjs = _dereq_('./component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsdomjs = _dereq_('./utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsbrowserjs = _dereq_('./utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); /** * the component that handles showing the poster image. * * @param {player|object} player * @param {object=} options * @extends button * @class posterimage */ var posterimage = (function (_clickablecomponent) { _inherits(posterimage, _clickablecomponent); function posterimage(player, options) { _classcallcheck(this, posterimage); _clickablecomponent.call(this, player, options); this.update(); player.on('posterchange', fn.bind(this, this.update)); } /** * clean up the poster image * * @method dispose */ posterimage.prototype.dispose = function dispose() { this.player().off('posterchange', this.update); _clickablecomponent.prototype.dispose.call(this); }; /** * create the poster's image element * * @return {element} * @method createel */ posterimage.prototype.createel = function createel() { var el = dom.createel('div', { classname: 'vjs-poster', // don't want poster to be tabbable. tabindex: -1 }); // to ensure the poster image resizes while maintaining its original aspect // ratio, use a div with `background-size` when available. for browsers that // do not support `background-size` (e.g. ie8), fall back on using a regular // img element. if (!browser.background_size_supported) { this.fallbackimg_ = dom.createel('img'); el.appendchild(this.fallbackimg_); } return el; }; /** * event handler for updates to the player's poster source * * @method update */ posterimage.prototype.update = function update() { var url = this.player().poster(); this.setsrc(url); // if there's no poster source we should display:none on this component // so it's not still clickable or right-clickable if (url) { this.show(); } else { this.hide(); } }; /** * set the poster source depending on the display method * * @param {string} url the url to the poster source * @method setsrc */ posterimage.prototype.setsrc = function setsrc(url) { if (this.fallbackimg_) { this.fallbackimg_.src = url; } else { var backgroundimage = ''; // any falsey values should stay as an empty string, otherwise // this will throw an extra error if (url) { backgroundimage = 'url("' + url + '")'; } this.el_.style.backgroundimage = backgroundimage; } }; /** * event handler for clicks on the poster image * * @method handleclick */ posterimage.prototype.handleclick = function handleclick() { // we don't want a click to trigger playback when controls are disabled // but css should be hiding the poster to prevent that from happening if (this.player_.paused()) { this.player_.play(); } else { this.player_.pause(); } }; return posterimage; })(_clickablecomponentjs2['default']); _componentjs2['default'].registercomponent('posterimage', posterimage); exports['default'] = posterimage; module.exports = exports['default']; },{"./clickable-component.js":65,"./component.js":67,"./utils/browser.js":131,"./utils/dom.js":134,"./utils/fn.js":136}],115:[function(_dereq_,module,exports){ /** * @file setup.js * * functions for automatically setting up a player * based on the data-setup attribute of the video tag */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _windowloaded = false; var videojs = undefined; // automatically set up any tags that have a data-setup attribute var autosetup = function autosetup() { // one day, when we stop supporting ie8, go back to this, but in the meantime...*hack hack hack* // var vids = array.prototype.slice.call(document.getelementsbytagname('video')); // var audios = array.prototype.slice.call(document.getelementsbytagname('audio')); // var mediaels = vids.concat(audios); // because ie8 doesn't support calling slice on a node list, we need to loop through each list of elements // to build up a new, combined list of elements. var vids = _globaldocument2['default'].getelementsbytagname('video'); var audios = _globaldocument2['default'].getelementsbytagname('audio'); var mediaels = []; if (vids && vids.length > 0) { for (var i = 0, e = vids.length; i < e; i++) { mediaels.push(vids[i]); } } if (audios && audios.length > 0) { for (var i = 0, e = audios.length; i < e; i++) { mediaels.push(audios[i]); } } // check if any media elements exist if (mediaels && mediaels.length > 0) { for (var i = 0, e = mediaels.length; i < e; i++) { var mediael = mediaels[i]; // check if element exists, has getattribute func. // ie seems to consider typeof el.getattribute == 'object' instead of 'function' like expected, at least when loading the player immediately. if (mediael && mediael.getattribute) { // make sure this player hasn't already been set up. if (mediael['player'] === undefined) { var options = mediael.getattribute('data-setup'); // check if data-setup attr exists. // we only auto-setup if they've added the data-setup attr. if (options !== null) { // create new video.js instance. var player = videojs(mediael); } } // if getattribute isn't defined, we need to wait for the dom. } else { autosetuptimeout(1); break; } } // no videos were found, so keep looping unless page is finished loading. } else if (!_windowloaded) { autosetuptimeout(1); } }; // pause to let the dom keep processing var autosetuptimeout = function autosetuptimeout(wait, vjs) { if (vjs) { videojs = vjs; } settimeout(autosetup, wait); }; if (_globaldocument2['default'].readystate === 'complete') { _windowloaded = true; } else { events.one(_globalwindow2['default'], 'load', function () { _windowloaded = true; }); } var hasloaded = function hasloaded() { return _windowloaded; }; exports.autosetup = autosetup; exports.autosetuptimeout = autosetuptimeout; exports.hasloaded = hasloaded; },{"./utils/events.js":135,"global/document":1,"global/window":2}],116:[function(_dereq_,module,exports){ /** * @file slider.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); /** * the base functionality for sliders like the volume bar and seek bar * * @param {player|object} player * @param {object=} options * @extends component * @class slider */ var slider = (function (_component) { _inherits(slider, _component); function slider(player, options) { _classcallcheck(this, slider); _component.call(this, player, options); // set property names to bar to match with the child slider class is looking for this.bar = this.getchild(this.options_.barname); // set a horizontal or vertical class on the slider depending on the slider type this.vertical(!!this.options_.vertical); this.on('mousedown', this.handlemousedown); this.on('touchstart', this.handlemousedown); this.on('focus', this.handlefocus); this.on('blur', this.handleblur); this.on('click', this.handleclick); this.on(player, 'controlsvisible', this.update); this.on(player, this.playerevent, this.update); } /** * create the component's dom element * * @param {string} type type of element to create * @param {object=} props list of properties in object form * @return {element} * @method createel */ slider.prototype.createel = function createel(type) { var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; // add the slider element class to all sub classes props.classname = props.classname + ' vjs-slider'; props = _objectassign2['default']({ tabindex: 0 }, props); attributes = _objectassign2['default']({ 'role': 'slider', 'aria-valuenow': 0, 'aria-valuemin': 0, 'aria-valuemax': 100, tabindex: 0 }, attributes); return _component.prototype.createel.call(this, type, props, attributes); }; /** * handle mouse down on slider * * @param {object} event mouse down event object * @method handlemousedown */ slider.prototype.handlemousedown = function handlemousedown(event) { var doc = this.bar.el_.ownerdocument; event.preventdefault(); dom.blocktextselection(); this.addclass('vjs-sliding'); this.trigger('slideractive'); this.on(doc, 'mousemove', this.handlemousemove); this.on(doc, 'mouseup', this.handlemouseup); this.on(doc, 'touchmove', this.handlemousemove); this.on(doc, 'touchend', this.handlemouseup); this.handlemousemove(event); }; /** * to be overridden by a subclass * * @method handlemousemove */ slider.prototype.handlemousemove = function handlemousemove() {}; /** * handle mouse up on slider * * @method handlemouseup */ slider.prototype.handlemouseup = function handlemouseup() { var doc = this.bar.el_.ownerdocument; dom.unblocktextselection(); this.removeclass('vjs-sliding'); this.trigger('sliderinactive'); this.off(doc, 'mousemove', this.handlemousemove); this.off(doc, 'mouseup', this.handlemouseup); this.off(doc, 'touchmove', this.handlemousemove); this.off(doc, 'touchend', this.handlemouseup); this.update(); }; /** * update slider * * @method update */ slider.prototype.update = function update() { // in volumebar init we have a settimeout for update that pops and update to the end of the // execution stack. the player is destroyed before then update will cause an error if (!this.el_) return; // if scrubbing, we could use a cached value to make the handle keep up with the user's mouse. // on html5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later. // var progress = (this.player_.scrubbing()) ? this.player_.getcache().currenttime / this.player_.duration() : this.player_.currenttime() / this.player_.duration(); var progress = this.getpercent(); var bar = this.bar; // if there's no bar... if (!bar) return; // protect against no duration and other division issues if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === infinity) { progress = 0; } // convert to a percentage for setting var percentage = (progress * 100).tofixed(2) + '%'; // set the new bar width or height if (this.vertical()) { bar.el().style.height = percentage; } else { bar.el().style.width = percentage; } }; /** * calculate distance for slider * * @param {object} event event object * @method calculatedistance */ slider.prototype.calculatedistance = function calculatedistance(event) { var position = dom.getpointerposition(this.el_, event); if (this.vertical()) { return position.y; } return position.x; }; /** * handle on focus for slider * * @method handlefocus */ slider.prototype.handlefocus = function handlefocus() { this.on(this.bar.el_.ownerdocument, 'keydown', this.handlekeypress); }; /** * handle key press for slider * * @param {object} event event object * @method handlekeypress */ slider.prototype.handlekeypress = function handlekeypress(event) { if (event.which === 37 || event.which === 40) { // left and down arrows event.preventdefault(); this.stepback(); } else if (event.which === 38 || event.which === 39) { // up and right arrows event.preventdefault(); this.stepforward(); } }; /** * handle on blur for slider * * @method handleblur */ slider.prototype.handleblur = function handleblur() { this.off(this.bar.el_.ownerdocument, 'keydown', this.handlekeypress); }; /** * listener for click events on slider, used to prevent clicks * from bubbling up to parent elements like button menus. * * @param {object} event event object * @method handleclick */ slider.prototype.handleclick = function handleclick(event) { event.stopimmediatepropagation(); event.preventdefault(); }; /** * get/set if slider is horizontal for vertical * * @param {boolean} bool true if slider is vertical, false is horizontal * @return {boolean} true if slider is vertical, false is horizontal * @method vertical */ slider.prototype.vertical = function vertical(bool) { if (bool === undefined) { return this.vertical_ || false; } this.vertical_ = !!bool; if (this.vertical_) { this.addclass('vjs-slider-vertical'); } else { this.addclass('vjs-slider-horizontal'); } return this; }; return slider; })(_componentjs2['default']); _componentjs2['default'].registercomponent('slider', slider); exports['default'] = slider; module.exports = exports['default']; },{"../component.js":67,"../utils/dom.js":134,"object.assign":45}],117:[function(_dereq_,module,exports){ /** * @file flash-rtmp.js */ 'use strict'; exports.__esmodule = true; function flashrtmpdecorator(flash) { flash.streamingformats = { 'rtmp/mp4': 'mp4', 'rtmp/flv': 'flv' }; flash.streamfromparts = function (connection, stream) { return connection + '&' + stream; }; flash.streamtoparts = function (src) { var parts = { connection: '', stream: '' }; if (!src) return parts; // look for the normal url separator we expect, '&'. // if found, we split the url into two pieces around the // first '&'. var connend = src.search(/&(?!\w+=)/); var streambegin = undefined; if (connend !== -1) { streambegin = connend + 1; } else { // if there's not a '&', we use the last '/' as the delimiter. connend = streambegin = src.lastindexof('/') + 1; if (connend === 0) { // really, there's not a '/'? connend = streambegin = src.length; } } parts.connection = src.substring(0, connend); parts.stream = src.substring(streambegin, src.length); return parts; }; flash.isstreamingtype = function (srctype) { return srctype in flash.streamingformats; }; // rtmp has four variations, any string starting // with one of these protocols should be valid flash.rtmp_re = /^rtmp[set]?:\/\//i; flash.isstreamingsrc = function (src) { return flash.rtmp_re.test(src); }; /** * a source handler for rtmp urls * @type {object} */ flash.rtmpsourcehandler = {}; /** * check if flash can play the given videotype * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) */ flash.rtmpsourcehandler.canplaytype = function (type) { if (flash.isstreamingtype(type)) { return 'maybe'; } return ''; }; /** * check if flash can handle the source natively * @param {object} source the source object * @return {string} 'probably', 'maybe', or '' (empty string) */ flash.rtmpsourcehandler.canhandlesource = function (source) { var can = flash.rtmpsourcehandler.canplaytype(source.type); if (can) { return can; } if (flash.isstreamingsrc(source.src)) { return 'maybe'; } return ''; }; /** * pass the source to the flash object * adaptive source handlers will have more complicated workflows before passing * video data to the video element * @param {object} source the source object * @param {flash} tech the instance of the flash tech */ flash.rtmpsourcehandler.handlesource = function (source, tech) { var srcparts = flash.streamtoparts(source.src); tech['setrtmpconnection'](srcparts.connection); tech['setrtmpstream'](srcparts.stream); }; // register the native source handler flash.registersourcehandler(flash.rtmpsourcehandler); return flash; } exports['default'] = flashrtmpdecorator; module.exports = exports['default']; },{}],118:[function(_dereq_,module,exports){ /** * @file flash.js * videojs-swf - custom flash player with html5-ish api * https://github.com/zencoder/video-js-swf * not using setuptriggers. using global onevent func to distribute events */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _tech = _dereq_('./tech'); var _tech2 = _interoprequiredefault(_tech); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsurljs = _dereq_('../utils/url.js'); var url = _interoprequirewildcard(_utilsurljs); var _utilstimerangesjs = _dereq_('../utils/time-ranges.js'); var _flashrtmp = _dereq_('./flash-rtmp'); var _flashrtmp2 = _interoprequiredefault(_flashrtmp); var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); var navigator = _globalwindow2['default'].navigator; /** * flash media controller - wrapper for fallback swf api * * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends tech * @class flash */ var flash = (function (_tech) { _inherits(flash, _tech); function flash(options, ready) { _classcallcheck(this, flash); _tech.call(this, options, ready); // set the source when ready if (options.source) { this.ready(function () { this.setsource(options.source); }, true); } // having issues with flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers // this allows resetting the playhead when we catch the reload if (options.starttime) { this.ready(function () { this.load(); this.play(); this.currenttime(options.starttime); }, true); } // add global window functions that the swf expects // a 4.x workflow we weren't able to solve for in 5.0 // because of the need to hard code these functions // into the swf for security reasons _globalwindow2['default'].videojs = _globalwindow2['default'].videojs || {}; _globalwindow2['default'].videojs.flash = _globalwindow2['default'].videojs.flash || {}; _globalwindow2['default'].videojs.flash.onready = flash.onready; _globalwindow2['default'].videojs.flash.onevent = flash.onevent; _globalwindow2['default'].videojs.flash.onerror = flash.onerror; this.on('seeked', function () { this.lastseektarget_ = undefined; }); } // create setters and getters for attributes /** * create the component's dom element * * @return {element} * @method createel */ flash.prototype.createel = function createel() { var options = this.options_; // if video.js is hosted locally you should also set the location // for the hosted swf, which should be relative to the page (not video.js) // otherwise this adds a cdn url. // the cdn also auto-adds a swf url for that specific version. if (!options.swf) { options.swf = '//vjs.zencdn.net/swf/5.0.1/video-js.swf'; } // generate id for swf object var objid = options.techid; // merge default flashvars with ones passed in to init var flashvars = _objectassign2['default']({ // swf callback functions 'readyfunction': 'videojs.flash.onready', 'eventproxyfunction': 'videojs.flash.onevent', 'erroreventproxyfunction': 'videojs.flash.onerror', // player settings 'autoplay': options.autoplay, 'preload': options.preload, 'loop': options.loop, 'muted': options.muted }, options.flashvars); // merge default parames with ones passed in var params = _objectassign2['default']({ 'wmode': 'opaque', // opaque is needed to overlay controls, but can affect playback performance 'bgcolor': '#000000' // using bgcolor prevents a white flash when the object is loading }, options.params); // merge default attributes with ones passed in var attributes = _objectassign2['default']({ 'id': objid, 'name': objid, // both id and name needed or swf to identify itself 'class': 'vjs-tech' }, options.attributes); this.el_ = flash.embed(options.swf, flashvars, params, attributes); this.el_.tech = this; return this.el_; }; /** * play for flash tech * * @method play */ flash.prototype.play = function play() { if (this.ended()) { this.setcurrenttime(0); } this.el_.vjs_play(); }; /** * pause for flash tech * * @method pause */ flash.prototype.pause = function pause() { this.el_.vjs_pause(); }; /** * get/set video * * @param {object=} src source object * @return {object} * @method src */ flash.prototype.src = function src(_src) { if (_src === undefined) { return this.currentsrc(); } // setting src through `src` not `setsrc` will be deprecated return this.setsrc(_src); }; /** * set video * * @param {object=} src source object * @deprecated * @method setsrc */ flash.prototype.setsrc = function setsrc(src) { // make sure source url is absolute. src = url.getabsoluteurl(src); this.el_.vjs_src(src); // currently the swf doesn't autoplay if you load a source later. // e.g. load player w/ no source, wait 2s, set src. if (this.autoplay()) { var tech = this; this.settimeout(function () { tech.play(); }, 0); } }; /** * returns true if the tech is currently seeking. * @return {boolean} true if seeking */ flash.prototype.seeking = function seeking() { return this.lastseektarget_ !== undefined; }; /** * set current time * * @param {number} time current time of video * @method setcurrenttime */ flash.prototype.setcurrenttime = function setcurrenttime(time) { var seekable = this.seekable(); if (seekable.length) { // clamp to the current seekable range time = time > seekable.start(0) ? time : seekable.start(0); time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); this.lastseektarget_ = time; this.trigger('seeking'); this.el_.vjs_setproperty('currenttime', time); _tech.prototype.setcurrenttime.call(this); } }; /** * get current time * * @param {number=} time current time of video * @return {number} current time * @method currenttime */ flash.prototype.currenttime = function currenttime(time) { // when seeking make the reported time keep up with the requested time // by reading the time we're seeking to if (this.seeking()) { return this.lastseektarget_ || 0; } return this.el_.vjs_getproperty('currenttime'); }; /** * get current source * * @method currentsrc */ flash.prototype.currentsrc = function currentsrc() { if (this.currentsource_) { return this.currentsource_.src; } else { return this.el_.vjs_getproperty('currentsrc'); } }; /** * load media into player * * @method load */ flash.prototype.load = function load() { this.el_.vjs_load(); }; /** * get poster * * @method poster */ flash.prototype.poster = function poster() { this.el_.vjs_getproperty('poster'); }; /** * poster images are not handled by the flash tech so make this a no-op * * @method setposter */ flash.prototype.setposter = function setposter() {}; /** * determine if can seek in media * * @return {timerangeobject} * @method seekable */ flash.prototype.seekable = function seekable() { var duration = this.duration(); if (duration === 0) { return _utilstimerangesjs.createtimerange(); } return _utilstimerangesjs.createtimerange(0, duration); }; /** * get buffered time range * * @return {timerangeobject} * @method buffered */ flash.prototype.buffered = function buffered() { var ranges = this.el_.vjs_getproperty('buffered'); if (ranges.length === 0) { return _utilstimerangesjs.createtimerange(); } return _utilstimerangesjs.createtimerange(ranges[0][0], ranges[0][1]); }; /** * get fullscreen support - * flash does not allow fullscreen through javascript * so always returns false * * @return {boolean} false * @method supportsfullscreen */ flash.prototype.supportsfullscreen = function supportsfullscreen() { return false; // flash does not allow fullscreen through javascript }; /** * request to enter fullscreen * flash does not allow fullscreen through javascript * so always returns false * * @return {boolean} false * @method enterfullscreen */ flash.prototype.enterfullscreen = function enterfullscreen() { return false; }; return flash; })(_tech2['default']); var _api = flash.prototype; var _readwrite = 'rtmpconnection,rtmpstream,preload,defaultplaybackrate,playbackrate,autoplay,loop,mediagroup,controller,controls,volume,muted,defaultmuted'.split(','); var _readonly = 'networkstate,readystate,initialtime,duration,startoffsettime,paused,ended,videotracks,audiotracks,videowidth,videoheight'.split(','); function _createsetter(attr) { var attrupper = attr.charat(0).touppercase() + attr.slice(1); _api['set' + attrupper] = function (val) { return this.el_.vjs_setproperty(attr, val); }; } function _creategetter(attr) { _api[attr] = function () { return this.el_.vjs_getproperty(attr); }; } // create getter and setters for all read/write attributes for (var i = 0; i < _readwrite.length; i++) { _creategetter(_readwrite[i]); _createsetter(_readwrite[i]); } // create getters for read-only attributes for (var i = 0; i < _readonly.length; i++) { _creategetter(_readonly[i]); } /* flash support testing -------------------------------------------------------- */ flash.issupported = function () { return flash.version()[0] >= 10; // return swfobject.hasflashplayerversion('10'); }; // add source handler pattern functions to this tech _tech2['default'].withsourcehandlers(flash); /* * the default native source handler. * this simply passes the source to the video element. nothing fancy. * * @param {object} source the source object * @param {flash} tech the instance of the flash tech */ flash.nativesourcehandler = {}; /** * check if flash can play the given videotype * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) */ flash.nativesourcehandler.canplaytype = function (type) { if (type in flash.formats) { return 'maybe'; } return ''; }; /* * check flash can handle the source natively * * @param {object} source the source object * @return {string} 'probably', 'maybe', or '' (empty string) */ flash.nativesourcehandler.canhandlesource = function (source) { var type; function guessmimetype(src) { var ext = url.getfileextension(src); if (ext) { return 'video/' + ext; } return ''; } if (!source.type) { type = guessmimetype(source.src); } else { // strip code information from the type because we don't get that specific type = source.type.replace(/;.*/, '').tolowercase(); } return flash.nativesourcehandler.canplaytype(type); }; /* * pass the source to the flash object * adaptive source handlers will have more complicated workflows before passing * video data to the video element * * @param {object} source the source object * @param {flash} tech the instance of the flash tech */ flash.nativesourcehandler.handlesource = function (source, tech) { tech.setsrc(source.src); }; /* * clean up the source handler when disposing the player or switching sources.. * (no cleanup is needed when supporting the format natively) */ flash.nativesourcehandler.dispose = function () {}; // register the native source handler flash.registersourcehandler(flash.nativesourcehandler); flash.formats = { 'video/flv': 'flv', 'video/x-flv': 'flv', 'video/mp4': 'mp4', 'video/m4v': 'mp4' }; flash.onready = function (currswf) { var el = dom.getel(currswf); var tech = el && el.tech; // if there is no el then the tech has been disposed // and the tech element was removed from the player div if (tech && tech.el()) { // check that the flash object is really ready flash.checkready(tech); } }; // the swf isn't always ready when it says it is. sometimes the api functions still need to be added to the object. // if it's not ready, we set a timeout to check again shortly. flash.checkready = function (tech) { // stop worrying if the tech has been disposed if (!tech.el()) { return; } // check if api property exists if (tech.el().vjs_getproperty) { // tell tech it's ready tech.triggerready(); } else { // wait longer this.settimeout(function () { flash['checkready'](tech); }, 50); } }; // trigger events from the swf on the player flash.onevent = function (swfid, eventname) { var tech = dom.getel(swfid).tech; tech.trigger(eventname); }; // log errors from the swf flash.onerror = function (swfid, err) { var tech = dom.getel(swfid).tech; // trigger media_err_src_not_supported if (err === 'srcnotfound') { return tech.error(4); } // trigger a custom error tech.error('flash: ' + err); }; // flash version check flash.version = function () { var version = '0,0,0'; // ie try { version = new _globalwindow2['default'].activexobject('shockwaveflash.shockwaveflash').getvariable('$version').replace(/\d+/g, ',').match(/^,?(.+),?$/)[1]; // other browsers } catch (e) { try { if (navigator.mimetypes['application/x-shockwave-flash'].enabledplugin) { version = (navigator.plugins['shockwave flash 2.0'] || navigator.plugins['shockwave flash']).description.replace(/\d+/g, ',').match(/^,?(.+),?$/)[1]; } } catch (err) {} } return version.split(','); }; // flash embedding method. only used in non-iframe mode flash.embed = function (swf, flashvars, params, attributes) { var code = flash.getembedcode(swf, flashvars, params, attributes); // get element by embedding code and retrieving created element var obj = dom.createel('div', { innerhtml: code }).childnodes[0]; return obj; }; flash.getembedcode = function (swf, flashvars, params, attributes) { var objtag = ''; }); attributes = _objectassign2['default']({ // add swf to attributes (need both for ie and others to work) 'data': swf, // default to 100% width/height 'width': '100%', 'height': '100%' }, attributes); // create attributes string object.getownpropertynames(attributes).foreach(function (key) { attrsstring += key + '="' + attributes[key] + '" '; }); return '' + objtag + attrsstring + '>' + paramsstring + ''; }; // run flash through the rtmp decorator _flashrtmp2['default'](flash); _component2['default'].registercomponent('flash', flash); _tech2['default'].registertech('flash', flash); exports['default'] = flash; module.exports = exports['default']; },{"../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){ /** * @file html5.js * html5 media controller - wrapper for html5 media api */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _techjs = _dereq_('./tech.js'); var _techjs2 = _interoprequiredefault(_techjs); var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _utilsdomjs = _dereq_('../utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsurljs = _dereq_('../utils/url.js'); var url = _interoprequirewildcard(_utilsurljs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilslogjs = _dereq_('../utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); var _utilsmergeoptionsjs = _dereq_('../utils/merge-options.js'); var _utilsmergeoptionsjs2 = _interoprequiredefault(_utilsmergeoptionsjs); /** * html5 media controller - wrapper for html5 media api * * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends tech * @class html5 */ var html5 = (function (_tech) { _inherits(html5, _tech); function html5(options, ready) { _classcallcheck(this, html5); _tech.call(this, options, ready); var source = options.source; // set the source if one is provided // 1) check if the source is new (if not, we want to keep the original so playback isn't interrupted) // 2) check to see if the network state of the tag was failed at init, and if so, reset the source // anyway so the error gets fired. if (source && (this.el_.currentsrc !== source.src || options.tag && options.tag.initnetworkstate_ === 3)) { this.setsource(source); } else { this.handlelateinit_(this.el_); } if (this.el_.haschildnodes()) { var nodes = this.el_.childnodes; var nodeslength = nodes.length; var removenodes = []; while (nodeslength--) { var node = nodes[nodeslength]; var nodename = node.nodename.tolowercase(); if (nodename === 'track') { if (!this.featuresnativetexttracks) { // empty video tag tracks so the built-in player doesn't use them also. // this may not be fast enough to stop html5 browsers from reading the tags // so we'll need to turn off any default tracks if we're manually doing // captions and subtitles. videoelement.texttracks removenodes.push(node); } else { // store htmltrackelement and texttrack to remote list this.remotetexttrackels().addtrackelement_(node); this.remotetexttracks().addtrack_(node.track); } } } for (var i = 0; i < removenodes.length; i++) { this.el_.removechild(removenodes[i]); } } if (this.featuresnativetexttracks) { this.handletexttrackchange_ = fn.bind(this, this.handletexttrackchange); this.handletexttrackadd_ = fn.bind(this, this.handletexttrackadd); this.handletexttrackremove_ = fn.bind(this, this.handletexttrackremove); this.proxynativetexttracks_(); } // determine if native controls should be used // our goal should be to get the custom controls on mobile solid everywhere // so we can remove this all together. right now this will block custom // controls on touch enabled laptops like the chrome pixel if (browser.touch_enabled && options.nativecontrolsfortouch === true || browser.is_iphone || browser.is_native_android) { this.setcontrols(true); } this.triggerready(); } /* html5 support testing ---------------------------------------------------- */ /* * element for testing browser html5 video capabilities * * @type {element} * @constant * @private */ /** * dispose of html5 media element * * @method dispose */ html5.prototype.dispose = function dispose() { var tt = this.el().texttracks; var emulatedtt = this.texttracks(); // remove native event listeners if (tt && tt.removeeventlistener) { tt.removeeventlistener('change', this.handletexttrackchange_); tt.removeeventlistener('addtrack', this.handletexttrackadd_); tt.removeeventlistener('removetrack', this.handletexttrackremove_); } // clearout the emulated text track list. var i = emulatedtt.length; while (i--) { emulatedtt.removetrack_(emulatedtt[i]); } html5.disposemediaelement(this.el_); _tech.prototype.dispose.call(this); }; /** * create the component's dom element * * @return {element} * @method createel */ html5.prototype.createel = function createel() { var el = this.options_.tag; // check if this browser supports moving the element into the box. // on the iphone video will break if you move the element, // so we have to create a brand new element. if (!el || this['movingmediaelementindom'] === false) { // if the original tag is still there, clone and remove it. if (el) { var clone = el.clonenode(true); el.parentnode.insertbefore(clone, el); html5.disposemediaelement(el); el = clone; } else { el = _globaldocument2['default'].createelement('video'); // determine if native controls should be used var tagattributes = this.options_.tag && dom.getelattributes(this.options_.tag); var attributes = _utilsmergeoptionsjs2['default']({}, tagattributes); if (!browser.touch_enabled || this.options_.nativecontrolsfortouch !== true) { delete attributes.controls; } dom.setelattributes(el, _objectassign2['default'](attributes, { id: this.options_.techid, 'class': 'vjs-tech' })); } } // update specific tag settings, in case they were overridden var settingsattrs = ['autoplay', 'preload', 'loop', 'muted']; for (var i = settingsattrs.length - 1; i >= 0; i--) { var attr = settingsattrs[i]; var overwriteattrs = {}; if (typeof this.options_[attr] !== 'undefined') { overwriteattrs[attr] = this.options_[attr]; } dom.setelattributes(el, overwriteattrs); } return el; // jenniisawesome = true; }; // if we're loading the playback object after it has started loading // or playing the video (often with autoplay on) then the loadstart event // has already fired and we need to fire it manually because many things // rely on it. html5.prototype.handlelateinit_ = function handlelateinit_(el) { var _this = this; if (el.networkstate === 0 || el.networkstate === 3) { // the video element hasn't started loading the source yet // or didn't find a source return; } if (el.readystate === 0) { var _ret = (function () { // networkstate is set synchronously but loadstart is fired at the // end of the current stack, usually before setinterval(fn, 0). // so at this point we know loadstart may have already fired or is // about to fire, and either way the player hasn't seen it yet. // we don't want to fire loadstart prematurely here and cause a // double loadstart so we'll wait and see if it happens between now // and the next loop, and fire it if not. // however, we also want to make sure it fires before loadedmetadata // which could also happen between now and the next loop, so we'll // watch for that also. var loadstartfired = false; var setloadstartfired = function setloadstartfired() { loadstartfired = true; }; _this.on('loadstart', setloadstartfired); var triggerloadstart = function triggerloadstart() { // we did miss the original loadstart. make sure the player // sees loadstart before loadedmetadata if (!loadstartfired) { this.trigger('loadstart'); } }; _this.on('loadedmetadata', triggerloadstart); _this.ready(function () { this.off('loadstart', setloadstartfired); this.off('loadedmetadata', triggerloadstart); if (!loadstartfired) { // we did miss the original native loadstart. fire it now. this.trigger('loadstart'); } }); return { v: undefined }; })(); if (typeof _ret === 'object') return _ret.v; } // from here on we know that loadstart already fired and we missed it. // the other readystate events aren't as much of a problem if we double // them, so not going to go to as much trouble as loadstart to prevent // that unless we find reason to. var eventstotrigger = ['loadstart']; // loadedmetadata: newly equal to have_metadata (1) or greater eventstotrigger.push('loadedmetadata'); // loadeddata: newly increased to have_current_data (2) or greater if (el.readystate >= 2) { eventstotrigger.push('loadeddata'); } // canplay: newly increased to have_future_data (3) or greater if (el.readystate >= 3) { eventstotrigger.push('canplay'); } // canplaythrough: newly equal to have_enough_data (4) if (el.readystate >= 4) { eventstotrigger.push('canplaythrough'); } // we still need to give the player time to add event listeners this.ready(function () { eventstotrigger.foreach(function (type) { this.trigger(type); }, this); }); }; html5.prototype.proxynativetexttracks_ = function proxynativetexttracks_() { var tt = this.el().texttracks; if (tt) { // add tracks - if player is initialised after dom loaded, texttracks // will not trigger addtrack for (var i = 0; i < tt.length; i++) { this.texttracks().addtrack_(tt[i]); } if (tt.addeventlistener) { tt.addeventlistener('change', this.handletexttrackchange_); tt.addeventlistener('addtrack', this.handletexttrackadd_); tt.addeventlistener('removetrack', this.handletexttrackremove_); } } }; html5.prototype.handletexttrackchange = function handletexttrackchange(e) { var tt = this.texttracks(); this.texttracks().trigger({ type: 'change', target: tt, currenttarget: tt, srcelement: tt }); }; html5.prototype.handletexttrackadd = function handletexttrackadd(e) { this.texttracks().addtrack_(e.track); }; html5.prototype.handletexttrackremove = function handletexttrackremove(e) { this.texttracks().removetrack_(e.track); }; /** * play for html5 tech * * @method play */ html5.prototype.play = function play() { this.el_.play(); }; /** * pause for html5 tech * * @method pause */ html5.prototype.pause = function pause() { this.el_.pause(); }; /** * paused for html5 tech * * @return {boolean} * @method paused */ html5.prototype.paused = function paused() { return this.el_.paused; }; /** * get current time * * @return {number} * @method currenttime */ html5.prototype.currenttime = function currenttime() { return this.el_.currenttime; }; /** * set current time * * @param {number} seconds current time of video * @method setcurrenttime */ html5.prototype.setcurrenttime = function setcurrenttime(seconds) { try { this.el_.currenttime = seconds; } catch (e) { _utilslogjs2['default'](e, 'video is not ready. (video.js)'); // this.warning(videojs.warnings.videonotready); } }; /** * get duration * * @return {number} * @method duration */ html5.prototype.duration = function duration() { return this.el_.duration || 0; }; /** * get a timerange object that represents the intersection * of the time ranges for which the user agent has all * relevant media * * @return {timerangeobject} * @method buffered */ html5.prototype.buffered = function buffered() { return this.el_.buffered; }; /** * get volume level * * @return {number} * @method volume */ html5.prototype.volume = function volume() { return this.el_.volume; }; /** * set volume level * * @param {number} percentasdecimal volume percent as a decimal * @method setvolume */ html5.prototype.setvolume = function setvolume(percentasdecimal) { this.el_.volume = percentasdecimal; }; /** * get if muted * * @return {boolean} * @method muted */ html5.prototype.muted = function muted() { return this.el_.muted; }; /** * set muted * * @param {boolean} if player is to be muted or note * @method setmuted */ html5.prototype.setmuted = function setmuted(muted) { this.el_.muted = muted; }; /** * get player width * * @return {number} * @method width */ html5.prototype.width = function width() { return this.el_.offsetwidth; }; /** * get player height * * @return {number} * @method height */ html5.prototype.height = function height() { return this.el_.offsetheight; }; /** * get if there is fullscreen support * * @return {boolean} * @method supportsfullscreen */ html5.prototype.supportsfullscreen = function supportsfullscreen() { if (typeof this.el_.webkitenterfullscreen === 'function') { var useragent = _globalwindow2['default'].navigator.useragent; // seems to be broken in chromium/chrome && safari in leopard if (/android/.test(useragent) || !/chrome|mac os x 10.5/.test(useragent)) { return true; } } return false; }; /** * request to enter fullscreen * * @method enterfullscreen */ html5.prototype.enterfullscreen = function enterfullscreen() { var video = this.el_; if ('webkitdisplayingfullscreen' in video) { this.one('webkitbeginfullscreen', function () { this.one('webkitendfullscreen', function () { this.trigger('fullscreenchange', { isfullscreen: false }); }); this.trigger('fullscreenchange', { isfullscreen: true }); }); } if (video.paused && video.networkstate <= video.have_metadata) { // attempt to prime the video element for programmatic access // this isn't necessary on the desktop but shouldn't hurt this.el_.play(); // playing and pausing synchronously during the transition to fullscreen // can get ios ~6.1 devices into a play/pause loop this.settimeout(function () { video.pause(); video.webkitenterfullscreen(); }, 0); } else { video.webkitenterfullscreen(); } }; /** * request to exit fullscreen * * @method exitfullscreen */ html5.prototype.exitfullscreen = function exitfullscreen() { this.el_.webkitexitfullscreen(); }; /** * get/set video * * @param {object=} src source object * @return {object} * @method src */ html5.prototype.src = function src(_src) { if (_src === undefined) { return this.el_.src; } else { // setting src through `src` instead of `setsrc` will be deprecated this.setsrc(_src); } }; /** * set video * * @param {object} src source object * @deprecated * @method setsrc */ html5.prototype.setsrc = function setsrc(src) { this.el_.src = src; }; /** * load media into player * * @method load */ html5.prototype.load = function load() { this.el_.load(); }; /** * reset the tech. removes all sources and calls `load`. * * @method reset */ html5.prototype.reset = function reset() { html5.resetmediaelement(this.el_); }; /** * get current source * * @return {object} * @method currentsrc */ html5.prototype.currentsrc = function currentsrc() { if (this.currentsource_) { return this.currentsource_.src; } else { return this.el_.currentsrc; } }; /** * get poster * * @return {string} * @method poster */ html5.prototype.poster = function poster() { return this.el_.poster; }; /** * set poster * * @param {string} val url to poster image * @method */ html5.prototype.setposter = function setposter(val) { this.el_.poster = val; }; /** * get preload attribute * * @return {string} * @method preload */ html5.prototype.preload = function preload() { return this.el_.preload; }; /** * set preload attribute * * @param {string} val value for preload attribute * @method setpreload */ html5.prototype.setpreload = function setpreload(val) { this.el_.preload = val; }; /** * get autoplay attribute * * @return {string} * @method autoplay */ html5.prototype.autoplay = function autoplay() { return this.el_.autoplay; }; /** * set autoplay attribute * * @param {string} val value for preload attribute * @method setautoplay */ html5.prototype.setautoplay = function setautoplay(val) { this.el_.autoplay = val; }; /** * get controls attribute * * @return {string} * @method controls */ html5.prototype.controls = function controls() { return this.el_.controls; }; /** * set controls attribute * * @param {string} val value for controls attribute * @method setcontrols */ html5.prototype.setcontrols = function setcontrols(val) { this.el_.controls = !!val; }; /** * get loop attribute * * @return {string} * @method loop */ html5.prototype.loop = function loop() { return this.el_.loop; }; /** * set loop attribute * * @param {string} val value for loop attribute * @method setloop */ html5.prototype.setloop = function setloop(val) { this.el_.loop = val; }; /** * get error value * * @return {string} * @method error */ html5.prototype.error = function error() { return this.el_.error; }; /** * get whether or not the player is in the "seeking" state * * @return {boolean} * @method seeking */ html5.prototype.seeking = function seeking() { return this.el_.seeking; }; /** * get a timeranges object that represents the * ranges of the media resource to which it is possible * for the user agent to seek. * * @return {timerangeobject} * @method seekable */ html5.prototype.seekable = function seekable() { return this.el_.seekable; }; /** * get if video ended * * @return {boolean} * @method ended */ html5.prototype.ended = function ended() { return this.el_.ended; }; /** * get the value of the muted content attribute * this attribute has no dynamic effect, it only * controls the default state of the element * * @return {boolean} * @method defaultmuted */ html5.prototype.defaultmuted = function defaultmuted() { return this.el_.defaultmuted; }; /** * get desired speed at which the media resource is to play * * @return {number} * @method playbackrate */ html5.prototype.playbackrate = function playbackrate() { return this.el_.playbackrate; }; /** * returns a timeranges object that represents the ranges of the * media resource that the user agent has played. * @return {timerangeobject} the range of points on the media * timeline that has been reached through normal playback * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played */ html5.prototype.played = function played() { return this.el_.played; }; /** * set desired speed at which the media resource is to play * * @param {number} val speed at which the media resource is to play * @method setplaybackrate */ html5.prototype.setplaybackrate = function setplaybackrate(val) { this.el_.playbackrate = val; }; /** * get the current state of network activity for the element, from * the list below * network_empty (numeric value 0) * network_idle (numeric value 1) * network_loading (numeric value 2) * network_no_source (numeric value 3) * * @return {number} * @method networkstate */ html5.prototype.networkstate = function networkstate() { return this.el_.networkstate; }; /** * get a value that expresses the current state of the element * with respect to rendering the current playback position, from * the codes in the list below * have_nothing (numeric value 0) * have_metadata (numeric value 1) * have_current_data (numeric value 2) * have_future_data (numeric value 3) * have_enough_data (numeric value 4) * * @return {number} * @method readystate */ html5.prototype.readystate = function readystate() { return this.el_.readystate; }; /** * get width of video * * @return {number} * @method videowidth */ html5.prototype.videowidth = function videowidth() { return this.el_.videowidth; }; /** * get height of video * * @return {number} * @method videoheight */ html5.prototype.videoheight = function videoheight() { return this.el_.videoheight; }; /** * get text tracks * * @return {texttracklist} * @method texttracks */ html5.prototype.texttracks = function texttracks() { return _tech.prototype.texttracks.call(this); }; /** * creates and returns a text track object * * @param {string} kind text track kind (subtitles, captions, descriptions * chapters and metadata) * @param {string=} label label to identify the text track * @param {string=} language two letter language abbreviation * @return {texttrackobject} * @method addtexttrack */ html5.prototype.addtexttrack = function addtexttrack(kind, label, language) { if (!this['featuresnativetexttracks']) { return _tech.prototype.addtexttrack.call(this, kind, label, language); } return this.el_.addtexttrack(kind, label, language); }; /** * creates a remote text track object and returns a html track element * * @param {object} options the object should contain values for * kind, language, label and src (location of the webvtt file) * @return {htmltrackelement} * @method addremotetexttrack */ html5.prototype.addremotetexttrack = function addremotetexttrack() { var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; if (!this['featuresnativetexttracks']) { return _tech.prototype.addremotetexttrack.call(this, options); } var htmltrackelement = _globaldocument2['default'].createelement('track'); if (options.kind) { htmltrackelement.kind = options.kind; } if (options.label) { htmltrackelement.label = options.label; } if (options.language || options.srclang) { htmltrackelement.srclang = options.language || options.srclang; } if (options['default']) { htmltrackelement['default'] = options['default']; } if (options.id) { htmltrackelement.id = options.id; } if (options.src) { htmltrackelement.src = options.src; } this.el().appendchild(htmltrackelement); // store htmltrackelement and texttrack to remote list this.remotetexttrackels().addtrackelement_(htmltrackelement); this.remotetexttracks().addtrack_(htmltrackelement.track); return htmltrackelement; }; /** * remove remote text track from texttracklist object * * @param {texttrackobject} track texttrack object to remove * @method removeremotetexttrack */ html5.prototype.removeremotetexttrack = function removeremotetexttrack(track) { if (!this['featuresnativetexttracks']) { return _tech.prototype.removeremotetexttrack.call(this, track); } var tracks = undefined, i = undefined; var trackelement = this.remotetexttrackels().gettrackelementbytrack_(track); // remove htmltrackelement and texttrack from remote list this.remotetexttrackels().removetrackelement_(trackelement); this.remotetexttracks().removetrack_(track); tracks = this.$$('track'); i = tracks.length; while (i--) { if (track === tracks[i] || track === tracks[i].track) { this.el().removechild(tracks[i]); } } }; return html5; })(_techjs2['default']); html5.test_vid = _globaldocument2['default'].createelement('video'); var track = _globaldocument2['default'].createelement('track'); track.kind = 'captions'; track.srclang = 'en'; track.label = 'english'; html5.test_vid.appendchild(track); /* * check if html5 video is supported by this browser/device * * @return {boolean} */ html5.issupported = function () { // ie9 with no media player is a liar! (#984) try { html5.test_vid['volume'] = 0.5; } catch (e) { return false; } return !!html5.test_vid.canplaytype; }; // add source handler pattern functions to this tech _techjs2['default'].withsourcehandlers(html5); /* * the default native source handler. * this simply passes the source to the video element. nothing fancy. * * @param {object} source the source object * @param {html5} tech the instance of the html5 tech */ html5.nativesourcehandler = {}; /* * check if the video element can play the given videotype * * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) */ html5.nativesourcehandler.canplaytype = function (type) { // ie9 on windows 7 without mediaplayer throws an error here // https://github.com/videojs/video.js/issues/519 try { return html5.test_vid.canplaytype(type); } catch (e) { return ''; } }; /* * check if the video element can handle the source natively * * @param {object} source the source object * @return {string} 'probably', 'maybe', or '' (empty string) */ html5.nativesourcehandler.canhandlesource = function (source) { var match, ext; // if a type was provided we should rely on that if (source.type) { return html5.nativesourcehandler.canplaytype(source.type); } else if (source.src) { // if no type, fall back to checking 'video/[extension]' ext = url.getfileextension(source.src); return html5.nativesourcehandler.canplaytype('video/' + ext); } return ''; }; /* * pass the source to the video element * adaptive source handlers will have more complicated workflows before passing * video data to the video element * * @param {object} source the source object * @param {html5} tech the instance of the html5 tech */ html5.nativesourcehandler.handlesource = function (source, tech) { tech.setsrc(source.src); }; /* * clean up the source handler when disposing the player or switching sources.. * (no cleanup is needed when supporting the format natively) */ html5.nativesourcehandler.dispose = function () {}; // register the native source handler html5.registersourcehandler(html5.nativesourcehandler); /* * check if the volume can be changed in this browser/device. * volume cannot be changed in a lot of mobile devices. * specifically, it can't be changed from 1 on ios. * * @return {boolean} */ html5.cancontrolvolume = function () { var volume = html5.test_vid.volume; html5.test_vid.volume = volume / 2 + 0.1; return volume !== html5.test_vid.volume; }; /* * check if playbackrate is supported in this browser/device. * * @return {boolean} */ html5.cancontrolplaybackrate = function () { // playback rate api is implemented in android chrome, but doesn't do anything // https://github.com/videojs/video.js/issues/3180 if (browser.is_android && browser.is_chrome) { return false; } var playbackrate = html5.test_vid.playbackrate; html5.test_vid.playbackrate = playbackrate / 2 + 0.1; return playbackrate !== html5.test_vid.playbackrate; }; /* * check to see if native text tracks are supported by this browser/device * * @return {boolean} */ html5.supportsnativetexttracks = function () { var supportstexttracks; // figure out native text track support // if mode is a number, we cannot change it because it'll disappear from view. // browsers with numeric modes include ie10 and older (<=2013) samsung android models. // firefox isn't playing nice either with modifying the mode // todo: investigate firefox: https://github.com/videojs/video.js/issues/1862 supportstexttracks = !!html5.test_vid.texttracks; if (supportstexttracks && html5.test_vid.texttracks.length > 0) { supportstexttracks = typeof html5.test_vid.texttracks[0]['mode'] !== 'number'; } if (supportstexttracks && browser.is_firefox) { supportstexttracks = false; } if (supportstexttracks && !('onremovetrack' in html5.test_vid.texttracks)) { supportstexttracks = false; } return supportstexttracks; }; /** * an array of events available on the html5 tech. * * @private * @type {array} */ html5.events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange']; /* * set the tech's volume control support status * * @type {boolean} */ html5.prototype['featuresvolumecontrol'] = html5.cancontrolvolume(); /* * set the tech's playbackrate support status * * @type {boolean} */ html5.prototype['featuresplaybackrate'] = html5.cancontrolplaybackrate(); /* * set the tech's status on moving the video element. * in ios, if you move a video element in the dom, it breaks video playback. * * @type {boolean} */ html5.prototype['movingmediaelementindom'] = !browser.is_ios; /* * set the the tech's fullscreen resize support status. * html video is able to automatically resize when going to fullscreen. * (no longer appears to be used. can probably be removed.) */ html5.prototype['featuresfullscreenresize'] = true; /* * set the tech's progress event support status * (this disables the manual progress events of the tech) */ html5.prototype['featuresprogressevents'] = true; /* * sets the tech's status on native text track support * * @type {boolean} */ html5.prototype['featuresnativetexttracks'] = html5.supportsnativetexttracks(); // html5 feature detection and device fixes --------------------------------- // var canplaytype = undefined; var mpegurlre = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; var mp4re = /^video\/mp4/i; html5.patchcanplaytype = function () { // android 4.0 and above can play hls to some extent but it reports being unable to do so if (browser.android_version >= 4.0) { if (!canplaytype) { canplaytype = html5.test_vid.constructor.prototype.canplaytype; } html5.test_vid.constructor.prototype.canplaytype = function (type) { if (type && mpegurlre.test(type)) { return 'maybe'; } return canplaytype.call(this, type); }; } // override android 2.2 and less canplaytype method which is broken if (browser.is_old_android) { if (!canplaytype) { canplaytype = html5.test_vid.constructor.prototype.canplaytype; } html5.test_vid.constructor.prototype.canplaytype = function (type) { if (type && mp4re.test(type)) { return 'maybe'; } return canplaytype.call(this, type); }; } }; html5.unpatchcanplaytype = function () { var r = html5.test_vid.constructor.prototype.canplaytype; html5.test_vid.constructor.prototype.canplaytype = canplaytype; canplaytype = null; return r; }; // by default, patch the video element html5.patchcanplaytype(); html5.disposemediaelement = function (el) { if (!el) { return; } if (el.parentnode) { el.parentnode.removechild(el); } // remove any child track or source nodes to prevent their loading while (el.haschildnodes()) { el.removechild(el.firstchild); } // remove any src reference. not setting `src=''` because that causes a warning // in firefox el.removeattribute('src'); // force the media element to update its loading state by calling load() // however ie on windows 7n has a bug that throws an error so need a try/catch (#793) if (typeof el.load === 'function') { // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) (function () { try { el.load(); } catch (e) { // not supported } })(); } }; html5.resetmediaelement = function (el) { if (!el) { return; } var sources = el.queryselectorall('source'); var i = sources.length; while (i--) { el.removechild(sources[i]); } // remove any src reference. // not setting `src=''` because that throws an error el.removeattribute('src'); if (typeof el.load === 'function') { // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) (function () { try { el.load(); } catch (e) {} })(); } }; _component2['default'].registercomponent('html5', html5); _techjs2['default'].registertech('html5', html5); exports['default'] = html5; module.exports = exports['default']; },{"../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){ /** * @file loader.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _componentjs = _dereq_('../component.js'); var _componentjs2 = _interoprequiredefault(_componentjs); var _techjs = _dereq_('./tech.js'); var _techjs2 = _interoprequiredefault(_techjs); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _utilstotitlecasejs = _dereq_('../utils/to-title-case.js'); var _utilstotitlecasejs2 = _interoprequiredefault(_utilstotitlecasejs); /** * the media loader is the component that decides which playback technology to load * when the player is initialized. * * @param {object} player main player * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends component * @class medialoader */ var medialoader = (function (_component) { _inherits(medialoader, _component); function medialoader(player, options, ready) { _classcallcheck(this, medialoader); _component.call(this, player, options, ready); // if there are no sources when the player is initialized, // load the first supported playback technology. if (!options.playeroptions['sources'] || options.playeroptions['sources'].length === 0) { for (var i = 0, j = options.playeroptions['techorder']; i < j.length; i++) { var techname = _utilstotitlecasejs2['default'](j[i]); var tech = _techjs2['default'].gettech(techname); // support old behavior of techs being registered as components. // remove once that deprecated behavior is removed. if (!techname) { tech = _componentjs2['default'].getcomponent(techname); } // check if the browser supports this technology if (tech && tech.issupported()) { player.loadtech_(techname); break; } } } else { // // loop through playback technologies (html5, flash) and check for support. // // then load the best source. // // a few assumptions here: // // all playback technologies respect preload false. player.src(options.playeroptions['sources']); } } return medialoader; })(_componentjs2['default']); _componentjs2['default'].registercomponent('medialoader', medialoader); exports['default'] = medialoader; module.exports = exports['default']; },{"../component.js":67,"../utils/to-title-case.js":143,"./tech.js":121,"global/window":2}],121:[function(_dereq_,module,exports){ /** * @file tech.js * media technology controller - base class for media playback * technology controllers like flash and html5 */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _trackshtmltrackelement = _dereq_('../tracks/html-track-element'); var _trackshtmltrackelement2 = _interoprequiredefault(_trackshtmltrackelement); var _trackshtmltrackelementlist = _dereq_('../tracks/html-track-element-list'); var _trackshtmltrackelementlist2 = _interoprequiredefault(_trackshtmltrackelementlist); var _utilsmergeoptionsjs = _dereq_('../utils/merge-options.js'); var _utilsmergeoptionsjs2 = _interoprequiredefault(_utilsmergeoptionsjs); var _trackstexttrack = _dereq_('../tracks/text-track'); var _trackstexttrack2 = _interoprequiredefault(_trackstexttrack); var _trackstexttracklist = _dereq_('../tracks/text-track-list'); var _trackstexttracklist2 = _interoprequiredefault(_trackstexttracklist); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilslogjs = _dereq_('../utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _utilstimerangesjs = _dereq_('../utils/time-ranges.js'); var _utilsbufferjs = _dereq_('../utils/buffer.js'); var _mediaerrorjs = _dereq_('../media-error.js'); var _mediaerrorjs2 = _interoprequiredefault(_mediaerrorjs); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /** * base class for media (html5 video, flash) controllers * * @param {object=} options options object * @param {function=} ready ready callback function * @extends component * @class tech */ var tech = (function (_component) { _inherits(tech, _component); function tech() { var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var ready = arguments.length <= 1 || arguments[1] === undefined ? function () {} : arguments[1]; _classcallcheck(this, tech); // we don't want the tech to report user activity automatically. // this is done manually in addcontrolslisteners options.reporttouchactivity = false; _component.call(this, null, options, ready); // keep track of whether the current source has played at all to // implement a very limited played() this.hasstarted_ = false; this.on('playing', function () { this.hasstarted_ = true; }); this.on('loadstart', function () { this.hasstarted_ = false; }); this.texttracks_ = options.texttracks; // manually track progress in cases where the browser/flash player doesn't report it. if (!this.featuresprogressevents) { this.manualprogresson(); } // manually track timeupdates in cases where the browser/flash player doesn't report it. if (!this.featurestimeupdateevents) { this.manualtimeupdateson(); } if (options.nativecaptions === false || options.nativetexttracks === false) { this.featuresnativetexttracks = false; } if (!this.featuresnativetexttracks) { this.on('ready', this.emulatetexttracks); } this.inittexttracklisteners(); // turn on component tap events this.emittapevents(); } /* * list of associated text tracks * * @type {array} * @private */ /* fallbacks for unsupported event types ================================================================================ */ // manually trigger progress events based on changes to the buffered amount // many flash players and older html5 browsers don't send progress or progress-like events /** * turn on progress events * * @method manualprogresson */ tech.prototype.manualprogresson = function manualprogresson() { this.on('durationchange', this.ondurationchange); this.manualprogress = true; // trigger progress watching when a source begins loading this.one('ready', this.trackprogress); }; /** * turn off progress events * * @method manualprogressoff */ tech.prototype.manualprogressoff = function manualprogressoff() { this.manualprogress = false; this.stoptrackingprogress(); this.off('durationchange', this.ondurationchange); }; /** * track progress * * @method trackprogress */ tech.prototype.trackprogress = function trackprogress() { this.stoptrackingprogress(); this.progressinterval = this.setinterval(fn.bind(this, function () { // don't trigger unless buffered amount is greater than last time var numbufferedpercent = this.bufferedpercent(); if (this.bufferedpercent_ !== numbufferedpercent) { this.trigger('progress'); } this.bufferedpercent_ = numbufferedpercent; if (numbufferedpercent === 1) { this.stoptrackingprogress(); } }), 500); }; /** * update duration * * @method ondurationchange */ tech.prototype.ondurationchange = function ondurationchange() { this.duration_ = this.duration(); }; /** * create and get timerange object for buffering * * @return {timerangeobject} * @method buffered */ tech.prototype.buffered = function buffered() { return _utilstimerangesjs.createtimerange(0, 0); }; /** * get buffered percent * * @return {number} * @method bufferedpercent */ tech.prototype.bufferedpercent = function bufferedpercent() { return _utilsbufferjs.bufferedpercent(this.buffered(), this.duration_); }; /** * stops tracking progress by clearing progress interval * * @method stoptrackingprogress */ tech.prototype.stoptrackingprogress = function stoptrackingprogress() { this.clearinterval(this.progressinterval); }; /*! time tracking -------------------------------------------------------------- */ /** * set event listeners for on play and pause and tracking current time * * @method manualtimeupdateson */ tech.prototype.manualtimeupdateson = function manualtimeupdateson() { this.manualtimeupdates = true; this.on('play', this.trackcurrenttime); this.on('pause', this.stoptrackingcurrenttime); }; /** * remove event listeners for on play and pause and tracking current time * * @method manualtimeupdatesoff */ tech.prototype.manualtimeupdatesoff = function manualtimeupdatesoff() { this.manualtimeupdates = false; this.stoptrackingcurrenttime(); this.off('play', this.trackcurrenttime); this.off('pause', this.stoptrackingcurrenttime); }; /** * tracks current time * * @method trackcurrenttime */ tech.prototype.trackcurrenttime = function trackcurrenttime() { if (this.currenttimeinterval) { this.stoptrackingcurrenttime(); } this.currenttimeinterval = this.setinterval(function () { this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); }, 250); // 42 = 24 fps // 250 is what webkit uses // ff uses 15 }; /** * turn off play progress tracking (when paused or dragging) * * @method stoptrackingcurrenttime */ tech.prototype.stoptrackingcurrenttime = function stoptrackingcurrenttime() { this.clearinterval(this.currenttimeinterval); // #1002 - if the video ends right before the next timeupdate would happen, // the progress bar won't make it all the way to the end this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); }; /** * turn off any manual progress or timeupdate tracking * * @method dispose */ tech.prototype.dispose = function dispose() { // clear out text tracks because we can't reuse them between techs var texttracks = this.texttracks(); if (texttracks) { var i = texttracks.length; while (i--) { this.removeremotetexttrack(texttracks[i]); } } // turn off any manual progress or timeupdate tracking if (this.manualprogress) { this.manualprogressoff(); } if (this.manualtimeupdates) { this.manualtimeupdatesoff(); } _component.prototype.dispose.call(this); }; /** * reset the tech. removes all sources and resets readystate. * * @method reset */ tech.prototype.reset = function reset() {}; /** * when invoked without an argument, returns a mediaerror object * representing the current error state of the player or null if * there is no error. when invoked with an argument, set the current * error state of the player. * @param {mediaerror=} err optional an error object * @return {mediaerror} the current error object or null * @method error */ tech.prototype.error = function error(err) { if (err !== undefined) { if (err instanceof _mediaerrorjs2['default']) { this.error_ = err; } else { this.error_ = new _mediaerrorjs2['default'](err); } this.trigger('error'); } return this.error_; }; /** * return the time ranges that have been played through for the * current source. this implementation is incomplete. it does not * track the played time ranges, only whether the source has played * at all or not. * @return {timerangeobject} a single time range if this video has * played or an empty set of ranges if not. * @method played */ tech.prototype.played = function played() { if (this.hasstarted_) { return _utilstimerangesjs.createtimerange(0, 0); } return _utilstimerangesjs.createtimerange(); }; /** * set current time * * @method setcurrenttime */ tech.prototype.setcurrenttime = function setcurrenttime() { // improve the accuracy of manual timeupdates if (this.manualtimeupdates) { this.trigger({ type: 'timeupdate', target: this, manuallytriggered: true }); } }; /** * initialize texttrack listeners * * @method inittexttracklisteners */ tech.prototype.inittexttracklisteners = function inittexttracklisteners() { var texttracklistchanges = fn.bind(this, function () { this.trigger('texttrackchange'); }); var tracks = this.texttracks(); if (!tracks) return; tracks.addeventlistener('removetrack', texttracklistchanges); tracks.addeventlistener('addtrack', texttracklistchanges); this.on('dispose', fn.bind(this, function () { tracks.removeeventlistener('removetrack', texttracklistchanges); tracks.removeeventlistener('addtrack', texttracklistchanges); })); }; /** * emulate texttracks * * @method emulatetexttracks */ tech.prototype.emulatetexttracks = function emulatetexttracks() { var _this = this; var tracks = this.texttracks(); if (!tracks) { return; } if (!_globalwindow2['default']['webvtt'] && this.el().parentnode != null) { (function () { var script = _globaldocument2['default'].createelement('script'); script.src = _this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js'; script.onload = function () { _this.trigger('vttjsloaded'); }; script.onerror = function () { _this.trigger('vttjserror'); }; _this.on('dispose', function () { script.onload = null; script.onerror = null; }); _this.el().parentnode.appendchild(script); _globalwindow2['default']['webvtt'] = true; })(); } var updatedisplay = function updatedisplay() { return _this.trigger('texttrackchange'); }; var texttrackschanges = function texttrackschanges() { updatedisplay(); for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; track.removeeventlistener('cuechange', updatedisplay); if (track.mode === 'showing') { track.addeventlistener('cuechange', updatedisplay); } } }; texttrackschanges(); tracks.addeventlistener('change', texttrackschanges); this.on('dispose', function () { tracks.removeeventlistener('change', texttrackschanges); }); }; /* * provide default methods for text tracks. * * html5 tech overrides these. */ /** * get texttracks * * @returns {texttracklist} * @method texttracks */ tech.prototype.texttracks = function texttracks() { this.texttracks_ = this.texttracks_ || new _trackstexttracklist2['default'](); return this.texttracks_; }; /** * get remote texttracks * * @returns {texttracklist} * @method remotetexttracks */ tech.prototype.remotetexttracks = function remotetexttracks() { this.remotetexttracks_ = this.remotetexttracks_ || new _trackstexttracklist2['default'](); return this.remotetexttracks_; }; /** * get remote htmltrackelements * * @returns {htmltrackelementlist} * @method remotetexttrackels */ tech.prototype.remotetexttrackels = function remotetexttrackels() { this.remotetexttrackels_ = this.remotetexttrackels_ || new _trackshtmltrackelementlist2['default'](); return this.remotetexttrackels_; }; /** * creates and returns a remote text track object * * @param {string} kind text track kind (subtitles, captions, descriptions * chapters and metadata) * @param {string=} label label to identify the text track * @param {string=} language two letter language abbreviation * @return {texttrackobject} * @method addtexttrack */ tech.prototype.addtexttrack = function addtexttrack(kind, label, language) { if (!kind) { throw new error('texttrack kind is required but was not provided'); } return createtrackhelper(this, kind, label, language); }; /** * creates a remote text track object and returns a emulated html track element * * @param {object} options the object should contain values for * kind, language, label and src (location of the webvtt file) * @return {htmltrackelement} * @method addremotetexttrack */ tech.prototype.addremotetexttrack = function addremotetexttrack(options) { var track = _utilsmergeoptionsjs2['default'](options, { tech: this }); var htmltrackelement = new _trackshtmltrackelement2['default'](track); // store htmltrackelement and texttrack to remote list this.remotetexttrackels().addtrackelement_(htmltrackelement); this.remotetexttracks().addtrack_(htmltrackelement.track); // must come after remotetexttracks() this.texttracks().addtrack_(htmltrackelement.track); return htmltrackelement; }; /** * remove remote texttrack * * @param {texttrackobject} track texttrack to remove * @method removeremotetexttrack */ tech.prototype.removeremotetexttrack = function removeremotetexttrack(track) { this.texttracks().removetrack_(track); var trackelement = this.remotetexttrackels().gettrackelementbytrack_(track); // remove htmltrackelement and texttrack from remote list this.remotetexttrackels().removetrackelement_(trackelement); this.remotetexttracks().removetrack_(track); }; /** * provide a default setposter method for techs * poster support for techs should be optional, so we don't want techs to * break if they don't have a way to set a poster. * * @method setposter */ tech.prototype.setposter = function setposter() {}; /* * check if the tech can support the given type * * the base tech does not support any type, but source handlers might * overwrite this. * * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) */ tech.prototype.canplaytype = function canplaytype() { return ''; }; /* * return whether the argument is a tech or not. * can be passed either a class like `html5` or a instance like `player.tech_` * * @param {object} component an item to check * @return {boolean} whether it is a tech or not */ tech.istech = function istech(component) { return component.prototype instanceof tech || component instanceof tech || component === tech; }; /** * registers a tech * * @param {string} name name of the tech to register * @param {object} tech the tech to register * @static * @method registercomponent */ tech.registertech = function registertech(name, tech) { if (!tech.techs_) { tech.techs_ = {}; } if (!tech.istech(tech)) { throw new error('tech ' + name + ' must be a tech'); } tech.techs_[name] = tech; return tech; }; /** * gets a component by name * * @param {string} name name of the component to get * @return {component} * @static * @method getcomponent */ tech.gettech = function gettech(name) { if (tech.techs_ && tech.techs_[name]) { return tech.techs_[name]; } if (_globalwindow2['default'] && _globalwindow2['default'].videojs && _globalwindow2['default'].videojs[name]) { _utilslogjs2['default'].warn('the ' + name + ' tech was added to the videojs object when it should be registered using videojs.registertech(name, tech)'); return _globalwindow2['default'].videojs[name]; } }; return tech; })(_component2['default']); tech.prototype.texttracks_; var createtrackhelper = function createtrackhelper(self, kind, label, language) { var options = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4]; var tracks = self.texttracks(); options.kind = kind; if (label) { options.label = label; } if (language) { options.language = language; } options.tech = self; var track = new _trackstexttrack2['default'](options); tracks.addtrack_(track); return track; }; tech.prototype.featuresvolumecontrol = true; // resizing plugins using request fullscreen reloads the plugin tech.prototype.featuresfullscreenresize = false; tech.prototype.featuresplaybackrate = false; // optional events that we can manually mimic with timers // currently not triggered by video-js-swf tech.prototype.featuresprogressevents = false; tech.prototype.featurestimeupdateevents = false; tech.prototype.featuresnativetexttracks = false; /* * a functional mixin for techs that want to use the source handler pattern. * * ##### example: * * tech.withsourcehandlers.call(mytech); * */ tech.withsourcehandlers = function (_tech) { /* * register a source handler * source handlers are scripts for handling specific formats. * the source handler pattern is used for adaptive formats (hls, dash) that * manually load video data and feed it into a source buffer (media source extensions) * @param {function} handler the source handler * @param {boolean} first register it before any existing handlers */ _tech.registersourcehandler = function (handler, index) { var handlers = _tech.sourcehandlers; if (!handlers) { handlers = _tech.sourcehandlers = []; } if (index === undefined) { // add to the end of the list index = handlers.length; } handlers.splice(index, 0, handler); }; /* * check if the tech can support the given type * @param {string} type the mimetype to check * @return {string} 'probably', 'maybe', or '' (empty string) */ _tech.canplaytype = function (type) { var handlers = _tech.sourcehandlers || []; var can = undefined; for (var i = 0; i < handlers.length; i++) { can = handlers[i].canplaytype(type); if (can) { return can; } } return ''; }; /* * return the first source handler that supports the source * todo: answer question: should 'probably' be prioritized over 'maybe' * @param {object} source the source object * @returns {object} the first source handler that supports the source * @returns {null} null if no source handler is found */ _tech.selectsourcehandler = function (source) { var handlers = _tech.sourcehandlers || []; var can = undefined; for (var i = 0; i < handlers.length; i++) { can = handlers[i].canhandlesource(source); if (can) { return handlers[i]; } } return null; }; /* * check if the tech can support the given source * @param {object} srcobj the source object * @return {string} 'probably', 'maybe', or '' (empty string) */ _tech.canplaysource = function (srcobj) { var sh = _tech.selectsourcehandler(srcobj); if (sh) { return sh.canhandlesource(srcobj); } return ''; }; /* * when using a source handler, prefer its implementation of * any function normally provided by the tech. */ var deferrable = ['seekable', 'duration']; deferrable.foreach(function (fnname) { var originalfn = this[fnname]; if (typeof originalfn !== 'function') { return; } this[fnname] = function () { if (this.sourcehandler_ && this.sourcehandler_[fnname]) { return this.sourcehandler_[fnname].apply(this.sourcehandler_, arguments); } return originalfn.apply(this, arguments); }; }, _tech.prototype); /* * create a function for setting the source using a source object * and source handlers. * should never be called unless a source handler was found. * @param {object} source a source object with src and type keys * @return {tech} self */ _tech.prototype.setsource = function (source) { var sh = _tech.selectsourcehandler(source); if (!sh) { // fall back to a native source hander when unsupported sources are // deliberately set if (_tech.nativesourcehandler) { sh = _tech.nativesourcehandler; } else { _utilslogjs2['default'].error('no source hander found for the current source.'); } } // dispose any existing source handler this.disposesourcehandler(); this.off('dispose', this.disposesourcehandler); this.currentsource_ = source; this.sourcehandler_ = sh.handlesource(source, this); this.on('dispose', this.disposesourcehandler); return this; }; /* * clean up any existing source handler */ _tech.prototype.disposesourcehandler = function () { if (this.sourcehandler_ && this.sourcehandler_.dispose) { this.sourcehandler_.dispose(); } }; }; _component2['default'].registercomponent('tech', tech); // old name for tech _component2['default'].registercomponent('mediatechcontroller', tech); tech.registertech('tech', tech); exports['default'] = tech; module.exports = exports['default']; },{"../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){ /** * @file html-track-element-list.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var htmltrackelementlist = (function () { function htmltrackelementlist() { var trackelements = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; _classcallcheck(this, htmltrackelementlist); var list = this; if (browser.is_ie8) { list = _globaldocument2['default'].createelement('custom'); for (var prop in htmltrackelementlist.prototype) { if (prop !== 'constructor') { list[prop] = htmltrackelementlist.prototype[prop]; } } } list.trackelements_ = []; object.defineproperty(list, 'length', { get: function get() { return this.trackelements_.length; } }); for (var i = 0, _length = trackelements.length; i < _length; i++) { list.addtrackelement_(trackelements[i]); } if (browser.is_ie8) { return list; } } htmltrackelementlist.prototype.addtrackelement_ = function addtrackelement_(trackelement) { this.trackelements_.push(trackelement); }; htmltrackelementlist.prototype.gettrackelementbytrack_ = function gettrackelementbytrack_(track) { var trackelement_ = undefined; for (var i = 0, _length2 = this.trackelements_.length; i < _length2; i++) { if (track === this.trackelements_[i].track) { trackelement_ = this.trackelements_[i]; break; } } return trackelement_; }; htmltrackelementlist.prototype.removetrackelement_ = function removetrackelement_(trackelement) { for (var i = 0, _length3 = this.trackelements_.length; i < _length3; i++) { if (trackelement === this.trackelements_[i]) { this.trackelements_.splice(i, 1); break; } } }; return htmltrackelementlist; })(); exports['default'] = htmltrackelementlist; module.exports = exports['default']; },{"../utils/browser.js":131,"global/document":1}],123:[function(_dereq_,module,exports){ /** * @file html-track-element.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _eventtarget = _dereq_('../event-target'); var _eventtarget2 = _interoprequiredefault(_eventtarget); var _trackstexttrack = _dereq_('../tracks/text-track'); var _trackstexttrack2 = _interoprequiredefault(_trackstexttrack); var none = 0; var loading = 1; var loaded = 2; var error = 3; /** * https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement * * interface htmltrackelement : htmlelement { * attribute domstring kind; * attribute domstring src; * attribute domstring srclang; * attribute domstring label; * attribute boolean default; * * const unsigned short none = 0; * const unsigned short loading = 1; * const unsigned short loaded = 2; * const unsigned short error = 3; * readonly attribute unsigned short readystate; * * readonly attribute texttrack track; * }; * * @param {object} options texttrack configuration * @class htmltrackelement */ var htmltrackelement = (function (_eventtarget) { _inherits(htmltrackelement, _eventtarget); function htmltrackelement() { var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; _classcallcheck(this, htmltrackelement); _eventtarget.call(this); var readystate = undefined, trackelement = this; if (browser.is_ie8) { trackelement = _globaldocument2['default'].createelement('custom'); for (var prop in htmltrackelement.prototype) { if (prop !== 'constructor') { trackelement[prop] = htmltrackelement.prototype[prop]; } } } var track = new _trackstexttrack2['default'](options); trackelement.kind = track.kind; trackelement.src = track.src; trackelement.srclang = track.language; trackelement.label = track.label; trackelement['default'] = track['default']; object.defineproperty(trackelement, 'readystate', { get: function get() { return readystate; } }); object.defineproperty(trackelement, 'track', { get: function get() { return track; } }); readystate = none; track.addeventlistener('loadeddata', function () { readystate = loaded; trackelement.trigger({ type: 'load', target: trackelement }); }); if (browser.is_ie8) { return trackelement; } } return htmltrackelement; })(_eventtarget2['default']); htmltrackelement.prototype.allowedevents_ = { load: 'load' }; htmltrackelement.none = none; htmltrackelement.loading = loading; htmltrackelement.loaded = loaded; htmltrackelement.error = error; exports['default'] = htmltrackelement; module.exports = exports['default']; },{"../event-target":101,"../tracks/text-track":130,"../utils/browser.js":131,"global/document":1}],124:[function(_dereq_,module,exports){ /** * @file text-track-cue-list.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /** * a list of text track cues as defined in: * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist * * interface texttrackcuelist { * readonly attribute unsigned long length; * getter texttrackcue (unsigned long index); * texttrackcue? getcuebyid(domstring id); * }; * * @param {array} cues a list of cues to be initialized with * @class texttrackcuelist */ var texttrackcuelist = (function () { function texttrackcuelist(cues) { _classcallcheck(this, texttrackcuelist); var list = this; if (browser.is_ie8) { list = _globaldocument2['default'].createelement('custom'); for (var prop in texttrackcuelist.prototype) { if (prop !== 'constructor') { list[prop] = texttrackcuelist.prototype[prop]; } } } texttrackcuelist.prototype.setcues_.call(list, cues); object.defineproperty(list, 'length', { get: function get() { return this.length_; } }); if (browser.is_ie8) { return list; } } /** * a setter for cues in this list * * @param {array} cues an array of cues * @method setcues_ * @private */ texttrackcuelist.prototype.setcues_ = function setcues_(cues) { var oldlength = this.length || 0; var i = 0; var l = cues.length; this.cues_ = cues; this.length_ = cues.length; var defineprop = function defineprop(index) { if (!('' + index in this)) { object.defineproperty(this, '' + index, { get: function get() { return this.cues_[index]; } }); } }; if (oldlength < l) { i = oldlength; for (; i < l; i++) { defineprop.call(this, i); } } }; /** * get a cue that is currently in the cue list by id * * @param {string} id * @method getcuebyid * @return {object} a single cue */ texttrackcuelist.prototype.getcuebyid = function getcuebyid(id) { var result = null; for (var i = 0, l = this.length; i < l; i++) { var cue = this[i]; if (cue.id === id) { result = cue; break; } } return result; }; return texttrackcuelist; })(); exports['default'] = texttrackcuelist; module.exports = exports['default']; },{"../utils/browser.js":131,"global/document":1}],125:[function(_dereq_,module,exports){ /** * @file text-track-display.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _menumenujs = _dereq_('../menu/menu.js'); var _menumenujs2 = _interoprequiredefault(_menumenujs); var _menumenuitemjs = _dereq_('../menu/menu-item.js'); var _menumenuitemjs2 = _interoprequiredefault(_menumenuitemjs); var _menumenubuttonjs = _dereq_('../menu/menu-button.js'); var _menumenubuttonjs2 = _interoprequiredefault(_menumenubuttonjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var darkgray = '#222'; var lightgray = '#ccc'; var fontmap = { monospace: 'monospace', sansserif: 'sans-serif', serif: 'serif', monospacesansserif: '"andale mono", "lucida console", monospace', monospaceserif: '"courier new", monospace', proportionalsansserif: 'sans-serif', proportionalserif: 'serif', casual: '"comic sans ms", impact, fantasy', script: '"monotype corsiva", cursive', smallcaps: '"andale mono", "lucida console", monospace, sans-serif' }; /** * the component for displaying text track cues * * @param {object} player main player * @param {object=} options object of option names and values * @param {function=} ready ready callback function * @extends component * @class texttrackdisplay */ var texttrackdisplay = (function (_component) { _inherits(texttrackdisplay, _component); function texttrackdisplay(player, options, ready) { _classcallcheck(this, texttrackdisplay); _component.call(this, player, options, ready); player.on('loadstart', fn.bind(this, this.toggledisplay)); player.on('texttrackchange', fn.bind(this, this.updatedisplay)); // this used to be called during player init, but was causing an error // if a track should show by default and the display hadn't loaded yet. // should probably be moved to an external track loader when we support // tracks that don't need a display. player.ready(fn.bind(this, function () { if (player.tech_ && player.tech_['featuresnativetexttracks']) { this.hide(); return; } player.on('fullscreenchange', fn.bind(this, this.updatedisplay)); var tracks = this.options_.playeroptions['tracks'] || []; for (var i = 0; i < tracks.length; i++) { var track = tracks[i]; this.player_.addremotetexttrack(track); } var modes = { 'captions': 1, 'subtitles': 1 }; var tracklist = this.player_.texttracks(); var firstdesc = undefined; var firstcaptions = undefined; if (tracklist) { for (var i = 0; i < tracklist.length; i++) { var track = tracklist[i]; if (track['default']) { if (track.kind === 'descriptions' && !firstdesc) { firstdesc = track; } else if (track.kind in modes && !firstcaptions) { firstcaptions = track; } } } // we want to show the first default track but captions and subtitles // take precedence over descriptions. // so, display the first default captions or subtitles track // and otherwise the first default descriptions track. if (firstcaptions) { firstcaptions.mode = 'showing'; } else if (firstdesc) { firstdesc.mode = 'showing'; } } })); } /** * add cue html to display * * @param {number} color hex number for color, like #f0e * @param {number} opacity value for opacity,0.0 - 1.0 * @return {rgbacolor} in the form 'rgba(255, 0, 0, 0.3)' * @method constructcolor */ /** * toggle display texttracks * * @method toggledisplay */ texttrackdisplay.prototype.toggledisplay = function toggledisplay() { if (this.player_.tech_ && this.player_.tech_['featuresnativetexttracks']) { this.hide(); } else { this.show(); } }; /** * create the component's dom element * * @return {element} * @method createel */ texttrackdisplay.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-text-track-display' }, { 'aria-live': 'assertive', 'aria-atomic': 'true' }); }; /** * clear display texttracks * * @method cleardisplay */ texttrackdisplay.prototype.cleardisplay = function cleardisplay() { if (typeof _globalwindow2['default']['webvtt'] === 'function') { _globalwindow2['default']['webvtt']['processcues'](_globalwindow2['default'], [], this.el_); } }; /** * update display texttracks * * @method updatedisplay */ texttrackdisplay.prototype.updatedisplay = function updatedisplay() { var tracks = this.player_.texttracks(); this.cleardisplay(); if (!tracks) { return; } // track display prioritization model: if multiple tracks are 'showing', // display the first 'subtitles' or 'captions' track which is 'showing', // otherwise display the first 'descriptions' track which is 'showing' var descriptionstrack = null; var captionssubtitlestrack = null; var i = tracks.length; while (i--) { var track = tracks[i]; if (track['mode'] === 'showing') { if (track['kind'] === 'descriptions') { descriptionstrack = track; } else { captionssubtitlestrack = track; } } } if (captionssubtitlestrack) { this.updatefortrack(captionssubtitlestrack); } else if (descriptionstrack) { this.updatefortrack(descriptionstrack); } }; /** * add texttrack to texttrack list * * @param {texttrackobject} track texttrack object to be added to list * @method updatefortrack */ texttrackdisplay.prototype.updatefortrack = function updatefortrack(track) { if (typeof _globalwindow2['default']['webvtt'] !== 'function' || !track['activecues']) { return; } var overrides = this.player_['texttracksettings'].getvalues(); var cues = []; for (var _i = 0; _i < track['activecues'].length; _i++) { cues.push(track['activecues'][_i]); } _globalwindow2['default']['webvtt']['processcues'](_globalwindow2['default'], cues, this.el_); var i = cues.length; while (i--) { var cue = cues[i]; if (!cue) { continue; } var cuediv = cue.displaystate; if (overrides.color) { cuediv.firstchild.style.color = overrides.color; } if (overrides.textopacity) { tryupdatestyle(cuediv.firstchild, 'color', constructcolor(overrides.color || '#fff', overrides.textopacity)); } if (overrides.backgroundcolor) { cuediv.firstchild.style.backgroundcolor = overrides.backgroundcolor; } if (overrides.backgroundopacity) { tryupdatestyle(cuediv.firstchild, 'backgroundcolor', constructcolor(overrides.backgroundcolor || '#000', overrides.backgroundopacity)); } if (overrides.windowcolor) { if (overrides.windowopacity) { tryupdatestyle(cuediv, 'backgroundcolor', constructcolor(overrides.windowcolor, overrides.windowopacity)); } else { cuediv.style.backgroundcolor = overrides.windowcolor; } } if (overrides.edgestyle) { if (overrides.edgestyle === 'dropshadow') { cuediv.firstchild.style.textshadow = '2px 2px 3px ' + darkgray + ', 2px 2px 4px ' + darkgray + ', 2px 2px 5px ' + darkgray; } else if (overrides.edgestyle === 'raised') { cuediv.firstchild.style.textshadow = '1px 1px ' + darkgray + ', 2px 2px ' + darkgray + ', 3px 3px ' + darkgray; } else if (overrides.edgestyle === 'depressed') { cuediv.firstchild.style.textshadow = '1px 1px ' + lightgray + ', 0 1px ' + lightgray + ', -1px -1px ' + darkgray + ', 0 -1px ' + darkgray; } else if (overrides.edgestyle === 'uniform') { cuediv.firstchild.style.textshadow = '0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray + ', 0 0 4px ' + darkgray; } } if (overrides.fontpercent && overrides.fontpercent !== 1) { var fontsize = _globalwindow2['default'].parsefloat(cuediv.style.fontsize); cuediv.style.fontsize = fontsize * overrides.fontpercent + 'px'; cuediv.style.height = 'auto'; cuediv.style.top = 'auto'; cuediv.style.bottom = '2px'; } if (overrides.fontfamily && overrides.fontfamily !== 'default') { if (overrides.fontfamily === 'small-caps') { cuediv.firstchild.style.fontvariant = 'small-caps'; } else { cuediv.firstchild.style.fontfamily = fontmap[overrides.fontfamily]; } } } }; return texttrackdisplay; })(_component2['default']); function constructcolor(color, opacity) { return 'rgba(' + // color looks like "#f0e" parseint(color[1] + color[1], 16) + ',' + parseint(color[2] + color[2], 16) + ',' + parseint(color[3] + color[3], 16) + ',' + opacity + ')'; } /** * try to update style * some style changes will throw an error, particularly in ie8. those should be noops. * * @param {element} el the element to be styles * @param {cssproperty} style the css property to be styled * @param {cssstyle} rule the actual style to be applied to the property * @method tryupdatestyle */ function tryupdatestyle(el, style, rule) { // try { el.style[style] = rule; } catch (e) {} } _component2['default'].registercomponent('texttrackdisplay', texttrackdisplay); exports['default'] = texttrackdisplay; module.exports = exports['default']; },{"../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){ /** * @file text-track-enums.js */ /** * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode * * enum texttrackmode { "disabled", "hidden", "showing" }; */ 'use strict'; exports.__esmodule = true; var texttrackmode = { disabled: 'disabled', hidden: 'hidden', showing: 'showing' }; /** * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind * * enum texttrackkind { * "subtitles", * "captions", * "descriptions", * "chapters", * "metadata" * }; */ var texttrackkind = { subtitles: 'subtitles', captions: 'captions', descriptions: 'descriptions', chapters: 'chapters', metadata: 'metadata' }; /* jshint ignore:start */ // we ignore jshint here because it does not see // texttrackmode or texttrackkind as defined here somehow... exports.texttrackmode = texttrackmode; exports.texttrackkind = texttrackkind; /* jshint ignore:end */ },{}],127:[function(_dereq_,module,exports){ /** * utilities for capturing text track state and re-creating tracks * based on a capture. * * @file text-track-list-converter.js */ /** * examine a single text track and return a json-compatible javascript * object that represents the text track's state. * @param track {texttrackobject} the text track to query * @return {object} a serializable javascript representation of the * @private */ 'use strict'; exports.__esmodule = true; var tracktojson_ = function tracktojson_(track) { var ret = ['kind', 'label', 'language', 'id', 'inbandmetadatatrackdispatchtype', 'mode', 'src'].reduce(function (acc, prop, i) { if (track[prop]) { acc[prop] = track[prop]; } return acc; }, { cues: track.cues && array.prototype.map.call(track.cues, function (cue) { return { starttime: cue.starttime, endtime: cue.endtime, text: cue.text, id: cue.id }; }) }); return ret; }; /** * examine a tech and return a json-compatible javascript array that * represents the state of all text tracks currently configured. the * return array is compatible with `jsontotexttracks`. * @param tech {tech} the tech object to query * @return {array} a serializable javascript representation of the * @function texttrackstojson */ var texttrackstojson = function texttrackstojson(tech) { var trackels = tech.$$('track'); var trackobjs = array.prototype.map.call(trackels, function (t) { return t.track; }); var tracks = array.prototype.map.call(trackels, function (trackel) { var json = tracktojson_(trackel.track); if (trackel.src) { json.src = trackel.src; } return json; }); return tracks.concat(array.prototype.filter.call(tech.texttracks(), function (track) { return trackobjs.indexof(track) === -1; }).map(tracktojson_)); }; /** * creates a set of remote text tracks on a tech based on an array of * javascript text track representations. * @param json {array} an array of text track representation objects, * like those that would be produced by `texttrackstojson` * @param tech {tech} the tech to create text tracks on * @function jsontotexttracks */ var jsontotexttracks = function jsontotexttracks(json, tech) { json.foreach(function (track) { var addedtrack = tech.addremotetexttrack(track).track; if (!track.src && track.cues) { track.cues.foreach(function (cue) { return addedtrack.addcue(cue); }); } }); return tech.texttracks(); }; exports['default'] = { texttrackstojson: texttrackstojson, jsontotexttracks: jsontotexttracks, tracktojson_: tracktojson_ }; module.exports = exports['default']; },{}],128:[function(_dereq_,module,exports){ /** * @file text-track-list.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _eventtarget = _dereq_('../event-target'); var _eventtarget2 = _interoprequiredefault(_eventtarget); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /** * a text track list as defined in: * https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist * * interface texttracklist : eventtarget { * readonly attribute unsigned long length; * getter texttrack (unsigned long index); * texttrack? gettrackbyid(domstring id); * * attribute eventhandler onchange; * attribute eventhandler onaddtrack; * attribute eventhandler onremovetrack; * }; * * @param {track[]} tracks a list of tracks to initialize the list with * @extends eventtarget * @class texttracklist */ var texttracklist = (function (_eventtarget) { _inherits(texttracklist, _eventtarget); function texttracklist() { var tracks = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; _classcallcheck(this, texttracklist); _eventtarget.call(this); var list = this; if (browser.is_ie8) { list = _globaldocument2['default'].createelement('custom'); for (var prop in texttracklist.prototype) { if (prop !== 'constructor') { list[prop] = texttracklist.prototype[prop]; } } } list.tracks_ = []; object.defineproperty(list, 'length', { get: function get() { return this.tracks_.length; } }); for (var i = 0; i < tracks.length; i++) { list.addtrack_(tracks[i]); } if (browser.is_ie8) { return list; } } /** * change - one or more tracks in the track list have been enabled or disabled. * addtrack - a track has been added to the track list. * removetrack - a track has been removed from the track list. */ /** * add texttrack from texttracklist * * @param {texttrack} track * @method addtrack_ * @private */ texttracklist.prototype.addtrack_ = function addtrack_(track) { var index = this.tracks_.length; if (!('' + index in this)) { object.defineproperty(this, index, { get: function get() { return this.tracks_[index]; } }); } track.addeventlistener('modechange', fn.bind(this, function () { this.trigger('change'); })); // do not add duplicate tracks if (this.tracks_.indexof(track) === -1) { this.tracks_.push(track); this.trigger({ track: track, type: 'addtrack' }); } }; /** * remove texttrack from texttracklist * note: be mindful of what is passed in as it may be a htmltrackelement * * @param {texttrack} rtrack * @method removetrack_ * @private */ texttracklist.prototype.removetrack_ = function removetrack_(rtrack) { var track = undefined; for (var i = 0, l = this.length; i < l; i++) { if (this[i] === rtrack) { track = this[i]; if (track.off) { track.off(); } this.tracks_.splice(i, 1); break; } } if (!track) { return; } this.trigger({ track: track, type: 'removetrack' }); }; /** * get a texttrack from texttracklist by a tracks id * * @param {string} id - the id of the track to get * @method gettrackbyid * @return {texttrack} * @private */ texttracklist.prototype.gettrackbyid = function gettrackbyid(id) { var result = null; for (var i = 0, l = this.length; i < l; i++) { var track = this[i]; if (track.id === id) { result = track; break; } } return result; }; return texttracklist; })(_eventtarget2['default']); texttracklist.prototype.allowedevents_ = { change: 'change', addtrack: 'addtrack', removetrack: 'removetrack' }; // emulate attribute eventhandler support to allow for feature detection for (var _event in texttracklist.prototype.allowedevents_) { texttracklist.prototype['on' + _event] = null; } exports['default'] = texttracklist; module.exports = exports['default']; },{"../event-target":101,"../utils/browser.js":131,"../utils/fn.js":136,"global/document":1}],129:[function(_dereq_,module,exports){ /** * @file text-track-settings.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _component = _dereq_('../component'); var _component2 = _interoprequiredefault(_component); var _utilseventsjs = _dereq_('../utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilslogjs = _dereq_('../utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _safejsonparsetuple = _dereq_('safe-json-parse/tuple'); var _safejsonparsetuple2 = _interoprequiredefault(_safejsonparsetuple); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); /** * manipulate settings of texttracks * * @param {object} player main player * @param {object=} options object of option names and values * @extends component * @class texttracksettings */ var texttracksettings = (function (_component) { _inherits(texttracksettings, _component); function texttracksettings(player, options) { _classcallcheck(this, texttracksettings); _component.call(this, player, options); this.hide(); // grab `persisttexttracksettings` from the player options if not passed in child options if (options.persisttexttracksettings === undefined) { this.options_.persisttexttracksettings = this.options_.playeroptions.persisttexttracksettings; } events.on(this.$('.vjs-done-button'), 'click', fn.bind(this, function () { this.savesettings(); this.hide(); })); events.on(this.$('.vjs-default-button'), 'click', fn.bind(this, function () { this.$('.vjs-fg-color > select').selectedindex = 0; this.$('.vjs-bg-color > select').selectedindex = 0; this.$('.window-color > select').selectedindex = 0; this.$('.vjs-text-opacity > select').selectedindex = 0; this.$('.vjs-bg-opacity > select').selectedindex = 0; this.$('.vjs-window-opacity > select').selectedindex = 0; this.$('.vjs-edge-style select').selectedindex = 0; this.$('.vjs-font-family select').selectedindex = 0; this.$('.vjs-font-percent select').selectedindex = 2; this.updatedisplay(); })); events.on(this.$('.vjs-fg-color > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-bg-color > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.window-color > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-text-opacity > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-bg-opacity > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-window-opacity > select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-font-percent select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-edge-style select'), 'change', fn.bind(this, this.updatedisplay)); events.on(this.$('.vjs-font-family select'), 'change', fn.bind(this, this.updatedisplay)); if (this.options_.persisttexttracksettings) { this.restoresettings(); } } /** * create the component's dom element * * @return {element} * @method createel */ texttracksettings.prototype.createel = function createel() { return _component.prototype.createel.call(this, 'div', { classname: 'vjs-caption-settings vjs-modal-overlay', innerhtml: captionoptionsmenutemplate() }); }; /** * get texttrack settings * settings are * .vjs-edge-style * .vjs-font-family * .vjs-fg-color * .vjs-text-opacity * .vjs-bg-color * .vjs-bg-opacity * .window-color * .vjs-window-opacity * * @return {object} * @method getvalues */ texttracksettings.prototype.getvalues = function getvalues() { var textedge = getselectedoptionvalue(this.$('.vjs-edge-style select')); var fontfamily = getselectedoptionvalue(this.$('.vjs-font-family select')); var fgcolor = getselectedoptionvalue(this.$('.vjs-fg-color > select')); var textopacity = getselectedoptionvalue(this.$('.vjs-text-opacity > select')); var bgcolor = getselectedoptionvalue(this.$('.vjs-bg-color > select')); var bgopacity = getselectedoptionvalue(this.$('.vjs-bg-opacity > select')); var windowcolor = getselectedoptionvalue(this.$('.window-color > select')); var windowopacity = getselectedoptionvalue(this.$('.vjs-window-opacity > select')); var fontpercent = _globalwindow2['default']['parsefloat'](getselectedoptionvalue(this.$('.vjs-font-percent > select'))); var result = { 'backgroundopacity': bgopacity, 'textopacity': textopacity, 'windowopacity': windowopacity, 'edgestyle': textedge, 'fontfamily': fontfamily, 'color': fgcolor, 'backgroundcolor': bgcolor, 'windowcolor': windowcolor, 'fontpercent': fontpercent }; for (var _name in result) { if (result[_name] === '' || result[_name] === 'none' || _name === 'fontpercent' && result[_name] === 1.00) { delete result[_name]; } } return result; }; /** * set texttrack settings * settings are * .vjs-edge-style * .vjs-font-family * .vjs-fg-color * .vjs-text-opacity * .vjs-bg-color * .vjs-bg-opacity * .window-color * .vjs-window-opacity * * @param {object} values object with texttrack setting values * @method setvalues */ texttracksettings.prototype.setvalues = function setvalues(values) { setselectedoption(this.$('.vjs-edge-style select'), values.edgestyle); setselectedoption(this.$('.vjs-font-family select'), values.fontfamily); setselectedoption(this.$('.vjs-fg-color > select'), values.color); setselectedoption(this.$('.vjs-text-opacity > select'), values.textopacity); setselectedoption(this.$('.vjs-bg-color > select'), values.backgroundcolor); setselectedoption(this.$('.vjs-bg-opacity > select'), values.backgroundopacity); setselectedoption(this.$('.window-color > select'), values.windowcolor); setselectedoption(this.$('.vjs-window-opacity > select'), values.windowopacity); var fontpercent = values.fontpercent; if (fontpercent) { fontpercent = fontpercent.tofixed(2); } setselectedoption(this.$('.vjs-font-percent > select'), fontpercent); }; /** * restore texttrack settings * * @method restoresettings */ texttracksettings.prototype.restoresettings = function restoresettings() { var err = undefined, values = undefined; try { var _safeparsetuple = _safejsonparsetuple2['default'](_globalwindow2['default'].localstorage.getitem('vjs-text-track-settings')); err = _safeparsetuple[0]; values = _safeparsetuple[1]; if (err) { _utilslogjs2['default'].error(err); } } catch (e) { _utilslogjs2['default'].warn(e); } if (values) { this.setvalues(values); } }; /** * save texttrack settings to local storage * * @method savesettings */ texttracksettings.prototype.savesettings = function savesettings() { if (!this.options_.persisttexttracksettings) { return; } var values = this.getvalues(); try { if (object.getownpropertynames(values).length > 0) { _globalwindow2['default'].localstorage.setitem('vjs-text-track-settings', json.stringify(values)); } else { _globalwindow2['default'].localstorage.removeitem('vjs-text-track-settings'); } } catch (e) { _utilslogjs2['default'].warn(e); } }; /** * update display of texttrack settings * * @method updatedisplay */ texttracksettings.prototype.updatedisplay = function updatedisplay() { var ttdisplay = this.player_.getchild('texttrackdisplay'); if (ttdisplay) { ttdisplay.updatedisplay(); } }; return texttracksettings; })(_component2['default']); _component2['default'].registercomponent('texttracksettings', texttracksettings); function getselectedoptionvalue(target) { var selectedoption = undefined; // not all browsers support selectedoptions, so, fallback to options if (target.selectedoptions) { selectedoption = target.selectedoptions[0]; } else if (target.options) { selectedoption = target.options[target.options.selectedindex]; } return selectedoption.value; } function setselectedoption(target, value) { if (!value) { return; } var i = undefined; for (i = 0; i < target.options.length; i++) { var option = target.options[i]; if (option.value === value) { break; } } target.selectedindex = i; } function captionoptionsmenutemplate() { var template = '
    \n
    \n
    \n \n \n \n \n \n
    \n
    \n \n \n \n \n \n
    \n
    \n \n \n \n \n \n
    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n
    '; return template; } exports['default'] = texttracksettings; module.exports = exports['default']; },{"../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){ /** * @file text-track.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _classcallcheck(instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror('cannot call a class as a function'); } } 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; } var _texttrackcuelist = _dereq_('./text-track-cue-list'); var _texttrackcuelist2 = _interoprequiredefault(_texttrackcuelist); var _utilsfnjs = _dereq_('../utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _utilsguidjs = _dereq_('../utils/guid.js'); var guid = _interoprequirewildcard(_utilsguidjs); var _utilsbrowserjs = _dereq_('../utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _texttrackenums = _dereq_('./text-track-enums'); var texttrackenum = _interoprequirewildcard(_texttrackenums); var _utilslogjs = _dereq_('../utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _eventtarget = _dereq_('../event-target'); var _eventtarget2 = _interoprequiredefault(_eventtarget); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _utilsurljs = _dereq_('../utils/url.js'); var _xhr = _dereq_('xhr'); var _xhr2 = _interoprequiredefault(_xhr); /** * takes a webvtt file contents and parses it into cues * * @param {string} srccontent webvtt file contents * @param {track} track track to addcues to */ var parsecues = function parsecues(srccontent, track) { var parser = new _globalwindow2['default'].webvtt.parser(_globalwindow2['default'], _globalwindow2['default'].vttjs, _globalwindow2['default'].webvtt.stringdecoder()); var errors = []; parser.oncue = function (cue) { track.addcue(cue); }; parser.onparsingerror = function (error) { errors.push(error); }; parser.onflush = function () { track.trigger({ type: 'loadeddata', target: track }); }; parser.parse(srccontent); if (errors.length > 0) { if (console.groupcollapsed) { console.groupcollapsed('text track parsing errors for ' + track.src); } errors.foreach(function (error) { return _utilslogjs2['default'].error(error); }); if (console.groupend) { console.groupend(); } } parser.flush(); }; /** * load a track from a specifed url * * @param {string} src url to load track from * @param {track} track track to addcues to */ var loadtrack = function loadtrack(src, track) { var opts = { uri: src }; var crossorigin = _utilsurljs.iscrossorigin(src); if (crossorigin) { opts.cors = crossorigin; } _xhr2['default'](opts, fn.bind(this, function (err, response, responsebody) { if (err) { return _utilslogjs2['default'].error(err, response); } track.loaded_ = true; // make sure that vttjs has loaded, otherwise, wait till it finished loading // note: this is only used for the alt/video.novtt.js build if (typeof _globalwindow2['default'].webvtt !== 'function') { if (track.tech_) { (function () { var loadhandler = function loadhandler() { return parsecues(responsebody, track); }; track.tech_.on('vttjsloaded', loadhandler); track.tech_.on('vttjserror', function () { _utilslogjs2['default'].error('vttjs failed to load, stopping trying to process ' + track.src); track.tech_.off('vttjsloaded', loadhandler); }); })(); } } else { parsecues(responsebody, track); } })); }; /** * a single text track as defined in: * https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack * * interface texttrack : eventtarget { * readonly attribute texttrackkind kind; * readonly attribute domstring label; * readonly attribute domstring language; * * readonly attribute domstring id; * readonly attribute domstring inbandmetadatatrackdispatchtype; * * attribute texttrackmode mode; * * readonly attribute texttrackcuelist? cues; * readonly attribute texttrackcuelist? activecues; * * void addcue(texttrackcue cue); * void removecue(texttrackcue cue); * * attribute eventhandler oncuechange; * }; * * @param {object=} options object of option names and values * @extends eventtarget * @class texttrack */ var texttrack = (function (_eventtarget) { _inherits(texttrack, _eventtarget); function texttrack() { var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; _classcallcheck(this, texttrack); _eventtarget.call(this); if (!options.tech) { throw new error('a tech was not provided.'); } var tt = this; if (browser.is_ie8) { tt = _globaldocument2['default'].createelement('custom'); for (var prop in texttrack.prototype) { if (prop !== 'constructor') { tt[prop] = texttrack.prototype[prop]; } } } tt.tech_ = options.tech; var mode = texttrackenum.texttrackmode[options.mode] || 'disabled'; var kind = texttrackenum.texttrackkind[options.kind] || 'subtitles'; var default_ = options['default']; var label = options.label || ''; var language = options.language || options.srclang || ''; var id = options.id || 'vjs_text_track_' + guid.newguid(); if (kind === 'metadata' || kind === 'chapters') { mode = 'hidden'; } tt.cues_ = []; tt.activecues_ = []; var cues = new _texttrackcuelist2['default'](tt.cues_); var activecues = new _texttrackcuelist2['default'](tt.activecues_); var changed = false; var timeupdatehandler = fn.bind(tt, function () { this.activecues; if (changed) { this.trigger('cuechange'); changed = false; } }); if (mode !== 'disabled') { tt.tech_.on('timeupdate', timeupdatehandler); } object.defineproperty(tt, 'kind', { get: function get() { return kind; }, set: function set() {} }); object.defineproperty(tt, 'label', { get: function get() { return label; }, set: function set() {} }); object.defineproperty(tt, 'language', { get: function get() { return language; }, set: function set() {} }); object.defineproperty(tt, 'id', { get: function get() { return id; }, set: function set() {} }); object.defineproperty(tt, 'default', { get: function get() { return default_; }, set: function set() {} }); object.defineproperty(tt, 'mode', { get: function get() { return mode; }, set: function set(newmode) { if (!texttrackenum.texttrackmode[newmode]) { return; } mode = newmode; if (mode === 'showing') { this.tech_.on('timeupdate', timeupdatehandler); } this.trigger('modechange'); } }); object.defineproperty(tt, 'cues', { get: function get() { if (!this.loaded_) { return null; } return cues; }, set: function set() {} }); object.defineproperty(tt, 'activecues', { get: function get() { if (!this.loaded_) { return null; } // nothing to do if (this.cues.length === 0) { return activecues; } var ct = this.tech_.currenttime(); var active = []; for (var i = 0, l = this.cues.length; i < l; i++) { var cue = this.cues[i]; if (cue.starttime <= ct && cue.endtime >= ct) { active.push(cue); } else if (cue.starttime === cue.endtime && cue.starttime <= ct && cue.starttime + 0.5 >= ct) { active.push(cue); } } changed = false; if (active.length !== this.activecues_.length) { changed = true; } else { for (var i = 0; i < active.length; i++) { if (this.activecues_.indexof(active[i]) === -1) { changed = true; } } } this.activecues_ = active; activecues.setcues_(this.activecues_); return activecues; }, set: function set() {} }); if (options.src) { tt.src = options.src; loadtrack(options.src, tt); } else { tt.loaded_ = true; } if (browser.is_ie8) { return tt; } } /** * cuechange - one or more cues in the track have become active or stopped being active. */ /** * add a cue to the internal list of cues * * @param {object} cue the cue to add to our internal list * @method addcue */ texttrack.prototype.addcue = function addcue(cue) { var tracks = this.tech_.texttracks(); if (tracks) { for (var i = 0; i < tracks.length; i++) { if (tracks[i] !== this) { tracks[i].removecue(cue); } } } this.cues_.push(cue); this.cues.setcues_(this.cues_); }; /** * remvoe a cue from our internal list * * @param {object} removecue the cue to remove from our internal list * @method removecue */ texttrack.prototype.removecue = function removecue(_removecue) { var removed = false; for (var i = 0, l = this.cues_.length; i < l; i++) { var cue = this.cues_[i]; if (cue === _removecue) { this.cues_.splice(i, 1); removed = true; } } if (removed) { this.cues.setcues_(this.cues_); } }; return texttrack; })(_eventtarget2['default']); texttrack.prototype.allowedevents_ = { cuechange: 'cuechange' }; exports['default'] = texttrack; module.exports = exports['default']; },{"../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){ /** * @file browser.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var user_agent = _globalwindow2['default'].navigator.useragent; var webkitversionmap = /applewebkit\/([\d.]+)/i.exec(user_agent); var applewebkitversion = webkitversionmap ? parsefloat(webkitversionmap.pop()) : null; /* * device is an iphone * * @type {boolean} * @constant * @private */ var is_ipad = /ipad/i.test(user_agent); exports.is_ipad = is_ipad; // the facebook app's uiwebview identifies as both an iphone and ipad, so // to identify iphones, we need to exclude ipads. // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/ var is_iphone = /iphone/i.test(user_agent) && !is_ipad; exports.is_iphone = is_iphone; var is_ipod = /ipod/i.test(user_agent); exports.is_ipod = is_ipod; var is_ios = is_iphone || is_ipad || is_ipod; exports.is_ios = is_ios; var ios_version = (function () { var match = user_agent.match(/os (\d+)_/i); if (match && match[1]) { return match[1]; } })(); exports.ios_version = ios_version; var is_android = /android/i.test(user_agent); exports.is_android = is_android; var android_version = (function () { // this matches android major.minor.patch versions // android_version is major.minor as a number, if minor isn't available, then only major is returned var match = user_agent.match(/android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i), major, minor; if (!match) { return null; } major = match[1] && parsefloat(match[1]); minor = match[2] && parsefloat(match[2]); if (major && minor) { return parsefloat(match[1] + '.' + match[2]); } else if (major) { return major; } else { return null; } })(); exports.android_version = android_version; // old android is defined as version older than 2.3, and requiring a webkit version of the android browser var is_old_android = is_android && /webkit/i.test(user_agent) && android_version < 2.3; exports.is_old_android = is_old_android; var is_native_android = is_android && android_version < 5 && applewebkitversion < 537; exports.is_native_android = is_native_android; var is_firefox = /firefox/i.test(user_agent); exports.is_firefox = is_firefox; var is_edge = /edge/i.test(user_agent); exports.is_edge = is_edge; var is_chrome = !is_edge && /chrome/i.test(user_agent); exports.is_chrome = is_chrome; var is_ie8 = /msie\s8\.0/.test(user_agent); exports.is_ie8 = is_ie8; var touch_enabled = !!('ontouchstart' in _globalwindow2['default'] || _globalwindow2['default'].documenttouch && _globaldocument2['default'] instanceof _globalwindow2['default'].documenttouch); exports.touch_enabled = touch_enabled; var background_size_supported = ('backgroundsize' in _globaldocument2['default'].createelement('video').style); exports.background_size_supported = background_size_supported; },{"global/document":1,"global/window":2}],132:[function(_dereq_,module,exports){ /** * @file buffer.js */ 'use strict'; exports.__esmodule = true; exports.bufferedpercent = bufferedpercent; var _timerangesjs = _dereq_('./time-ranges.js'); /** * compute how much your video has been buffered * * @param {object} buffered object * @param {number} total duration * @return {number} percent buffered of the total duration * @private * @function bufferedpercent */ function bufferedpercent(buffered, duration) { var bufferedduration = 0, start, end; if (!duration) { return 0; } if (!buffered || !buffered.length) { buffered = _timerangesjs.createtimerange(0, 0); } for (var i = 0; i < buffered.length; i++) { start = buffered.start(i); end = buffered.end(i); // buffered end can be bigger than duration by a very small fraction if (end > duration) { end = duration; } bufferedduration += end - start; } return bufferedduration / duration; } },{"./time-ranges.js":142}],133:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _logjs = _dereq_('./log.js'); var _logjs2 = _interoprequiredefault(_logjs); /** * object containing the default behaviors for available handler methods. * * @private * @type {object} */ var defaultbehaviors = { get: function get(obj, key) { return obj[key]; }, set: function set(obj, key, value) { obj[key] = value; return true; } }; /** * expose private objects publicly using a proxy to log deprecation warnings. * * browsers that do not support proxy objects will simply return the `target` * object, so it can be directly exposed. * * @param {object} target the target object. * @param {object} messages messages to display from a proxy. only operations * with an associated message will be proxied. * @param {string} [messages.get] * @param {string} [messages.set] * @return {object} a proxy if supported or the `target` argument. */ exports['default'] = function (target) { var messages = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; if (typeof proxy === 'function') { var _ret = (function () { var handler = {}; // build a handler object based on those keys that have both messages // and default behaviors. object.keys(messages).foreach(function (key) { if (defaultbehaviors.hasownproperty(key)) { handler[key] = function () { _logjs2['default'].warn(messages[key]); return defaultbehaviors[key].apply(this, arguments); }; } }); return { v: new proxy(target, handler) }; })(); if (typeof _ret === 'object') return _ret.v; } return target; }; module.exports = exports['default']; },{"./log.js":139}],134:[function(_dereq_,module,exports){ /** * @file dom.js */ 'use strict'; exports.__esmodule = true; exports.getel = getel; exports.createel = createel; exports.textcontent = textcontent; exports.insertelfirst = insertelfirst; exports.geteldata = geteldata; exports.haseldata = haseldata; exports.removeeldata = removeeldata; exports.haselclass = haselclass; exports.addelclass = addelclass; exports.removeelclass = removeelclass; exports.toggleelclass = toggleelclass; exports.setelattributes = setelattributes; exports.getelattributes = getelattributes; exports.blocktextselection = blocktextselection; exports.unblocktextselection = unblocktextselection; exports.findelposition = findelposition; exports.getpointerposition = getpointerposition; exports.isel = isel; exports.istextnode = istextnode; exports.emptyel = emptyel; exports.normalizecontent = normalizecontent; exports.appendcontent = appendcontent; exports.insertcontent = insertcontent; 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 ', '.']); 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } function _taggedtemplateliteralloose(strings, raw) { strings.raw = raw; return strings; } var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _guidjs = _dereq_('./guid.js'); var guid = _interoprequirewildcard(_guidjs); var _logjs = _dereq_('./log.js'); var _logjs2 = _interoprequiredefault(_logjs); var _tsml = _dereq_('tsml'); var _tsml2 = _interoprequiredefault(_tsml); /** * detect if a value is a string with any non-whitespace characters. * * @param {string} str * @return {boolean} */ function isnonblankstring(str) { return typeof str === 'string' && /\s/.test(str); } /** * throws an error if the passed string has whitespace. this is used by * class methods to be relatively consistent with the classlist api. * * @param {string} str * @return {boolean} */ function throwifwhitespace(str) { if (/\s/.test(str)) { throw new error('class has illegal whitespace characters'); } } /** * produce a regular expression for matching a class name. * * @param {string} classname * @return {regexp} */ function classregexp(classname) { return new regexp('(^|\\s)' + classname + '($|\\s)'); } /** * creates functions to query the dom using a given method. * * @function createquerier * @private * @param {string} method * @return {function} */ function createquerier(method) { return function (selector, context) { if (!isnonblankstring(selector)) { return _globaldocument2['default'][method](null); } if (isnonblankstring(context)) { context = _globaldocument2['default'].queryselector(context); } return (isel(context) ? context : _globaldocument2['default'])[method](selector); }; } /** * shorthand for document.getelementbyid() * also allows for css (jquery) id syntax. but nothing other than ids. * * @param {string} id element id * @return {element} element with supplied id * @function getel */ function getel(id) { if (id.indexof('#') === 0) { id = id.slice(1); } return _globaldocument2['default'].getelementbyid(id); } /** * creates an element and applies properties. * * @param {string} [tagname='div'] name of tag to be created. * @param {object} [properties={}] element properties to be applied. * @param {object} [attributes={}] element attributes to be applied. * @return {element} * @function createel */ function createel() { var tagname = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0]; var properties = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; var el = _globaldocument2['default'].createelement(tagname); object.getownpropertynames(properties).foreach(function (propname) { var val = properties[propname]; // see #2176 // we originally were accepting both properties and attributes in the // same object, but that doesn't work so well. if (propname.indexof('aria-') !== -1 || propname === 'role' || propname === 'type') { _logjs2['default'].warn(_tsml2['default'](_templateobject, propname, val)); el.setattribute(propname, val); } else { el[propname] = val; } }); object.getownpropertynames(attributes).foreach(function (attrname) { var val = attributes[attrname]; el.setattribute(attrname, attributes[attrname]); }); return el; } /** * injects text into an element, replacing any existing contents entirely. * * @param {element} el * @param {string} text * @return {element} * @function textcontent */ function textcontent(el, text) { if (typeof el.textcontent === 'undefined') { el.innertext = text; } else { el.textcontent = text; } } /** * insert an element as the first child node of another * * @param {element} child element to insert * @param {element} parent element to insert child into * @private * @function insertelfirst */ function insertelfirst(child, parent) { if (parent.firstchild) { parent.insertbefore(child, parent.firstchild); } else { parent.appendchild(child); } } /** * element data store. allows for binding data to an element without putting it directly on the element. * ex. event listeners are stored here. * (also from jsninja.com, slightly modified and updated for closure compiler) * * @type {object} * @private */ var eldata = {}; /* * unique attribute name to store an element's guid in * * @type {string} * @constant * @private */ var elidattr = 'vdata' + new date().gettime(); /** * returns the cache object where data for an element is stored * * @param {element} el element to store data for. * @return {object} * @function geteldata */ function geteldata(el) { var id = el[elidattr]; if (!id) { id = el[elidattr] = guid.newguid(); } if (!eldata[id]) { eldata[id] = {}; } return eldata[id]; } /** * returns whether or not an element has cached data * * @param {element} el a dom element * @return {boolean} * @private * @function haseldata */ function haseldata(el) { var id = el[elidattr]; if (!id) { return false; } return !!object.getownpropertynames(eldata[id]).length; } /** * delete data for the element from the cache and the guid attr from getelementbyid * * @param {element} el remove data for an element * @private * @function removeeldata */ function removeeldata(el) { var id = el[elidattr]; if (!id) { return; } // remove all stored data delete eldata[id]; // remove the elidattr property from the dom node try { delete el[elidattr]; } catch (e) { if (el.removeattribute) { el.removeattribute(elidattr); } else { // ie doesn't appear to support removeattribute on the document element el[elidattr] = null; } } } /** * check if an element has a css class * * @function haselclass * @param {element} element element to check * @param {string} classtocheck classname to check */ function haselclass(element, classtocheck) { if (element.classlist) { return element.classlist.contains(classtocheck); } else { throwifwhitespace(classtocheck); return classregexp(classtocheck).test(element.classname); } } /** * add a css class name to an element * * @function addelclass * @param {element} element element to add class name to * @param {string} classtoadd classname to add */ function addelclass(element, classtoadd) { if (element.classlist) { element.classlist.add(classtoadd); // don't need to `throwifwhitespace` here because `haselclass` will do it // in the case of classlist not being supported. } else if (!haselclass(element, classtoadd)) { element.classname = (element.classname + ' ' + classtoadd).trim(); } return element; } /** * remove a css class name from an element * * @function removeelclass * @param {element} element element to remove from class name * @param {string} classtoremove classname to remove */ function removeelclass(element, classtoremove) { if (element.classlist) { element.classlist.remove(classtoremove); } else { throwifwhitespace(classtoremove); element.classname = element.classname.split(/\s+/).filter(function (c) { return c !== classtoremove; }).join(' '); } return element; } /** * adds or removes a css class name on an element depending on an optional * condition or the presence/absence of the class name. * * @function toggleelclass * @param {element} element * @param {string} classtotoggle * @param {boolean|function} [predicate] * can be a function that returns a boolean. if `true`, the class * will be added; if `false`, the class will be removed. if not * given, the class will be added if not present and vice versa. */ function toggleelclass(element, classtotoggle, predicate) { // this cannot use `classlist` internally because ie does not support the // second parameter to the `classlist.toggle()` method! which is fine because // `classlist` will be used by the add/remove functions. var has = haselclass(element, classtotoggle); if (typeof predicate === 'function') { predicate = predicate(element, classtotoggle); } if (typeof predicate !== 'boolean') { predicate = !has; } // if the necessary class operation matches the current state of the // element, no action is required. if (predicate === has) { return; } if (predicate) { addelclass(element, classtotoggle); } else { removeelclass(element, classtotoggle); } return element; } /** * apply attributes to an html element. * * @param {element} el target element. * @param {object=} attributes element attributes to be applied. * @private * @function setelattributes */ function setelattributes(el, attributes) { object.getownpropertynames(attributes).foreach(function (attrname) { var attrvalue = attributes[attrname]; if (attrvalue === null || typeof attrvalue === 'undefined' || attrvalue === false) { el.removeattribute(attrname); } else { el.setattribute(attrname, attrvalue === true ? '' : attrvalue); } }); } /** * get an element's attribute values, as defined on the html tag * attributes are not the same as properties. they're defined on the tag * or with setattribute (which shouldn't be used with html) * this will return true or false for boolean attributes. * * @param {element} tag element from which to get tag attributes * @return {object} * @private * @function getelattributes */ function getelattributes(tag) { var obj, knownbooleans, attrs, attrname, attrval; obj = {}; // known boolean attributes // we can check for matching boolean properties, but older browsers // won't know about html5 boolean attributes that we still read from knownbooleans = ',' + 'autoplay,controls,loop,muted,default' + ','; if (tag && tag.attributes && tag.attributes.length > 0) { attrs = tag.attributes; for (var i = attrs.length - 1; i >= 0; i--) { attrname = attrs[i].name; attrval = attrs[i].value; // check for known booleans // the matching element property will return a value for typeof if (typeof tag[attrname] === 'boolean' || knownbooleans.indexof(',' + attrname + ',') !== -1) { // the value of an included boolean attribute is typically an empty // string ('') which would equal false if we just check for a false value. // we also don't want support bad code like autoplay='false' attrval = attrval !== null ? true : false; } obj[attrname] = attrval; } } return obj; } /** * attempt to block the ability to select text while dragging controls * * @return {boolean} * @function blocktextselection */ function blocktextselection() { _globaldocument2['default'].body.focus(); _globaldocument2['default'].onselectstart = function () { return false; }; } /** * turn off text selection blocking * * @return {boolean} * @function unblocktextselection */ function unblocktextselection() { _globaldocument2['default'].onselectstart = function () { return true; }; } /** * offset left * getboundingclientrect technique from * john resig http://ejohn.org/blog/getboundingclientrect-is-awesome/ * * @function findelposition * @param {element} el element from which to get offset * @return {object} */ function findelposition(el) { var box = undefined; if (el.getboundingclientrect && el.parentnode) { box = el.getboundingclientrect(); } if (!box) { return { left: 0, top: 0 }; } var docel = _globaldocument2['default'].documentelement; var body = _globaldocument2['default'].body; var clientleft = docel.clientleft || body.clientleft || 0; var scrollleft = _globalwindow2['default'].pagexoffset || body.scrollleft; var left = box.left + scrollleft - clientleft; var clienttop = docel.clienttop || body.clienttop || 0; var scrolltop = _globalwindow2['default'].pageyoffset || body.scrolltop; var top = box.top + scrolltop - clienttop; // android sometimes returns slightly off decimal values, so need to round return { left: math.round(left), top: math.round(top) }; } /** * get pointer position in element * returns an object with x and y coordinates. * the base on the coordinates are the bottom left of the element. * * @function getpointerposition * @param {element} el element on which to get the pointer position on * @param {event} event event object * @return {object} this object will have x and y coordinates corresponding to the mouse position */ function getpointerposition(el, event) { var position = {}; var box = findelposition(el); var boxw = el.offsetwidth; var boxh = el.offsetheight; var boxy = box.top; var boxx = box.left; var pagey = event.pagey; var pagex = event.pagex; if (event.changedtouches) { pagex = event.changedtouches[0].pagex; pagey = event.changedtouches[0].pagey; } position.y = math.max(0, math.min(1, (boxy - pagey + boxh) / boxh)); position.x = math.max(0, math.min(1, (pagex - boxx) / boxw)); return position; } /** * determines, via duck typing, whether or not a value is a dom element. * * @function isel * @param {mixed} value * @return {boolean} */ function isel(value) { return !!value && typeof value === 'object' && value.nodetype === 1; } /** * determines, via duck typing, whether or not a value is a text node. * * @param {mixed} value * @return {boolean} */ function istextnode(value) { return !!value && typeof value === 'object' && value.nodetype === 3; } /** * empties the contents of an element. * * @function emptyel * @param {element} el * @return {element} */ function emptyel(el) { while (el.firstchild) { el.removechild(el.firstchild); } return el; } /** * normalizes content for eventual insertion into the dom. * * this allows a wide range of content definition methods, but protects * from falling into the trap of simply writing to `innerhtml`, which is * an xss concern. * * the content for an element can be passed in multiple types and * combinations, whose behavior is as follows: * * - string * normalized into a text node. * * - element, textnode * passed through. * * - array * a one-dimensional array of strings, elements, nodes, or functions (which * return single strings, elements, or nodes). * * - function * if the sole argument, is expected to produce a string, element, * node, or array. * * @function normalizecontent * @param {string|element|textnode|array|function} content * @return {array} */ function normalizecontent(content) { // first, invoke content if it is a function. if it produces an array, // that needs to happen before normalization. if (typeof content === 'function') { content = content(); } // next up, normalize to an array, so one or many items can be normalized, // filtered, and returned. return (array.isarray(content) ? content : [content]).map(function (value) { // first, invoke value if it is a function to produce a new value, // which will be subsequently normalized to a node of some kind. if (typeof value === 'function') { value = value(); } if (isel(value) || istextnode(value)) { return value; } if (typeof value === 'string' && /\s/.test(value)) { return _globaldocument2['default'].createtextnode(value); } }).filter(function (value) { return value; }); } /** * normalizes and appends content to an element. * * @function appendcontent * @param {element} el * @param {string|element|textnode|array|function} content * see: `normalizecontent` * @return {element} */ function appendcontent(el, content) { normalizecontent(content).foreach(function (node) { return el.appendchild(node); }); return el; } /** * normalizes and inserts content into an element; this is identical to * `appendcontent()`, except it empties the element first. * * @function insertcontent * @param {element} el * @param {string|element|textnode|array|function} content * see: `normalizecontent` * @return {element} */ function insertcontent(el, content) { return appendcontent(emptyel(el), content); } /** * finds a single dom element matching `selector` within the optional * `context` of another dom element (defaulting to `document`). * * @function $ * @param {string} selector * a valid css selector, which will be passed to `queryselector`. * * @param {element|string} [context=document] * a dom element within which to query. can also be a selector * string in which case the first matching element will be used * as context. if missing (or no element matches selector), falls * back to `document`. * * @return {element|null} */ var $ = createquerier('queryselector'); exports.$ = $; /** * finds a all dom elements matching `selector` within the optional * `context` of another dom element (defaulting to `document`). * * @function $$ * @param {string} selector * a valid css selector, which will be passed to `queryselectorall`. * * @param {element|string} [context=document] * a dom element within which to query. can also be a selector * string in which case the first matching element will be used * as context. if missing (or no element matches selector), falls * back to `document`. * * @return {nodelist} */ var $$ = createquerier('queryselectorall'); exports.$$ = $$; },{"./guid.js":138,"./log.js":139,"global/document":1,"global/window":2,"tsml":55}],135:[function(_dereq_,module,exports){ /** * @file events.js * * event system (john resig - secrets of a js ninja http://jsninja.com/) * (original book version wasn't completely usable, so fixed some things and made closure compiler compatible) * this should work very similarly to jquery's events, however it's based off the book version which isn't as * robust as jquery's, so there's probably some differences. */ 'use strict'; exports.__esmodule = true; exports.on = on; exports.off = off; exports.trigger = trigger; exports.one = one; exports.fixevent = fixevent; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } 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; } } var _domjs = _dereq_('./dom.js'); var dom = _interoprequirewildcard(_domjs); var _guidjs = _dereq_('./guid.js'); var guid = _interoprequirewildcard(_guidjs); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); /** * add an event listener to element * it stores the handler function in a separate cache object * and adds a generic handler to the element's event, * along with a unique id (guid) to the element. * * @param {element|object} elem element or object to bind listeners to * @param {string|array} type type of event to bind to. * @param {function} fn event listener. * @method on */ function on(elem, type, fn) { if (array.isarray(type)) { return _handlemultipleevents(on, elem, type, fn); } var data = dom.geteldata(elem); // we need a place to store all our handler data if (!data.handlers) data.handlers = {}; if (!data.handlers[type]) data.handlers[type] = []; if (!fn.guid) fn.guid = guid.newguid(); data.handlers[type].push(fn); if (!data.dispatcher) { data.disabled = false; data.dispatcher = function (event, hash) { if (data.disabled) return; event = fixevent(event); var handlers = data.handlers[event.type]; if (handlers) { // copy handlers so if handlers are added/removed during the process it doesn't throw everything off. var handlerscopy = handlers.slice(0); for (var m = 0, n = handlerscopy.length; m < n; m++) { if (event.isimmediatepropagationstopped()) { break; } else { handlerscopy[m].call(elem, event, hash); } } } }; } if (data.handlers[type].length === 1) { if (elem.addeventlistener) { elem.addeventlistener(type, data.dispatcher, false); } else if (elem.attachevent) { elem.attachevent('on' + type, data.dispatcher); } } } /** * removes event listeners from an element * * @param {element|object} elem object to remove listeners from * @param {string|array=} type type of listener to remove. don't include to remove all events from element. * @param {function} fn specific listener to remove. don't include to remove listeners for an event type. * @method off */ function off(elem, type, fn) { // don't want to add a cache object through geteldata if not needed if (!dom.haseldata(elem)) return; var data = dom.geteldata(elem); // if no events exist, nothing to unbind if (!data.handlers) { return; } if (array.isarray(type)) { return _handlemultipleevents(off, elem, type, fn); } // utility function var removetype = function removetype(t) { data.handlers[t] = []; _cleanupevents(elem, t); }; // are we removing all bound events? if (!type) { for (var t in data.handlers) { removetype(t); }return; } var handlers = data.handlers[type]; // if no handlers exist, nothing to unbind if (!handlers) return; // if no listener was provided, remove all listeners for type if (!fn) { removetype(type); return; } // we're only removing a single handler if (fn.guid) { for (var n = 0; n < handlers.length; n++) { if (handlers[n].guid === fn.guid) { handlers.splice(n--, 1); } } } _cleanupevents(elem, type); } /** * trigger an event for an element * * @param {element|object} elem element to trigger an event on * @param {event|object|string} event a string (the type) or an event object with a type attribute * @param {object} [hash] data hash to pass along with the event * @return {boolean=} returned only if default was prevented * @method trigger */ function trigger(elem, event, hash) { // fetches element data and a reference to the parent (for bubbling). // don't want to add a data object to cache for every parent, // so checking haseldata first. var elemdata = dom.haseldata(elem) ? dom.geteldata(elem) : {}; var parent = elem.parentnode || elem.ownerdocument; // type = event.type || event, // handler; // if an event name was passed as a string, creates an event out of it if (typeof event === 'string') { event = { type: event, target: elem }; } // normalizes the event properties. event = fixevent(event); // if the passed element has a dispatcher, executes the established handlers. if (elemdata.dispatcher) { elemdata.dispatcher.call(elem, event, hash); } // unless explicitly stopped or the event does not bubble (e.g. media events) // recursively calls this function to bubble the event up the dom. if (parent && !event.ispropagationstopped() && event.bubbles === true) { trigger.call(null, parent, event, hash); // if at the top of the dom, triggers the default action unless disabled. } else if (!parent && !event.defaultprevented) { var targetdata = dom.geteldata(event.target); // checks if the target has a default action for this event. if (event.target[event.type]) { // temporarily disables event dispatching on the target as we have already executed the handler. targetdata.disabled = true; // executes the default action. if (typeof event.target[event.type] === 'function') { event.target[event.type](); } // re-enables event dispatching. targetdata.disabled = false; } } // inform the triggerer if the default was prevented by returning false return !event.defaultprevented; } /** * trigger a listener only once for an event * * @param {element|object} elem element or object to * @param {string|array} type name/type of event * @param {function} fn event handler function * @method one */ function one(elem, type, fn) { if (array.isarray(type)) { return _handlemultipleevents(one, elem, type, fn); } var func = function func() { off(elem, type, func); fn.apply(this, arguments); }; // copy the guid to the new function so it can removed using the original function's id func.guid = fn.guid = fn.guid || guid.newguid(); on(elem, type, func); } /** * fix a native event to have standard property values * * @param {object} event event object to fix * @return {object} * @private * @method fixevent */ function fixevent(event) { function returntrue() { return true; } function returnfalse() { return false; } // test if fixing up is needed // used to check if !event.stoppropagation instead of ispropagationstopped // but native events return true for stoppropagation, but don't have // other expected methods like ispropagationstopped. seems to be a problem // with the javascript ninja code. so we're just overriding all events now. if (!event || !event.ispropagationstopped) { var old = event || _globalwindow2['default'].event; event = {}; // clone the old object so that we can modify the values event = {}; // ie8 doesn't like when you mess with native event properties // firefox returns false for event.hasownproperty('type') and other props // which makes copying more difficult. // todo: probably best to create a whitelist of event props for (var key in old) { // safari 6.0.3 warns you if you try to copy deprecated layerx/y // chrome warns you if you try to copy deprecated keyboardevent.keylocation // and webkitmovementx/y if (key !== 'layerx' && key !== 'layery' && key !== 'keylocation' && key !== 'webkitmovementx' && key !== 'webkitmovementy') { // chrome 32+ warns if you try to copy deprecated returnvalue, but // we still want to if preventdefault isn't supported (ie8). if (!(key === 'returnvalue' && old.preventdefault)) { event[key] = old[key]; } } } // the event occurred on this element if (!event.target) { event.target = event.srcelement || _globaldocument2['default']; } // handle which other element the event is related to if (!event.relatedtarget) { event.relatedtarget = event.fromelement === event.target ? event.toelement : event.fromelement; } // stop the default browser action event.preventdefault = function () { if (old.preventdefault) { old.preventdefault(); } event.returnvalue = false; old.returnvalue = false; event.defaultprevented = true; }; event.defaultprevented = false; // stop the event from bubbling event.stoppropagation = function () { if (old.stoppropagation) { old.stoppropagation(); } event.cancelbubble = true; old.cancelbubble = true; event.ispropagationstopped = returntrue; }; event.ispropagationstopped = returnfalse; // stop the event from bubbling and executing other handlers event.stopimmediatepropagation = function () { if (old.stopimmediatepropagation) { old.stopimmediatepropagation(); } event.isimmediatepropagationstopped = returntrue; event.stoppropagation(); }; event.isimmediatepropagationstopped = returnfalse; // handle mouse position if (event.clientx != null) { var doc = _globaldocument2['default'].documentelement, body = _globaldocument2['default'].body; event.pagex = event.clientx + (doc && doc.scrollleft || body && body.scrollleft || 0) - (doc && doc.clientleft || body && body.clientleft || 0); event.pagey = event.clienty + (doc && doc.scrolltop || body && body.scrolltop || 0) - (doc && doc.clienttop || body && body.clienttop || 0); } // handle key presses event.which = event.charcode || event.keycode; // fix button for mouse clicks: // 0 == left; 1 == middle; 2 == right if (event.button != null) { event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0; } } // returns fixed-up instance return event; } /** * clean up the listener cache and dispatchers * * @param {element|object} elem element to clean up * @param {string} type type of event to clean up * @private * @method _cleanupevents */ function _cleanupevents(elem, type) { var data = dom.geteldata(elem); // remove the events of a particular type if there are none left if (data.handlers[type].length === 0) { delete data.handlers[type]; // data.handlers[type] = null; // setting to null was causing an error with data.handlers // remove the meta-handler from the element if (elem.removeeventlistener) { elem.removeeventlistener(type, data.dispatcher, false); } else if (elem.detachevent) { elem.detachevent('on' + type, data.dispatcher); } } // remove the events object if there are no types left if (object.getownpropertynames(data.handlers).length <= 0) { delete data.handlers; delete data.dispatcher; delete data.disabled; } // finally remove the element data if there is no data left if (object.getownpropertynames(data).length === 0) { dom.removeeldata(elem); } } /** * loops through an array of event types and calls the requested method for each type. * * @param {function} fn the event method we want to use. * @param {element|object} elem element or object to bind listeners to * @param {string} type type of event to bind to. * @param {function} callback event listener. * @private * @function _handlemultipleevents */ function _handlemultipleevents(fn, elem, types, callback) { types.foreach(function (type) { //call the event method for each one of the types fn(elem, type, callback); }); } },{"./dom.js":134,"./guid.js":138,"global/document":1,"global/window":2}],136:[function(_dereq_,module,exports){ /** * @file fn.js */ 'use strict'; exports.__esmodule = true; var _guidjs = _dereq_('./guid.js'); /** * bind (a.k.a proxy or context). a simple method for changing the context of a function * it also stores a unique id on the function so it can be easily removed from events * * @param {*} context the object to bind as scope * @param {function} fn the function to be bound to a scope * @param {number=} uid an optional unique id for the function to be set * @return {function} * @private * @method bind */ var bind = function bind(context, fn, uid) { // make sure the function has a unique id if (!fn.guid) { fn.guid = _guidjs.newguid(); } // create the new function that changes the context var ret = function ret() { return fn.apply(context, arguments); }; // allow for the ability to individualize this function // needed in the case where multiple objects might share the same prototype // if both items add an event listener with the same function, then you try to remove just one // it will remove both because they both have the same guid. // when using this, you need to use the bind method when you remove the listener as well. // currently used in text tracks ret.guid = uid ? uid + '_' + fn.guid : fn.guid; return ret; }; exports.bind = bind; },{"./guid.js":138}],137:[function(_dereq_,module,exports){ /** * @file format-time.js * * format seconds as a time string, h:mm:ss or m:ss * supplying a guide (in seconds) will force a number of leading zeros * to cover the length of the guide * * @param {number} seconds number of seconds to be turned into a string * @param {number} guide number (in seconds) to model the string after * @return {string} time formatted as h:mm:ss or m:ss * @private * @function formattime */ 'use strict'; exports.__esmodule = true; function formattime(seconds) { var guide = arguments.length <= 1 || arguments[1] === undefined ? seconds : arguments[1]; return (function () { seconds = seconds < 0 ? 0 : seconds; var s = math.floor(seconds % 60); var m = math.floor(seconds / 60 % 60); var h = math.floor(seconds / 3600); var gm = math.floor(guide / 60 % 60); var gh = math.floor(guide / 3600); // handle invalid times if (isnan(seconds) || seconds === infinity) { // '-' is false for all relational operators (e.g. <, >=) so this setting // will add the minimum number of fields specified by the guide h = m = s = '-'; } // check if we need to show hours h = h > 0 || gh > 0 ? h + ':' : ''; // if hours are showing, we may need to add a leading zero. // always show at least one digit of minutes. m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':'; // check if leading zero is need for seconds s = s < 10 ? '0' + s : s; return h + m + s; })(); } exports['default'] = formattime; module.exports = exports['default']; },{}],138:[function(_dereq_,module,exports){ /** * @file guid.js * * unique id for an element or function * @type {number} * @private */ "use strict"; exports.__esmodule = true; exports.newguid = newguid; var _guid = 1; /** * get the next unique id * * @return {string} * @function newguid */ function newguid() { return _guid++; } },{}],139:[function(_dereq_,module,exports){ /** * @file log.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); /** * log plain debug messages */ var log = function log() { _logtype(null, arguments); }; /** * keep a history of log messages * @type {array} */ log.history = []; /** * log error messages */ log.error = function () { _logtype('error', arguments); }; /** * log warning messages */ log.warn = function () { _logtype('warn', arguments); }; /** * log messages to the console and history based on the type of message * * @param {string} type the type of message, or `null` for `log` * @param {object} args the args to be passed to the log * @private * @method _logtype */ function _logtype(type, args) { // convert args to an array to get array functions var argsarray = array.prototype.slice.call(args); // if there's no console then don't try to output messages // they will still be stored in log.history // was setting these once outside of this function, but containing them // in the function makes it easier to test cases where console doesn't exist var noop = function noop() {}; var console = _globalwindow2['default']['console'] || { 'log': noop, 'warn': noop, 'error': noop }; if (type) { // add the type to the front of the message argsarray.unshift(type.touppercase() + ':'); } else { // default to log with no prefix type = 'log'; } // add to history log.history.push(argsarray); // add console prefix after adding to history argsarray.unshift('videojs:'); // call appropriate log function if (console[type].apply) { console[type].apply(console, argsarray); } else { // ie8 doesn't allow error.apply, but it will just join() the array anyway console[type](argsarray.join(' ')); } } exports['default'] = log; module.exports = exports['default']; },{"global/window":2}],140:[function(_dereq_,module,exports){ /** * @file merge-options.js */ 'use strict'; exports.__esmodule = true; exports['default'] = mergeoptions; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _lodashcompatobjectmerge = _dereq_('lodash-compat/object/merge'); var _lodashcompatobjectmerge2 = _interoprequiredefault(_lodashcompatobjectmerge); function isplain(obj) { return !!obj && typeof obj === 'object' && obj.tostring() === '[object object]' && obj.constructor === object; } /** * merge customizer. video.js simply overwrites non-simple objects * (like arrays) instead of attempting to overlay them. * @see https://lodash.com/docs#merge */ var customizer = function customizer(destination, source) { // if we're not working with a plain object, copy the value as is // if source is an array, for instance, it will replace destination if (!isplain(source)) { return source; } // if the new value is a plain object but the first object value is not // we need to create a new object for the first object to merge with. // this makes it consistent with how merge() works by default // and also protects from later changes the to first object affecting // the second object's values. if (!isplain(destination)) { return mergeoptions(source); } }; /** * merge one or more options objects, recursively merging **only** * plain object properties. previously `deepmerge`. * * @param {...object} source one or more objects to merge * @returns {object} a new object that is the union of all * provided objects * @function mergeoptions */ function mergeoptions() { // contruct the call dynamically to handle the variable number of // objects to merge var args = array.prototype.slice.call(arguments); // unshift an empty object into the front of the call as the target // of the merge args.unshift({}); // customize conflict resolution to match our historical merge behavior args.push(customizer); _lodashcompatobjectmerge2['default'].apply(null, args); // return the mutated result object return args[0]; } module.exports = exports['default']; },{"lodash-compat/object/merge":40}],141:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var createstyleelement = function createstyleelement(classname) { var style = _globaldocument2['default'].createelement('style'); style.classname = classname; return style; }; exports.createstyleelement = createstyleelement; var settextcontent = function settextcontent(el, content) { if (el.stylesheet) { el.stylesheet.csstext = content; } else { el.textcontent = content; } }; exports.settextcontent = settextcontent; },{"global/document":1}],142:[function(_dereq_,module,exports){ 'use strict'; exports.__esmodule = true; exports.createtimeranges = createtimeranges; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _logjs = _dereq_('./log.js'); var _logjs2 = _interoprequiredefault(_logjs); /** * @file time-ranges.js * * should create a fake timerange object * mimics an html5 time range instance, which has functions that * return the start and end times for a range * timeranges are returned by the buffered() method * * @param {(number|array)} start of a single range or an array of ranges * @param {number} end of a single range * @private * @method createtimeranges */ function createtimeranges(start, end) { if (array.isarray(start)) { return createtimerangesobj(start); } else if (start === undefined || end === undefined) { return createtimerangesobj(); } return createtimerangesobj([[start, end]]); } exports.createtimerange = createtimeranges; function createtimerangesobj(ranges) { if (ranges === undefined || ranges.length === 0) { return { length: 0, start: function start() { throw new error('this timeranges object is empty'); }, end: function end() { throw new error('this timeranges object is empty'); } }; } return { length: ranges.length, start: getrange.bind(null, 'start', 0, ranges), end: getrange.bind(null, 'end', 1, ranges) }; } function getrange(fnname, valueindex, ranges, rangeindex) { if (rangeindex === undefined) { _logjs2['default'].warn('deprecated: function \'' + fnname + '\' on \'timeranges\' called without an index argument.'); rangeindex = 0; } rangecheck(fnname, rangeindex, ranges.length - 1); return ranges[rangeindex][valueindex]; } function rangecheck(fnname, index, maxindex) { if (index < 0 || index > maxindex) { throw new error('failed to execute \'' + fnname + '\' on \'timeranges\': the index provided (' + index + ') is greater than or equal to the maximum bound (' + maxindex + ').'); } } },{"./log.js":139}],143:[function(_dereq_,module,exports){ /** * @file to-title-case.js * * uppercase the first letter of a string * * @param {string} string string to be uppercased * @return {string} * @private * @method totitlecase */ "use strict"; exports.__esmodule = true; function totitlecase(string) { return string.charat(0).touppercase() + string.slice(1); } exports["default"] = totitlecase; module.exports = exports["default"]; },{}],144:[function(_dereq_,module,exports){ /** * @file url.js */ 'use strict'; exports.__esmodule = true; function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); /** * resolve and parse the elements of a url * * @param {string} url the url to parse * @return {object} an object of url details * @method parseurl */ var parseurl = function parseurl(url) { var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; // add the url to an anchor and let the browser parse the url var a = _globaldocument2['default'].createelement('a'); a.href = url; // ie8 (and 9?) fix // ie8 doesn't parse the url correctly until the anchor is actually // added to the body, and an innerhtml is needed to trigger the parsing var addtobody = a.host === '' && a.protocol !== 'file:'; var div = undefined; if (addtobody) { div = _globaldocument2['default'].createelement('div'); div.innerhtml = ''; a = div.firstchild; // prevent the div from affecting layout div.setattribute('style', 'display:none; position:absolute;'); _globaldocument2['default'].body.appendchild(div); } // copy the specific url properties to a new object // this is also needed for ie8 because the anchor loses its // properties when it's removed from the dom var details = {}; for (var i = 0; i < props.length; i++) { details[props[i]] = a[props[i]]; } // ie9 adds the port to the host property unlike everyone else. if // a port identifier is added for standard ports, strip it. if (details.protocol === 'http:') { details.host = details.host.replace(/:80$/, ''); } if (details.protocol === 'https:') { details.host = details.host.replace(/:443$/, ''); } if (addtobody) { _globaldocument2['default'].body.removechild(div); } return details; }; exports.parseurl = parseurl; /** * get absolute version of relative url. used to tell flash correct url. * http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue * * @param {string} url url to make absolute * @return {string} absolute url * @private * @method getabsoluteurl */ var getabsoluteurl = function getabsoluteurl(url) { // check if absolute url if (!url.match(/^https?:\/\//)) { // convert to absolute url. flash hosted off-site needs an absolute url. var div = _globaldocument2['default'].createelement('div'); div.innerhtml = 'x'; url = div.firstchild.href; } return url; }; exports.getabsoluteurl = getabsoluteurl; /** * returns the extension of the passed file name. it will return an empty string if you pass an invalid path * * @param {string} path the filename path like '/path/to/file.mp4' * @returns {string} the extension in lower case or an empty string if no extension could be found. * @method getfileextension */ var getfileextension = function getfileextension(path) { if (typeof path === 'string') { var splitpathre = /^(\/?)([\s\s]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i; var pathparts = splitpathre.exec(path); if (pathparts) { return pathparts.pop().tolowercase(); } } return ''; }; exports.getfileextension = getfileextension; /** * returns whether the url passed is a cross domain request or not. * * @param {string} url the url to check * @return {boolean} whether it is a cross domain request or not * @method iscrossorigin */ var iscrossorigin = function iscrossorigin(url) { var winloc = _globalwindow2['default'].location; var urlinfo = parseurl(url); // ie8 protocol relative urls will return ':' for protocol var srcprotocol = urlinfo.protocol === ':' ? winloc.protocol : urlinfo.protocol; // check if url is for another domain/origin // ie8 doesn't know location.origin, so we won't rely on it here var crossorigin = srcprotocol + urlinfo.host !== winloc.protocol + winloc.host; return crossorigin; }; exports.iscrossorigin = iscrossorigin; },{"global/document":1,"global/window":2}],145:[function(_dereq_,module,exports){ /** * @file video.js */ 'use strict'; exports.__esmodule = true; 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; } } function _interoprequiredefault(obj) { return obj && obj.__esmodule ? obj : { 'default': obj }; } var _globalwindow = _dereq_('global/window'); var _globalwindow2 = _interoprequiredefault(_globalwindow); var _globaldocument = _dereq_('global/document'); var _globaldocument2 = _interoprequiredefault(_globaldocument); var _setup = _dereq_('./setup'); var setup = _interoprequirewildcard(_setup); var _utilsstylesheetjs = _dereq_('./utils/stylesheet.js'); var stylesheet = _interoprequirewildcard(_utilsstylesheetjs); var _component = _dereq_('./component'); var _component2 = _interoprequiredefault(_component); var _eventtarget = _dereq_('./event-target'); var _eventtarget2 = _interoprequiredefault(_eventtarget); var _utilseventsjs = _dereq_('./utils/events.js'); var events = _interoprequirewildcard(_utilseventsjs); var _player = _dereq_('./player'); var _player2 = _interoprequiredefault(_player); var _pluginsjs = _dereq_('./plugins.js'); var _pluginsjs2 = _interoprequiredefault(_pluginsjs); var _srcjsutilsmergeoptionsjs = _dereq_('../../src/js/utils/merge-options.js'); var _srcjsutilsmergeoptionsjs2 = _interoprequiredefault(_srcjsutilsmergeoptionsjs); var _utilsfnjs = _dereq_('./utils/fn.js'); var fn = _interoprequirewildcard(_utilsfnjs); var _trackstexttrackjs = _dereq_('./tracks/text-track.js'); var _trackstexttrackjs2 = _interoprequiredefault(_trackstexttrackjs); var _objectassign = _dereq_('object.assign'); var _objectassign2 = _interoprequiredefault(_objectassign); var _utilstimerangesjs = _dereq_('./utils/time-ranges.js'); var _utilsformattimejs = _dereq_('./utils/format-time.js'); var _utilsformattimejs2 = _interoprequiredefault(_utilsformattimejs); var _utilslogjs = _dereq_('./utils/log.js'); var _utilslogjs2 = _interoprequiredefault(_utilslogjs); var _utilsdomjs = _dereq_('./utils/dom.js'); var dom = _interoprequirewildcard(_utilsdomjs); var _utilsbrowserjs = _dereq_('./utils/browser.js'); var browser = _interoprequirewildcard(_utilsbrowserjs); var _utilsurljs = _dereq_('./utils/url.js'); var url = _interoprequirewildcard(_utilsurljs); var _extendjs = _dereq_('./extend.js'); var _extendjs2 = _interoprequiredefault(_extendjs); var _lodashcompatobjectmerge = _dereq_('lodash-compat/object/merge'); var _lodashcompatobjectmerge2 = _interoprequiredefault(_lodashcompatobjectmerge); var _utilscreatedeprecationproxyjs = _dereq_('./utils/create-deprecation-proxy.js'); var _utilscreatedeprecationproxyjs2 = _interoprequiredefault(_utilscreatedeprecationproxyjs); var _xhr = _dereq_('xhr'); var _xhr2 = _interoprequiredefault(_xhr); // include the built-in techs var _techtechjs = _dereq_('./tech/tech.js'); var _techtechjs2 = _interoprequiredefault(_techtechjs); var _techhtml5js = _dereq_('./tech/html5.js'); var _techhtml5js2 = _interoprequiredefault(_techhtml5js); var _techflashjs = _dereq_('./tech/flash.js'); var _techflashjs2 = _interoprequiredefault(_techflashjs); // html5 element shim for ie8 if (typeof htmlvideoelement === 'undefined') { _globaldocument2['default'].createelement('video'); _globaldocument2['default'].createelement('audio'); _globaldocument2['default'].createelement('track'); } /** * doubles as the main function for users to create a player instance and also * the main library object. * the `videojs` function can be used to initialize or retrieve a player. * ```js * var myplayer = videojs('my_video_id'); * ``` * * @param {string|element} id video element or video element id * @param {object=} options optional options object for config/settings * @param {function=} ready optional ready callback * @return {player} a player instance * @mixes videojs * @method videojs */ var videojs = function videojs(id, options, ready) { var tag = undefined; // element of id // allow for element or id to be passed in // string id if (typeof id === 'string') { // adjust for jquery id syntax if (id.indexof('#') === 0) { id = id.slice(1); } // if a player instance has already been created for this id return it. if (videojs.getplayers()[id]) { // if options or ready funtion are passed, warn if (options) { _utilslogjs2['default'].warn('player "' + id + '" is already initialised. options will not be applied.'); } if (ready) { videojs.getplayers()[id].ready(ready); } return videojs.getplayers()[id]; // otherwise get element for id } else { tag = dom.getel(id); } // id is a media element } else { tag = id; } // check for a useable element if (!tag || !tag.nodename) { // re: nodename, could be a box div also throw new typeerror('the element or id supplied is not valid. (videojs)'); // returns } // element may have a player attr referring to an already created player instance. // if not, set up a new player and return the instance. return tag['player'] || _player2['default'].players[tag.playerid] || new _player2['default'](tag, options, ready); }; // add default styles if (_globalwindow2['default'].videojs_no_dynamic_style !== true) { var style = dom.$('.vjs-styles-defaults'); if (!style) { style = stylesheet.createstyleelement('vjs-styles-defaults'); var head = dom.$('head'); head.insertbefore(style, head.firstchild); stylesheet.settextcontent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); } } // run auto-load players // 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) setup.autosetuptimeout(1, videojs); /* * current software version (semver) * * @type {string} */ videojs.version = '5.9.2'; /** * the global options object. these are the settings that take effect * if no overrides are specified when the player is created. * * ```js * videojs.options.autoplay = true * // -> all players will autoplay by default * ``` * * @type {object} */ videojs.options = _player2['default'].prototype.options_; /** * get an object with the currently created players, keyed by player id * * @return {object} the created players * @mixes videojs * @method getplayers */ videojs.getplayers = function () { return _player2['default'].players; }; /** * for backward compatibility, expose players object. * * @deprecated * @memberof videojs * @property {object|proxy} players */ videojs.players = _utilscreatedeprecationproxyjs2['default'](_player2['default'].players, { get: 'access to videojs.players is deprecated; use videojs.getplayers instead', set: 'modification of videojs.players is deprecated' }); /** * get a component class object by name * ```js * var vjsbutton = videojs.getcomponent('button'); * // create a new instance of the component * var mybutton = new vjsbutton(myplayer); * ``` * * @return {component} component identified by name * @mixes videojs * @method getcomponent */ videojs.getcomponent = _component2['default'].getcomponent; /** * register a component so it can referred to by name * used when adding to other * components, either through addchild * `component.addchild('mycomponent')` * or through default children options * `{ children: ['mycomponent'] }`. * ```js * // get a component to subclass * var vjsbutton = videojs.getcomponent('button'); * // subclass the component (see 'extend' doc for more info) * var myspecialbutton = videojs.extend(vjsbutton, {}); * // register the new component * vjsbutton.registercomponent('mysepcialbutton', mysepcialbutton); * // (optionally) add the new component as a default player child * myplayer.addchild('mysepcialbutton'); * ``` * note: you could also just initialize the component before adding. * `component.addchild(new mycomponent());` * * @param {string} the class name of the component * @param {component} the component class * @return {component} the newly registered component * @mixes videojs * @method registercomponent */ videojs.registercomponent = function (name, comp) { if (_techtechjs2['default'].istech(comp)) { _utilslogjs2['default'].warn('the ' + name + ' tech was registered as a component. it should instead be registered using videojs.registertech(name, tech)'); } _component2['default'].registercomponent.call(_component2['default'], name, comp); }; /** * get a tech class object by name * ```js * var html5 = videojs.gettech('html5'); * // create a new instance of the component * var html5 = new html5(options); * ``` * * @return {tech} tech identified by name * @mixes videojs * @method getcomponent */ videojs.gettech = _techtechjs2['default'].gettech; /** * register a tech so it can referred to by name. * this is used in the tech order for the player. * * ```js * // get the html5 tech * var html5 = videojs.gettech('html5'); * var mytech = videojs.extend(html5, {}); * // register the new tech * vjsbutton.registertech('tech', mytech); * var player = videojs('myplayer', { * techorder: ['mytech', 'html5'] * }); * ``` * * @param {string} the class name of the tech * @param {tech} the tech class * @return {tech} the newly registered tech * @mixes videojs * @method registertech */ videojs.registertech = _techtechjs2['default'].registertech; /** * a suite of browser and device tests * * @type {object} * @private */ videojs.browser = browser; /** * whether or not the browser supports touch events. included for backward * compatibility with 4.x, but deprecated. use `videojs.browser.touch_enabled` * instead going forward. * * @deprecated * @type {boolean} */ videojs.touch_enabled = browser.touch_enabled; /** * subclass an existing class * mimics es6 subclassing with the `extend` keyword * ```js * // create a basic javascript 'class' * function myclass(name){ * // set a property at initialization * this.myname = name; * } * // create an instance method * myclass.prototype.saymyname = function(){ * alert(this.myname); * }; * // subclass the exisitng class and change the name * // when initializing * var mysubclass = videojs.extend(myclass, { * constructor: function(name) { * // call the super class constructor for the subclass * myclass.call(this, name) * } * }); * // create an instance of the new sub class * var myinstance = new mysubclass('john'); * myinstance.saymyname(); // -> should alert "john" * ``` * * @param {function} the class to subclass * @param {object} an object including instace methods for the new class * optionally including a `constructor` function * @return {function} the newly created subclass * @mixes videojs * @method extend */ videojs.extend = _extendjs2['default']; /** * merge two options objects recursively * performs a deep merge like lodash.merge but **only merges plain objects** * (not arrays, elements, anything else) * other values will be copied directly from the second object. * ```js * var defaultoptions = { * foo: true, * bar: { * a: true, * b: [1,2,3] * } * }; * var newoptions = { * foo: false, * bar: { * b: [4,5,6] * } * }; * var result = videojs.mergeoptions(defaultoptions, newoptions); * // result.foo = false; * // result.bar.a = true; * // result.bar.b = [4,5,6]; * ``` * * @param {object} defaults the options object whose values will be overriden * @param {object} overrides the options object with values to override the first * @param {object} etc any number of additional options objects * * @return {object} a new object with the merged values * @mixes videojs * @method mergeoptions */ videojs.mergeoptions = _srcjsutilsmergeoptionsjs2['default']; /** * change the context (this) of a function * * videojs.bind(newcontext, function(){ * this === newcontext * }); * * note: as of v5.0 we require an es5 shim, so you should use the native * `function(){}.bind(newcontext);` instead of this. * * @param {*} context the object to bind as scope * @param {function} fn the function to be bound to a scope * @param {number=} uid an optional unique id for the function to be set * @return {function} */ videojs.bind = fn.bind; /** * create a video.js player plugin * plugins are only initialized when options for the plugin are included * in the player options, or the plugin function on the player instance is * called. * **see the plugin guide in the docs for a more detailed example** * ```js * // make a plugin that alerts when the player plays * videojs.plugin('myplugin', function(mypluginoptions) { * mypluginoptions = mypluginoptions || {}; * * var player = this; * var alerttext = mypluginoptions.text || 'player is playing!' * * player.on('play', function(){ * alert(alerttext); * }); * }); * // usage examples * // example 1: new player with plugin options, call plugin immediately * var player1 = videojs('idone', { * myplugin: { * text: 'custom text!' * } * }); * // click play * // --> should alert 'custom text!' * // example 3: new player, initialize plugin later * var player3 = videojs('idthree'); * // click play * // --> no alert * // click pause * // initialize plugin using the plugin function on the player instance * player3.myplugin({ * text: 'plugin added later!' * }); * // click play * // --> should alert 'plugin added later!' * ``` * * @param {string} name the plugin name * @param {function} fn the plugin function that will be called with options * @mixes videojs * @method plugin */ videojs.plugin = _pluginsjs2['default']; /** * adding languages so that they're available to all players. * ```js * videojs.addlanguage('es', { 'hello': 'hola' }); * ``` * * @param {string} code the language code or dictionary property * @param {object} data the data values to be translated * @return {object} the resulting language dictionary object * @mixes videojs * @method addlanguage */ videojs.addlanguage = function (code, data) { var _merge; code = ('' + code).tolowercase(); return _lodashcompatobjectmerge2['default'](videojs.options.languages, (_merge = {}, _merge[code] = data, _merge))[code]; }; /** * log debug messages. * * @param {...object} messages one or more messages to log */ videojs.log = _utilslogjs2['default']; /** * creates an emulated timerange object. * * @param {number|array} start start time in seconds or an array of ranges * @param {number} end end time in seconds * @return {object} fake timerange object * @method createtimerange */ videojs.createtimerange = videojs.createtimeranges = _utilstimerangesjs.createtimeranges; /** * format seconds as a time string, h:mm:ss or m:ss * supplying a guide (in seconds) will force a number of leading zeros * to cover the length of the guide * * @param {number} seconds number of seconds to be turned into a string * @param {number} guide number (in seconds) to model the string after * @return {string} time formatted as h:mm:ss or m:ss * @method formattime */ videojs.formattime = _utilsformattimejs2['default']; /** * resolve and parse the elements of a url * * @param {string} url the url to parse * @return {object} an object of url details * @method parseurl */ videojs.parseurl = url.parseurl; /** * returns whether the url passed is a cross domain request or not. * * @param {string} url the url to check * @return {boolean} whether it is a cross domain request or not * @method iscrossorigin */ videojs.iscrossorigin = url.iscrossorigin; /** * event target class. * * @type {function} */ videojs.eventtarget = _eventtarget2['default']; /** * add an event listener to element * it stores the handler function in a separate cache object * and adds a generic handler to the element's event, * along with a unique id (guid) to the element. * * @param {element|object} elem element or object to bind listeners to * @param {string|array} type type of event to bind to. * @param {function} fn event listener. * @method on */ videojs.on = events.on; /** * trigger a listener only once for an event * * @param {element|object} elem element or object to * @param {string|array} type name/type of event * @param {function} fn event handler function * @method one */ videojs.one = events.one; /** * removes event listeners from an element * * @param {element|object} elem object to remove listeners from * @param {string|array=} type type of listener to remove. don't include to remove all events from element. * @param {function} fn specific listener to remove. don't include to remove listeners for an event type. * @method off */ videojs.off = events.off; /** * trigger an event for an element * * @param {element|object} elem element to trigger an event on * @param {event|object|string} event a string (the type) or an event object with a type attribute * @param {object} [hash] data hash to pass along with the event * @return {boolean=} returned only if default was prevented * @method trigger */ videojs.trigger = events.trigger; /** * a cross-browser xmlhttprequest wrapper. here's a simple example: * * videojs.xhr({ * body: somejsonstring, * uri: "/foo", * headers: { * "content-type": "application/json" * } * }, function (err, resp, body) { * // check resp.statuscode * }); * * check out the [full * documentation](https://github.com/raynos/xhr/blob/v2.1.0/readme.md) * for more options. * * @param {object} options settings for the request. * @return {xmlhttprequest|xdomainrequest} the request object. * @see https://github.com/raynos/xhr */ videojs.xhr = _xhr2['default']; /** * texttrack class * * @type {function} */ videojs.texttrack = _trackstexttrackjs2['default']; /** * determines, via duck typing, whether or not a value is a dom element. * * @method isel * @param {mixed} value * @return {boolean} */ videojs.isel = dom.isel; /** * determines, via duck typing, whether or not a value is a text node. * * @method istextnode * @param {mixed} value * @return {boolean} */ videojs.istextnode = dom.istextnode; /** * creates an element and applies properties. * * @method createel * @param {string} [tagname='div'] name of tag to be created. * @param {object} [properties={}] element properties to be applied. * @param {object} [attributes={}] element attributes to be applied. * @return {element} */ videojs.createel = dom.createel; /** * check if an element has a css class * * @method hasclass * @param {element} element element to check * @param {string} classtocheck classname to check */ videojs.hasclass = dom.haselclass; /** * add a css class name to an element * * @method addclass * @param {element} element element to add class name to * @param {string} classtoadd classname to add */ videojs.addclass = dom.addelclass; /** * remove a css class name from an element * * @method removeclass * @param {element} element element to remove from class name * @param {string} classtoremove classname to remove */ videojs.removeclass = dom.removeelclass; /** * adds or removes a css class name on an element depending on an optional * condition or the presence/absence of the class name. * * @method toggleelclass * @param {element} element * @param {string} classtotoggle * @param {boolean|function} [predicate] * can be a function that returns a boolean. if `true`, the class * will be added; if `false`, the class will be removed. if not * given, the class will be added if not present and vice versa. */ videojs.toggleclass = dom.toggleelclass; /** * apply attributes to an html element. * * @method setattributes * @param {element} el target element. * @param {object=} attributes element attributes to be applied. */ videojs.setattributes = dom.setelattributes; /** * get an element's attribute values, as defined on the html tag * attributes are not the same as properties. they're defined on the tag * or with setattribute (which shouldn't be used with html) * this will return true or false for boolean attributes. * * @method getattributes * @param {element} tag element from which to get tag attributes * @return {object} */ videojs.getattributes = dom.getelattributes; /** * empties the contents of an element. * * @method emptyel * @param {element} el * @return {element} */ videojs.emptyel = dom.emptyel; /** * normalizes and appends content to an element. * * the content for an element can be passed in multiple types and * combinations, whose behavior is as follows: * * - string * normalized into a text node. * * - element, textnode * passed through. * * - array * a one-dimensional array of strings, elements, nodes, or functions (which * return single strings, elements, or nodes). * * - function * if the sole argument, is expected to produce a string, element, * node, or array. * * @method appendcontent * @param {element} el * @param {string|element|textnode|array|function} content * @return {element} */ videojs.appendcontent = dom.appendcontent; /** * normalizes and inserts content into an element; this is identical to * `appendcontent()`, except it empties the element first. * * the content for an element can be passed in multiple types and * combinations, whose behavior is as follows: * * - string * normalized into a text node. * * - element, textnode * passed through. * * - array * a one-dimensional array of strings, elements, nodes, or functions (which * return single strings, elements, or nodes). * * - function * if the sole argument, is expected to produce a string, element, * node, or array. * * @method insertcontent * @param {element} el * @param {string|element|textnode|array|function} content * @return {element} */ videojs.insertcontent = dom.insertcontent; /* * custom universal module definition (umd) * * video.js will never be a non-browser lib so we can simplify umd a bunch and * still support requirejs and browserify. this also needs to be closure * compiler compatible, so string keys are used. */ if (typeof define === 'function' && define['amd']) { define('videojs', [], function () { return videojs; }); // checking that module is an object too because of umdjs/umd#35 } else if (typeof exports === 'object' && typeof module === 'object') { module['exports'] = videojs; } exports['default'] = videojs; module.exports = exports['default']; },{"../../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) }); //# sourcemappingurl=video.js.map /* vtt.js - v0.12.1 (https://github.com/mozilla/vtt.js) built on 08-07-2015 */ (function(root) { var vttjs = root.vttjs = {}; var cueshim = vttjs.vttcue; var regionshim = vttjs.vttregion; var oldvttcue = root.vttcue; var oldvttregion = root.vttregion; vttjs.shim = function() { vttjs.vttcue = cueshim; vttjs.vttregion = regionshim; }; vttjs.restore = function() { vttjs.vttcue = oldvttcue; vttjs.vttregion = oldvttregion; }; }(this)); /** * copyright 2013 vtt.js contributors * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ (function(root, vttjs) { var autokeyword = "auto"; var directionsetting = { "": true, "lr": true, "rl": true }; var alignsetting = { "start": true, "middle": true, "end": true, "left": true, "right": true }; function finddirectionsetting(value) { if (typeof value !== "string") { return false; } var dir = directionsetting[value.tolowercase()]; return dir ? value.tolowercase() : false; } function findalignsetting(value) { if (typeof value !== "string") { return false; } var align = alignsetting[value.tolowercase()]; return align ? value.tolowercase() : false; } function extend(obj) { var i = 1; for (; i < arguments.length; i++) { var cobj = arguments[i]; for (var p in cobj) { obj[p] = cobj[p]; } } return obj; } function vttcue(starttime, endtime, text) { var cue = this; var isie8 = (/msie\s8\.0/).test(navigator.useragent); var baseobj = {}; if (isie8) { cue = document.createelement('custom'); } else { baseobj.enumerable = true; } /** * shim implementation specific properties. these properties are not in * the spec. */ // lets us know when the vttcue's data has changed in such a way that we need // to recompute its display state. this lets us compute its display state // lazily. cue.hasbeenreset = false; /** * vttcue and texttrackcue properties * http://dev.w3.org/html5/webvtt/#vttcue-interface */ var _id = ""; var _pauseonexit = false; var _starttime = starttime; var _endtime = endtime; var _text = text; var _region = null; var _vertical = ""; var _snaptolines = true; var _line = "auto"; var _linealign = "start"; var _position = 50; var _positionalign = "middle"; var _size = 50; var _align = "middle"; object.defineproperty(cue, "id", extend({}, baseobj, { get: function() { return _id; }, set: function(value) { _id = "" + value; } })); object.defineproperty(cue, "pauseonexit", extend({}, baseobj, { get: function() { return _pauseonexit; }, set: function(value) { _pauseonexit = !!value; } })); object.defineproperty(cue, "starttime", extend({}, baseobj, { get: function() { return _starttime; }, set: function(value) { if (typeof value !== "number") { throw new typeerror("start time must be set to a number."); } _starttime = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "endtime", extend({}, baseobj, { get: function() { return _endtime; }, set: function(value) { if (typeof value !== "number") { throw new typeerror("end time must be set to a number."); } _endtime = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "text", extend({}, baseobj, { get: function() { return _text; }, set: function(value) { _text = "" + value; this.hasbeenreset = true; } })); object.defineproperty(cue, "region", extend({}, baseobj, { get: function() { return _region; }, set: function(value) { _region = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "vertical", extend({}, baseobj, { get: function() { return _vertical; }, set: function(value) { var setting = finddirectionsetting(value); // have to check for false because the setting an be an empty string. if (setting === false) { throw new syntaxerror("an invalid or illegal string was specified."); } _vertical = setting; this.hasbeenreset = true; } })); object.defineproperty(cue, "snaptolines", extend({}, baseobj, { get: function() { return _snaptolines; }, set: function(value) { _snaptolines = !!value; this.hasbeenreset = true; } })); object.defineproperty(cue, "line", extend({}, baseobj, { get: function() { return _line; }, set: function(value) { if (typeof value !== "number" && value !== autokeyword) { throw new syntaxerror("an invalid number or illegal string was specified."); } _line = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "linealign", extend({}, baseobj, { get: function() { return _linealign; }, set: function(value) { var setting = findalignsetting(value); if (!setting) { throw new syntaxerror("an invalid or illegal string was specified."); } _linealign = setting; this.hasbeenreset = true; } })); object.defineproperty(cue, "position", extend({}, baseobj, { get: function() { return _position; }, set: function(value) { if (value < 0 || value > 100) { throw new error("position must be between 0 and 100."); } _position = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "positionalign", extend({}, baseobj, { get: function() { return _positionalign; }, set: function(value) { var setting = findalignsetting(value); if (!setting) { throw new syntaxerror("an invalid or illegal string was specified."); } _positionalign = setting; this.hasbeenreset = true; } })); object.defineproperty(cue, "size", extend({}, baseobj, { get: function() { return _size; }, set: function(value) { if (value < 0 || value > 100) { throw new error("size must be between 0 and 100."); } _size = value; this.hasbeenreset = true; } })); object.defineproperty(cue, "align", extend({}, baseobj, { get: function() { return _align; }, set: function(value) { var setting = findalignsetting(value); if (!setting) { throw new syntaxerror("an invalid or illegal string was specified."); } _align = setting; this.hasbeenreset = true; } })); /** * other spec defined properties */ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state cue.displaystate = undefined; if (isie8) { return cue; } } /** * vttcue methods */ vttcue.prototype.getcueashtml = function() { // assume webvtt.convertcuetodomtree is on the global. return webvtt.convertcuetodomtree(window, this.text); }; root.vttcue = root.vttcue || vttcue; vttjs.vttcue = vttcue; }(this, (this.vttjs || {}))); /** * copyright 2013 vtt.js contributors * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ (function(root, vttjs) { var scrollsetting = { "": true, "up": true }; function findscrollsetting(value) { if (typeof value !== "string") { return false; } var scroll = scrollsetting[value.tolowercase()]; return scroll ? value.tolowercase() : false; } function isvalidpercentvalue(value) { return typeof value === "number" && (value >= 0 && value <= 100); } // vttregion shim http://dev.w3.org/html5/webvtt/#vttregion-interface function vttregion() { var _width = 100; var _lines = 3; var _regionanchorx = 0; var _regionanchory = 100; var _viewportanchorx = 0; var _viewportanchory = 100; var _scroll = ""; object.defineproperties(this, { "width": { enumerable: true, get: function() { return _width; }, set: function(value) { if (!isvalidpercentvalue(value)) { throw new error("width must be between 0 and 100."); } _width = value; } }, "lines": { enumerable: true, get: function() { return _lines; }, set: function(value) { if (typeof value !== "number") { throw new typeerror("lines must be set to a number."); } _lines = value; } }, "regionanchory": { enumerable: true, get: function() { return _regionanchory; }, set: function(value) { if (!isvalidpercentvalue(value)) { throw new error("regionanchorx must be between 0 and 100."); } _regionanchory = value; } }, "regionanchorx": { enumerable: true, get: function() { return _regionanchorx; }, set: function(value) { if(!isvalidpercentvalue(value)) { throw new error("regionanchory must be between 0 and 100."); } _regionanchorx = value; } }, "viewportanchory": { enumerable: true, get: function() { return _viewportanchory; }, set: function(value) { if (!isvalidpercentvalue(value)) { throw new error("viewportanchory must be between 0 and 100."); } _viewportanchory = value; } }, "viewportanchorx": { enumerable: true, get: function() { return _viewportanchorx; }, set: function(value) { if (!isvalidpercentvalue(value)) { throw new error("viewportanchorx must be between 0 and 100."); } _viewportanchorx = value; } }, "scroll": { enumerable: true, get: function() { return _scroll; }, set: function(value) { var setting = findscrollsetting(value); // have to check for false as an empty string is a legal value. if (setting === false) { throw new syntaxerror("an invalid or illegal string was specified."); } _scroll = setting; } } }); } root.vttregion = root.vttregion || vttregion; vttjs.vttregion = vttregion; }(this, (this.vttjs || {}))); /** * copyright 2013 vtt.js contributors * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ /* -*- mode: java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ (function(global) { var _objcreate = object.create || (function() { function f() {} return function(o) { if (arguments.length !== 1) { throw new error('object.create shim only accepts one parameter.'); } f.prototype = o; return new f(); }; })(); // creates a new parsererror object from an errordata object. the errordata // object should have default code and message properties. the default message // property can be overriden by passing in a message parameter. // see parsingerror.errors below for acceptable errors. function parsingerror(errordata, message) { this.name = "parsingerror"; this.code = errordata.code; this.message = message || errordata.message; } parsingerror.prototype = _objcreate(error.prototype); parsingerror.prototype.constructor = parsingerror; // parsingerror metadata for acceptable parsingerrors. parsingerror.errors = { badsignature: { code: 0, message: "malformed webvtt signature." }, badtimestamp: { code: 1, message: "malformed time stamp." } }; // try to parse input as a time stamp. function parsetimestamp(input) { function computeseconds(h, m, s, f) { return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; } var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); if (!m) { return null; } if (m[3]) { // timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] return computeseconds(m[1], m[2], m[3].replace(":", ""), m[4]); } else if (m[1] > 59) { // timestamp takes the form of [hours]:[minutes].[milliseconds] // first position is hours as it's over 59. return computeseconds(m[1], m[2], 0, m[4]); } else { // timestamp takes the form of [minutes]:[seconds].[milliseconds] return computeseconds(0, m[1], m[2], m[4]); } } // a settings object holds key/value pairs and will ignore anything but the first // assignment to a specific key. function settings() { this.values = _objcreate(null); } settings.prototype = { // only accept the first assignment to any key. set: function(k, v) { if (!this.get(k) && v !== "") { this.values[k] = v; } }, // return the value for a key, or a default value. // if 'defaultkey' is passed then 'dflt' is assumed to be an object with // a number of possible default values as properties where 'defaultkey' is // the key of the property that will be chosen; otherwise it's assumed to be // a single value. get: function(k, dflt, defaultkey) { if (defaultkey) { return this.has(k) ? this.values[k] : dflt[defaultkey]; } return this.has(k) ? this.values[k] : dflt; }, // check whether we have a value for a key. has: function(k) { return k in this.values; }, // accept a setting if its one of the given alternatives. alt: function(k, v, a) { for (var n = 0; n < a.length; ++n) { if (v === a[n]) { this.set(k, v); break; } } }, // accept a setting if its a valid (signed) integer. integer: function(k, v) { if (/^-?\d+$/.test(v)) { // integer this.set(k, parseint(v, 10)); } }, // accept a setting if its a valid percentage. percent: function(k, v) { var m; if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) { v = parsefloat(v); if (v >= 0 && v <= 100) { this.set(k, v); return true; } } return false; } }; // helper function to parse input into groups separated by 'groupdelim', and // interprete each group as a key/value pair separated by 'keyvaluedelim'. function parseoptions(input, callback, keyvaluedelim, groupdelim) { var groups = groupdelim ? input.split(groupdelim) : [input]; for (var i in groups) { if (typeof groups[i] !== "string") { continue; } var kv = groups[i].split(keyvaluedelim); if (kv.length !== 2) { continue; } var k = kv[0]; var v = kv[1]; callback(k, v); } } function parsecue(input, cue, regionlist) { // remember the original input if we need to throw an error. var oinput = input; // 4.1 webvtt timestamp function consumetimestamp() { var ts = parsetimestamp(input); if (ts === null) { throw new parsingerror(parsingerror.errors.badtimestamp, "malformed timestamp: " + oinput); } // remove time stamp from input. input = input.replace(/^[^\sa-za-z-]+/, ""); return ts; } // 4.4.2 webvtt cue settings function consumecuesettings(input, cue) { var settings = new settings(); parseoptions(input, function (k, v) { switch (k) { case "region": // find the last region we parsed with the same region id. for (var i = regionlist.length - 1; i >= 0; i--) { if (regionlist[i].id === v) { settings.set(k, regionlist[i].region); break; } } break; case "vertical": settings.alt(k, v, ["rl", "lr"]); break; case "line": var vals = v.split(","), vals0 = vals[0]; settings.integer(k, vals0); settings.percent(k, vals0) ? settings.set("snaptolines", false) : null; settings.alt(k, vals0, ["auto"]); if (vals.length === 2) { settings.alt("linealign", vals[1], ["start", "middle", "end"]); } break; case "position": vals = v.split(","); settings.percent(k, vals[0]); if (vals.length === 2) { settings.alt("positionalign", vals[1], ["start", "middle", "end"]); } break; case "size": settings.percent(k, v); break; case "align": settings.alt(k, v, ["start", "middle", "end", "left", "right"]); break; } }, /:/, /\s/); // apply default values for any missing fields. cue.region = settings.get("region", null); cue.vertical = settings.get("vertical", ""); cue.line = settings.get("line", "auto"); cue.linealign = settings.get("linealign", "start"); cue.snaptolines = settings.get("snaptolines", true); cue.size = settings.get("size", 100); cue.align = settings.get("align", "middle"); cue.position = settings.get("position", { start: 0, left: 0, middle: 50, end: 100, right: 100 }, cue.align); cue.positionalign = settings.get("positionalign", { start: "start", left: "start", middle: "middle", end: "end", right: "end" }, cue.align); } function skipwhitespace() { input = input.replace(/^\s+/, ""); } // 4.1 webvtt cue timings. skipwhitespace(); cue.starttime = consumetimestamp(); // (1) collect cue start time skipwhitespace(); if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->" throw new parsingerror(parsingerror.errors.badtimestamp, "malformed time stamp (time stamps must be separated by '-->'): " + oinput); } input = input.substr(3); skipwhitespace(); cue.endtime = consumetimestamp(); // (5) collect cue end time // 4.1 webvtt cue settings list. skipwhitespace(); consumecuesettings(input, cue); } var escape = { "&": "&", "<": "<", ">": ">", "‎": "\u200e", "‏": "\u200f", " ": "\u00a0" }; var tag_name = { c: "span", i: "i", b: "b", u: "u", ruby: "ruby", rt: "rt", v: "span", lang: "span" }; var tag_annotation = { v: "title", lang: "lang" }; var needs_parent = { rt: "ruby" }; // parse content into a document fragment. function parsecontent(window, input) { function nexttoken() { // check for end-of-string. if (!input) { return null; } // consume 'n' characters from the input. function consume(result) { input = input.substr(result.length); return result; } var m = input.match(/^([^<]*)(<[^>]+>?)?/); // if there is some text before the next tag, return it, otherwise return // the tag. return consume(m[1] ? m[1] : m[2]); } // unescape a string 's'. function unescape1(e) { return escape[e]; } function unescape(s) { while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) { s = s.replace(m[0], unescape1); } return s; } function shouldadd(current, element) { return !needs_parent[element.localname] || needs_parent[element.localname] === current.localname; } // create an element for this tag. function createelement(type, annotation) { var tagname = tag_name[type]; if (!tagname) { return null; } var element = window.document.createelement(tagname); element.localname = tagname; var name = tag_annotation[type]; if (name && annotation) { element[name] = annotation.trim(); } return element; } var rootdiv = window.document.createelement("div"), current = rootdiv, t, tagstack = []; while ((t = nexttoken()) !== null) { if (t[0] === '<') { if (t[1] === "/") { // if the closing tag matches, move back up to the parent node. if (tagstack.length && tagstack[tagstack.length - 1] === t.substr(2).replace(">", "")) { tagstack.pop(); current = current.parentnode; } // otherwise just ignore the end tag. continue; } var ts = parsetimestamp(t.substr(1, t.length - 2)); var node; if (ts) { // timestamps are lead nodes as well. node = window.document.createprocessinginstruction("timestamp", ts); current.appendchild(node); continue; } var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); // if we can't parse the tag, skip to the next tag. if (!m) { continue; } // try to construct an element, and ignore the tag if we couldn't. node = createelement(m[1], m[3]); if (!node) { continue; } // determine if the tag should be added based on the context of where it // is placed in the cuetext. if (!shouldadd(current, node)) { continue; } // set the class list (as a list of classes, separated by space). if (m[2]) { node.classname = m[2].substr(1).replace('.', ' '); } // append the node to the current node, and enter the scope of the new // node. tagstack.push(m[1]); current.appendchild(node); current = node; continue; } // text nodes are leaf nodes. current.appendchild(window.document.createtextnode(unescape(t))); } return rootdiv; } // this is a list of all the unicode characters that have a strong // right-to-left category. what this means is that these characters are // written right-to-left for sure. it was generated by pulling all the strong // right-to-left characters out of the unicode data table. that table can // found at: http://www.unicode.org/public/unidata/unicodedata.txt var strongrtlchars = [0x05be, 0x05c0, 0x05c3, 0x05c6, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x0608, 0x060b, 0x060d, 0x061b, 0x061e, 0x061f, 0x0620, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x063b, 0x063c, 0x063d, 0x063e, 0x063f, 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x066d, 0x066e, 0x066f, 0x0671, 0x0672, 0x0673, 0x0674, 0x0675, 0x0676, 0x0677, 0x0678, 0x0679, 0x067a, 0x067b, 0x067c, 0x067d, 0x067e, 0x067f, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0686, 0x0687, 0x0688, 0x0689, 0x068a, 0x068b, 0x068c, 0x068d, 0x068e, 0x068f, 0x0690, 0x0691, 0x0692, 0x0693, 0x0694, 0x0695, 0x0696, 0x0697, 0x0698, 0x0699, 0x069a, 0x069b, 0x069c, 0x069d, 0x069e, 0x069f, 0x06a0, 0x06a1, 0x06a2, 0x06a3, 0x06a4, 0x06a5, 0x06a6, 0x06a7, 0x06a8, 0x06a9, 0x06aa, 0x06ab, 0x06ac, 0x06ad, 0x06ae, 0x06af, 0x06b0, 0x06b1, 0x06b2, 0x06b3, 0x06b4, 0x06b5, 0x06b6, 0x06b7, 0x06b8, 0x06b9, 0x06ba, 0x06bb, 0x06bc, 0x06bd, 0x06be, 0x06bf, 0x06c0, 0x06c1, 0x06c2, 0x06c3, 0x06c4, 0x06c5, 0x06c6, 0x06c7, 0x06c8, 0x06c9, 0x06ca, 0x06cb, 0x06cc, 0x06cd, 0x06ce, 0x06cf, 0x06d0, 0x06d1, 0x06d2, 0x06d3, 0x06d4, 0x06d5, 0x06e5, 0x06e6, 0x06ee, 0x06ef, 0x06fa, 0x06fb, 0x06fc, 0x06fd, 0x06fe, 0x06ff, 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709, 0x070a, 0x070b, 0x070c, 0x070d, 0x070f, 0x0710, 0x0712, 0x0713, 0x0714, 0x0715, 0x0716, 0x0717, 0x0718, 0x0719, 0x071a, 0x071b, 0x071c, 0x071d, 0x071e, 0x071f, 0x0720, 0x0721, 0x0722, 0x0723, 0x0724, 0x0725, 0x0726, 0x0727, 0x0728, 0x0729, 0x072a, 0x072b, 0x072c, 0x072d, 0x072e, 0x072f, 0x074d, 0x074e, 0x074f, 0x0750, 0x0751, 0x0752, 0x0753, 0x0754, 0x0755, 0x0756, 0x0757, 0x0758, 0x0759, 0x075a, 0x075b, 0x075c, 0x075d, 0x075e, 0x075f, 0x0760, 0x0761, 0x0762, 0x0763, 0x0764, 0x0765, 0x0766, 0x0767, 0x0768, 0x0769, 0x076a, 0x076b, 0x076c, 0x076d, 0x076e, 0x076f, 0x0770, 0x0771, 0x0772, 0x0773, 0x0774, 0x0775, 0x0776, 0x0777, 0x0778, 0x0779, 0x077a, 0x077b, 0x077c, 0x077d, 0x077e, 0x077f, 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0786, 0x0787, 0x0788, 0x0789, 0x078a, 0x078b, 0x078c, 0x078d, 0x078e, 0x078f, 0x0790, 0x0791, 0x0792, 0x0793, 0x0794, 0x0795, 0x0796, 0x0797, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, 0x079e, 0x079f, 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07b1, 0x07c0, 0x07c1, 0x07c2, 0x07c3, 0x07c4, 0x07c5, 0x07c6, 0x07c7, 0x07c8, 0x07c9, 0x07ca, 0x07cb, 0x07cc, 0x07cd, 0x07ce, 0x07cf, 0x07d0, 0x07d1, 0x07d2, 0x07d3, 0x07d4, 0x07d5, 0x07d6, 0x07d7, 0x07d8, 0x07d9, 0x07da, 0x07db, 0x07dc, 0x07dd, 0x07de, 0x07df, 0x07e0, 0x07e1, 0x07e2, 0x07e3, 0x07e4, 0x07e5, 0x07e6, 0x07e7, 0x07e8, 0x07e9, 0x07ea, 0x07f4, 0x07f5, 0x07fa, 0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809, 0x080a, 0x080b, 0x080c, 0x080d, 0x080e, 0x080f, 0x0810, 0x0811, 0x0812, 0x0813, 0x0814, 0x0815, 0x081a, 0x0824, 0x0828, 0x0830, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, 0x0837, 0x0838, 0x0839, 0x083a, 0x083b, 0x083c, 0x083d, 0x083e, 0x0840, 0x0841, 0x0842, 0x0843, 0x0844, 0x0845, 0x0846, 0x0847, 0x0848, 0x0849, 0x084a, 0x084b, 0x084c, 0x084d, 0x084e, 0x084f, 0x0850, 0x0851, 0x0852, 0x0853, 0x0854, 0x0855, 0x0856, 0x0857, 0x0858, 0x085e, 0x08a0, 0x08a2, 0x08a3, 0x08a4, 0x08a5, 0x08a6, 0x08a7, 0x08a8, 0x08a9, 0x08aa, 0x08ab, 0x08ac, 0x200f, 0xfb1d, 0xfb1f, 0xfb20, 0xfb21, 0xfb22, 0xfb23, 0xfb24, 0xfb25, 0xfb26, 0xfb27, 0xfb28, 0xfb2a, 0xfb2b, 0xfb2c, 0xfb2d, 0xfb2e, 0xfb2f, 0xfb30, 0xfb31, 0xfb32, 0xfb33, 0xfb34, 0xfb35, 0xfb36, 0xfb38, 0xfb39, 0xfb3a, 0xfb3b, 0xfb3c, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb49, 0xfb4a, 0xfb4b, 0xfb4c, 0xfb4d, 0xfb4e, 0xfb4f, 0xfb50, 0xfb51, 0xfb52, 0xfb53, 0xfb54, 0xfb55, 0xfb56, 0xfb57, 0xfb58, 0xfb59, 0xfb5a, 0xfb5b, 0xfb5c, 0xfb5d, 0xfb5e, 0xfb5f, 0xfb60, 0xfb61, 0xfb62, 0xfb63, 0xfb64, 0xfb65, 0xfb66, 0xfb67, 0xfb68, 0xfb69, 0xfb6a, 0xfb6b, 0xfb6c, 0xfb6d, 0xfb6e, 0xfb6f, 0xfb70, 0xfb71, 0xfb72, 0xfb73, 0xfb74, 0xfb75, 0xfb76, 0xfb77, 0xfb78, 0xfb79, 0xfb7a, 0xfb7b, 0xfb7c, 0xfb7d, 0xfb7e, 0xfb7f, 0xfb80, 0xfb81, 0xfb82, 0xfb83, 0xfb84, 0xfb85, 0xfb86, 0xfb87, 0xfb88, 0xfb89, 0xfb8a, 0xfb8b, 0xfb8c, 0xfb8d, 0xfb8e, 0xfb8f, 0xfb90, 0xfb91, 0xfb92, 0xfb93, 0xfb94, 0xfb95, 0xfb96, 0xfb97, 0xfb98, 0xfb99, 0xfb9a, 0xfb9b, 0xfb9c, 0xfb9d, 0xfb9e, 0xfb9f, 0xfba0, 0xfba1, 0xfba2, 0xfba3, 0xfba4, 0xfba5, 0xfba6, 0xfba7, 0xfba8, 0xfba9, 0xfbaa, 0xfbab, 0xfbac, 0xfbad, 0xfbae, 0xfbaf, 0xfbb0, 0xfbb1, 0xfbb2, 0xfbb3, 0xfbb4, 0xfbb5, 0xfbb6, 0xfbb7, 0xfbb8, 0xfbb9, 0xfbba, 0xfbbb, 0xfbbc, 0xfbbd, 0xfbbe, 0xfbbf, 0xfbc0, 0xfbc1, 0xfbd3, 0xfbd4, 0xfbd5, 0xfbd6, 0xfbd7, 0xfbd8, 0xfbd9, 0xfbda, 0xfbdb, 0xfbdc, 0xfbdd, 0xfbde, 0xfbdf, 0xfbe0, 0xfbe1, 0xfbe2, 0xfbe3, 0xfbe4, 0xfbe5, 0xfbe6, 0xfbe7, 0xfbe8, 0xfbe9, 0xfbea, 0xfbeb, 0xfbec, 0xfbed, 0xfbee, 0xfbef, 0xfbf0, 0xfbf1, 0xfbf2, 0xfbf3, 0xfbf4, 0xfbf5, 0xfbf6, 0xfbf7, 0xfbf8, 0xfbf9, 0xfbfa, 0xfbfb, 0xfbfc, 0xfbfd, 0xfbfe, 0xfbff, 0xfc00, 0xfc01, 0xfc02, 0xfc03, 0xfc04, 0xfc05, 0xfc06, 0xfc07, 0xfc08, 0xfc09, 0xfc0a, 0xfc0b, 0xfc0c, 0xfc0d, 0xfc0e, 0xfc0f, 0xfc10, 0xfc11, 0xfc12, 0xfc13, 0xfc14, 0xfc15, 0xfc16, 0xfc17, 0xfc18, 0xfc19, 0xfc1a, 0xfc1b, 0xfc1c, 0xfc1d, 0xfc1e, 0xfc1f, 0xfc20, 0xfc21, 0xfc22, 0xfc23, 0xfc24, 0xfc25, 0xfc26, 0xfc27, 0xfc28, 0xfc29, 0xfc2a, 0xfc2b, 0xfc2c, 0xfc2d, 0xfc2e, 0xfc2f, 0xfc30, 0xfc31, 0xfc32, 0xfc33, 0xfc34, 0xfc35, 0xfc36, 0xfc37, 0xfc38, 0xfc39, 0xfc3a, 0xfc3b, 0xfc3c, 0xfc3d, 0xfc3e, 0xfc3f, 0xfc40, 0xfc41, 0xfc42, 0xfc43, 0xfc44, 0xfc45, 0xfc46, 0xfc47, 0xfc48, 0xfc49, 0xfc4a, 0xfc4b, 0xfc4c, 0xfc4d, 0xfc4e, 0xfc4f, 0xfc50, 0xfc51, 0xfc52, 0xfc53, 0xfc54, 0xfc55, 0xfc56, 0xfc57, 0xfc58, 0xfc59, 0xfc5a, 0xfc5b, 0xfc5c, 0xfc5d, 0xfc5e, 0xfc5f, 0xfc60, 0xfc61, 0xfc62, 0xfc63, 0xfc64, 0xfc65, 0xfc66, 0xfc67, 0xfc68, 0xfc69, 0xfc6a, 0xfc6b, 0xfc6c, 0xfc6d, 0xfc6e, 0xfc6f, 0xfc70, 0xfc71, 0xfc72, 0xfc73, 0xfc74, 0xfc75, 0xfc76, 0xfc77, 0xfc78, 0xfc79, 0xfc7a, 0xfc7b, 0xfc7c, 0xfc7d, 0xfc7e, 0xfc7f, 0xfc80, 0xfc81, 0xfc82, 0xfc83, 0xfc84, 0xfc85, 0xfc86, 0xfc87, 0xfc88, 0xfc89, 0xfc8a, 0xfc8b, 0xfc8c, 0xfc8d, 0xfc8e, 0xfc8f, 0xfc90, 0xfc91, 0xfc92, 0xfc93, 0xfc94, 0xfc95, 0xfc96, 0xfc97, 0xfc98, 0xfc99, 0xfc9a, 0xfc9b, 0xfc9c, 0xfc9d, 0xfc9e, 0xfc9f, 0xfca0, 0xfca1, 0xfca2, 0xfca3, 0xfca4, 0xfca5, 0xfca6, 0xfca7, 0xfca8, 0xfca9, 0xfcaa, 0xfcab, 0xfcac, 0xfcad, 0xfcae, 0xfcaf, 0xfcb0, 0xfcb1, 0xfcb2, 0xfcb3, 0xfcb4, 0xfcb5, 0xfcb6, 0xfcb7, 0xfcb8, 0xfcb9, 0xfcba, 0xfcbb, 0xfcbc, 0xfcbd, 0xfcbe, 0xfcbf, 0xfcc0, 0xfcc1, 0xfcc2, 0xfcc3, 0xfcc4, 0xfcc5, 0xfcc6, 0xfcc7, 0xfcc8, 0xfcc9, 0xfcca, 0xfccb, 0xfccc, 0xfccd, 0xfcce, 0xfccf, 0xfcd0, 0xfcd1, 0xfcd2, 0xfcd3, 0xfcd4, 0xfcd5, 0xfcd6, 0xfcd7, 0xfcd8, 0xfcd9, 0xfcda, 0xfcdb, 0xfcdc, 0xfcdd, 0xfcde, 0xfcdf, 0xfce0, 0xfce1, 0xfce2, 0xfce3, 0xfce4, 0xfce5, 0xfce6, 0xfce7, 0xfce8, 0xfce9, 0xfcea, 0xfceb, 0xfcec, 0xfced, 0xfcee, 0xfcef, 0xfcf0, 0xfcf1, 0xfcf2, 0xfcf3, 0xfcf4, 0xfcf5, 0xfcf6, 0xfcf7, 0xfcf8, 0xfcf9, 0xfcfa, 0xfcfb, 0xfcfc, 0xfcfd, 0xfcfe, 0xfcff, 0xfd00, 0xfd01, 0xfd02, 0xfd03, 0xfd04, 0xfd05, 0xfd06, 0xfd07, 0xfd08, 0xfd09, 0xfd0a, 0xfd0b, 0xfd0c, 0xfd0d, 0xfd0e, 0xfd0f, 0xfd10, 0xfd11, 0xfd12, 0xfd13, 0xfd14, 0xfd15, 0xfd16, 0xfd17, 0xfd18, 0xfd19, 0xfd1a, 0xfd1b, 0xfd1c, 0xfd1d, 0xfd1e, 0xfd1f, 0xfd20, 0xfd21, 0xfd22, 0xfd23, 0xfd24, 0xfd25, 0xfd26, 0xfd27, 0xfd28, 0xfd29, 0xfd2a, 0xfd2b, 0xfd2c, 0xfd2d, 0xfd2e, 0xfd2f, 0xfd30, 0xfd31, 0xfd32, 0xfd33, 0xfd34, 0xfd35, 0xfd36, 0xfd37, 0xfd38, 0xfd39, 0xfd3a, 0xfd3b, 0xfd3c, 0xfd3d, 0xfd50, 0xfd51, 0xfd52, 0xfd53, 0xfd54, 0xfd55, 0xfd56, 0xfd57, 0xfd58, 0xfd59, 0xfd5a, 0xfd5b, 0xfd5c, 0xfd5d, 0xfd5e, 0xfd5f, 0xfd60, 0xfd61, 0xfd62, 0xfd63, 0xfd64, 0xfd65, 0xfd66, 0xfd67, 0xfd68, 0xfd69, 0xfd6a, 0xfd6b, 0xfd6c, 0xfd6d, 0xfd6e, 0xfd6f, 0xfd70, 0xfd71, 0xfd72, 0xfd73, 0xfd74, 0xfd75, 0xfd76, 0xfd77, 0xfd78, 0xfd79, 0xfd7a, 0xfd7b, 0xfd7c, 0xfd7d, 0xfd7e, 0xfd7f, 0xfd80, 0xfd81, 0xfd82, 0xfd83, 0xfd84, 0xfd85, 0xfd86, 0xfd87, 0xfd88, 0xfd89, 0xfd8a, 0xfd8b, 0xfd8c, 0xfd8d, 0xfd8e, 0xfd8f, 0xfd92, 0xfd93, 0xfd94, 0xfd95, 0xfd96, 0xfd97, 0xfd98, 0xfd99, 0xfd9a, 0xfd9b, 0xfd9c, 0xfd9d, 0xfd9e, 0xfd9f, 0xfda0, 0xfda1, 0xfda2, 0xfda3, 0xfda4, 0xfda5, 0xfda6, 0xfda7, 0xfda8, 0xfda9, 0xfdaa, 0xfdab, 0xfdac, 0xfdad, 0xfdae, 0xfdaf, 0xfdb0, 0xfdb1, 0xfdb2, 0xfdb3, 0xfdb4, 0xfdb5, 0xfdb6, 0xfdb7, 0xfdb8, 0xfdb9, 0xfdba, 0xfdbb, 0xfdbc, 0xfdbd, 0xfdbe, 0xfdbf, 0xfdc0, 0xfdc1, 0xfdc2, 0xfdc3, 0xfdc4, 0xfdc5, 0xfdc6, 0xfdc7, 0xfdf0, 0xfdf1, 0xfdf2, 0xfdf3, 0xfdf4, 0xfdf5, 0xfdf6, 0xfdf7, 0xfdf8, 0xfdf9, 0xfdfa, 0xfdfb, 0xfdfc, 0xfe70, 0xfe71, 0xfe72, 0xfe73, 0xfe74, 0xfe76, 0xfe77, 0xfe78, 0xfe79, 0xfe7a, 0xfe7b, 0xfe7c, 0xfe7d, 0xfe7e, 0xfe7f, 0xfe80, 0xfe81, 0xfe82, 0xfe83, 0xfe84, 0xfe85, 0xfe86, 0xfe87, 0xfe88, 0xfe89, 0xfe8a, 0xfe8b, 0xfe8c, 0xfe8d, 0xfe8e, 0xfe8f, 0xfe90, 0xfe91, 0xfe92, 0xfe93, 0xfe94, 0xfe95, 0xfe96, 0xfe97, 0xfe98, 0xfe99, 0xfe9a, 0xfe9b, 0xfe9c, 0xfe9d, 0xfe9e, 0xfe9f, 0xfea0, 0xfea1, 0xfea2, 0xfea3, 0xfea4, 0xfea5, 0xfea6, 0xfea7, 0xfea8, 0xfea9, 0xfeaa, 0xfeab, 0xfeac, 0xfead, 0xfeae, 0xfeaf, 0xfeb0, 0xfeb1, 0xfeb2, 0xfeb3, 0xfeb4, 0xfeb5, 0xfeb6, 0xfeb7, 0xfeb8, 0xfeb9, 0xfeba, 0xfebb, 0xfebc, 0xfebd, 0xfebe, 0xfebf, 0xfec0, 0xfec1, 0xfec2, 0xfec3, 0xfec4, 0xfec5, 0xfec6, 0xfec7, 0xfec8, 0xfec9, 0xfeca, 0xfecb, 0xfecc, 0xfecd, 0xfece, 0xfecf, 0xfed0, 0xfed1, 0xfed2, 0xfed3, 0xfed4, 0xfed5, 0xfed6, 0xfed7, 0xfed8, 0xfed9, 0xfeda, 0xfedb, 0xfedc, 0xfedd, 0xfede, 0xfedf, 0xfee0, 0xfee1, 0xfee2, 0xfee3, 0xfee4, 0xfee5, 0xfee6, 0xfee7, 0xfee8, 0xfee9, 0xfeea, 0xfeeb, 0xfeec, 0xfeed, 0xfeee, 0xfeef, 0xfef0, 0xfef1, 0xfef2, 0xfef3, 0xfef4, 0xfef5, 0xfef6, 0xfef7, 0xfef8, 0xfef9, 0xfefa, 0xfefb, 0xfefc, 0x10800, 0x10801, 0x10802, 0x10803, 0x10804, 0x10805, 0x10808, 0x1080a, 0x1080b, 0x1080c, 0x1080d, 0x1080e, 0x1080f, 0x10810, 0x10811, 0x10812, 0x10813, 0x10814, 0x10815, 0x10816, 0x10817, 0x10818, 0x10819, 0x1081a, 0x1081b, 0x1081c, 0x1081d, 0x1081e, 0x1081f, 0x10820, 0x10821, 0x10822, 0x10823, 0x10824, 0x10825, 0x10826, 0x10827, 0x10828, 0x10829, 0x1082a, 0x1082b, 0x1082c, 0x1082d, 0x1082e, 0x1082f, 0x10830, 0x10831, 0x10832, 0x10833, 0x10834, 0x10835, 0x10837, 0x10838, 0x1083c, 0x1083f, 0x10840, 0x10841, 0x10842, 0x10843, 0x10844, 0x10845, 0x10846, 0x10847, 0x10848, 0x10849, 0x1084a, 0x1084b, 0x1084c, 0x1084d, 0x1084e, 0x1084f, 0x10850, 0x10851, 0x10852, 0x10853, 0x10854, 0x10855, 0x10857, 0x10858, 0x10859, 0x1085a, 0x1085b, 0x1085c, 0x1085d, 0x1085e, 0x1085f, 0x10900, 0x10901, 0x10902, 0x10903, 0x10904, 0x10905, 0x10906, 0x10907, 0x10908, 0x10909, 0x1090a, 0x1090b, 0x1090c, 0x1090d, 0x1090e, 0x1090f, 0x10910, 0x10911, 0x10912, 0x10913, 0x10914, 0x10915, 0x10916, 0x10917, 0x10918, 0x10919, 0x1091a, 0x1091b, 0x10920, 0x10921, 0x10922, 0x10923, 0x10924, 0x10925, 0x10926, 0x10927, 0x10928, 0x10929, 0x1092a, 0x1092b, 0x1092c, 0x1092d, 0x1092e, 0x1092f, 0x10930, 0x10931, 0x10932, 0x10933, 0x10934, 0x10935, 0x10936, 0x10937, 0x10938, 0x10939, 0x1093f, 0x10980, 0x10981, 0x10982, 0x10983, 0x10984, 0x10985, 0x10986, 0x10987, 0x10988, 0x10989, 0x1098a, 0x1098b, 0x1098c, 0x1098d, 0x1098e, 0x1098f, 0x10990, 0x10991, 0x10992, 0x10993, 0x10994, 0x10995, 0x10996, 0x10997, 0x10998, 0x10999, 0x1099a, 0x1099b, 0x1099c, 0x1099d, 0x1099e, 0x1099f, 0x109a0, 0x109a1, 0x109a2, 0x109a3, 0x109a4, 0x109a5, 0x109a6, 0x109a7, 0x109a8, 0x109a9, 0x109aa, 0x109ab, 0x109ac, 0x109ad, 0x109ae, 0x109af, 0x109b0, 0x109b1, 0x109b2, 0x109b3, 0x109b4, 0x109b5, 0x109b6, 0x109b7, 0x109be, 0x109bf, 0x10a00, 0x10a10, 0x10a11, 0x10a12, 0x10a13, 0x10a15, 0x10a16, 0x10a17, 0x10a19, 0x10a1a, 0x10a1b, 0x10a1c, 0x10a1d, 0x10a1e, 0x10a1f, 0x10a20, 0x10a21, 0x10a22, 0x10a23, 0x10a24, 0x10a25, 0x10a26, 0x10a27, 0x10a28, 0x10a29, 0x10a2a, 0x10a2b, 0x10a2c, 0x10a2d, 0x10a2e, 0x10a2f, 0x10a30, 0x10a31, 0x10a32, 0x10a33, 0x10a40, 0x10a41, 0x10a42, 0x10a43, 0x10a44, 0x10a45, 0x10a46, 0x10a47, 0x10a50, 0x10a51, 0x10a52, 0x10a53, 0x10a54, 0x10a55, 0x10a56, 0x10a57, 0x10a58, 0x10a60, 0x10a61, 0x10a62, 0x10a63, 0x10a64, 0x10a65, 0x10a66, 0x10a67, 0x10a68, 0x10a69, 0x10a6a, 0x10a6b, 0x10a6c, 0x10a6d, 0x10a6e, 0x10a6f, 0x10a70, 0x10a71, 0x10a72, 0x10a73, 0x10a74, 0x10a75, 0x10a76, 0x10a77, 0x10a78, 0x10a79, 0x10a7a, 0x10a7b, 0x10a7c, 0x10a7d, 0x10a7e, 0x10a7f, 0x10b00, 0x10b01, 0x10b02, 0x10b03, 0x10b04, 0x10b05, 0x10b06, 0x10b07, 0x10b08, 0x10b09, 0x10b0a, 0x10b0b, 0x10b0c, 0x10b0d, 0x10b0e, 0x10b0f, 0x10b10, 0x10b11, 0x10b12, 0x10b13, 0x10b14, 0x10b15, 0x10b16, 0x10b17, 0x10b18, 0x10b19, 0x10b1a, 0x10b1b, 0x10b1c, 0x10b1d, 0x10b1e, 0x10b1f, 0x10b20, 0x10b21, 0x10b22, 0x10b23, 0x10b24, 0x10b25, 0x10b26, 0x10b27, 0x10b28, 0x10b29, 0x10b2a, 0x10b2b, 0x10b2c, 0x10b2d, 0x10b2e, 0x10b2f, 0x10b30, 0x10b31, 0x10b32, 0x10b33, 0x10b34, 0x10b35, 0x10b40, 0x10b41, 0x10b42, 0x10b43, 0x10b44, 0x10b45, 0x10b46, 0x10b47, 0x10b48, 0x10b49, 0x10b4a, 0x10b4b, 0x10b4c, 0x10b4d, 0x10b4e, 0x10b4f, 0x10b50, 0x10b51, 0x10b52, 0x10b53, 0x10b54, 0x10b55, 0x10b58, 0x10b59, 0x10b5a, 0x10b5b, 0x10b5c, 0x10b5d, 0x10b5e, 0x10b5f, 0x10b60, 0x10b61, 0x10b62, 0x10b63, 0x10b64, 0x10b65, 0x10b66, 0x10b67, 0x10b68, 0x10b69, 0x10b6a, 0x10b6b, 0x10b6c, 0x10b6d, 0x10b6e, 0x10b6f, 0x10b70, 0x10b71, 0x10b72, 0x10b78, 0x10b79, 0x10b7a, 0x10b7b, 0x10b7c, 0x10b7d, 0x10b7e, 0x10b7f, 0x10c00, 0x10c01, 0x10c02, 0x10c03, 0x10c04, 0x10c05, 0x10c06, 0x10c07, 0x10c08, 0x10c09, 0x10c0a, 0x10c0b, 0x10c0c, 0x10c0d, 0x10c0e, 0x10c0f, 0x10c10, 0x10c11, 0x10c12, 0x10c13, 0x10c14, 0x10c15, 0x10c16, 0x10c17, 0x10c18, 0x10c19, 0x10c1a, 0x10c1b, 0x10c1c, 0x10c1d, 0x10c1e, 0x10c1f, 0x10c20, 0x10c21, 0x10c22, 0x10c23, 0x10c24, 0x10c25, 0x10c26, 0x10c27, 0x10c28, 0x10c29, 0x10c2a, 0x10c2b, 0x10c2c, 0x10c2d, 0x10c2e, 0x10c2f, 0x10c30, 0x10c31, 0x10c32, 0x10c33, 0x10c34, 0x10c35, 0x10c36, 0x10c37, 0x10c38, 0x10c39, 0x10c3a, 0x10c3b, 0x10c3c, 0x10c3d, 0x10c3e, 0x10c3f, 0x10c40, 0x10c41, 0x10c42, 0x10c43, 0x10c44, 0x10c45, 0x10c46, 0x10c47, 0x10c48, 0x1ee00, 0x1ee01, 0x1ee02, 0x1ee03, 0x1ee05, 0x1ee06, 0x1ee07, 0x1ee08, 0x1ee09, 0x1ee0a, 0x1ee0b, 0x1ee0c, 0x1ee0d, 0x1ee0e, 0x1ee0f, 0x1ee10, 0x1ee11, 0x1ee12, 0x1ee13, 0x1ee14, 0x1ee15, 0x1ee16, 0x1ee17, 0x1ee18, 0x1ee19, 0x1ee1a, 0x1ee1b, 0x1ee1c, 0x1ee1d, 0x1ee1e, 0x1ee1f, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27, 0x1ee29, 0x1ee2a, 0x1ee2b, 0x1ee2c, 0x1ee2d, 0x1ee2e, 0x1ee2f, 0x1ee30, 0x1ee31, 0x1ee32, 0x1ee34, 0x1ee35, 0x1ee36, 0x1ee37, 0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee4d, 0x1ee4e, 0x1ee4f, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee57, 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee67, 0x1ee68, 0x1ee69, 0x1ee6a, 0x1ee6c, 0x1ee6d, 0x1ee6e, 0x1ee6f, 0x1ee70, 0x1ee71, 0x1ee72, 0x1ee74, 0x1ee75, 0x1ee76, 0x1ee77, 0x1ee79, 0x1ee7a, 0x1ee7b, 0x1ee7c, 0x1ee7e, 0x1ee80, 0x1ee81, 0x1ee82, 0x1ee83, 0x1ee84, 0x1ee85, 0x1ee86, 0x1ee87, 0x1ee88, 0x1ee89, 0x1ee8b, 0x1ee8c, 0x1ee8d, 0x1ee8e, 0x1ee8f, 0x1ee90, 0x1ee91, 0x1ee92, 0x1ee93, 0x1ee94, 0x1ee95, 0x1ee96, 0x1ee97, 0x1ee98, 0x1ee99, 0x1ee9a, 0x1ee9b, 0x1eea1, 0x1eea2, 0x1eea3, 0x1eea5, 0x1eea6, 0x1eea7, 0x1eea8, 0x1eea9, 0x1eeab, 0x1eeac, 0x1eead, 0x1eeae, 0x1eeaf, 0x1eeb0, 0x1eeb1, 0x1eeb2, 0x1eeb3, 0x1eeb4, 0x1eeb5, 0x1eeb6, 0x1eeb7, 0x1eeb8, 0x1eeb9, 0x1eeba, 0x1eebb, 0x10fffd]; function determinebidi(cuediv) { var nodestack = [], text = "", charcode; if (!cuediv || !cuediv.childnodes) { return "ltr"; } function pushnodes(nodestack, node) { for (var i = node.childnodes.length - 1; i >= 0; i--) { nodestack.push(node.childnodes[i]); } } function nexttextnode(nodestack) { if (!nodestack || !nodestack.length) { return null; } var node = nodestack.pop(), text = node.textcontent || node.innertext; if (text) { // todo: this should match all unicode type b characters (paragraph // separator characters). see issue #115. var m = text.match(/^.*(\n|\r)/); if (m) { nodestack.length = 0; return m[0]; } return text; } if (node.tagname === "ruby") { return nexttextnode(nodestack); } if (node.childnodes) { pushnodes(nodestack, node); return nexttextnode(nodestack); } } pushnodes(nodestack, cuediv); while ((text = nexttextnode(nodestack))) { for (var i = 0; i < text.length; i++) { charcode = text.charcodeat(i); for (var j = 0; j < strongrtlchars.length; j++) { if (strongrtlchars[j] === charcode) { return "rtl"; } } } } return "ltr"; } function computelinepos(cue) { if (typeof cue.line === "number" && (cue.snaptolines || (cue.line >= 0 && cue.line <= 100))) { return cue.line; } if (!cue.track || !cue.track.texttracklist || !cue.track.texttracklist.mediaelement) { return -1; } var track = cue.track, tracklist = track.texttracklist, count = 0; for (var i = 0; i < tracklist.length && tracklist[i] !== track; i++) { if (tracklist[i].mode === "showing") { count++; } } return ++count * -1; } function stylebox() { } // apply styles to a div. if there is no div passed then it defaults to the // div on 'this'. stylebox.prototype.applystyles = function(styles, div) { div = div || this.div; for (var prop in styles) { if (styles.hasownproperty(prop)) { div.style[prop] = styles[prop]; } } }; stylebox.prototype.formatstyle = function(val, unit) { return val === 0 ? 0 : val + unit; }; // constructs the computed display state of the cue (a div). places the div // into the overlay which should be a block level element (usually a div). function cuestylebox(window, cue, styleoptions) { var isie8 = (/msie\s8\.0/).test(navigator.useragent); var color = "rgba(255, 255, 255, 1)"; var backgroundcolor = "rgba(0, 0, 0, 0.8)"; if (isie8) { color = "rgb(255, 255, 255)"; backgroundcolor = "rgb(0, 0, 0)"; } stylebox.call(this); this.cue = cue; // parse our cue's text into a dom tree rooted at 'cuediv'. this div will // have inline positioning and will function as the cue background box. this.cuediv = parsecontent(window, cue.text); var styles = { color: color, backgroundcolor: backgroundcolor, position: "relative", left: 0, right: 0, top: 0, bottom: 0, display: "inline" }; if (!isie8) { styles.writingmode = cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl"; styles.unicodebidi = "plaintext"; } this.applystyles(styles, this.cuediv); // create an absolutely positioned div that will be used to position the cue // div. note, all webvtt cue-setting alignments are equivalent to the css // mirrors of them except "middle" which is "center" in css. this.div = window.document.createelement("div"); styles = { textalign: cue.align === "middle" ? "center" : cue.align, font: styleoptions.font, whitespace: "pre-line", position: "absolute" }; if (!isie8) { styles.direction = determinebidi(this.cuediv); styles.writingmode = cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl". stylesunicodebidi = "plaintext"; } this.applystyles(styles); this.div.appendchild(this.cuediv); // calculate the distance from the reference edge of the viewport to the text // position of the cue box. the reference edge will be resolved later when // the box orientation styles are applied. var textpos = 0; switch (cue.positionalign) { case "start": textpos = cue.position; break; case "middle": textpos = cue.position - (cue.size / 2); break; case "end": textpos = cue.position - cue.size; break; } // horizontal box orientation; textpos is the distance from the left edge of the // area to the left edge of the box and cue.size is the distance extending to // the right from there. if (cue.vertical === "") { this.applystyles({ left: this.formatstyle(textpos, "%"), width: this.formatstyle(cue.size, "%") }); // vertical box orientation; textpos is the distance from the top edge of the // area to the top edge of the box and cue.size is the height extending // downwards from there. } else { this.applystyles({ top: this.formatstyle(textpos, "%"), height: this.formatstyle(cue.size, "%") }); } this.move = function(box) { this.applystyles({ top: this.formatstyle(box.top, "px"), bottom: this.formatstyle(box.bottom, "px"), left: this.formatstyle(box.left, "px"), right: this.formatstyle(box.right, "px"), height: this.formatstyle(box.height, "px"), width: this.formatstyle(box.width, "px") }); }; } cuestylebox.prototype = _objcreate(stylebox.prototype); cuestylebox.prototype.constructor = cuestylebox; // represents the co-ordinates of an element in a way that we can easily // compute things with such as if it overlaps or intersects with another element. // can initialize it with either a stylebox or another boxposition. function boxposition(obj) { var isie8 = (/msie\s8\.0/).test(navigator.useragent); // either a boxposition was passed in and we need to copy it, or a stylebox // was passed in and we need to copy the results of 'getboundingclientrect' // as the object returned is readonly. all co-ordinate values are in reference // to the viewport origin (top left). var lh, height, width, top; if (obj.div) { height = obj.div.offsetheight; width = obj.div.offsetwidth; top = obj.div.offsettop; var rects = (rects = obj.div.childnodes) && (rects = rects[0]) && rects.getclientrects && rects.getclientrects(); obj = obj.div.getboundingclientrect(); // in certain cases the outter div will be slightly larger then the sum of // the inner div's lines. this could be due to bold text, etc, on some platforms. // in this case we should get the average line height and use that. this will // result in the desired behaviour. lh = rects ? math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length) : 0; } this.left = obj.left; this.right = obj.right; this.top = obj.top || top; this.height = obj.height || height; this.bottom = obj.bottom || (top + (obj.height || height)); this.width = obj.width || width; this.lineheight = lh !== undefined ? lh : obj.lineheight; if (isie8 && !this.lineheight) { this.lineheight = 13; } } // move the box along a particular axis. optionally pass in an amount to move // the box. if no amount is passed then the default is the line height of the // box. boxposition.prototype.move = function(axis, tomove) { tomove = tomove !== undefined ? tomove : this.lineheight; switch (axis) { case "+x": this.left += tomove; this.right += tomove; break; case "-x": this.left -= tomove; this.right -= tomove; break; case "+y": this.top += tomove; this.bottom += tomove; break; case "-y": this.top -= tomove; this.bottom -= tomove; break; } }; // check if this box overlaps another box, b2. boxposition.prototype.overlaps = function(b2) { return this.left < b2.right && this.right > b2.left && this.top < b2.bottom && this.bottom > b2.top; }; // check if this box overlaps any other boxes in boxes. boxposition.prototype.overlapsany = function(boxes) { for (var i = 0; i < boxes.length; i++) { if (this.overlaps(boxes[i])) { return true; } } return false; }; // check if this box is within another box. boxposition.prototype.within = function(container) { return this.top >= container.top && this.bottom <= container.bottom && this.left >= container.left && this.right <= container.right; }; // check if this box is entirely within the container or it is overlapping // on the edge opposite of the axis direction passed. for example, if "+x" is // passed and the box is overlapping on the left edge of the container, then // return true. boxposition.prototype.overlapsoppositeaxis = function(container, axis) { switch (axis) { case "+x": return this.left < container.left; case "-x": return this.right > container.right; case "+y": return this.top < container.top; case "-y": return this.bottom > container.bottom; } }; // find the percentage of the area that this box is overlapping with another // box. boxposition.prototype.intersectpercentage = function(b2) { var x = math.max(0, math.min(this.right, b2.right) - math.max(this.left, b2.left)), y = math.max(0, math.min(this.bottom, b2.bottom) - math.max(this.top, b2.top)), intersectarea = x * y; return intersectarea / (this.height * this.width); }; // convert the positions from this box to css compatible positions using // the reference container's positions. this has to be done because this // box's positions are in reference to the viewport origin, whereas, css // values are in referecne to their respective edges. boxposition.prototype.tocsscompatvalues = function(reference) { return { top: this.top - reference.top, bottom: reference.bottom - this.bottom, left: this.left - reference.left, right: reference.right - this.right, height: this.height, width: this.width }; }; // get an object that represents the box's position without anything extra. // can pass a stylebox, htmlelement, or another boxpositon. boxposition.getsimpleboxposition = function(obj) { var height = obj.div ? obj.div.offsetheight : obj.tagname ? obj.offsetheight : 0; var width = obj.div ? obj.div.offsetwidth : obj.tagname ? obj.offsetwidth : 0; var top = obj.div ? obj.div.offsettop : obj.tagname ? obj.offsettop : 0; obj = obj.div ? obj.div.getboundingclientrect() : obj.tagname ? obj.getboundingclientrect() : obj; var ret = { left: obj.left, right: obj.right, top: obj.top || top, height: obj.height || height, bottom: obj.bottom || (top + (obj.height || height)), width: obj.width || width }; return ret; }; // move a stylebox to its specified, or next best, position. the containerbox // is the box that contains the stylebox, such as a div. boxpositions are // a list of other boxes that the stylebox can't overlap with. function moveboxtolineposition(window, stylebox, containerbox, boxpositions) { // find the best position for a cue box, b, on the video. the axis parameter // is a list of axis, the order of which, it will move the box along. for example: // passing ["+x", "-x"] will move the box first along the x axis in the positive // direction. if it doesn't find a good position for it there it will then move // it along the x axis in the negative direction. function findbestposition(b, axis) { var bestposition, specifiedposition = new boxposition(b), percentage = 1; // highest possible so the first thing we get is better. for (var i = 0; i < axis.length; i++) { while (b.overlapsoppositeaxis(containerbox, axis[i]) || (b.within(containerbox) && b.overlapsany(boxpositions))) { b.move(axis[i]); } // we found a spot where we aren't overlapping anything. this is our // best position. if (b.within(containerbox)) { return b; } var p = b.intersectpercentage(containerbox); // if we're outside the container box less then we were on our last try // then remember this position as the best position. if (percentage > p) { bestposition = new boxposition(b); percentage = p; } // reset the box position to the specified position. b = new boxposition(specifiedposition); } return bestposition || specifiedposition; } var boxposition = new boxposition(stylebox), cue = stylebox.cue, linepos = computelinepos(cue), axis = []; // if we have a line number to align the cue to. if (cue.snaptolines) { var size; switch (cue.vertical) { case "": axis = [ "+y", "-y" ]; size = "height"; break; case "rl": axis = [ "+x", "-x" ]; size = "width"; break; case "lr": axis = [ "-x", "+x" ]; size = "width"; break; } var step = boxposition.lineheight, position = step * math.round(linepos), maxposition = containerbox[size] + step, initialaxis = axis[0]; // if the specified intial position is greater then the max position then // clamp the box to the amount of steps it would take for the box to // reach the max position. if (math.abs(position) > maxposition) { position = position < 0 ? -1 : 1; position *= math.ceil(maxposition / step) * step; } // if computed line position returns negative then line numbers are // relative to the bottom of the video instead of the top. therefore, we // need to increase our initial position by the length or width of the // video, depending on the writing direction, and reverse our axis directions. if (linepos < 0) { position += cue.vertical === "" ? containerbox.height : containerbox.width; axis = axis.reverse(); } // move the box to the specified position. this may not be its best // position. boxposition.move(initialaxis, position); } else { // if we have a percentage line value for the cue. var calculatedpercentage = (boxposition.lineheight / containerbox.height) * 100; switch (cue.linealign) { case "middle": linepos -= (calculatedpercentage / 2); break; case "end": linepos -= calculatedpercentage; break; } // apply initial line position to the cue box. switch (cue.vertical) { case "": stylebox.applystyles({ top: stylebox.formatstyle(linepos, "%") }); break; case "rl": stylebox.applystyles({ left: stylebox.formatstyle(linepos, "%") }); break; case "lr": stylebox.applystyles({ right: stylebox.formatstyle(linepos, "%") }); break; } axis = [ "+y", "-x", "+x", "-y" ]; // get the box position again after we've applied the specified positioning // to it. boxposition = new boxposition(stylebox); } var bestposition = findbestposition(boxposition, axis); stylebox.move(bestposition.tocsscompatvalues(containerbox)); } function webvtt() { // nothing } // helper to allow strings to be decoded instead of the default binary utf8 data. webvtt.stringdecoder = function() { return { decode: function(data) { if (!data) { return ""; } if (typeof data !== "string") { throw new error("error - expected string data."); } return decodeuricomponent(encodeuricomponent(data)); } }; }; webvtt.convertcuetodomtree = function(window, cuetext) { if (!window || !cuetext) { return null; } return parsecontent(window, cuetext); }; var font_size_percent = 0.05; var font_style = "sans-serif"; var cue_background_padding = "1.5%"; // runs the processing model over the cues and regions passed to it. // @param overlay a block level element (usually a div) that the computed cues // and regions will be placed into. webvtt.processcues = function(window, cues, overlay) { if (!window || !cues || !overlay) { return null; } // remove all previous children. while (overlay.firstchild) { overlay.removechild(overlay.firstchild); } var paddedoverlay = window.document.createelement("div"); paddedoverlay.style.position = "absolute"; paddedoverlay.style.left = "0"; paddedoverlay.style.right = "0"; paddedoverlay.style.top = "0"; paddedoverlay.style.bottom = "0"; paddedoverlay.style.margin = cue_background_padding; overlay.appendchild(paddedoverlay); // determine if we need to compute the display states of the cues. this could // be the case if a cue's state has been changed since the last computation or // if it has not been computed yet. function shouldcompute(cues) { for (var i = 0; i < cues.length; i++) { if (cues[i].hasbeenreset || !cues[i].displaystate) { return true; } } return false; } // we don't need to recompute the cues' display states. just reuse them. if (!shouldcompute(cues)) { for (var i = 0; i < cues.length; i++) { paddedoverlay.appendchild(cues[i].displaystate); } return; } var boxpositions = [], containerbox = boxposition.getsimpleboxposition(paddedoverlay), fontsize = math.round(containerbox.height * font_size_percent * 100) / 100; var styleoptions = { font: fontsize + "px " + font_style }; (function() { var stylebox, cue; for (var i = 0; i < cues.length; i++) { cue = cues[i]; // compute the intial position and styles of the cue div. stylebox = new cuestylebox(window, cue, styleoptions); paddedoverlay.appendchild(stylebox.div); // move the cue div to it's correct line position. moveboxtolineposition(window, stylebox, containerbox, boxpositions); // remember the computed div so that we don't have to recompute it later // if we don't have too. cue.displaystate = stylebox.div; boxpositions.push(boxposition.getsimpleboxposition(stylebox)); } })(); }; webvtt.parser = function(window, vttjs, decoder) { if (!decoder) { decoder = vttjs; vttjs = {}; } if (!vttjs) { vttjs = {}; } this.window = window; this.vttjs = vttjs; this.state = "initial"; this.buffer = ""; this.decoder = decoder || new textdecoder("utf8"); this.regionlist = []; }; webvtt.parser.prototype = { // if the error is a parsingerror then report it to the consumer if // possible. if it's not a parsingerror then throw it like normal. reportorthrowerror: function(e) { if (e instanceof parsingerror) { this.onparsingerror && this.onparsingerror(e); } else { throw e; } }, parse: function (data) { var self = this; // if there is no data then we won't decode it, but will just try to parse // whatever is in buffer already. this may occur in circumstances, for // example when flush() is called. if (data) { // try to decode the data that we received. self.buffer += self.decoder.decode(data, {stream: true}); } function collectnextline() { var buffer = self.buffer; var pos = 0; while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { ++pos; } var line = buffer.substr(0, pos); // advance the buffer early in case we fail below. if (buffer[pos] === '\r') { ++pos; } if (buffer[pos] === '\n') { ++pos; } self.buffer = buffer.substr(pos); return line; } // 3.4 webvtt region and webvtt region settings syntax function parseregion(input) { var settings = new settings(); parseoptions(input, function (k, v) { switch (k) { case "id": settings.set(k, v); break; case "width": settings.percent(k, v); break; case "lines": settings.integer(k, v); break; case "regionanchor": case "viewportanchor": var xy = v.split(','); if (xy.length !== 2) { break; } // we have to make sure both x and y parse, so use a temporary // settings object here. var anchor = new settings(); anchor.percent("x", xy[0]); anchor.percent("y", xy[1]); if (!anchor.has("x") || !anchor.has("y")) { break; } settings.set(k + "x", anchor.get("x")); settings.set(k + "y", anchor.get("y")); break; case "scroll": settings.alt(k, v, ["up"]); break; } }, /=/, /\s/); // create the region, using default values for any values that were not // specified. if (settings.has("id")) { var region = new (self.vttjs.vttregion || self.window.vttregion)(); region.width = settings.get("width", 100); region.lines = settings.get("lines", 3); region.regionanchorx = settings.get("regionanchorx", 0); region.regionanchory = settings.get("regionanchory", 100); region.viewportanchorx = settings.get("viewportanchorx", 0); region.viewportanchory = settings.get("viewportanchory", 100); region.scroll = settings.get("scroll", ""); // register the region. self.onregion && self.onregion(region); // remember the vttregion for later in case we parse any vttcues that // reference it. self.regionlist.push({ id: settings.get("id"), region: region }); } } // 3.2 webvtt metadata header syntax function parseheader(input) { parseoptions(input, function (k, v) { switch (k) { case "region": // 3.3 webvtt region metadata header syntax parseregion(v); break; } }, /:/); } // 5.1 webvtt file parsing. try { var line; if (self.state === "initial") { // we can't start parsing until we have the first line. if (!/\r\n|\n/.test(self.buffer)) { return this; } line = collectnextline(); var m = line.match(/^webvtt([ \t].*)?$/); if (!m || !m[0]) { throw new parsingerror(parsingerror.errors.badsignature); } self.state = "header"; } var alreadycollectedline = false; while (self.buffer) { // we can't parse a line until we have the full line. if (!/\r\n|\n/.test(self.buffer)) { return this; } if (!alreadycollectedline) { line = collectnextline(); } else { alreadycollectedline = false; } switch (self.state) { case "header": // 13-18 - allow a header (metadata) under the webvtt line. if (/:/.test(line)) { parseheader(line); } else if (!line) { // an empty line terminates the header and starts the body (cues). self.state = "id"; } continue; case "note": // ignore note blocks. if (!line) { self.state = "id"; } continue; case "id": // check for the start of note blocks. if (/^note($|[ \t])/.test(line)) { self.state = "note"; break; } // 19-29 - allow any number of line terminators, then initialize new cue values. if (!line) { continue; } self.cue = new (self.vttjs.vttcue || self.window.vttcue)(0, 0, ""); self.state = "cue"; // 30-39 - check if self line contains an optional identifier or timing data. if (line.indexof("-->") === -1) { self.cue.id = line; continue; } // process line as start of a cue. /*falls through*/ case "cue": // 40 - collect cue timings and settings. try { parsecue(line, self.cue, self.regionlist); } catch (e) { self.reportorthrowerror(e); // in case of an error ignore rest of the cue. self.cue = null; self.state = "badcue"; continue; } self.state = "cuetext"; continue; case "cuetext": var hassubstring = line.indexof("-->") !== -1; // 34 - if we have an empty line then report the cue. // 35 - if we have the special substring '-->' then report the cue, // but do not collect the line as we need to process the current // one as a new cue. if (!line || hassubstring && (alreadycollectedline = true)) { // we are done parsing self cue. self.oncue && self.oncue(self.cue); self.cue = null; self.state = "id"; continue; } if (self.cue.text) { self.cue.text += "\n"; } self.cue.text += line; continue; case "badcue": // badcue // 54-62 - collect and discard the remaining cue. if (!line) { self.state = "id"; } continue; } } } catch (e) { self.reportorthrowerror(e); // if we are currently parsing a cue, report what we have. if (self.state === "cuetext" && self.cue && self.oncue) { self.oncue(self.cue); } self.cue = null; // enter badwebvtt state if header was not parsed correctly otherwise // another exception occurred so enter badcue state. self.state = self.state === "initial" ? "badwebvtt" : "badcue"; } return this; }, flush: function () { var self = this; try { // finish decoding the stream. self.buffer += self.decoder.decode(); // synthesize the end of the current cue or region. if (self.cue || self.state === "header") { self.buffer += "\n\n"; self.parse(); } // if we've flushed, parsed, and we're still on the initial state then // that means we don't have enough of the stream to parse the first // line. if (self.state === "initial") { throw new parsingerror(parsingerror.errors.badsignature); } } catch(e) { self.reportorthrowerror(e); } self.onflush && self.onflush(); return this; } }; global.webvtt = webvtt; }(this, (this.vttjs || {})));