var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
var __privateMethod = (obj, member, method) => {
__accessCheck(obj, member, "access private method");
return method;
};
var _rootNode, _animation, _boxes, _previewTime, _previewBox, _currentBox, _boxPaddingLeft, _boxPaddingRight, _mediaChaptersCues, _toggleRangeAnimation, toggleRangeAnimation_fn, _shouldRangeAnimate, shouldRangeAnimate_fn, _updateRange, _getElementRects, getElementRects_fn, _getBoxPosition, getBoxPosition_fn, _getBoxShiftPosition, getBoxShiftPosition_fn, _handlePointerMove, handlePointerMove_fn, _previewRequest, previewRequest_fn, _seekRequest, seekRequest_fn;
import { globalThis, document } from "./utils/server-safe-globals.js";
import { MediaChromeRange } from "./media-chrome-range.js";
import "./media-preview-thumbnail.js";
import "./media-preview-time-display.js";
import "./media-preview-chapter-display.js";
import { MediaUIEvents, MediaUIAttributes } from "./constants.js";
import { nouns } from "./labels/labels.js";
import { isValidNumber } from "./utils/utils.js";
import { formatAsTimePhrase } from "./utils/time.js";
import { isElementVisible } from "./utils/element-utils.js";
import { RangeAnimation } from "./utils/range-animation.js";
import {
getOrInsertCSSRule,
containsComposedNode,
closestComposedNode,
getBooleanAttr,
setBooleanAttr,
getNumericAttr,
setNumericAttr,
getStringAttr,
setStringAttr
} from "./utils/element-utils.js";
const DEFAULT_MISSING_TIME_PHRASE = "video not loaded, unknown time.";
const updateAriaValueText = (el) => {
const range = el.range;
const currentTimePhrase = formatAsTimePhrase(+calcTimeFromRangeValue(el));
const totalTimePhrase = formatAsTimePhrase(+el.mediaSeekableEnd);
const fullPhrase = !(currentTimePhrase && totalTimePhrase) ? DEFAULT_MISSING_TIME_PHRASE : `${currentTimePhrase} of ${totalTimePhrase}`;
range.setAttribute("aria-valuetext", fullPhrase);
};
const template = document.createElement("template");
template.innerHTML = /*html*/
`
${/* Example: add the current time w/ arrow to the playhead
*/
""}
`;
const calcRangeValueFromTime = (el, time = el.mediaCurrentTime) => {
const startTime = Number.isFinite(el.mediaSeekableStart) ? el.mediaSeekableStart : 0;
const endTime = Number.isFinite(el.mediaDuration) ? el.mediaDuration : el.mediaSeekableEnd;
if (Number.isNaN(endTime))
return 0;
const value = (time - startTime) / (endTime - startTime);
return Math.max(0, Math.min(value, 1));
};
const calcTimeFromRangeValue = (el, value = el.range.valueAsNumber) => {
const startTime = Number.isFinite(el.mediaSeekableStart) ? el.mediaSeekableStart : 0;
const endTime = Number.isFinite(el.mediaDuration) ? el.mediaDuration : el.mediaSeekableEnd;
if (Number.isNaN(endTime))
return 0;
return value * (endTime - startTime) + startTime;
};
class MediaTimeRange extends MediaChromeRange {
constructor() {
super();
__privateAdd(this, _toggleRangeAnimation);
__privateAdd(this, _shouldRangeAnimate);
__privateAdd(this, _getElementRects);
/**
* Get the position, max and min for the box in percentage.
* It's important this is in percentage so when the player is resized
* the box will move accordingly.
*/
__privateAdd(this, _getBoxPosition);
__privateAdd(this, _getBoxShiftPosition);
__privateAdd(this, _handlePointerMove);
__privateAdd(this, _previewRequest);
__privateAdd(this, _seekRequest);
__privateAdd(this, _rootNode, void 0);
__privateAdd(this, _animation, void 0);
__privateAdd(this, _boxes, void 0);
__privateAdd(this, _previewTime, void 0);
__privateAdd(this, _previewBox, void 0);
__privateAdd(this, _currentBox, void 0);
__privateAdd(this, _boxPaddingLeft, void 0);
__privateAdd(this, _boxPaddingRight, void 0);
__privateAdd(this, _mediaChaptersCues, void 0);
__privateAdd(this, _updateRange, (value) => {
if (this.dragging)
return;
if (isValidNumber(value)) {
this.range.valueAsNumber = value;
}
this.updateBar();
});
this.container.appendChild(template.content.cloneNode(true));
const track = this.shadowRoot.querySelector("#track");
track.insertAdjacentHTML("afterbegin", '');
__privateSet(this, _boxes, this.shadowRoot.querySelectorAll('[part~="box"]'));
__privateSet(this, _previewBox, this.shadowRoot.querySelector('[part~="preview-box"]'));
__privateSet(this, _currentBox, this.shadowRoot.querySelector('[part~="current-box"]'));
const computedStyle = getComputedStyle(this);
__privateSet(this, _boxPaddingLeft, parseInt(
computedStyle.getPropertyValue("--media-box-padding-left")
));
__privateSet(this, _boxPaddingRight, parseInt(
computedStyle.getPropertyValue("--media-box-padding-right")
));
__privateSet(this, _animation, new RangeAnimation(this.range, __privateGet(this, _updateRange), 60));
}
static get observedAttributes() {
return [
...super.observedAttributes,
MediaUIAttributes.MEDIA_PAUSED,
MediaUIAttributes.MEDIA_DURATION,
MediaUIAttributes.MEDIA_SEEKABLE,
MediaUIAttributes.MEDIA_CURRENT_TIME,
MediaUIAttributes.MEDIA_PREVIEW_IMAGE,
MediaUIAttributes.MEDIA_PREVIEW_TIME,
MediaUIAttributes.MEDIA_PREVIEW_CHAPTER,
MediaUIAttributes.MEDIA_BUFFERED,
MediaUIAttributes.MEDIA_PLAYBACK_RATE,
MediaUIAttributes.MEDIA_LOADING,
MediaUIAttributes.MEDIA_ENDED
];
}
connectedCallback() {
var _a;
super.connectedCallback();
this.range.setAttribute("aria-label", nouns.SEEK());
__privateMethod(this, _toggleRangeAnimation, toggleRangeAnimation_fn).call(this);
__privateSet(this, _rootNode, this.getRootNode());
(_a = __privateGet(this, _rootNode)) == null ? void 0 : _a.addEventListener("transitionstart", this);
}
disconnectedCallback() {
var _a;
super.disconnectedCallback();
__privateMethod(this, _toggleRangeAnimation, toggleRangeAnimation_fn).call(this);
(_a = __privateGet(this, _rootNode)) == null ? void 0 : _a.removeEventListener("transitionstart", this);
__privateSet(this, _rootNode, null);
}
attributeChangedCallback(attrName, oldValue, newValue) {
super.attributeChangedCallback(attrName, oldValue, newValue);
if (oldValue == newValue)
return;
if (attrName === MediaUIAttributes.MEDIA_CURRENT_TIME || attrName === MediaUIAttributes.MEDIA_PAUSED || attrName === MediaUIAttributes.MEDIA_ENDED || attrName === MediaUIAttributes.MEDIA_LOADING || attrName === MediaUIAttributes.MEDIA_DURATION || attrName === MediaUIAttributes.MEDIA_SEEKABLE) {
__privateGet(this, _animation).update({
start: calcRangeValueFromTime(this),
duration: this.mediaSeekableEnd - this.mediaSeekableStart,
playbackRate: this.mediaPlaybackRate
});
__privateMethod(this, _toggleRangeAnimation, toggleRangeAnimation_fn).call(this);
updateAriaValueText(this);
} else if (attrName === MediaUIAttributes.MEDIA_BUFFERED) {
this.updateBufferedBar();
}
if (attrName === MediaUIAttributes.MEDIA_DURATION || attrName === MediaUIAttributes.MEDIA_SEEKABLE) {
this.mediaChaptersCues = __privateGet(this, _mediaChaptersCues);
this.updateBar();
}
}
get mediaChaptersCues() {
return __privateGet(this, _mediaChaptersCues);
}
set mediaChaptersCues(value) {
var _a;
__privateSet(this, _mediaChaptersCues, value);
this.updateSegments(
(_a = __privateGet(this, _mediaChaptersCues)) == null ? void 0 : _a.map((c) => ({
start: calcRangeValueFromTime(this, c.startTime),
end: calcRangeValueFromTime(this, c.endTime)
}))
);
}
/**
* Is the media paused
*/
get mediaPaused() {
return getBooleanAttr(this, MediaUIAttributes.MEDIA_PAUSED);
}
set mediaPaused(value) {
setBooleanAttr(this, MediaUIAttributes.MEDIA_PAUSED, value);
}
/**
* Is the media loading
*/
get mediaLoading() {
return getBooleanAttr(this, MediaUIAttributes.MEDIA_LOADING);
}
set mediaLoading(value) {
setBooleanAttr(this, MediaUIAttributes.MEDIA_LOADING, value);
}
/**
*
*/
get mediaDuration() {
return getNumericAttr(this, MediaUIAttributes.MEDIA_DURATION);
}
set mediaDuration(value) {
setNumericAttr(this, MediaUIAttributes.MEDIA_DURATION, value);
}
/**
*
*/
get mediaCurrentTime() {
return getNumericAttr(this, MediaUIAttributes.MEDIA_CURRENT_TIME);
}
set mediaCurrentTime(value) {
setNumericAttr(this, MediaUIAttributes.MEDIA_CURRENT_TIME, value);
}
/**
*
*/
get mediaPlaybackRate() {
return getNumericAttr(this, MediaUIAttributes.MEDIA_PLAYBACK_RATE, 1);
}
set mediaPlaybackRate(value) {
setNumericAttr(this, MediaUIAttributes.MEDIA_PLAYBACK_RATE, value);
}
/**
* An array of ranges, each range being an array of two numbers.
* e.g. [[1, 2], [3, 4]]
*/
get mediaBuffered() {
const buffered = this.getAttribute(MediaUIAttributes.MEDIA_BUFFERED);
if (!buffered)
return [];
return buffered.split(" ").map((timePair) => timePair.split(":").map((timeStr) => +timeStr));
}
set mediaBuffered(list) {
if (!list) {
this.removeAttribute(MediaUIAttributes.MEDIA_BUFFERED);
return;
}
const strVal = list.map((tuple) => tuple.join(":")).join(" ");
this.setAttribute(MediaUIAttributes.MEDIA_BUFFERED, strVal);
}
/**
* Range of values that can be seeked to
* An array of two numbers [start, end]
*/
get mediaSeekable() {
const seekable = this.getAttribute(MediaUIAttributes.MEDIA_SEEKABLE);
if (!seekable)
return void 0;
return seekable.split(":").map((time) => +time);
}
set mediaSeekable(range) {
if (range == null) {
this.removeAttribute(MediaUIAttributes.MEDIA_SEEKABLE);
return;
}
this.setAttribute(MediaUIAttributes.MEDIA_SEEKABLE, range.join(":"));
}
/**
*
*/
get mediaSeekableEnd() {
var _a;
const [, end = this.mediaDuration] = (_a = this.mediaSeekable) != null ? _a : [];
return end;
}
get mediaSeekableStart() {
var _a;
const [start = 0] = (_a = this.mediaSeekable) != null ? _a : [];
return start;
}
/**
* The url of the preview image
*/
get mediaPreviewImage() {
return getStringAttr(this, MediaUIAttributes.MEDIA_PREVIEW_IMAGE);
}
set mediaPreviewImage(value) {
setStringAttr(this, MediaUIAttributes.MEDIA_PREVIEW_IMAGE, value);
}
/**
*
*/
get mediaPreviewTime() {
return getNumericAttr(this, MediaUIAttributes.MEDIA_PREVIEW_TIME);
}
set mediaPreviewTime(value) {
setNumericAttr(this, MediaUIAttributes.MEDIA_PREVIEW_TIME, value);
}
/**
*
*/
get mediaEnded() {
return getBooleanAttr(this, MediaUIAttributes.MEDIA_ENDED);
}
set mediaEnded(value) {
setBooleanAttr(this, MediaUIAttributes.MEDIA_ENDED, value);
}
/* Add a buffered progress bar */
updateBar() {
super.updateBar();
this.updateBufferedBar();
this.updateCurrentBox();
}
updateBufferedBar() {
var _a;
const buffered = this.mediaBuffered;
if (!buffered.length) {
return;
}
let relativeBufferedEnd;
if (!this.mediaEnded) {
const currentTime = this.mediaCurrentTime;
const [, bufferedEnd = this.mediaSeekableStart] = (_a = buffered.find(
([start, end]) => start <= currentTime && currentTime <= end
)) != null ? _a : [];
relativeBufferedEnd = calcRangeValueFromTime(this, bufferedEnd);
} else {
relativeBufferedEnd = 1;
}
const { style } = getOrInsertCSSRule(this.shadowRoot, "#buffered");
style.setProperty("width", `${relativeBufferedEnd * 100}%`);
}
updateCurrentBox() {
const currentSlot = this.shadowRoot.querySelector(
'slot[name="current"]'
);
if (!currentSlot.assignedElements().length)
return;
const currentRailRule = getOrInsertCSSRule(
this.shadowRoot,
"#current-rail"
);
const currentBoxRule = getOrInsertCSSRule(
this.shadowRoot,
'[part~="current-box"]'
);
const rects = __privateMethod(this, _getElementRects, getElementRects_fn).call(this, __privateGet(this, _currentBox));
const boxPos = __privateMethod(this, _getBoxPosition, getBoxPosition_fn).call(this, rects, this.range.valueAsNumber);
const boxShift = __privateMethod(this, _getBoxShiftPosition, getBoxShiftPosition_fn).call(this, rects, this.range.valueAsNumber);
currentRailRule.style.transform = `translateX(${boxPos})`;
currentRailRule.style.setProperty("--_range-width", `${rects.range.width}`);
currentBoxRule.style.setProperty("--_box-shift", `${boxShift}`);
currentBoxRule.style.setProperty("--_box-width", `${rects.box.width}px`);
currentBoxRule.style.setProperty("visibility", "initial");
}
handleEvent(evt) {
super.handleEvent(evt);
switch (evt.type) {
case "input":
__privateMethod(this, _seekRequest, seekRequest_fn).call(this);
break;
case "pointermove":
__privateMethod(this, _handlePointerMove, handlePointerMove_fn).call(this, evt);
break;
case "pointerup":
case "pointerleave":
__privateMethod(this, _previewRequest, previewRequest_fn).call(this, null);
break;
case "transitionstart":
if (containsComposedNode(evt.target, this)) {
setTimeout(() => __privateMethod(this, _toggleRangeAnimation, toggleRangeAnimation_fn).call(this), 0);
}
break;
}
}
}
_rootNode = new WeakMap();
_animation = new WeakMap();
_boxes = new WeakMap();
_previewTime = new WeakMap();
_previewBox = new WeakMap();
_currentBox = new WeakMap();
_boxPaddingLeft = new WeakMap();
_boxPaddingRight = new WeakMap();
_mediaChaptersCues = new WeakMap();
_toggleRangeAnimation = new WeakSet();
toggleRangeAnimation_fn = function() {
if (__privateMethod(this, _shouldRangeAnimate, shouldRangeAnimate_fn).call(this)) {
__privateGet(this, _animation).start();
} else {
__privateGet(this, _animation).stop();
}
};
_shouldRangeAnimate = new WeakSet();
shouldRangeAnimate_fn = function() {
return this.isConnected && !this.mediaPaused && !this.mediaLoading && !this.mediaEnded && this.mediaSeekableEnd > 0 && isElementVisible(this);
};
_updateRange = new WeakMap();
_getElementRects = new WeakSet();
getElementRects_fn = function(box) {
var _a;
const bounds = (_a = this.getAttribute("bounds") ? closestComposedNode(this, `#${this.getAttribute("bounds")}`) : this.parentElement) != null ? _a : this;
const boundsRect = bounds.getBoundingClientRect();
const rangeRect = this.range.getBoundingClientRect();
const width = box.offsetWidth;
const min = -(rangeRect.left - boundsRect.left - width / 2);
const max = boundsRect.right - rangeRect.left - width / 2;
return {
box: { width, min, max },
bounds: boundsRect,
range: rangeRect
};
};
_getBoxPosition = new WeakSet();
getBoxPosition_fn = function(rects, ratio) {
let position = `${ratio * 100}%`;
const { width, min, max } = rects.box;
if (!width)
return position;
if (!Number.isNaN(min)) {
const pad = `var(--media-box-padding-left)`;
const minPos = `calc(1 / var(--_range-width) * 100 * ${min}% + ${pad})`;
position = `max(${minPos}, ${position})`;
}
if (!Number.isNaN(max)) {
const pad = `var(--media-box-padding-right)`;
const maxPos = `calc(1 / var(--_range-width) * 100 * ${max}% - ${pad})`;
position = `min(${position}, ${maxPos})`;
}
return position;
};
_getBoxShiftPosition = new WeakSet();
getBoxShiftPosition_fn = function(rects, ratio) {
const { width, min, max } = rects.box;
const pointerX = ratio * rects.range.width;
if (pointerX < min + __privateGet(this, _boxPaddingLeft)) {
const offset = rects.range.left - rects.bounds.left - __privateGet(this, _boxPaddingLeft);
return `${pointerX - width / 2 + offset}px`;
}
if (pointerX > max - __privateGet(this, _boxPaddingRight)) {
const offset = rects.bounds.right - rects.range.right - __privateGet(this, _boxPaddingRight);
return `${pointerX + width / 2 - offset - rects.range.width}px`;
}
return 0;
};
_handlePointerMove = new WeakSet();
handlePointerMove_fn = function(evt) {
const isOverBoxes = [...__privateGet(this, _boxes)].some(
(b) => evt.composedPath().includes(b)
);
if (!this.dragging && (isOverBoxes || !evt.composedPath().includes(this))) {
__privateMethod(this, _previewRequest, previewRequest_fn).call(this, null);
return;
}
const duration = this.mediaSeekableEnd;
if (!duration)
return;
const previewRailRule = getOrInsertCSSRule(
this.shadowRoot,
"#preview-rail"
);
const previewBoxRule = getOrInsertCSSRule(
this.shadowRoot,
'[part~="preview-box"]'
);
const rects = __privateMethod(this, _getElementRects, getElementRects_fn).call(this, __privateGet(this, _previewBox));
let pointerRatio = (evt.clientX - rects.range.left) / rects.range.width;
pointerRatio = Math.max(0, Math.min(1, pointerRatio));
const boxPos = __privateMethod(this, _getBoxPosition, getBoxPosition_fn).call(this, rects, pointerRatio);
const boxShift = __privateMethod(this, _getBoxShiftPosition, getBoxShiftPosition_fn).call(this, rects, pointerRatio);
previewRailRule.style.transform = `translateX(${boxPos})`;
previewRailRule.style.setProperty("--_range-width", `${rects.range.width}`);
previewBoxRule.style.setProperty("--_box-shift", `${boxShift}`);
previewBoxRule.style.setProperty("--_box-width", `${rects.box.width}px`);
const diff = Math.round(__privateGet(this, _previewTime)) - Math.round(pointerRatio * duration);
if (Math.abs(diff) < 1 && pointerRatio > 0.01 && pointerRatio < 0.99)
return;
__privateSet(this, _previewTime, pointerRatio * duration);
__privateMethod(this, _previewRequest, previewRequest_fn).call(this, __privateGet(this, _previewTime));
};
_previewRequest = new WeakSet();
previewRequest_fn = function(detail) {
this.dispatchEvent(
new globalThis.CustomEvent(MediaUIEvents.MEDIA_PREVIEW_REQUEST, {
composed: true,
bubbles: true,
detail
})
);
};
_seekRequest = new WeakSet();
seekRequest_fn = function() {
__privateGet(this, _animation).stop();
const detail = calcTimeFromRangeValue(this);
this.dispatchEvent(
new globalThis.CustomEvent(MediaUIEvents.MEDIA_SEEK_REQUEST, {
composed: true,
bubbles: true,
detail
})
);
};
if (!globalThis.customElements.get("media-time-range")) {
globalThis.customElements.define("media-time-range", MediaTimeRange);
}
var media_time_range_default = MediaTimeRange;
export {
media_time_range_default as default
};