Skip to content

Commit

Permalink
Merge pull request #4760 from dmitrylyzo/slider-bubble-value
Browse files Browse the repository at this point in the history
Simplify subtitle sync
  • Loading branch information
thornbill authored Sep 26, 2023
2 parents 9403ada + 6063ba6 commit c1ef338
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 51 deletions.
53 changes: 15 additions & 38 deletions src/components/subtitlesync/subtitlesync.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,8 @@ function init(instance) {
if (inputOffset) {
inputOffset = inputOffset[0];
inputOffset = parseFloat(inputOffset);
inputOffset = Math.min(30, Math.max(-30, inputOffset));

// replace current text by considered offset
this.textContent = inputOffset + 's';
// set new offset
playbackManager.setSubtitleOffset(inputOffset, player);
// synchronize with slider value
subtitleSyncSlider.updateOffset(
getSliderValueFromOffset(inputOffset));

subtitleSyncSlider.updateOffset(inputOffset);
} else {
this.textContent = (playbackManager.getPlayerSubtitleOffset(player) || 0) + 's';
}
Expand All @@ -79,23 +72,26 @@ function init(instance) {
}
};

function updateSubtitleOffset() {
const value = parseFloat(subtitleSyncSlider.value);
// set new offset
playbackManager.setSubtitleOffset(value, player);
// synchronize with textField value
subtitleSyncTextField.updateOffset(value);
}

subtitleSyncSlider.updateOffset = function (sliderValue) {
// default value is 0s = 0ms
this.value = sliderValue === undefined ? 0 : sliderValue;

updateSubtitleOffset();
};

subtitleSyncSlider.addEventListener('change', function () {
// set new offset
playbackManager.setSubtitleOffset(getOffsetFromSliderValue(this.value), player);
// synchronize with textField value
subtitleSyncTextField.updateOffset(
getOffsetFromSliderValue(this.value));
});
subtitleSyncSlider.addEventListener('change', () => updateSubtitleOffset());

