summaryrefslogtreecommitdiff
path: root/javascript/videojs/src/js/utils/time.js
diff options
context:
space:
mode:
Diffstat (limited to 'javascript/videojs/src/js/utils/time.js')
-rw-r--r--javascript/videojs/src/js/utils/time.js237
1 files changed, 237 insertions, 0 deletions
diff --git a/javascript/videojs/src/js/utils/time.js b/javascript/videojs/src/js/utils/time.js
new file mode 100644
index 0000000..408bea0
--- /dev/null
+++ b/javascript/videojs/src/js/utils/time.js
@@ -0,0 +1,237 @@
+/**
+ * @file time.js
+ * @module time
+ */
+import window from 'global/window';
+
+/**
+ * Returns the time for the specified index at the start or end
+ * of a TimeRange object.
+ *
+ * @typedef {Function} TimeRangeIndex
+ *
+ * @param {number} [index=0]
+ * The range number to return the time for.
+ *
+ * @return {number}
+ * The time offset at the specified index.
+ *
+ * @deprecated The index argument must be provided.
+ * In the future, leaving it out will throw an error.
+ */
+
+/**
+ * An object that contains ranges of time, which mimics {@link TimeRanges}.
+ *
+ * @typedef {Object} TimeRange
+ *
+ * @property {number} length
+ * The number of time ranges represented by this object.
+ *
+ * @property {module:time~TimeRangeIndex} start
+ * Returns the time offset at which a specified time range begins.
+ *
+ * @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
+ */
+
+/**
+ * Check if any of the time ranges are over the maximum index.
+ *
+ * @private
+ * @param {string} fnName
+ * The function name to use for logging
+ *
+ * @param {number} index
+ * The index to check
+ *
+ * @param {number} maxIndex
+ * The maximum possible index
+ *
+ * @throws {Error} if the timeRanges provided are over the maxIndex
+ */
+function rangeCheck(fnName, index, maxIndex) {
+ if (typeof index !== 'number' || index < 0 || index > maxIndex) {
+ throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is non-numeric or out of bounds (0-${maxIndex}).`);
+ }
+}
+
+/**
+ * Get the time for the specified index at the start or end
+ * of a TimeRange object.
+ *
+ * @private
+ * @param {string} fnName
+ * The function name to use for logging
+ *
+ * @param {string} valueIndex
+ * The property that should be used to get the time. should be
+ * 'start' or 'end'
+ *
+ * @param {Array} ranges
+ * An array of time ranges
+ *
+ * @param {Array} [rangeIndex=0]
+ * The index to start the search at
+ *
+ * @return {number}
+ * The time that offset at the specified index.
+ *
+ * @deprecated rangeIndex must be set to a value, in the future this will throw an error.
+ * @throws {Error} if rangeIndex is more than the length of ranges
+ */
+function getRange(fnName, valueIndex, ranges, rangeIndex) {
+ rangeCheck(fnName, rangeIndex, ranges.length - 1);
+ return ranges[rangeIndex][valueIndex];
+}
+
+/**
+ * Create a time range object given ranges of time.
+ *
+ * @private
+ * @param {Array} [ranges]
+ * An array of time ranges.
+ *
+ * @return {TimeRange}
+ */
+function createTimeRangesObj(ranges) {
+ let timeRangesObj;
+
+ if (ranges === undefined || ranges.length === 0) {
+ timeRangesObj = {
+ length: 0,
+ start() {
+ throw new Error('This TimeRanges object is empty');
+ },
+ end() {
+ throw new Error('This TimeRanges object is empty');
+ }
+ };
+ } else {
+ timeRangesObj = {
+ length: ranges.length,
+ start: getRange.bind(null, 'start', 0, ranges),
+ end: getRange.bind(null, 'end', 1, ranges)
+ };
+ }
+
+ if (window.Symbol && window.Symbol.iterator) {
+ timeRangesObj[window.Symbol.iterator] = () => (ranges || []).values();
+ }
+
+ return timeRangesObj;
+}
+
+/**
+ * Create a `TimeRange` object which mimics an
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}.
+ *
+ * @param {number|Array[]} start
+ * The start of a single range (a number) or an array of ranges (an
+ * array of arrays of two numbers each).
+ *
+ * @param {number} end
+ * The end of a single range. Cannot be used with the array form of
+ * the `start` argument.
+ *
+ * @return {TimeRange}
+ */
+export function createTimeRanges(start, end) {
+ if (Array.isArray(start)) {
+ return createTimeRangesObj(start);
+ } else if (start === undefined || end === undefined) {
+ return createTimeRangesObj();
+ }
+ return createTimeRangesObj([[start, end]]);
+}
+
+export { createTimeRanges as createTimeRange };
+
+/**
+ * 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.
+ *
+ * @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);
+}