[REF] website: multirange input
This commit improve the design and simplify the implementation. Popovers have been removed and the overall integration with boostrap is increased allowing customization with the default boostrap variables. Variables for (multi-)range input have been exposed at "theme-level" allowing to customize these components when creating a new theme. task-2907955 Part-of: odoo/odoo#98558
This commit is contained in:
@@ -5,11 +5,23 @@
|
||||
// customization (eg. form-range)
|
||||
|
||||
// gray-color-variables
|
||||
$white: #fff !default;
|
||||
$gray-400: #ced4da !default;
|
||||
|
||||
// color-variables
|
||||
$blue: #0d6efd !default;
|
||||
|
||||
// theme-color-variables
|
||||
$primary: $blue !default;
|
||||
|
||||
// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.
|
||||
// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast
|
||||
$min-contrast-ratio: 3 !default;
|
||||
|
||||
// Body
|
||||
|
||||
$body-bg: $white !default; // BS Default
|
||||
|
||||
// Components
|
||||
//
|
||||
// Define common padding and border radius sizes and more.
|
||||
@@ -37,6 +49,11 @@ $input-transition: background-color .05s ease-in-out, border-color .05s ease-in-
|
||||
$form-check-input-border: $border-width solid $gray-400 !default;
|
||||
$form-check-input-border-radius: 0 !default;
|
||||
|
||||
$form-range-track-height: .1rem !default;
|
||||
$form-range-thumb-border: $border-width solid $primary !default;
|
||||
$form-range-thumb-bg: $body-bg !default;
|
||||
$form-range-thumb-active-bg: $primary !default;
|
||||
|
||||
// Figures
|
||||
|
||||
// Inherit color for figure-caption, use text-muted on top of it if you want
|
||||
|
||||
@@ -76,62 +76,43 @@ class Multirange {
|
||||
this.input.step = this.step = options.step || this.input.step || 1;
|
||||
this.currency = options.currency || this.input.dataset.currency || '';
|
||||
this.currencyPosition = options.currencyPosition || this.input.dataset.currencyPosition || 'after';
|
||||
const inputClasses = ["multirange", "d-inline-block", "p-0", "align-top"];
|
||||
|
||||
/* Wrap the input and add its ghost */
|
||||
this.rangeDiv = document.createElement("div");
|
||||
this.rangeDiv.classList.add("multirange-wrapper");
|
||||
this.rangeDiv.classList.add("multirange-wrapper", "position-relative", "mb-5");
|
||||
this.countersWrapper = document.createElement("small");
|
||||
this.countersWrapper.classList.add("d-flex", "justify-content-between", "mt-2");
|
||||
this.rangeDiv.appendChild(this.countersWrapper);
|
||||
this.input.parentNode.insertBefore(this.rangeDiv, this.input.nextSibling);
|
||||
this.rangeDiv.appendChild(this.input);
|
||||
this.ghost = this.input.cloneNode();
|
||||
this.rangeDiv.appendChild(this.ghost);
|
||||
|
||||
this.input.classList.add("multirange", "original");
|
||||
this.ghost.classList.add("multirange", "ghost");
|
||||
this.input.classList.add("original", "position-absolute", "w-100", "m-0", ...inputClasses);
|
||||
this.ghost.classList.add("ghost", "position-relative", ...inputClasses);
|
||||
this.input.value = values[0] || this.min;
|
||||
this.ghost.value = values[1] || this.max;
|
||||
|
||||
this.inputTipLocator = document.createElement("div");
|
||||
this.inputTipLocator.classList.add("tip-locator");
|
||||
this.ghostTipLocator = document.createElement("div");
|
||||
this.ghostTipLocator.classList.add("tip-locator");
|
||||
this.rangeDiv.insertBefore(this.ghostTipLocator, this.input.nextSibling);
|
||||
this.rangeDiv.insertBefore(this.inputTipLocator, this.ghost.nextSibling);
|
||||
this.leftCounter = document.createElement("span");
|
||||
this.leftCounter.classList.add("multirange-min");
|
||||
this.leftCounter.classList.add("multirange-min", "position-absolute", "opacity-75", "opacity-100-hover", "mt-1");
|
||||
this.rightCounter = document.createElement("span");
|
||||
this.rightCounter.classList.add("multirange-max");
|
||||
this.tipLocatorOptions = {
|
||||
container: this.rangeDiv,
|
||||
html: true,
|
||||
};
|
||||
$(this.inputTipLocator).popover(Object.assign(
|
||||
this.tipLocatorOptions,
|
||||
{
|
||||
placement: 'top',
|
||||
content: this.leftCounter
|
||||
})
|
||||
);
|
||||
$(this.ghostTipLocator).popover(Object.assign(
|
||||
this.tipLocatorOptions,
|
||||
{
|
||||
placement: 'bottom',
|
||||
content: this.rightCounter
|
||||
})
|
||||
);
|
||||
this.rightCounter.classList.add("multirange-max", "position-absolute", "opacity-75", "opacity-100-hover", "mt-1");
|
||||
this.rightCounter.style.right = 0;
|
||||
this.countersWrapper.append(this.leftCounter, this.rightCounter);
|
||||
|
||||
$(this.inputTipLocator).add($(this.ghostTipLocator)).popover('show');
|
||||
/* Add the counterInput */
|
||||
if (this.rangeWithInput) {
|
||||
this.leftInput = document.createElement("input");
|
||||
this.leftInput.type = "number";
|
||||
this.leftInput.style.display = "none";
|
||||
this.leftInput.classList.add("invisible", "form-control", "form-control-sm", "w-auto", "mb-2", "mb-lg-1");
|
||||
this.leftInput.min = this.min;
|
||||
this.leftInput.max = this.max;
|
||||
this.leftInput.step = this.step;
|
||||
this.rightInput = this.leftInput.cloneNode();
|
||||
|
||||
this.leftInput.classList.add("multirange-min");
|
||||
this.rightInput.classList.add("multirange-max");
|
||||
this.leftInput.classList.add("multirange-min", "invisible");
|
||||
this.rightInput.classList.add("multirange-max", "invisible");
|
||||
|
||||
this.leftCounter.parentNode.appendChild(this.leftInput);
|
||||
this.rightCounter.parentNode.appendChild(this.rightInput);
|
||||
@@ -221,19 +202,9 @@ class Multirange {
|
||||
update() {
|
||||
const low = 100 * (this.input.valueLow - this.min) / (this.max - this.min);
|
||||
const high = 100 * (this.input.valueHigh - this.min) / (this.max - this.min);
|
||||
const tipOffsetLow = 8 - (low * 0.15);
|
||||
const tipOffsetHigh = 8 - (high * 0.15);
|
||||
|
||||
this.rangeDiv.style.setProperty("--low", low + '%');
|
||||
this.rangeDiv.style.setProperty("--high", high + '%');
|
||||
$(this.inputTipLocator).css({
|
||||
'left': `calc(${low}% + (${tipOffsetLow}px))`,
|
||||
'top': '3px'
|
||||
});
|
||||
$(this.ghostTipLocator).css({
|
||||
'left': `calc(${high}% + (${tipOffsetHigh}px))`,
|
||||
'top': '18px'
|
||||
});
|
||||
$(this.inputTipLocator).add($(this.ghostTipLocator)).popover('update');
|
||||
this.counterInputUpdate();
|
||||
}
|
||||
|
||||
@@ -253,16 +224,17 @@ class Multirange {
|
||||
counter = this.leftCounter;
|
||||
input = this.leftInput;
|
||||
}
|
||||
if (counter.style.display === "none") {
|
||||
|
||||
if (counter.classList.contains("invisible")) {
|
||||
this.input.valueLow = this.leftInput.value;
|
||||
this.input.valueHigh = this.rightInput.value;
|
||||
this.dispatchNewValueEvent();
|
||||
this.update();
|
||||
counter.style.display = "";
|
||||
input.style.display = "none";
|
||||
counter.classList.remove("invisible");
|
||||
input.classList.add("invisible");
|
||||
} else {
|
||||
counter.style.display = "none";
|
||||
input.style.display = "";
|
||||
counter.classList.add("invisible");
|
||||
input.classList.remove("invisible");
|
||||
this.saveOldValues();
|
||||
// Hack because firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1057858
|
||||
window.setTimeout(function () {
|
||||
|
||||
@@ -2,84 +2,74 @@
|
||||
// which can be found on https://github.com/LeaVerou/multirange.
|
||||
// The license file can be found in the same folder as this file.
|
||||
|
||||
input[type="range"][multiple] {
|
||||
input[type="range"][multiple] {
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&.reverse {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&.multirange {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.multirange-wrapper {
|
||||
input[type="range"][multiple] {
|
||||
visibility: initial;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&.original {
|
||||
position: absolute;
|
||||
&::-moz-range-thumb {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
&.reverse {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&.multirange {
|
||||
&::-moz-range-track {
|
||||
border-color: transparent; /* needed to switch Firefox to "styleable" control */
|
||||
}
|
||||
|
||||
&.original::-webkit-slider-thumb {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
transform: scale(1); /* Firefox doesn't apply position it seems */
|
||||
z-index: 1;
|
||||
&.ghost {
|
||||
|
||||
// Workaround to handle Firefox's lack of support of z-index rules
|
||||
// for #shadow-root elements, see '&.original::-webkit-slider-thumb'
|
||||
// rules. The entire @media query could be removed once Firefox
|
||||
// will support the feature.
|
||||
@media all and (min--moz-device-pixel-ratio:0) and (min-resolution: .001dpcm) {
|
||||
|
||||
// Helper function to retrive the 'width' segment from a 'border' shorthand rule.
|
||||
@function -get-border-width($input) {
|
||||
@each $part in $input {
|
||||
@if type-of($part) == number {
|
||||
@return $part;
|
||||
}
|
||||
}
|
||||
@return null;
|
||||
}
|
||||
|
||||
$-thumb-border-width: #{-get-border-width($form-range-thumb-border)};
|
||||
$-ghostGap: calc(#{$form-range-thumb-width} + (#{$-thumb-border-width} * 2));
|
||||
|
||||
margin-inline-start: $-ghostGap;
|
||||
width: calc(100% - #{$-ghostGap});
|
||||
}
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
background: linear-gradient(to right, transparent var(--low), var(--primary) var(--low) var(--high), transparent 0) no-repeat 50% / 100% 100%;
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
background: linear-gradient(to right, transparent var(--low), var(--primary) var(--low) var(--high), transparent 0) no-repeat 50% / 100% 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
border-color: transparent; /* needed to switch Firefox to "styleable" control */
|
||||
}
|
||||
|
||||
&.ghost {
|
||||
border-radius: 45%;
|
||||
position: relative;
|
||||
background: var(--track-background);
|
||||
--track-background: linear-gradient(to right, transparent var(--low), #{theme-color('primary')} var(--low) var(--high), transparent 0) no-repeat 50% / 100% 35%;
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
background: var(--track-background);
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
background: var(--track-background);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.multirange-wrapper {
|
||||
position: relative;
|
||||
margin: 3rem 0;
|
||||
visibility: hidden;
|
||||
|
||||
input[type="range"][multiple] {
|
||||
visibility: initial;
|
||||
}
|
||||
|
||||
[x-out-of-boundaries] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tip-locator {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user