subtitleSyncSlider.getBubbleHtml = function (value) {
const newOffset = getOffsetFromPercentage(value);
subtitleSyncSlider.getBubbleHtml = function (_, value) {
return '<h1 class="sliderBubbleText">'
+ (newOffset > 0 ? '+' : '') + parseFloat(newOffset) + 's'
+ (value > 0 ? '+' : '') + parseFloat(value) + 's'
+ '</h1>';
};

Expand All @@ -107,25 +103,6 @@ function init(instance) {
instance.element = parent;
}

function getOffsetFromPercentage(value) {
// convert percentage to fraction
let offset = (value - 50) / 50;
// multiply by offset min/max range value (-x to +x) :
offset *= 30;
return offset.toFixed(1);
}

function getOffsetFromSliderValue(value) {
// convert slider value to offset
const offset = value / 10;
return offset.toFixed(1);
}

function getSliderValueFromOffset(value) {
const sliderValue = value * 10;
return Math.min(300, Math.max(-300, sliderValue.toFixed(1)));
}

class SubtitleSync {
constructor(currentPlayer) {
player = currentPlayer;
Expand Down
2 changes: 1 addition & 1 deletion src/components/subtitlesync/subtitlesync.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<button type="button" is="paper-icon-button-light" class="subtitleSync-closeButton"><span class="material-icons close" aria-hidden="true"></span></button>
<div class="subtitleSyncTextField" contenteditable="true" spellcheck="false">0s</div>
<div class="sliderContainer subtitleSyncSliderContainer">
<input is="emby-slider" type="range" step="1" min="-300" max="300" value="0" class="subtitleSyncSlider" data-slider-keep-progress="true" />
<input is="emby-slider" type="range" step="0.1" min="-30" max="30" value="0" class="subtitleSyncSlider" data-slider-keep-progress="true" />
</div>
</div>
</div>
39 changes: 27 additions & 12 deletions src/elements/emby-slider/emby-slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import './emby-slider.scss';
import 'webcomponents.js/webcomponents-lite';
import '../emby-input/emby-input';
import globalize from '../../scripts/globalize';
import { decimalCount } from '../../utils/number';

const EmbySliderPrototype = Object.create(HTMLInputElement.prototype);

Expand Down Expand Up @@ -75,13 +76,23 @@ function mapClientToFraction(range, clientX) {
function mapFractionToValue(range, fraction) {
let value = (range.max - range.min) * fraction;

let decimals = null;

// Snap to step
if (range.step !== 'any') {
const step = normalizeSliderStep(range);
decimals = decimalCount(step);
value = Math.round(value / step) * step;
}

value += parseFloat(range.min);
const min = parseFloat(range.min);

value += min;

if (decimals != null) {
decimals = Math.max(decimals, decimalCount(min));
value = parseFloat(value.toFixed(decimals));
}

return Math.min(Math.max(value, range.min), range.max);
}
Expand Down Expand Up @@ -135,31 +146,33 @@ function updateValues(isValueSet) {
});
}

function updateBubble(range, value, bubble) {
function updateBubble(range, percent, value, bubble) {
requestAnimationFrame(function () {
const bubbleTrackRect = range.sliderBubbleTrack.getBoundingClientRect();
const bubbleRect = bubble.getBoundingClientRect();

let bubblePos = bubbleTrackRect.width * value / 100;
let bubblePos = bubbleTrackRect.width * percent / 100;
if (globalize.getIsElementRTL(range)) {
bubblePos = bubbleTrackRect.width - bubblePos;
}
bubblePos = Math.min(Math.max(bubblePos, bubbleRect.width / 2), bubbleTrackRect.width - bubbleRect.width / 2);

bubble.style.left = bubblePos + 'px';

let html;

if (range.getBubbleHtml) {
value = range.getBubbleHtml(value);
html = range.getBubbleHtml(percent, value);
} else {
if (range.getBubbleText) {
value = range.getBubbleText(value);
html = range.getBubbleText(percent, value);
} else {
value = mapFractionToValue(range, value / 100).toLocaleString();
html = value.toLocaleString();
}
value = '<h1 class="sliderBubbleText">' + value + '</h1>';
html = '<h1 class="sliderBubbleText">' + html + '</h1>';
}

bubble.innerHTML = value;
bubble.innerHTML = html;
});
}

Expand Down Expand Up @@ -295,8 +308,8 @@ EmbySliderPrototype.attachedCallback = function () {
updateValues.call(this);
}

const bubbleValue = mapValueToFraction(this, this.value) * 100;
updateBubble(this, bubbleValue, sliderBubble);
const percent = mapValueToFraction(this, this.value) * 100;
updateBubble(this, percent, parseFloat(this.value), sliderBubble);

if (hasHideBubbleClass) {
sliderBubble.classList.remove('hide');
Expand All @@ -322,9 +335,11 @@ EmbySliderPrototype.attachedCallback = function () {
/* eslint-disable-next-line compat/compat */
dom.addEventListener(this, (window.PointerEvent ? 'pointermove' : 'mousemove'), function (e) {
if (!this.dragging) {
const bubbleValue = mapClientToFraction(this, e.clientX) * 100;
const fraction = mapClientToFraction(this, e.clientX);
const percent = fraction * 100;
const value = mapFractionToValue(this, fraction);

updateBubble(this, bubbleValue, sliderBubble);
updateBubble(this, percent, value, sliderBubble);

if (hasHideBubbleClass) {
sliderBubble.classList.remove('hide');
Expand Down
13 changes: 13 additions & 0 deletions src/utils/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,16 @@ export function toPercent(value: number | null | undefined, locale: string): str

return `${Math.round(value * 100)}%`;
}

/**
* Gets decimal count of a Number.
* @param {number} value Number.
* @returns {number} Decimal count of a Number.
*/
export function decimalCount(value: number): number {
if (Number.isInteger(value)) return 0;

const arr = value.toString().split('.');

return arr[1].length;
}

0 comments on commit c1ef338

Please sign in to comment.