runtimeSliderJs top-level constant
String
const runtimeSliderJs
Implementation
const String runtimeSliderJs = r'''
function sliderRoot(sliderId) {
return document.querySelector('[data-arcane-slider="' + cssEscape(sliderId) + '"][data-arcane-slider-min]');
}
function sliderClampValue(root, value) {
const min = parseFloat(root.getAttribute('data-arcane-slider-min') || '0');
const max = parseFloat(root.getAttribute('data-arcane-slider-max') || '100');
const step = parseFloat(root.getAttribute('data-arcane-slider-step') || '0') || 0;
let v = Math.max(min, Math.min(max, value));
if (step > 0) {
const ticks = Math.round((v - min) / step);
v = min + ticks * step;
}
if (v < min) v = min;
if (v > max) v = max;
return v;
}
function sliderApplyValue(root, value, opts) {
opts = opts || {};
const sliderId = root.getAttribute('data-arcane-slider');
const min = parseFloat(root.getAttribute('data-arcane-slider-min') || '0');
const max = parseFloat(root.getAttribute('data-arcane-slider-max') || '100');
const range = root.getAttribute('data-arcane-slider-range') === 'true';
const role = opts.role || 'value';
const clamped = sliderClampValue(root, value);
const pct = max > min ? ((clamped - min) / (max - min)) * 100 : 0;
if (range) {
let lo = parseFloat(root.getAttribute('data-arcane-slider-lo') || min);
let hi = parseFloat(root.getAttribute('data-arcane-slider-hi') || max);
if (role === 'lo') {
lo = clamped;
if (lo > hi) lo = hi;
} else {
hi = clamped;
if (hi < lo) hi = lo;
}
root.setAttribute('data-arcane-slider-lo', String(lo));
root.setAttribute('data-arcane-slider-hi', String(hi));
const loPct = max > min ? ((lo - min) / (max - min)) * 100 : 0;
const hiPct = max > min ? ((hi - min) / (max - min)) * 100 : 0;
const fill = root.querySelector('[data-arcane-slider-fill]');
if (fill) {
fill.style.left = loPct + '%';
fill.style.right = (100 - hiPct) + '%';
fill.style.width = (hiPct - loPct) + '%';
}
const thumbLo = root.querySelector('[data-arcane-slider-thumb="lo"]');
if (thumbLo) {
thumbLo.style.left = loPct + '%';
thumbLo.setAttribute('aria-valuenow', String(lo));
}
const thumbHi = root.querySelector('[data-arcane-slider-thumb="hi"]');
if (thumbHi) {
thumbHi.style.left = hiPct + '%';
thumbHi.setAttribute('aria-valuenow', String(hi));
}
fireEvent(root, 'arcane:slider-change', {
sliderId: sliderId, lo: lo, hi: hi
});
} else {
root.setAttribute('data-arcane-slider-value', String(clamped));
const fill = root.querySelector('[data-arcane-slider-fill]');
if (fill) {
fill.style.width = pct + '%';
}
const thumb = root.querySelector('[data-arcane-slider-thumb]');
if (thumb) {
thumb.style.left = pct + '%';
thumb.setAttribute('aria-valuenow', String(clamped));
}
fireEvent(root, 'arcane:slider-change', {
sliderId: sliderId, value: clamped
});
}
const changeAction = root.getAttribute('data-arcane-slider-change');
if (changeAction) {
runActions(changeAction, { trigger: root, sliderId: sliderId });
}
}
function sliderValueFromPointer(root, clientX) {
const track = root.querySelector('[data-arcane-slider-track]') || root;
const rect = track.getBoundingClientRect();
if (rect.width <= 0) return 0;
const min = parseFloat(root.getAttribute('data-arcane-slider-min') || '0');
const max = parseFloat(root.getAttribute('data-arcane-slider-max') || '100');
const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
return min + ratio * (max - min);
}
function sliderRoleFromTarget(root, target) {
const t = findClosest(target, '[data-arcane-slider-thumb]');
if (t) {
return t.getAttribute('data-arcane-slider-thumb') === 'hi' ? 'hi' : 'lo';
}
if (root.getAttribute('data-arcane-slider-range') === 'true') {
const lo = parseFloat(root.getAttribute('data-arcane-slider-lo') || '0');
const hi = parseFloat(root.getAttribute('data-arcane-slider-hi') || '100');
const target_value = sliderValueFromPointer(root, event.clientX);
return Math.abs(target_value - lo) < Math.abs(target_value - hi) ? 'lo' : 'hi';
}
return 'value';
}
function bindSliders() {
let activeSlider = null;
let activeRole = null;
function onMove(e) {
if (!activeSlider) return;
e.preventDefault();
const v = sliderValueFromPointer(activeSlider, e.clientX);
sliderApplyValue(activeSlider, v, { role: activeRole });
}
function onUp() {
activeSlider = null;
activeRole = null;
document.removeEventListener('pointermove', onMove);
document.removeEventListener('pointerup', onUp);
document.removeEventListener('pointercancel', onUp);
}
document.addEventListener('pointerdown', function(e) {
const root = findClosest(e.target, '[data-arcane-slider]');
if (!root) return;
if (root.getAttribute('data-arcane-disabled') === 'true') return;
const range = root.getAttribute('data-arcane-slider-range') === 'true';
let role = 'value';
if (range) {
const t = findClosest(e.target, '[data-arcane-slider-thumb]');
if (t) {
role = t.getAttribute('data-arcane-slider-thumb');
} else {
const v = sliderValueFromPointer(root, e.clientX);
const lo = parseFloat(root.getAttribute('data-arcane-slider-lo') || '0');
const hi = parseFloat(root.getAttribute('data-arcane-slider-hi') || '100');
role = Math.abs(v - lo) < Math.abs(v - hi) ? 'lo' : 'hi';
}
}
activeSlider = root;
activeRole = role;
const v = sliderValueFromPointer(root, e.clientX);
sliderApplyValue(root, v, { role: role });
document.addEventListener('pointermove', onMove);
document.addEventListener('pointerup', onUp);
document.addEventListener('pointercancel', onUp);
}, true);
document.addEventListener('keydown', function(e) {
const thumb = findClosest(e.target, '[data-arcane-slider-thumb]');
if (!thumb) return;
const root = findClosest(thumb, '[data-arcane-slider]');
if (!root) return;
if (root.getAttribute('data-arcane-disabled') === 'true') return;
const role = thumb.getAttribute('data-arcane-slider-thumb');
const step = parseFloat(root.getAttribute('data-arcane-slider-step') || '1') || 1;
const min = parseFloat(root.getAttribute('data-arcane-slider-min') || '0');
const max = parseFloat(root.getAttribute('data-arcane-slider-max') || '100');
let cur;
if (role === 'lo' || role === 'hi') {
cur = parseFloat(root.getAttribute('data-arcane-slider-' + role) || '0');
} else {
cur = parseFloat(root.getAttribute('data-arcane-slider-value') || '0');
}
let next = cur;
if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') next = cur - step;
else if (e.key === 'ArrowRight' || e.key === 'ArrowUp') next = cur + step;
else if (e.key === 'PageDown') next = cur - step * 10;
else if (e.key === 'PageUp') next = cur + step * 10;
else if (e.key === 'Home') next = min;
else if (e.key === 'End') next = max;
else return;
e.preventDefault();
sliderApplyValue(root, next, {
role: role === 'lo' || role === 'hi' ? role : 'value'
});
}, true);
}
function setSliderValue(sliderId, value, role) {
const root = sliderRoot(sliderId);
if (!root) return;
const v = parseFloat(value);
if (isNaN(v)) return;
sliderApplyValue(root, v, { role: role || 'value' });
}
ARCANE.slider = {
set: setSliderValue,
bind: bindSliders
};
''';