diff --git a/documentation/behaviour-option.php b/documentation/behaviour-option.php index c9df959..e242046 100644 --- a/documentation/behaviour-option.php +++ b/documentation/behaviour-option.php @@ -10,9 +10,9 @@
noUiSlider offers several ways to handle user interaction. The range can be made draggable, or handles can move to tapped positions. All these effects are optional, and can be enable by adding their keyword to the behaviour
option.
noUiSlider offers several ways to handle user interaction. The range can be made draggable, or handles can move to tapped positions. All these effects are optional, and can be enabled by adding their keyword to the behaviour
option.
This option accepts a "-"
separated list of "drag"
, "drag-all"
, "tap"
, "fixed"
, "snap"
, "unconstrained"
or "none"
.
This option accepts a "-"
separated list of "drag"
, "drag-all"
, "tap"
, "fixed"
, "snap"
, "unconstrained"
, "invert-connects"
or "none"
.
With this option set, connects invert when handles pass each other.
-Requires the unconstrained
behaviour and the connect
option.
Requires the unconstrained
behaviour and the connect
option. This option is only applicable for sliders with two handles.
noUiSlider has an update method that can change the 'margin'
, 'padding'
, 'limit'
, 'step'
, 'range'
, 'pips'
, 'tooltips'
, 'animate'
and 'snap'
options.
noUiSlider has an update method that can change the 'margin'
, 'padding'
, 'limit'
, 'step'
, 'range'
, 'pips'
, 'tooltips'
, 'connect'
, 'animate'
and 'snap'
options.
All other options require changes to the slider's HTML or event bindings.
diff --git a/src/nouislider.ts b/src/nouislider.ts index 5978522..e7ee831 100644 --- a/src/nouislider.ts +++ b/src/nouislider.ts @@ -1150,6 +1150,10 @@ function testBehaviour(parsed: ParsedOptions, entry: unknown): void { testMargin(parsed, parsed.start[1] - parsed.start[0]); } + if (invertConnects && parsed.handles !== 2) { + throw new Error("noUiSlider: 'invert-connects' behaviour must be used with 2 handles"); + } + if (unconstrained && (parsed.margin || parsed.limit)) { throw new Error("noUiSlider: 'unconstrained' behaviour cannot be used with margin or limit"); } @@ -1383,7 +1387,7 @@ function scope(target: TargetElement, options: ParsedOptions, originalOptions: O const scope_HandleNumbers: number[] = []; let scope_ActiveHandlesCount = 0; const scope_Events: { [key: string]: EventCallback[] } = {}; - let scope_ConnectsInverted: boolean = false; + let scope_ConnectsInverted = false; // Document Nodes const scope_Document = target.ownerDocument; @@ -2671,23 +2675,27 @@ function scope(target: TargetElement, options: ParsedOptions, originalOptions: O (scope_Handles[handleNumber].style as CSSStyleDeclarationIE10)[options.transformRule] = translateRule; - if( - options.events.invertConnects && - // sanity check for at least 2 handles - scope_Locations.length > 1 && + // sanity check for at least 2 handles (e.g. during setup) + if (options.events.invertConnects && scope_Locations.length > 1) { // check if handles passed each other, but don't match the ConnectsInverted state - scope_ConnectsInverted !== !scope_Locations.every( - (position: number, index: number, locations: number[]): boolean => + const handlesAreInOrder = scope_Locations.every( + (position: number, index: number, locations: number[]): boolean => index === 0 || position >= locations[index - 1] - )) { - // when invertConnects is set, automatically invert connects when handles pass each other + ); + + if (scope_ConnectsInverted !== !handlesAreInOrder) { + // invert connects when handles pass each other invertConnects(); + + // invertConnects already updates all connect elements + return; } + } updateConnect(handleNumber); updateConnect(handleNumber + 1); - - if(scope_ConnectsInverted) { + + if (scope_ConnectsInverted) { // When connects are inverted, we also have to update adjacent connects updateConnect(handleNumber - 1); updateConnect(handleNumber + 2); @@ -2744,9 +2752,10 @@ function scope(target: TargetElement, options: ParsedOptions, originalOptions: O } // Create a copy of locations, so we can sort them for the local scope logic - let locations = scope_Locations.slice(); + const locations = scope_Locations.slice(); + if (scope_ConnectsInverted) { - locations.sort(function(a, b) { + locations.sort(function (a, b) { return a - b; }); } @@ -3048,30 +3057,36 @@ function scope(target: TargetElement, options: ParsedOptions, originalOptions: O // Update connects only if it was set if (optionsToUpdate.connect) { - // IE supported way of removing children including event handlers - while (scope_ConnectBase.firstChild) { - scope_ConnectBase.removeChild(scope_ConnectBase.firstChild); - } + updateConnectOption(); + } + } - // Adding new connects according to the new connect options - for (let i = 0; i <= options.handles; i++) { - scope_Connects[i] = addConnect(scope_ConnectBase, options.connect[i]); - updateConnect(i); - } + function updateConnectOption() { + // IE supported way of removing children including event handlers + while (scope_ConnectBase.firstChild) { + scope_ConnectBase.removeChild(scope_ConnectBase.firstChild); + } - // readding drag events for the new connect elements - // to ignore the other events we have to negate the 'if (!behaviour.fixed)' check - bindSliderEvents({ drag: options.events.drag, fixed: true } as Behaviour); + // Adding new connects according to the new connect options + for (let i = 0; i <= options.handles; i++) { + scope_Connects[i] = addConnect(scope_ConnectBase, options.connect[i]); + updateConnect(i); } + + // re-adding drag events for the new connect elements + // to ignore the other events we have to negate the 'if (!behaviour.fixed)' check + bindSliderEvents({ drag: options.events.drag, fixed: true } as Behaviour); } // Invert options for connect handles function invertConnects() { scope_ConnectsInverted = !scope_ConnectsInverted; - updateOptions({ + testConnect( + options, // inverse the connect boolean array - connect: options.connect.map((b: boolean) => !b) - }, false); // don't fire the set event + options.connect.map((b: boolean) => !b) + ); + updateConnectOption(); } // Initialization steps