range function done

Signed-off-by: vagabond-0 <220229@tkmce.ac.in>
This commit is contained in:
vagabond-0 2025-05-13 18:52:16 +05:30
parent 36f6b4fbd1
commit e78d32e458

View file

@ -1,7 +1,3 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
(() => {
"use strict";
@ -77,6 +73,147 @@
.padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
}
class CustomRangeInput {
constructor(originalInput) {
this.originalInput = originalInput;
this.container = document.createElement('div');
this.container.className = 'custom-range-container';
this.container.style.position = 'relative';
this.container.style.height = '20px';
this.container.style.width = '150px';
this.track = document.createElement('div');
this.track.className = 'custom-range-track';
this.track.style.position = 'absolute';
this.track.style.top = '50%';
this.track.style.transform = 'translateY(-50%)';
this.track.style.width = '100%';
this.track.style.height = '4px';
this.track.style.backgroundColor = '#d3d3d3';
this.track.style.borderRadius = '2px';
this.progress = document.createElement('div');
this.progress.className = 'custom-range-progress';
this.progress.style.position = 'absolute';
this.progress.style.top = '50%';
this.progress.style.transform = 'translateY(-50%)';
this.progress.style.width = '0%';
this.progress.style.height = '4px';
this.progress.style.backgroundColor = '#4c8bf5';
this.progress.style.borderRadius = '2px';
this.thumb = document.createElement('div');
this.thumb.className = 'custom-range-thumb';
this.thumb.style.position = 'absolute';
this.thumb.style.top = '50%';
this.thumb.style.transform = 'translate(-50%, -50%)';
this.thumb.style.width = '16px';
this.thumb.style.height = '16px';
this.thumb.style.backgroundColor = '#4c8bf5';
this.thumb.style.borderRadius = '50%';
this.thumb.style.cursor = 'pointer';
this.thumb.style.zIndex = '1';
this.originalInput.style.display = 'none';
// Assemble component
this.container.appendChild(this.track);
this.container.appendChild(this.progress);
this.container.appendChild(this.thumb);
this.originalInput.parentNode.insertBefore(this.container, this.originalInput.nextSibling);
this.updateThumbPosition();
// Bind event handlers
this.bindEvents();
}
updateThumbPosition() {
const min = parseFloat(this.originalInput.min) || 0;
const max = parseFloat(this.originalInput.max) || 100;
const value = parseFloat(this.originalInput.value) || min;
// Calculate percentage
const percentage = ((value - min) / (max - min)) * 100;
// Update thumb and progress position
this.thumb.style.left = `${percentage}%`;
this.progress.style.width = `${percentage}%`;
}
setValue(clientX) {
const rect = this.track.getBoundingClientRect();
const min = parseFloat(this.originalInput.min) || 0;
const max = parseFloat(this.originalInput.max) || 100;
const step = parseFloat(this.originalInput.step) || 1;
// Calculate percentage of position within track
let percentage = (clientX - rect.left) / rect.width;
// Clamp percentage to 0-1 range
percentage = Math.max(0, Math.min(1, percentage));
// Calculate value based on percentage
let value = min + percentage * (max - min);
// Apply step if specified
if (step > 0) {
value = Math.round(value / step) * step;
}
// Ensure value is within min/max bounds
value = Math.max(min, Math.min(max, value));
// Update original input value
this.originalInput.value = value;
// Dispatch input and change events
const inputEvent = new Event('input', { bubbles: true });
const changeEvent = new Event('change', { bubbles: true });
this.originalInput.dispatchEvent(inputEvent);
this.originalInput.dispatchEvent(changeEvent);
// Update thumb position
this.updateThumbPosition();
}
bindEvents() {
// Mouse events
this.container.addEventListener('mousedown', (e) => {
this.isDragging = true;
this.setValue(e.clientX);
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (this.isDragging) {
this.setValue(e.clientX);
}
});
document.addEventListener('mouseup', () => {
this.isDragging = false;
});
// Touch events
this.container.addEventListener('touchstart', (e) => {
this.isDragging = true;
this.setValue(e.touches[0].clientX);
e.preventDefault();
});
document.addEventListener('touchmove', (e) => {
if (this.isDragging) {
this.setValue(e.touches[0].clientX);
}
});
document.addEventListener('touchend', () => {
this.isDragging = false;
});
}
}
class MediaControls {
constructor() {
this.nonce = Date.now();
@ -101,7 +238,6 @@
this.root.innerHTML = generateMarkup(this.isAudioOnly);
this.controls.appendChild(this.root);
const elementNames = [
"duration",
"play-pause-button",
@ -122,6 +258,10 @@
this.elements[camelCase(id)] = this.controls.getElementById(id);
});
// Replace standard range inputs with custom ones
this.customProgress = new CustomRangeInput(this.elements.progress);
this.customVolume = new CustomRangeInput(this.elements.volumeLevel);
// Init position duration box.
const positionTextNode = this.elements.positionText;
const durationSpan = this.elements.duration;
@ -205,10 +345,6 @@
});
// Create state transitions.
//
// It exposes one method per transition. i.e. this.pause(), this.play(), etc.
// For each transition, we check that the transition is possible and call
// the `onStateChange` handler.
for (let name in TRANSITIONS) {
if (!TRANSITIONS.hasOwnProperty(name)) {
continue;
@ -216,7 +352,6 @@
this[name] = () => {
const from = this.state;
// Checks if the transition is valid in the current state.
if (!TRANSITIONS[name][from]) {
const error = `Transition "${name}" invalid for the current state "${from}"`;
console.error(error);
@ -229,7 +364,6 @@
return;
}
// Transition to the next state.
this.state = to;
this.onStateChange(from);
};
@ -250,28 +384,21 @@
});
}
// State change handler
onStateChange(from) {
this.render(from);
}
render(from = this.state) {
if (!this.isAudioOnly) {
// XXX This should ideally use clientHeight/clientWidth,
// but for some reason I couldn't figure out yet,
// using it breaks layout.
this.root.style.height = this.media.videoHeight;
this.root.style.width = this.media.videoWidth;
}
// Error
if (this.state == ERRORED) {
//XXX render errored state
return;
}
if (this.state != from) {
// Play/Pause button.
const playPauseButton = this.elements.playPauseButton;
playPauseButton.classList.remove(from);
playPauseButton.classList.add(this.state);
@ -282,8 +409,10 @@
(this.media.currentTime / this.media.duration) * 100;
if (Number.isFinite(positionPercent)) {
this.elements.progress.value = positionPercent;
this.customProgress.updateThumbPosition();
} else {
this.elements.progress.value = 0;
this.customProgress.updateThumbPosition();
}
// Current time and duration.
@ -303,6 +432,7 @@
: Math.round(this.media.volume * 100);
if (this.elements.volumeLevel.value != volumeLevelValue) {
this.elements.volumeLevel.value = volumeLevelValue;
this.customVolume.updateThumbPosition();
}
}
@ -346,7 +476,6 @@
}
}
// HTMLMediaElement event handler
onMediaEvent(event) {
switch (event.type) {
case "ended":
@ -354,7 +483,6 @@
break;
case "play":
case "pause":
// Transition to PLAYING or PAUSED state.
this[event.type]();
break;
case "volumechange":
@ -368,7 +496,6 @@
}
/* Media actions */
playOrPause() {
switch (this.state) {
case PLAYING:
@ -390,7 +517,6 @@
toggleFullscreen() {
const { fullscreenEnabled, fullscreenElement } = document;
const isElementFullscreen = fullscreenElement && fullscreenElement === this.media;
if (fullscreenEnabled && isElementFullscreen) {
@ -414,4 +540,3 @@
new MediaControls();
})();