diff --git a/build/jsdoc-typeof-plugin.js b/build/jsdoc-typeof-plugin.js index 70564825a1..5788275cf7 100644 --- a/build/jsdoc-typeof-plugin.js +++ b/build/jsdoc-typeof-plugin.js @@ -1,8 +1,19 @@ /** - * The jsdoc plugin that will convert types like {typeof ClassName} into {Class} + * The jsdoc plugin to transform some typescript jsdoc to actual jsdoc, so doc generation works. */ exports.handlers = { jsdocCommentFound: event => { + // @template {ClassName} T ; {T} -> {typeof ClassName} + const templateMatch = /@template {(typeof )?(.*)} ([A-Z])\n/.exec(event.comment || ''); + + if (templateMatch) { + const className = templateMatch[2]; + const templateName = templateMatch[3]; + + event.comment = event.comment.replace(new RegExp(`{(.*\\b)(${templateName})(\\b.*)}`, 'g'), `{$1typeof ${className}$3}`); + } + + // {typeof ClassName} -> {Class} event.comment = (event.comment || '').replace(/\{.*typeof\s+([^\s\|]+).*\}/g, typeExpression => { return typeExpression.replace(/typeof\s+([^\s\|\}]+)/g, (expression, className) => { return 'Class<' + className + '>'; diff --git a/package-lock.json b/package-lock.json index 9131c97a30..4466a8547b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1701,9 +1701,9 @@ "dev": true }, "@types/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "requires": { "@types/linkify-it": "^5", @@ -8108,9 +8108,9 @@ "dev": true }, "jsdoc": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", - "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", "dev": true, "requires": { "@babel/parser": "^7.20.15", @@ -14077,9 +14077,9 @@ } }, "typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true }, "ua-parser-js": { diff --git a/package.json b/package.json index 115c4b50af..d0a2c83278 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "humanize-duration": "^3.26.0", "husky": "^1.3.1", "is-ci": "^3.0.0", - "jsdoc": "^4.0.3", + "jsdoc": "^4.0.4", "karma": "^6.4.3", "lint-staged": "^10.5.4", "markdown-table": "^1.1.3", @@ -160,7 +160,7 @@ "shelljs": "^0.8.5", "shx": "^0.3.2", "sinon": "^11.1.1", - "typescript": "^5.5.2", + "typescript": "^5.7.2", "uglify-js": "^3.19.0", "unified": "^7.0.2", "videojs-generate-karma-config": "^8.1.0", diff --git a/src/js/component.js b/src/js/component.js index 8ba1079db6..2077fc1818 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -23,6 +23,18 @@ import {merge} from './utils/obj.js'; * @returns {void} */ +/** + * @typedef {Object} ComponentOptions + * @property {Object[]} [children] + * @property {string} [classname] + * @property {boolean} [initChildren] + * @property {boolean} [reportTouchActivity] + * @property {string} [name] + * @property {boolean} [createEl=true] + * @property {HTMLElement} [el] + * @property {boolean} [evented] + */ + /** * Base class for all UI Components. * Components are UI objects which represent both a javascript object and an element @@ -39,17 +51,9 @@ class Component { * @param {Player} player * The `Player` that this class should be attached to. * - * @param {Object} [options] + * @param {ComponentOptions} [options] * The key/value store of component options. * - * @param {Object[]} [options.children] - * An array of children objects to initialize this component with. Children objects have - * a name property that will be used if more than one component of the same type needs to be - * added. - * - * @param {string} [options.className] - * A class or space separated list of classes to add the component - * * @param {ReadyCallback} [ready] * Function that gets called when the `Component` is ready. */ @@ -589,14 +593,14 @@ class Component { return iconContainer; } - /** * Add a child `Component` inside the current `Component`. * - * @param {string|Component} child + * @template {Component} T + * @param {string|T} child * The name or instance of a child to add. * - * @param {Object} [options={}] + * @param {ComponentOptions} [options={}] * The key/value store of options that will get passed to children of * the child. * @@ -604,7 +608,7 @@ class Component { * The index to attempt to add a child into. * * - * @return {Component} + * @return {T} * The `Component` that gets added as a child. When using a string the * `Component` will get created by this process. */ @@ -1242,7 +1246,7 @@ class Component { * An object that contains width and height values of the `Component`s * computed style. Uses `window.getComputedStyle`. * - * @typedef {Object} Component~DimensionObject + * @typedef {Object} DimensionObject * * @property {number} width * The width of the `Component`s computed style. @@ -1257,7 +1261,7 @@ class Component { * * Uses `window.getComputedStyle`. * - * @return {Component~DimensionObject} + * @return {DimensionObject} * The computed dimensions of the component's element. */ currentDimensions() { @@ -1967,6 +1971,8 @@ class Component { } /** + * @template {typeof Component} T + * * Register a `Component` with `videojs` given the name and the component. * * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s @@ -1979,10 +1985,10 @@ class Component { * @param {string} name * The name of the `Component` to register. * - * @param {Component} ComponentToRegister + * @param {T} ComponentToRegister * The `Component` class to register. * - * @return {Component} + * @return {T} * The `Component` that was registered. */ static registerComponent(name, ComponentToRegister) { diff --git a/src/js/fullscreen-api.js b/src/js/fullscreen-api.js index 86ad091758..7ae4ee3f60 100644 --- a/src/js/fullscreen-api.js +++ b/src/js/fullscreen-api.js @@ -8,6 +8,14 @@ import document from 'global/document'; * Store the browser-specific methods for the fullscreen API. * * @type {Object} + * @property {string} requestFullscreen + * @property {string} exitFullscreen + * @property {string} fullscreenElement + * @property {string} fullscreenEnabled + * @property {string} fullscreenchange + * @property {string} fullscreenerror + * @property {string} fullscreen + * @property {boolean} prefixed * @see [Specification]{@link https://fullscreen.spec.whatwg.org} * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js} */ diff --git a/src/js/player.js b/src/js/player.js index 6b2f424a74..5f856eeb9d 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -62,6 +62,7 @@ import './tech/html5.js'; /** @import TextTrackList from './tracks/text-track-list' */ /** @import { TimeRange } from './utils/time' */ /** @import VideoTrackList from './tracks/video-track-list' */ +/** @import { SourceObject } from './tech/tech' */ /** * @callback PlayerReadyCallback @@ -69,6 +70,145 @@ import './tech/html5.js'; * @returns {void} */ +/** + * @typedef {Object} PlayerOptions Player setup options + * @property {boolean|'play'|'muted'|'any'} [autoplay] + * Autoplay behaviour. Don't use the `autoplay` attribute if set. + * - `false` or `'none'`: No autoplay + * - `true`: Browser's autoplay + * - `'muted'`: Mute, then play on `loadstart` + * - `'any'`: Attempt to play on `loadstart`. If rejected, mute and then play + * @property {Object} [controlBar] + * Options for the controlbar component + * @property {boolean} [controlBar.remainingTimeDisplay.displayNegative] + * If false, show remaining time without a negative sign + * @property {boolean} [controls] + * Whether to show controls + * @property {number|string} [height] + * Player height in pixels + * @property {boolean} [loop] + * Whether to loop + * @property {boolean} [muted] + * Whether to mute + * @property {string} [poster] + * Poster image URL + * @property {'auto'|'metadata'|'none'} [preload] + * Whether to preload + * @property {string|Object|Array} [src] + * Source or source object or array of source objects + * @property {number|string} [width] + * Player height in pixels + * @property {string} [aspectRatio] + * e.g. '16:9'. Sets aspect ratio of player using fluid mode + * @property {boolean} [audioOnlyMode] + * If true show only control bar and appropriate controls + * @property {boolean} [audioPosterMode] + * Show poster throughtout audio playback + * @property {Object} [breakpoints] + * Breakpoints for responsive layout mode + * @property {number} [breakpoints.tiny=300] + * @property {number} [breakpoints.xsmall=400] + * @property {number} [breakpoints.small=500] + * @property {number} [breakpoints.medium=600] + * @property {number} [breakpoints.large=700] + * @property {number} [breakpoints.xlarge=800] + * @property {number} [breakpoints.huge=900] + * @property {Array|Object} [children] + * @property {boolean} [disablePictureInPicture] + * Prevents picture-in-picture mode + * @property {boolean} [enableDocumentPictureInPicture] + * Enable picture-in-picture using the document picture-in-picture API if available + * @property {boolean} [enableSmoothSeeking] + * Smoother seeking experience (recommended) + * @property {boolean} [experimentalSvgIcons] + * Use SVG icons istead of the default font icons + * @property {boolean} [fluid] + * Resize the player to the video's intrinsic ratio once known (metadata has loaded), fitting the contianers width. + * @property {Object} [fullscreen] + * @property {'auto'|'hide'|'show'} [fullscreen.options.navigationUI] + * Navigation UI preference to pass to browser fullscreen API + * @property {string} [id] + * If the player element doesn't already have an id, set this id. + * @property {number} [inactivityTimeout] + * Milliseconds before considered inactive, e.g. controls hide + * @property {string} [language] + * Language to use for localisation. If unset, detect from HTML or navigator.language + * @property {Object.} [languages] + * Object of translations to add to the player + * @property {boolean} [liveui] + * Inlcude live UI with seekbar for DVR + * @property {number} [liveTracker.trackingThreshold] + * An option for the liveTracker component of the player that controls when the liveui should be shown. By default if a stream has less than 20s on the seekBar then we do not show the new liveui even with the liveui option set. + * @property {number} [liveTracker.liveTolerance] + * How far from the seekable end should be considered live playback. Default 15s. + * @property {boolean} [nativeControlsForTouch] + * Explicitly set a default value for tech option + * @property {boolean} [normalizeAutoplay] + * Specify whether setting `autoplay: true` or `