1
0
mirror of https://github.com/videojs/video.js.git synced 2024-12-21 01:39:04 +02:00

feat: rework how utility functions are exposed, organizing them into sub-objects

This commit is contained in:
Pat O'Neill 2022-05-13 12:44:59 -04:00
parent e767053049
commit a5fd093a42
19 changed files with 255 additions and 211 deletions

View File

@ -33,7 +33,7 @@
};
// register the plugin
videojs.plugin('progressed', progressed);
videojs.registerPlugin('progressed', progressed);
// initialize it
vid1 = videojs('vid1');

View File

@ -9,7 +9,7 @@ import stateful from './mixins/stateful';
import * as Dom from './utils/dom.js';
import * as Fn from './utils/fn.js';
import * as Guid from './utils/guid.js';
import {toTitleCase, toLowerCase} from './utils/string-cases.js';
import {toTitleCase, toLowerCase} from './utils/str.js';
import mergeOptions from './utils/merge-options.js';
import computedStyle from './utils/computed-style';
import Map from './utils/map.js';

View File

@ -4,7 +4,7 @@
import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
import ChaptersTrackMenuItem from './chapters-track-menu-item.js';
import {toTitleCase} from '../../utils/string-cases.js';
import {toTitleCase} from '../../utils/str.js';
/**
* The button component for toggling and selecting chapters

View File

@ -5,7 +5,7 @@ import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
import SubsCapsMenuItem from './subs-caps-menu-item.js';
import {toTitleCase} from '../../utils/string-cases.js';
import {toTitleCase} from '../../utils/str.js';
/**
* The button component for toggling and selecting captions and/or subtitles
*

View File

@ -31,8 +31,6 @@ class ErrorDisplay extends ModalDialog {
*
* @return {string}
* The DOM `className` for this object.
*
* @deprecated Since version 5.
*/
buildCSSClass() {
return `vjs-error-display ${super.buildCSSClass()}`;

View File

@ -4,7 +4,6 @@
*/
import _inherits from '@babel/runtime/helpers/inherits';
import log from './utils/log';
/**
* Used to subclass an existing class by emulating ES subclassing using the
@ -30,8 +29,6 @@ import log from './utils/log';
* @deprecated videojs.extend() is deprecated as of v8; use native ES6 classes instead
*/
const extend = function(superClass, subClassMethods = {}) {
log.warn('The extend() method is deprecated. Please use native ES6 classes instead.');
const isNativeClass = superClass && /^class/.test(superClass.toString());
let subClass = function() {

View File

@ -6,7 +6,7 @@ import Component from '../component.js';
import Menu from './menu.js';
import * as Dom from '../utils/dom.js';
import * as Events from '../utils/events.js';
import {toTitleCase} from '../utils/string-cases.js';
import {toTitleCase} from '../utils/str.js';
import { IS_IOS } from '../utils/browser.js';
import document from 'global/document';
import keycode from 'keycode';

View File

@ -16,7 +16,7 @@ import * as Guid from './utils/guid.js';
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/string-cases.js';
import {toTitleCase, titleCaseEquals} from './utils/str.js';
import { createTimeRange } from './utils/time-ranges.js';
import { bufferedPercent } from './utils/buffer.js';
import * as stylesheet from './utils/stylesheet.js';

View File

@ -10,7 +10,7 @@ import document from 'global/document';
import window from 'global/window';
import {assign} from '../utils/obj';
import mergeOptions from '../utils/merge-options.js';
import {toTitleCase} from '../utils/string-cases.js';
import {toTitleCase} from '../utils/str.js';
import {NORMAL as TRACK_TYPES, REMOTE} from '../tracks/track-types';
import setupSourceset from './setup-sourceset';
import defineLazyProperty from '../utils/define-lazy-property.js';

View File

@ -3,7 +3,7 @@
*/
import Component from '../component.js';
import Tech from './tech.js';
import {toTitleCase} from '../utils/string-cases.js';
import {toTitleCase} from '../utils/str.js';
import mergeOptions from '../utils/merge-options.js';
/**

View File

@ -3,7 +3,7 @@
* @module middleware
*/
import { assign } from '../utils/obj.js';
import {toTitleCase} from '../utils/string-cases.js';
import {toTitleCase} from '../utils/str.js';
const middlewares = {};
const middlewareInstances = {};

View File

@ -13,7 +13,7 @@ import window from 'global/window';
import document from 'global/document';
import {isPlain} from '../utils/obj';
import * as TRACK_TYPES from '../tracks/track-types';
import {toTitleCase, toLowerCase} from '../utils/string-cases.js';
import {toTitleCase, toLowerCase} from '../utils/str.js';
import vtt from 'videojs-vtt.js';
import * as Guid from '../utils/guid.js';

34
src/js/utils/deprecate.js Normal file
View File

@ -0,0 +1,34 @@
/**
* @file deprecate.js
* @module deprecate
*/
import log from './log.js';
/**
* Decorate a function with a deprecation message the first time it is called.
*
* @param {string} message
* A deprecation message to log the first time the returned function
* is called.
*
* @param {Function} fn
* The function to be deprecated.
*
* @return {Function}
* A wrapper function that will log a deprecation warning the first
* time it is called. The return value will be the return value of
* the wrapped function.
*/
export default function deprecate(message, fn) {
let warned = false;
return function(...args) {
if (!warned) {
log.warn(message);
}
warned = true;
return fn.apply(this, args);
};
}

View File

@ -2,48 +2,6 @@
* @file merge-options.js
* @module merge-options
*/
import {each, isPlain} from './obj';
import {merge} from './obj';
/**
* Merge two objects recursively.
*
* Performs a deep merge like
* {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges
* plain objects (not arrays, elements, or anything else).
*
* Non-plain object values will be copied directly from the right-most
* argument.
*
* @static
* @param {Object[]} sources
* One or more objects to merge into a new object.
*
* @return {Object}
* A new object that is the merged result of all sources.
*/
function mergeOptions(...sources) {
const result = {};
sources.forEach(source => {
if (!source) {
return;
}
each(source, (value, key) => {
if (!isPlain(value)) {
result[key] = value;
return;
}
if (!isPlain(result[key])) {
result[key] = {};
}
result[key] = mergeOptions(result[key], value);
});
});
return result;
}
export default mergeOptions;
export default merge;

View File

@ -131,3 +131,45 @@ export function isPlain(value) {
toString.call(value) === '[object Object]' &&
value.constructor === Object;
}
/**
* Merge two objects recursively.
*
* Performs a deep merge like
* {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges
* plain objects (not arrays, elements, or anything else).
*
* Non-plain object values will be copied directly from the right-most
* argument.
*
* @static
* @param {Object[]} sources
* One or more objects to merge into a new object.
*
* @return {Object}
* A new object that is the merged result of all sources.
*/
export function merge(...sources) {
const result = {};
sources.forEach(source => {
if (!source) {
return;
}
each(source, (value, key) => {
if (!isPlain(value)) {
result[key] = value;
return;
}
if (!isPlain(result[key])) {
result[key] = {};
}
result[key] = merge(result[key], value);
});
});
return result;
}

View File

@ -1,6 +1,6 @@
/**
* @file string-cases.js
* @module to-lower-case
* @file str.js
* @module str
*/
/**

View File

@ -4,6 +4,31 @@
*/
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';
import EventTarget from './event-target';
import Player from './player';
import Plugin from './plugin';
import TextTrack from './tracks/text-track';
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';
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 {
hooks_,
hooks,
@ -11,36 +36,18 @@ import {
hookOnce,
removeHook
} from './utils/hooks';
import * as setup from './setup';
import * as stylesheet from './utils/stylesheet.js';
import Component from './component';
import EventTarget from './event-target';
import * as Events from './utils/events.js';
import Player from './player';
import Plugin from './plugin';
import mergeOptions from './utils/merge-options.js';
import * as Fn from './utils/fn.js';
import TextTrack from './tracks/text-track.js';
import AudioTrack from './tracks/audio-track.js';
import VideoTrack from './tracks/video-track.js';
import { createTimeRanges } from './utils/time-ranges.js';
import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js';
import log, { createLogger } from './utils/log.js';
import * as Dom from './utils/dom.js';
import * as browser from './utils/browser.js';
import * as Url from './utils/url.js';
import * as Obj from './utils/obj';
import clamp from './utils/clamp';
import { isPromise, silencePromise } from './utils/promise';
import * as StringCases from './utils/string-cases';
import computedStyle from './utils/computed-style.js';
import extend from './extend.js';
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 xhr from '@videojs/xhr';
// Include the built-in techs
import Tech from './tech/tech.js';
import { use as middlewareUse, TERMINATOR } from './tech/middleware.js';
import defineLazyProperty from './utils/define-lazy-property.js';
import Tech from './tech/tech';
import { use as middlewareUse, TERMINATOR } from './tech/middleware';
import defineLazyProperty from './utils/define-lazy-property';
/**
* Normalize an `id` value by trimming off a leading `#`
@ -146,9 +153,9 @@ function videojs(id, options, ready) {
return player;
}
const el = (typeof id === 'string') ? Dom.$('#' + normalizeId(id)) : id;
const el = (typeof id === 'string') ? dom.$('#' + normalizeId(id)) : id;
if (!Dom.isEl(el)) {
if (!dom.isEl(el)) {
throw new TypeError('The element or ID supplied is not valid. (videojs)');
}
@ -165,14 +172,14 @@ function videojs(id, options, ready) {
options = options || {};
hooks('beforesetup').forEach((hookFunction) => {
const opts = hookFunction(el, mergeOptions(options));
const opts = hookFunction(el, obj.merge(options));
if (!Obj.isObject(opts) || Array.isArray(opts)) {
if (!obj.isObject(opts) || Array.isArray(opts)) {
log.error('please return an object in beforesetup hooks');
return;
}
options = mergeOptions(options, opts);
options = obj.merge(options, opts);
});
// We get the current "Player" component here in case an integration has
@ -193,12 +200,12 @@ videojs.hookOnce = hookOnce;
videojs.removeHook = removeHook;
// Add default styles
if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true && Dom.isReal()) {
let style = Dom.$('.vjs-styles-defaults');
if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true && dom.isReal()) {
let style = dom.$('.vjs-styles-defaults');
if (!style) {
style = stylesheet.createStyleElement('vjs-styles-defaults');
const head = Dom.$('head');
const head = dom.$('head');
if (head) {
head.insertBefore(style, head.firstChild);
@ -270,12 +277,12 @@ videojs.getPlayer = (id) => {
return player;
}
tag = Dom.$('#' + nId);
tag = dom.$('#' + nId);
} else {
tag = id;
}
if (Dom.isEl(tag)) {
if (dom.isEl(tag)) {
const {player, playerId} = tag;
// Element may have a `player` property referring to an already created
@ -352,49 +359,6 @@ Object.defineProperty(videojs.middleware, 'TERMINATOR', {
enumerable: true
});
/**
* A reference to the {@link module:browser|browser utility module} as an object.
*
* @type {Object}
* @see {@link module:browser|browser}
*/
videojs.browser = browser;
/**
* Use {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED} instead; only
* included for backward-compatibility with 4.x.
*
* @deprecated Since version 5.0, use {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED instead.
* @type {boolean}
*/
videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED;
videojs.extend = extend;
videojs.mergeOptions = mergeOptions;
videojs.bind = Fn.bind;
videojs.registerPlugin = Plugin.registerPlugin;
videojs.deregisterPlugin = Plugin.deregisterPlugin;
/**
* Deprecated method to register a plugin with Video.js
*
* @deprecated videojs.plugin() is deprecated; use videojs.registerPlugin() instead
*
* @param {string} name
* The plugin name
*
* @param {Plugin|Function} plugin
* The plugin sub-class or function
*/
videojs.plugin = (name, plugin) => {
log.warn('videojs.plugin() is deprecated; use videojs.registerPlugin() instead');
return Plugin.registerPlugin(name, plugin);
};
videojs.getPlugins = Plugin.getPlugins;
videojs.getPlugin = Plugin.getPlugin;
videojs.getPluginVersion = Plugin.getPluginVersion;
/**
* Adding languages so that they're available to all players.
* Example: `videojs.addLanguage('es', { 'Hello': 'Hola' });`
@ -411,7 +375,7 @@ videojs.getPluginVersion = Plugin.getPluginVersion;
videojs.addLanguage = function(code, data) {
code = ('' + code).toLowerCase();
videojs.options.languages = mergeOptions(
videojs.options.languages = obj.merge(
videojs.options.languages,
{[code]: data}
);
@ -428,17 +392,124 @@ videojs.addLanguage = function(code, data) {
videojs.log = log;
videojs.createLogger = createLogger;
videojs.createTimeRange = videojs.createTimeRanges = createTimeRanges;
videojs.formatTime = formatTime;
videojs.setFormatTime = setFormatTime;
videojs.resetFormatTime = resetFormatTime;
videojs.parseUrl = Url.parseUrl;
videojs.isCrossOrigin = Url.isCrossOrigin;
videojs.registerPlugin = Plugin.registerPlugin;
videojs.deregisterPlugin = Plugin.deregisterPlugin;
videojs.getPlugins = Plugin.getPlugins;
videojs.getPlugin = Plugin.getPlugin;
videojs.getPluginVersion = Plugin.getPluginVersion;
/**
* A reference to the {@link module:browser|browser utility module} as an object.
*
* @type {Object}
* @see {@link module:browser|browser}
*/
videojs.browser = browser;
/**
* A reference to the {@link module:dom|DOM utility module} as an object.
*
* @type {Object}
* @see {@link module:dom|dom}
*/
videojs.dom = dom;
/**
* A reference to the {@link module:fn|function utility module} as an object.
*
* @type {Object}
* @see {@link module:fn|fn}
*/
videojs.fn = fn;
/**
* An object containing number-related functions.
*
* @type {Object}
*/
videojs.num = {
clamp
};
/**
* A reference to the {@link module:obj|object utility module} as an object.
*
* @type {Object}
* @see {@link module:obj|obj}
*/
videojs.obj = obj;
/**
* A reference to the {@link module:promise|promise utility module} as an object.
*
* @type {Object}
* @see {@link module:promise|promise}
*/
videojs.promise = promise;
/**
* A reference to the {@link module:str|string utility module} as an object.
*
* @type {Object}
* @see {@link module:str|str}
*/
videojs.str = str;
/**
* An object containing time-related functions.
*
* @type {Object}
*/
videojs.time = {
createTimeRange,
format: formatTime,
setFormat: setFormatTime,
resetFormat: resetFormatTime
};
/**
* A reference to the {@link module:url|URL utility module} as an object.
*
* @type {Object}
* @see {@link module:url|url}
*/
videojs.url = url;
/**
* Namespace for general utility functions.
*
* @type {Object}
*/
videojs.utils = {
computedStyle,
defineLazyProperty
};
// 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.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.on = events.on;
videojs.one = events.one;
videojs.off = events.off;
videojs.trigger = events.trigger;
videojs.EventTarget = EventTarget;
videojs.on = Events.on;
videojs.one = Events.one;
videojs.off = Events.off;
videojs.trigger = Events.trigger;
videojs.TextTrack = TextTrack;
videojs.AudioTrack = AudioTrack;
videojs.VideoTrack = VideoTrack;
/**
* A cross-browser XMLHttpRequest wrapper.
@ -454,60 +525,5 @@ videojs.trigger = Events.trigger;
*/
videojs.xhr = xhr;
videojs.TextTrack = TextTrack;
videojs.AudioTrack = AudioTrack;
videojs.VideoTrack = VideoTrack;
[
'isEl',
'isTextNode',
'createEl',
'hasClass',
'addClass',
'removeClass',
'toggleClass',
'setAttributes',
'getAttributes',
'emptyEl',
'appendContent',
'insertContent'
].forEach(k => {
videojs[k] = function() {
log.warn(`videojs.${k}() is deprecated; use videojs.dom.${k}() instead`);
return Dom[k].apply(null, arguments);
};
});
videojs.computedStyle = computedStyle;
/**
* A reference to the {@link module:dom|DOM utility module} as an object.
*
* @type {Object}
* @see {@link module:dom|dom}
*/
videojs.dom = Dom;
/**
* A reference to the {@link module:url|URL utility module} as an object.
*
* @type {Object}
* @see {@link module:url|url}
*/
videojs.url = Url;
videojs.defineLazyProperty = defineLazyProperty;
// Adding less ambiguous text for fullscreen button.
// In a major update this could become the default text and key.
videojs.addLanguage('en', {'Non-Fullscreen': 'Exit Fullscreen'});
videojs.clamp = clamp;
videojs.fn = Fn;
videojs.obj = Obj;
videojs.isPromise = isPromise;
videojs.silencePromise = silencePromise;
videojs.strings = StringCases;
export default videojs;

View File

@ -1,7 +1,7 @@
/* eslint-env qunit */
import {toLowerCase, toTitleCase, titleCaseEquals} from '../../../src/js/utils/string-cases.js';
import {toLowerCase, toTitleCase, titleCaseEquals} from '../../../src/js/utils/str.js';
QUnit.module('string-cases');
QUnit.module('str');
QUnit.test('toTitleCase should make a string start with an uppercase letter', function(assert) {
const foo = toTitleCase('bar');

View File

@ -212,7 +212,6 @@ QUnit.test('should add the value to the languages object with lower case lang co
QUnit.test('should expose plugin functions', function(assert) {
[
'registerPlugin',
'plugin',
'getPlugins',
'getPlugin',
'getPluginVersion'
@ -243,7 +242,7 @@ QUnit.test('should expose DOM functions', function(assert) {
];
methods.forEach(name => {
assert.strictEqual(typeof videojs[name], 'function', `function videojs.${name}`);
assert.strictEqual(typeof videojs.dom[name], 'function', `function videojs.${name}`);
assert.strictEqual(typeof Dom[name], 'function', `Dom.${name} function exists`);
});
});