diff --git a/src/js/button.js b/src/js/button.js index 010f9de64..b5e5f5dc1 100644 --- a/src/js/button.js +++ b/src/js/button.js @@ -4,7 +4,6 @@ import ClickableComponent from './clickable-component.js'; import Component from './component'; import log from './utils/log.js'; -import {assign} from './utils/obj'; import keycode from 'keycode'; import {createEl} from './utils/dom.js'; @@ -34,12 +33,12 @@ class Button extends ClickableComponent { createEl(tag, props = {}, attributes = {}) { tag = 'button'; - props = assign({ + props = Object.assign({ className: this.buildCSSClass() }, props); // Add attributes for button element - attributes = assign({ + attributes = Object.assign({ // Necessary since the default button type is "submit" type: 'button' diff --git a/src/js/clickable-component.js b/src/js/clickable-component.js index ba7410cae..f02895be0 100644 --- a/src/js/clickable-component.js +++ b/src/js/clickable-component.js @@ -4,7 +4,6 @@ import Component from './component'; import * as Dom from './utils/dom.js'; import log from './utils/log.js'; -import {assign} from './utils/obj'; import keycode from 'keycode'; /** @@ -68,7 +67,7 @@ class ClickableComponent extends Component { * The element that gets created. */ createEl(tag = 'div', props = {}, attributes = {}) { - props = assign({ + props = Object.assign({ className: this.buildCSSClass(), tabIndex: 0 }, props); @@ -78,7 +77,7 @@ class ClickableComponent extends Component { } // Add ARIA attributes for clickable element which is not a native HTML button - attributes = assign({ + attributes = Object.assign({ role: 'button' }, attributes); diff --git a/src/js/control-bar/progress-control/load-progress-bar.js b/src/js/control-bar/progress-control/load-progress-bar.js index fb48890f7..31d108eb3 100644 --- a/src/js/control-bar/progress-control/load-progress-bar.js +++ b/src/js/control-bar/progress-control/load-progress-bar.js @@ -3,7 +3,7 @@ */ import Component from '../../component.js'; import * as Dom from '../../utils/dom.js'; -import clamp from '../../utils/clamp'; +import {clamp} from '../../utils/num'; import document from 'global/document'; // get the percent width of a time compared to the total end diff --git a/src/js/control-bar/progress-control/progress-control.js b/src/js/control-bar/progress-control/progress-control.js index 2d4e6926d..8a7879443 100644 --- a/src/js/control-bar/progress-control/progress-control.js +++ b/src/js/control-bar/progress-control/progress-control.js @@ -3,7 +3,7 @@ */ import Component from '../../component.js'; import * as Dom from '../../utils/dom.js'; -import clamp from '../../utils/clamp.js'; +import {clamp} from '../../utils/num'; import {bind, throttle, UPDATE_REFRESH_INTERVAL} from '../../utils/fn.js'; import {silencePromise} from '../../utils/promise'; diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index 5f806c7d8..499462333 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -6,7 +6,7 @@ import Component from '../../component.js'; import {IS_IOS, IS_ANDROID} from '../../utils/browser.js'; import * as Dom from '../../utils/dom.js'; import * as Fn from '../../utils/fn.js'; -import formatTime from '../../utils/format-time.js'; +import {formatTime} from '../../utils/time'; import {silencePromise} from '../../utils/promise'; import keycode from 'keycode'; import document from 'global/document'; diff --git a/src/js/control-bar/progress-control/time-tooltip.js b/src/js/control-bar/progress-control/time-tooltip.js index ede9bb4d7..4eebd3340 100644 --- a/src/js/control-bar/progress-control/time-tooltip.js +++ b/src/js/control-bar/progress-control/time-tooltip.js @@ -3,7 +3,7 @@ */ import Component from '../../component'; import * as Dom from '../../utils/dom.js'; -import formatTime from '../../utils/format-time.js'; +import { formatTime } from '../../utils/time'; import * as Fn from '../../utils/fn.js'; /** diff --git a/src/js/control-bar/time-controls/time-display.js b/src/js/control-bar/time-controls/time-display.js index 99999ee62..88dd2eb40 100644 --- a/src/js/control-bar/time-controls/time-display.js +++ b/src/js/control-bar/time-controls/time-display.js @@ -4,7 +4,7 @@ import document from 'global/document'; import Component from '../../component.js'; import * as Dom from '../../utils/dom.js'; -import formatTime from '../../utils/format-time.js'; +import { formatTime } from '../../utils/time'; import log from '../../utils/log.js'; /** diff --git a/src/js/control-bar/volume-control/volume-bar.js b/src/js/control-bar/volume-control/volume-bar.js index c7148837e..ac6f86080 100644 --- a/src/js/control-bar/volume-control/volume-bar.js +++ b/src/js/control-bar/volume-control/volume-bar.js @@ -4,7 +4,7 @@ import Slider from '../../slider/slider.js'; import Component from '../../component.js'; import * as Dom from '../../utils/dom.js'; -import clamp from '../../utils/clamp.js'; +import {clamp} from '../../utils/num'; import {IS_IOS, IS_ANDROID} from '../../utils/browser.js'; // Required children diff --git a/src/js/media-error.js b/src/js/media-error.js index b313c5065..57fa92e07 100644 --- a/src/js/media-error.js +++ b/src/js/media-error.js @@ -1,7 +1,7 @@ /** * @file media-error.js */ -import {assign, isObject} from './utils/obj'; +import {isObject} from './utils/obj'; /** * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class. @@ -41,7 +41,7 @@ function MediaError(value) { this.code = value.code; } - assign(this, value); + Object.assign(this, value); } if (!this.message) { diff --git a/src/js/menu/menu-item.js b/src/js/menu/menu-item.js index f8b660f2b..7a95e19a5 100644 --- a/src/js/menu/menu-item.js +++ b/src/js/menu/menu-item.js @@ -3,7 +3,6 @@ */ import ClickableComponent from '../clickable-component.js'; import Component from '../component.js'; -import {assign} from '../utils/obj'; import {MenuKeys} from './menu-keys.js'; import keycode from 'keycode'; import {createEl} from '../utils/dom.js'; @@ -64,7 +63,7 @@ class MenuItem extends ClickableComponent { // The control is textual, not just an icon this.nonIconControl = true; - const el = super.createEl('li', assign({ + const el = super.createEl('li', Object.assign({ className: 'vjs-menu-item', tabIndex: -1 }, props), attrs); diff --git a/src/js/mixins/evented.js b/src/js/mixins/evented.js index c03273ceb..4bdd475ed 100644 --- a/src/js/mixins/evented.js +++ b/src/js/mixins/evented.js @@ -6,7 +6,6 @@ import window from 'global/window'; import * as Dom from '../utils/dom'; import * as Events from '../utils/events'; import * as Fn from '../utils/fn'; -import * as Obj from '../utils/obj'; import EventTarget from '../event-target'; import DomData from '../utils/dom-data'; import log from '../utils/log'; @@ -489,7 +488,7 @@ function evented(target, options = {}) { target.eventBusEl_ = Dom.createEl('span', {className: 'vjs-event-bus'}); } - Obj.assign(target, EventedMixin); + Object.assign(target, EventedMixin); if (target.eventedCallbacks) { target.eventedCallbacks.forEach((callback) => { diff --git a/src/js/mixins/stateful.js b/src/js/mixins/stateful.js index 0e24bdeaf..0fd72d089 100644 --- a/src/js/mixins/stateful.js +++ b/src/js/mixins/stateful.js @@ -103,11 +103,11 @@ const StatefulMixin = { * Returns the `target`. */ function stateful(target, defaultState) { - Obj.assign(target, StatefulMixin); + Object.assign(target, StatefulMixin); // This happens after the mixing-in because we need to replace the `state` // added in that step. - target.state = Obj.assign({}, target.state, defaultState); + target.state = Object.assign({}, target.state, defaultState); // Auto-bind the `handleStateChanged` method of the target object if it exists. if (typeof target.handleStateChanged === 'function' && isEvented(target)) { diff --git a/src/js/player.js b/src/js/player.js index b2074d86a..5d272ef16 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -17,7 +17,7 @@ import * as browser from './utils/browser.js'; import {IE_VERSION, IS_CHROME, IS_WINDOWS} from './utils/browser.js'; import log, { createLogger } from './utils/log.js'; import {toTitleCase, titleCaseEquals} from './utils/str.js'; -import { createTimeRange } from './utils/time-ranges.js'; +import { createTimeRanges } from './utils/time'; import { bufferedPercent } from './utils/buffer.js'; import * as stylesheet from './utils/stylesheet.js'; import FullscreenApi from './fullscreen-api.js'; @@ -32,7 +32,7 @@ import {ALL as TRACK_TYPES} from './tracks/track-types'; import filterSource from './utils/filter-source'; import {getMimetype, findMimetype} from './utils/mimetypes'; import {hooks} from './utils/hooks'; -import {assign, merge, isObject} from './utils/obj'; +import {merge, isObject} from './utils/obj'; import keycode from 'keycode'; // The following imports are used only to ensure that the corresponding modules @@ -310,7 +310,7 @@ class Player extends Component { // which overrides globally set options. // This latter part coincides with the load order // (tag must exist before Player) - options = assign(Player.getTagSettings(tag), options); + options = Object.assign(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()` @@ -1185,9 +1185,9 @@ class Player extends Component { techOptions[props.getterName] = this[props.privateName]; }); - assign(techOptions, this.options_[titleTechName]); - assign(techOptions, this.options_[camelTechName]); - assign(techOptions, this.options_[techName.toLowerCase()]); + Object.assign(techOptions, this.options_[titleTechName]); + Object.assign(techOptions, this.options_[camelTechName]); + Object.assign(techOptions, this.options_[techName.toLowerCase()]); if (this.tag) { techOptions.tag = this.tag; @@ -2487,7 +2487,7 @@ class Player extends Component { * been played. */ played() { - return this.techGet_('played') || createTimeRange(0, 0); + return this.techGet_('played') || createTimeRanges(0, 0); } /** @@ -2650,7 +2650,7 @@ class Player extends Component { let buffered = this.techGet_('buffered'); if (!buffered || !buffered.length) { - buffered = createTimeRange(0, 0); + buffered = createTimeRanges(0, 0); } return buffered; @@ -4796,18 +4796,18 @@ class Player extends Component { // Used as a getter. if (breakpoints === undefined) { - return assign(this.breakpoints_); + return Object.assign(this.breakpoints_); } this.breakpoint_ = ''; - this.breakpoints_ = assign({}, DEFAULT_BREAKPOINTS, breakpoints); + this.breakpoints_ = Object.assign({}, DEFAULT_BREAKPOINTS, breakpoints); // When breakpoint definitions change, we need to update the currently // selected breakpoint. this.updateCurrentBreakpoint_(); // Clone the breakpoints before returning. - return assign(this.breakpoints_); + return Object.assign(this.breakpoints_); } /** @@ -5037,10 +5037,10 @@ class Player extends Component { if (err) { log.error(err); } - assign(tagOptions, data); + Object.assign(tagOptions, data); } - assign(baseOptions, tagOptions); + Object.assign(baseOptions, tagOptions); // Get tag children settings if (tag.hasChildNodes()) { diff --git a/src/js/slider/slider.js b/src/js/slider/slider.js index 0fe41ee89..d1f0d028a 100644 --- a/src/js/slider/slider.js +++ b/src/js/slider/slider.js @@ -3,9 +3,8 @@ */ import Component from '../component.js'; import * as Dom from '../utils/dom.js'; -import {assign} from '../utils/obj'; import {IS_CHROME} from '../utils/browser.js'; -import clamp from '../utils/clamp.js'; +import {clamp} from '../utils/num'; import keycode from 'keycode'; /** @@ -126,11 +125,11 @@ class Slider extends Component { createEl(type, props = {}, attributes = {}) { // Add the slider element class to all sub classes props.className = props.className + ' vjs-slider'; - props = assign({ + props = Object.assign({ tabIndex: 0 }, props); - attributes = assign({ + attributes = Object.assign({ 'role': 'slider', 'aria-valuenow': 0, 'aria-valuemin': 0, diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index fd7f060af..6ec0101bd 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -8,7 +8,7 @@ import log from '../utils/log.js'; import * as browser from '../utils/browser.js'; import document from 'global/document'; import window from 'global/window'; -import {assign, merge} from '../utils/obj'; +import {merge} from '../utils/obj'; import {toTitleCase} from '../utils/str.js'; import {NORMAL as TRACK_TYPES, REMOTE} from '../tracks/track-types'; import setupSourceset from './setup-sourceset'; @@ -392,7 +392,7 @@ class Html5 extends Tech { Dom.setAttributes( el, - assign(attributes, { + Object.assign(attributes, { id: this.options_.techId, class: 'vjs-tech' }) diff --git a/src/js/tech/middleware.js b/src/js/tech/middleware.js index b978bf29e..bb7f3ad94 100644 --- a/src/js/tech/middleware.js +++ b/src/js/tech/middleware.js @@ -2,7 +2,6 @@ * @file middleware.js * @module middleware */ -import { assign } from '../utils/obj.js'; import {toTitleCase} from '../utils/str.js'; const middlewares = {}; @@ -301,7 +300,7 @@ function setSourceHelper(src = {}, middleware = [], next, player, acc = [], last return setSourceHelper(src, mwrest, next, player, acc, lastRun); } - mw.setSource(assign({}, src), function(err, _src) { + mw.setSource(Object.assign({}, src), function(err, _src) { // something happened, try the next middleware on the current level // make sure to use the old src diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index c0e546bcc..29a8f9705 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -5,7 +5,7 @@ import Component from '../component'; import * as Fn from '../utils/fn.js'; import log from '../utils/log.js'; -import { createTimeRange } from '../utils/time-ranges.js'; +import { createTimeRanges } from '../utils/time'; import { bufferedPercent } from '../utils/buffer.js'; import MediaError from '../media-error.js'; import window from 'global/window'; @@ -279,7 +279,7 @@ class Tech extends Component { * The time range object that was created. */ buffered() { - return createTimeRange(0, 0); + return createTimeRanges(0, 0); } /** @@ -486,9 +486,9 @@ class Tech extends Component { */ played() { if (this.hasStarted_) { - return createTimeRange(0, 0); + return createTimeRanges(0, 0); } - return createTimeRange(); + return createTimeRanges(); } /** diff --git a/src/js/utils/buffer.js b/src/js/utils/buffer.js index 83a94b3f1..3ee45cf6a 100644 --- a/src/js/utils/buffer.js +++ b/src/js/utils/buffer.js @@ -2,7 +2,7 @@ * @file buffer.js * @module buffer */ -import { createTimeRange } from './time-ranges.js'; +import { createTimeRanges } from './time'; /** * Compute the percentage of the media that has been buffered. @@ -26,7 +26,7 @@ export function bufferedPercent(buffered, duration) { } if (!buffered || !buffered.length) { - buffered = createTimeRange(0, 0); + buffered = createTimeRanges(0, 0); } for (let i = 0; i < buffered.length; i++) { diff --git a/src/js/utils/format-time.js b/src/js/utils/format-time.js deleted file mode 100644 index 1ae1425b1..000000000 --- a/src/js/utils/format-time.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @file format-time.js - * @module format-time - */ - -/** - * 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. - * - * @private - * @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 - */ -const defaultImplementation = function(seconds, guide) { - seconds = seconds < 0 ? 0 : seconds; - let s = Math.floor(seconds % 60); - let m = Math.floor(seconds / 60 % 60); - let h = Math.floor(seconds / 3600); - const gm = Math.floor(guide / 60 % 60); - const 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; -}; - -// Internal pointer to the current implementation. -let implementation = defaultImplementation; - -/** - * Replaces the default formatTime implementation with a custom implementation. - * - * @param {Function} customImplementation - * A function which will be used in place of the default formatTime - * implementation. Will receive the current time in seconds and the - * guide (in seconds) as arguments. - */ -export function setFormatTime(customImplementation) { - implementation = customImplementation; -} - -/** - * Resets formatTime to the default implementation. - */ -export function resetFormatTime() { - implementation = defaultImplementation; -} - -/** - * Delegates to either the default time formatting function or a custom - * function supplied via `setFormatTime`. - * - * Formats 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. - * - * @static - * @example formatTime(125, 600) === "02:05" - * @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 - */ -function formatTime(seconds, guide = seconds) { - return implementation(seconds, guide); -} - -export default formatTime; diff --git a/src/js/utils/clamp.js b/src/js/utils/num.js similarity index 84% rename from src/js/utils/clamp.js rename to src/js/utils/num.js index f4b1e52ee..c4557ca32 100644 --- a/src/js/utils/clamp.js +++ b/src/js/utils/num.js @@ -12,10 +12,8 @@ * @return {number} * the clamped number */ -const clamp = function(number, min, max) { +export const clamp = function(number, min, max) { number = Number(number); return Math.min(max, Math.max(min, isNaN(number) ? min : number)); }; - -export default clamp; diff --git a/src/js/utils/obj.js b/src/js/utils/obj.js index 4ea4a26cb..af53d9315 100644 --- a/src/js/utils/obj.js +++ b/src/js/utils/obj.js @@ -80,31 +80,6 @@ export function reduce(object, fn, initial = 0) { return keys(object).reduce((accum, key) => fn(accum, object[key], key), initial); } -/** - * Object.assign-style object shallow merge/extend. - * - * @param {Object} target - * @param {Object} ...sources - * @return {Object} - */ -export function assign(target, ...sources) { - if (Object.assign) { - return Object.assign(target, ...sources); - } - - sources.forEach(source => { - if (!source) { - return; - } - - each(source, (value, key) => { - target[key] = value; - }); - }); - - return target; -} - /** * Returns whether a value is an object of any kind - including DOM nodes, * arrays, regular expressions, etc. Not functions, though. diff --git a/src/js/utils/time-ranges.js b/src/js/utils/time.js similarity index 56% rename from src/js/utils/time-ranges.js rename to src/js/utils/time.js index 0627eae45..386292702 100644 --- a/src/js/utils/time-ranges.js +++ b/src/js/utils/time.js @@ -1,12 +1,100 @@ /** - * @file time-ranges.js - * @module time-ranges + * @file time.js + * @module time */ import window from 'global/window'; +/** + * 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. + * + * @private + * @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 + */ +const defaultImplementation = function(seconds, guide) { + seconds = seconds < 0 ? 0 : seconds; + let s = Math.floor(seconds % 60); + let m = Math.floor(seconds / 60 % 60); + let h = Math.floor(seconds / 3600); + const gm = Math.floor(guide / 60 % 60); + const 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; +}; + +// Internal pointer to the current implementation. +let implementation = defaultImplementation; + +/** + * Replaces the default formatTime implementation with a custom implementation. + * + * @param {Function} customImplementation + * A function which will be used in place of the default formatTime + * implementation. Will receive the current time in seconds and the + * guide (in seconds) as arguments. + */ +export function setFormatTime(customImplementation) { + implementation = customImplementation; +} + +/** + * Resets formatTime to the default implementation. + */ +export function resetFormatTime() { + implementation = defaultImplementation; +} + +/** + * Delegates to either the default time formatting function or a custom + * function supplied via `setFormatTime`. + * + * Formats 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. + * + * @static + * @example formatTime(125, 600) === "02:05" + * @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 + */ +export function formatTime(seconds, guide = seconds) { + return implementation(seconds, guide); +} + /** * Returns the time for the specified index at the start or end - * of a TimeRange object. + * of a TimeRanges object. * * @typedef {Function} TimeRangeIndex * @@ -23,15 +111,15 @@ import window from 'global/window'; /** * An object that contains ranges of time. * - * @typedef {Object} TimeRange + * @typedef {Object} TimeRanges * * @property {number} length * The number of time ranges represented by this object. * - * @property {module:time-ranges~TimeRangeIndex} start + * @property {module:time~TimeRangeIndex} start * Returns the time offset at which a specified time range begins. * - * @property {module:time-ranges~TimeRangeIndex} end + * @property {module:time~TimeRangeIndex} end * Returns the time offset at which a specified time range ends. * * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges @@ -60,7 +148,7 @@ function rangeCheck(fnName, index, maxIndex) { /** * Get the time for the specified index at the start or end - * of a TimeRange object. + * of a TimeRanges object. * * @private * @param {string} fnName @@ -123,7 +211,7 @@ function createTimeRangesObj(ranges) { } /** - * Create a `TimeRange` object which mimics an + * Create a `TimeRanges` object which mimics an * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}. * * @param {number|Array[]} start @@ -142,5 +230,3 @@ export function createTimeRanges(start, end) { } return createTimeRangesObj([[start, end]]); } - -export { createTimeRanges as createTimeRange }; diff --git a/src/js/utils/url.js b/src/js/utils/url.js index 7d8ef047a..3eecd959a 100644 --- a/src/js/utils/url.js +++ b/src/js/utils/url.js @@ -82,7 +82,7 @@ export const parseUrl = function(url) { }; /** - * Get absolute version of relative URL. Used to tell Flash the correct URL. + * Get absolute version of relative URL. * * @function * @param {string} url diff --git a/src/js/video.js b/src/js/video.js index 06a2cd446..0faa79074 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -2,11 +2,10 @@ * @file video.js * @module videojs */ -import {version} from '../../package.json'; +import { version } from '../../package.json'; import window from 'global/window'; // Include core functions and classes -import extend from './extend'; import * as setup from './setup'; import * as stylesheet from './utils/stylesheet'; import Component from './component'; @@ -18,16 +17,17 @@ import AudioTrack from './tracks/audio-track'; import VideoTrack from './tracks/video-track'; // Include utilities -import { createTimeRange } from './utils/time-ranges'; -import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time'; import log, { createLogger } from './utils/log'; -import deprecate from './utils/deprecate'; + +// The browser and DOM utilities are the only ones that are exported wholesale +// on the videojs function. All others are exported selectively/explicitly. import * as browser from './utils/browser'; -import clamp from './utils/clamp'; -import computedStyle from './utils/computed-style'; import * as dom from './utils/dom'; -import * as events from './utils/events'; -import * as fn from './utils/fn'; + +import computedStyle from './utils/computed-style'; +import deprecate from './utils/deprecate'; +import { any, off, on, one, trigger } from './utils/events'; +import { debounce, throttle } from './utils/fn'; import { hooks_, @@ -37,10 +37,12 @@ import { removeHook } from './utils/hooks'; -import * as obj from './utils/obj'; -import * as promise from './utils/promise'; -import * as str from './utils/str'; -import * as url from './utils/url'; +import { clamp } from './utils/num'; +import { each, reduce, isObject, isPlain, merge } from './utils/obj'; +import { isPromise, silencePromise } from './utils/promise'; +import { toLowerCase, toTitleCase, titleCaseEquals } from './utils/str'; +import { createTimeRanges, formatTime, resetFormatTime, setFormatTime } from './utils/time'; +import { parseUrl, getAbsoluteURL, getFileExtension, isCrossOrigin } from './utils/url'; import xhr from '@videojs/xhr'; @@ -106,9 +108,9 @@ const normalizeId = (id) => id.indexOf('#') === 0 ? id.slice(1) : id; * @borrows EventTarget as EventTarget * @borrows module:extend~extend as extend * @borrows module:fn.bind as bind - * @borrows module:format-time.formatTime as formatTime - * @borrows module:format-time.resetFormatTime as resetFormatTime - * @borrows module:format-time.setFormatTime as setFormatTime + * @borrows module:time.formatTime as formatTime + * @borrows module:time.resetFormatTime as resetFormatTime + * @borrows module:time.setFormatTime as setFormatTime * @borrows module:middleware.use as use * @borrows Player.players as players * @borrows Plugin.registerPlugin as registerPlugin @@ -119,8 +121,8 @@ const normalizeId = (id) => id.indexOf('#') === 0 ? id.slice(1) : id; * @borrows Tech.getTech as getTech * @borrows Tech.registerTech as registerTech * @borrows TextTrack as TextTrack - * @borrows module:time-ranges.createTimeRanges as createTimeRange - * @borrows module:time-ranges.createTimeRanges as createTimeRanges + * @borrows module:time.createTimeRanges as createTimeRanges + * @borrows module:time.createTimeRanges as createTimeRanges * @borrows module:url.isCrossOrigin as isCrossOrigin * @borrows module:url.parseUrl as parseUrl * @borrows VideoTrack as VideoTrack @@ -171,14 +173,14 @@ function videojs(id, options, ready) { options = options || {}; hooks('beforesetup').forEach((hookFunction) => { - const opts = hookFunction(el, obj.merge(options)); + const opts = hookFunction(el, merge(options)); - if (!obj.isObject(opts) || Array.isArray(opts)) { + if (!isObject(opts) || Array.isArray(opts)) { log.error('please return an object in beforesetup hooks'); return; } - options = obj.merge(options, opts); + options = merge(options, opts); }); // We get the current "Player" component here in case an integration has @@ -374,7 +376,7 @@ Object.defineProperty(videojs.middleware, 'TERMINATOR', { videojs.addLanguage = function(code, data) { code = ('' + code).toLowerCase(); - videojs.options.languages = obj.merge( + videojs.options.languages = merge( videojs.options.languages, {[code]: data} ); @@ -419,16 +421,14 @@ videojs.dom = dom; * @type {Object} * @see {@link module:fn|fn} */ -videojs.fn = fn; +videojs.fn = { debounce, throttle }; /** * An object containing number-related functions. * * @type {Object} */ -videojs.num = { - clamp -}; +videojs.num = { clamp }; /** * A reference to the {@link module:obj|object utility module} as an object. @@ -436,7 +436,7 @@ videojs.num = { * @type {Object} * @see {@link module:obj|obj} */ -videojs.obj = obj; +videojs.obj = { each, reduce, isObject, isPlain, merge }; /** * A reference to the {@link module:promise|promise utility module} as an object. @@ -444,7 +444,7 @@ videojs.obj = obj; * @type {Object} * @see {@link module:promise|promise} */ -videojs.promise = promise; +videojs.promise = { isPromise, silencePromise }; /** * A reference to the {@link module:str|string utility module} as an object. @@ -452,19 +452,14 @@ videojs.promise = promise; * @type {Object} * @see {@link module:str|str} */ -videojs.str = str; +videojs.str = { toLowerCase, toTitleCase, titleCaseEquals }; /** * An object containing time-related functions. * * @type {Object} */ -videojs.time = { - createTimeRange, - format: formatTime, - setFormat: setFormatTime, - resetFormat: resetFormatTime -}; +videojs.time = { createTimeRanges, formatTime, resetFormatTime, setFormatTime }; /** * A reference to the {@link module:url|URL utility module} as an object. @@ -472,7 +467,7 @@ videojs.time = { * @type {Object} * @see {@link module:url|url} */ -videojs.url = url; +videojs.url = { parseUrl, getAbsoluteURL, getFileExtension, isCrossOrigin }; /** * Namespace for general utility functions. @@ -485,25 +480,23 @@ videojs.utils = { }; // Deprecated global namespace functions -videojs.extend = deprecate('videojs.extend is deprecated as of 8.0. Please use native ES6 classes instead.', extend); -videojs.mergeOptions = deprecate('videojs.mergeOptions is deprecated as of 8.0. Please use videojs.obj.merge instead.', obj.merge); -videojs.bind = deprecate('videojs.bind is deprecated as of 8.0. Please use native Function.prototype.bind instead.', fn.bind); -videojs.createTimeRange = deprecate('videojs.createTimeRange is deprecated as of 8.0. Please use videojs.time.createTimeRange instead.', createTimeRange); -videojs.createTimeRanges = deprecate('videojs.createTimeRanges is deprecated as of 8.0. Please use videojs.time.createTimeRange instead.', createTimeRange); +videojs.createTimeRanges = deprecate('videojs.createTimeRanges is deprecated as of 8.0. Please use videojs.time.createTimeRanges instead.', createTimeRanges); +videojs.createTimeRanges = deprecate('videojs.createTimeRanges is deprecated as of 8.0. Please use videojs.time.createTimeRanges instead.', createTimeRanges); videojs.formatTime = deprecate('videojs.formatTime is deprecated as of 8.0. Please use videojs.time.format instead.', formatTime); videojs.setFormatTime = deprecate('videojs.setFormatTime is deprecated as of 8.0. Please use videojs.time.setFormat instead.', setFormatTime); videojs.resetFormatTime = deprecate('videojs.resetFormatTime is deprecated as of 8.0. Please use videojs.time.resetFormat instead.', resetFormatTime); videojs.computedStyle = deprecate('videojs.computedStyle is deprecated as of 8.0. Please use videojs.utils.computedStyle instead.', computedStyle); videojs.defineLazyProperty = deprecate('videojs.defineLazyProperty is deprecated as of 8.0. Please use videojs.utils.defineLazyProperty instead.', defineLazyProperty); -videojs.isPromise = deprecate('videojs.isPromise is deprecated as of 8.0. Please use videojs.promise.isPromise instead.', promise.isPromise); -videojs.silencePromise = deprecate('videojs.silencePromise is deprecated as of 8.0. Please use videojs.promise.silencePromise instead.', promise.silencePromise); -videojs.parseUrl = deprecate('videojs.parseUrl is deprecated as of 8.0. Please use videojs.url.parseUrl instead.', url.parseUrl); -videojs.isCrossOrigin = deprecate('videojs.isCrossOrigin is deprecated as of 8.0. Please use videojs.url.isCrossOrigin instead.', url.isCrossOrigin); +videojs.isPromise = deprecate('videojs.isPromise is deprecated as of 8.0. Please use videojs.promise.isPromise instead.', isPromise); +videojs.silencePromise = deprecate('videojs.silencePromise is deprecated as of 8.0. Please use videojs.promise.silencePromise instead.', silencePromise); +videojs.parseUrl = deprecate('videojs.parseUrl is deprecated as of 8.0. Please use videojs.url.parseUrl instead.', parseUrl); +videojs.isCrossOrigin = deprecate('videojs.isCrossOrigin is deprecated as of 8.0. Please use videojs.url.isCrossOrigin instead.', isCrossOrigin); -videojs.on = events.on; -videojs.one = events.one; -videojs.off = events.off; -videojs.trigger = events.trigger; +videojs.any = any; +videojs.off = off; +videojs.on = on; +videojs.one = one; +videojs.trigger = trigger; videojs.EventTarget = EventTarget; videojs.TextTrack = TextTrack; diff --git a/test/unit/live-tracker.test.js b/test/unit/live-tracker.test.js index de88e4600..cf7416db8 100644 --- a/test/unit/live-tracker.test.js +++ b/test/unit/live-tracker.test.js @@ -1,6 +1,6 @@ /* eslint-env qunit */ import TestHelpers from './test-helpers.js'; -import {createTimeRanges} from '../../src/js/utils/time-ranges.js'; +import {createTimeRanges} from '../../src/js/utils/time'; import sinon from 'sinon'; QUnit.module('LiveTracker', () => { diff --git a/test/unit/player-breakpoints.test.js b/test/unit/player-breakpoints.test.js index c6531de94..06b311ed7 100644 --- a/test/unit/player-breakpoints.test.js +++ b/test/unit/player-breakpoints.test.js @@ -1,9 +1,8 @@ /* eslint-env qunit */ import sinon from 'sinon'; import TestHelpers from './test-helpers'; -import {assign} from '../../src/js/utils/obj'; -const getExpectedBreakpoints = (o) => assign({}, { +const getExpectedBreakpoints = (o) => Object.assign({}, { tiny: 210, xsmall: 320, small: 425, diff --git a/test/unit/seek-to-live.test.js b/test/unit/seek-to-live.test.js index e4721f55b..3346fb001 100644 --- a/test/unit/seek-to-live.test.js +++ b/test/unit/seek-to-live.test.js @@ -2,7 +2,7 @@ import TestHelpers from './test-helpers.js'; import sinon from 'sinon'; import computedStyle from '../../src/js/utils/computed-style.js'; -import { createTimeRange } from '../../src/js/utils/time-ranges.js'; +import { createTimeRanges } from '../../src/js/utils/time'; QUnit.module('SeekToLive', { beforeEach() { @@ -17,7 +17,7 @@ QUnit.module('SeekToLive', { this.player.paused = () => false; this.player.hasStarted = () => true; this.player.options_.liveui = true; - this.player.seekable = () => createTimeRange(0, 45); + this.player.seekable = () => createTimeRanges(0, 45); this.player.currentTime = () => this.player.liveTracker.liveCurrentTime(); this.player.duration(Infinity); }; @@ -35,7 +35,7 @@ QUnit.test('liveui enabled, can switch between at and behind live edge ', functi assert.ok(this.seekToLive.hasClass('vjs-at-live-edge'), 'has at live edge class'); this.player.currentTime = () => 0; - this.player.seekable = () => createTimeRange(0, 38); + this.player.seekable = () => createTimeRanges(0, 38); this.clock.tick(30); assert.notOk(this.seekToLive.hasClass('vjs-at-live-edge'), 'does not have at live edge class'); @@ -84,7 +84,7 @@ QUnit.test('liveui disabled live window is never shown', function(assert) { // liveui false this.player.options_.liveui = false; - this.player.seekable = () => createTimeRange(0, 19); + this.player.seekable = () => createTimeRanges(0, 19); this.player.duration(Infinity); assert.equal(this.getComputedDisplay(), 'none', 'is hidden'); diff --git a/test/unit/tech/tech-faker.js b/test/unit/tech/tech-faker.js index a9523e2c4..2267f0e23 100644 --- a/test/unit/tech/tech-faker.js +++ b/test/unit/tech/tech-faker.js @@ -1,7 +1,7 @@ // Fake a media playback tech controller so that player tests // can run without HTML5 which PhantomJS does not support. import Tech from '../../../src/js/tech/tech.js'; -import {createTimeRanges} from '../../../src/js/utils/time-ranges.js'; +import {createTimeRanges} from '../../../src/js/utils/time'; /** * @class */ diff --git a/test/unit/tech/tech.test.js b/test/unit/tech/tech.test.js index 07bc9bffe..0b923d2a8 100644 --- a/test/unit/tech/tech.test.js +++ b/test/unit/tech/tech.test.js @@ -2,7 +2,7 @@ import Tech from '../../../src/js/tech/tech.js'; import Html5 from '../../../src/js/tech/html5.js'; import Button from '../../../src/js/button.js'; -import { createTimeRange } from '../../../src/js/utils/time-ranges.js'; +import { createTimeRanges } from '../../../src/js/utils/time'; import extend from '../../../src/js/extend.js'; import MediaError from '../../../src/js/media-error.js'; import AudioTrack from '../../../src/js/tracks/audio-track'; @@ -573,7 +573,7 @@ QUnit.test('delegates deferrables to the source handler', function(assert) { const handler = { seekable() { seekableCount++; - return createTimeRange(0, 0); + return createTimeRanges(0, 0); }, seeking() { seekingCount++; @@ -624,7 +624,7 @@ QUnit.test('delegates only deferred deferrables to the source handler', function const handler = { seekable() { seekableCount++; - return createTimeRange(0, 0); + return createTimeRanges(0, 0); }, duration() { durationCount++; diff --git a/test/unit/utils/format-time.test.js b/test/unit/utils/format-time.test.js deleted file mode 100644 index ec64aa567..000000000 --- a/test/unit/utils/format-time.test.js +++ /dev/null @@ -1,50 +0,0 @@ -/* eslint-env qunit */ -import formatTime, { setFormatTime, resetFormatTime } from '../../../src/js/utils/format-time.js'; - -QUnit.module('format-time standard implementation', { - afterEach: resetFormatTime() -}); - -QUnit.test('should format time as a string', function(assert) { - assert.ok(formatTime(1) === '0:01'); - assert.ok(formatTime(10) === '0:10'); - assert.ok(formatTime(60) === '1:00'); - assert.ok(formatTime(600) === '10:00'); - assert.ok(formatTime(3600) === '1:00:00'); - assert.ok(formatTime(36000) === '10:00:00'); - assert.ok(formatTime(360000) === '100:00:00'); - - // Using guide should provide extra leading zeros - assert.ok(formatTime(1, 1) === '0:01'); - assert.ok(formatTime(1, 10) === '0:01'); - assert.ok(formatTime(1, 60) === '0:01'); - assert.ok(formatTime(1, 600) === '00:01'); - assert.ok(formatTime(1, 3600) === '0:00:01'); - // Don't do extra leading zeros for hours - assert.ok(formatTime(1, 36000) === '0:00:01'); - assert.ok(formatTime(1, 360000) === '0:00:01'); - - // Do not display negative time - assert.ok(formatTime(-1) === '0:00'); - assert.ok(formatTime(-1, 3600) === '0:00:00'); -}); - -QUnit.test('should format invalid times as dashes', function(assert) { - assert.equal(formatTime(Infinity, 90), '-:-'); - assert.equal(formatTime(NaN), '-:-'); - assert.equal(formatTime(10, Infinity), '0:00:10'); - assert.equal(formatTime(90, NaN), '1:30'); -}); - -QUnit.test('setFormatTime', function(assert) { - setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); - assert.equal(formatTime(1, 2), 'custom:1:2', 'it should replace the default formatTime implementation'); -}); - -QUnit.test('resetFormatTime ', function(assert) { - setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); - assert.equal(formatTime(1, 2), 'custom:1:2'); - resetFormatTime(); - assert.equal(formatTime(1), '0:01', 'it should reset formatTime to the default implementation'); -}); - diff --git a/test/unit/utils/obj.test.js b/test/unit/utils/obj.test.js index 0138b1b0f..523b7ed50 100644 --- a/test/unit/utils/obj.test.js +++ b/test/unit/utils/obj.test.js @@ -106,119 +106,6 @@ QUnit.test('isPlain', function(assert) { }); }); -QUnit.module('utils/obj.assign', function() { - const assignTests = ['mocked']; - - // we only run "normal" tests where Object.assign is used when - // Object.assign is supported - if (Object.assign) { - assignTests.push('unmocked'); - } - - assignTests.forEach(function(k) { - QUnit.module(`with ${k} Object.assign`, { - before() { - if (k === 'mocked') { - this.oldObjectAssign = Object.assign; - Object.assign = null; - } - }, - after() { - if (this.oldObjectAssign) { - Object.assign = this.oldObjectAssign; - } - this.oldObjectAssign = null; - } - }); - - QUnit.test('override object', function(assert) { - const foo = {foo: 'yellow'}; - - assert.deepEqual(obj.assign(foo, {foo: 'blue'}), {foo: 'blue'}, 'obj.assign should return overriden result'); - assert.deepEqual(foo, {foo: 'blue'}, 'foo should be modified directly'); - }); - - QUnit.test('new object', function(assert) { - const foo = {foo: 'yellow'}; - - assert.deepEqual(obj.assign({}, foo, {foo: 'blue'}), {foo: 'blue'}, 'obj.assign should return result'); - assert.deepEqual(foo, {foo: 'yellow'}, 'foo should not be modified'); - }); - - QUnit.test('empty override', function(assert) { - const foo = {foo: 'yellow'}; - - assert.deepEqual(obj.assign(foo, {}), {foo: 'yellow'}, 'obj.assign should return result'); - assert.deepEqual(foo, {foo: 'yellow'}, 'foo should not be modified'); - }); - - QUnit.test('multiple override object', function(assert) { - const foo = {foo: 'foo'}; - const bar = {foo: 'bar'}; - const baz = {foo: 'baz'}; - - assert.deepEqual(obj.assign(foo, bar, baz), baz, 'obj.assign should return result'); - assert.deepEqual(foo, baz, 'foo should be overridden'); - }); - - QUnit.test('additive properties', function(assert) { - const foo = {}; - const expected = {one: 1, two: 2, three: 3}; - - assert.deepEqual(obj.assign(foo, {one: 1}, {two: 2}, {three: 3}), expected, 'obj.assign should return result'); - assert.deepEqual(foo, expected, 'foo should be equal to result'); - }); - - QUnit.test('deep override', function(assert) { - const foo = { - foo: { - bar: { - baz: 'buzz' - } - }, - blue: [55, 56], - red: 'nope' - }; - - const baz = { - foo: { - bar: { - baz: 'red' - } - }, - blue: [57] - }; - - const expected = { - foo: { - bar: { - baz: 'red' - } - }, - blue: [57], - red: 'nope' - }; - - assert.deepEqual(obj.assign(foo, baz), expected, 'obj.assign should return result'); - assert.deepEqual(foo, expected, 'foo is overridden'); - }); - - QUnit.test('negative tests', function(assert) { - const expected = {foo: 11}; - - assert.deepEqual(obj.assign({}, expected, undefined), expected, 'assign should undefined'); - assert.deepEqual(obj.assign({}, expected, null), expected, 'assign should ignore null'); - assert.deepEqual(obj.assign({}, expected, []), expected, 'assign should ignore Array'); - assert.deepEqual(obj.assign({}, expected, ''), expected, 'assign should ignore string'); - assert.deepEqual(obj.assign({}, expected, 11), expected, 'assign should ignore number'); - assert.deepEqual(obj.assign({}, expected, new RegExp()), expected, 'assign should ignore RegExp'); - assert.deepEqual(obj.assign({}, expected, new Date()), expected, 'assign should ignore Date'); - assert.deepEqual(obj.assign({}, expected, true), expected, 'assign should ignore boolean'); - assert.deepEqual(obj.assign({}, expected, () => {}), expected, 'assign should ignore function'); - }); - }); -}); - QUnit.test('utils/obj.merge', function(assert) { const ob1 = { a: true, diff --git a/test/unit/utils/time-ranges.test.js b/test/unit/utils/time.test.js similarity index 53% rename from test/unit/utils/time-ranges.test.js rename to test/unit/utils/time.test.js index 3c40e779c..1a605d8fc 100644 --- a/test/unit/utils/time-ranges.test.js +++ b/test/unit/utils/time.test.js @@ -1,17 +1,56 @@ /* eslint-env qunit */ -import { createTimeRanges, createTimeRange } from '../../../src/js/utils/time-ranges.js'; import window from 'global/window'; +import { createTimeRanges, formatTime, resetFormatTime, setFormatTime } from '../../../src/js/utils/time'; -QUnit.module('time-ranges'); - -QUnit.test('should export the deprecated createTimeRange function', function(assert) { - assert.equal( - createTimeRange, - createTimeRanges, - 'createTimeRange is an alias to createTimeRanges' - ); +QUnit.module('time formatting', { + afterEach: resetFormatTime() }); +QUnit.test('should format time as a string', function(assert) { + assert.ok(formatTime(1) === '0:01'); + assert.ok(formatTime(10) === '0:10'); + assert.ok(formatTime(60) === '1:00'); + assert.ok(formatTime(600) === '10:00'); + assert.ok(formatTime(3600) === '1:00:00'); + assert.ok(formatTime(36000) === '10:00:00'); + assert.ok(formatTime(360000) === '100:00:00'); + + // Using guide should provide extra leading zeros + assert.ok(formatTime(1, 1) === '0:01'); + assert.ok(formatTime(1, 10) === '0:01'); + assert.ok(formatTime(1, 60) === '0:01'); + assert.ok(formatTime(1, 600) === '00:01'); + assert.ok(formatTime(1, 3600) === '0:00:01'); + // Don't do extra leading zeros for hours + assert.ok(formatTime(1, 36000) === '0:00:01'); + assert.ok(formatTime(1, 360000) === '0:00:01'); + + // Do not display negative time + assert.ok(formatTime(-1) === '0:00'); + assert.ok(formatTime(-1, 3600) === '0:00:00'); +}); + +QUnit.test('should format invalid times as dashes', function(assert) { + assert.equal(formatTime(Infinity, 90), '-:-'); + assert.equal(formatTime(NaN), '-:-'); + assert.equal(formatTime(10, Infinity), '0:00:10'); + assert.equal(formatTime(90, NaN), '1:30'); +}); + +QUnit.test('setFormatTime', function(assert) { + setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); + assert.equal(formatTime(1, 2), 'custom:1:2', 'it should replace the default formatTime implementation'); +}); + +QUnit.test('resetFormatTime ', function(assert) { + setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); + assert.equal(formatTime(1, 2), 'custom:1:2'); + resetFormatTime(); + assert.equal(formatTime(1), '0:01', 'it should reset formatTime to the default implementation'); +}); + +QUnit.module('time ranges'); + QUnit.test('should create a fake single timerange', function(assert) { const tr = createTimeRanges(0, 10); @@ -95,3 +134,4 @@ QUnit[testOrSkip]('Array.from works on our time ranges object', function(assert) tr = createTimeRanges(0, 10); assert.deepEqual(Array.from(tr), [[0, 10]], 'we got back a ranges representation'); }); +