UNPKG

@eclipse-scout/core

Version:
179 lines (145 loc) 5.6 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ import {aria, fields, FormField, HtmlComponent, InitModelOf, NumberField, objects, PropertyChangeEvent, scout, Slider, SliderFieldEventMap, SliderFieldLayout, SliderFieldModel, ValueField} from '../../../index'; export class SliderField extends NumberField implements SliderFieldModel { declare model: SliderFieldModel; declare eventMap: SliderFieldEventMap; step: number; valueEditable: boolean; sliderTabbable: boolean; slider: Slider; $valueLabel: JQuery; fieldHtmlComp: HtmlComponent; protected _syncingValue = false; constructor() { super(); this.fieldHtmlComp = null; this.$valueLabel = null; this.fieldStyle = FormField.FieldStyle.CLASSIC; this.clearable = ValueField.Clearable.NEVER; this.gridDataHints.horizontalAlignment = -1; this.updateDisplayTextOnModify = true; this.minValue = 0; this.maxValue = 100; this.step = 1; this.valueEditable = true; this.sliderTabbable = true; } protected override _init(model: InitModelOf<this>) { super._init(model); this.slider = scout.create(Slider, { parent: this, minValue: this.minValue, maxValue: this.maxValue, value: this.value, step: this.step, tabbable: this.sliderTabbable, valueEditable: this.valueEditable }); this.slider.on('propertyChange', this._onSliderPropertyChange.bind(this)); this.on('propertyChange:displayText', event => this._syncDisplayTextToSlider(event.newValue)); } protected override _render() { this.addContainer(this.$parent, 'slider-field', new SliderFieldLayout(this)); this.addLabel(); this.addMandatoryIndicator(); let $fieldContainer = this.$container.appendDiv(); this.fieldHtmlComp = HtmlComponent.install($fieldContainer, this.session); this.slider.render($fieldContainer); aria.linkElementWithLabel(this.slider.$container, this.$label); let $field = fields.makeTextField($fieldContainer, 'field'); $fieldContainer.append($field); this.$valueLabel = $fieldContainer.appendDiv('slider-value'); this._updateValueLabel(); this.addFieldContainer($fieldContainer); this.addField($field); this.addStatus(); } protected override _remove() { super._remove(); this.$valueLabel = null; this.fieldHtmlComp = null; } protected override _renderProperties() { super._renderProperties(); this._renderValueEditable(); } protected override _renderClearable() { // nop (slider value should never be clearable) } setStep(step: number) { this.setProperty('step', step); } protected _setStep(step: number) { this._setProperty('step', step); if (!objects.isNullOrUndefined(step)) { this.slider.setStep(step); } } setValueEditable(valueEditable: boolean) { this.setProperty('valueEditable', valueEditable); } protected _renderValueEditable() { this.$fieldContainer.toggleClass('value-editable', !!this.valueEditable); this.$field.setVisible(this.valueEditable); this.$valueLabel.setVisible(!this.valueEditable); this.fieldHtmlComp.invalidateLayoutTree(false); } setSliderTabbable(sliderTabbable: boolean) { this.setProperty('sliderTabbable', sliderTabbable); } protected _setSliderTabbable(sliderTabbable: boolean) { this._setProperty('sliderTabbable', sliderTabbable); this.slider.setTabbable(sliderTabbable); } protected override _setMinValue(minValue: number) { super._setMinValue(minValue); // This null check is required. this.slider is created after super._init is called. Since minValue is a property from NumberField it will be set in super.init which would lead to a NPE. if (this.slider) { this.slider.setMinValue(minValue); } } protected override _setMaxValue(maxValue: number) { super._setMaxValue(maxValue); // This null check is required. this.slider is created after super._init is called. Since maxValue is a property from NumberField it will be set in super.init which would lead to a NPE. if (this.slider) { this.slider.setMaxValue(maxValue); } } protected override _validateValue(value: number): number { return super._validateValue(scout.nvl(value, this.minValue)); } protected _onSliderPropertyChange(event: PropertyChangeEvent) { if (event.propertyName === 'value' && !this._syncingValue) { this.setValue(event.newValue); } else if (event.propertyName === 'focused') { // When the slider is tabbable, it will receive the focus when the user clicks it. This is needed for the keystrokes. // However, we only want to set the 'focused' property of the slider field accordingly (to change the color of the label) // when the focus happens during keyboard navigation. if (!event.newValue || this.slider.$container?.hasClass('keyboard-navigation')) { this.setFocused(event.newValue); } } } protected _syncDisplayTextToSlider(displayText: string) { try { this._syncingValue = true; this.slider.setValue(this.parseValue(displayText)); this._updateValueLabel(); } catch (error) { // nop } finally { this._syncingValue = false; } } protected _updateValueLabel() { this.$valueLabel?.text(this.displayText); } }