UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

137 lines 5.33 kB
import * as numbro from "@bokeh/numbro"; import { InputWidgetView, InputWidget } from "./input_widget"; import { TickFormatter } from "../formatters/tick_formatter"; import { input } from "../../core/dom"; import { isString } from "../../core/util/types"; import { assert } from "../../core/util/assert"; import * as inputs from "../../styles/widgets/inputs.css"; const int_regex = /^[-+]?\d*$/; const float_regex = /^[-+]?\d*\.?\d*(?:(?:\d|\d.)[eE][-+]?)*\d*$/; export class NumericInputView extends InputWidgetView { static __name__ = "NumericInputView"; old_value; connect_signals() { super.connect_signals(); this.connect(this.model.properties.name.change, () => this.input_el.name = this.model.name ?? ""); this.connect(this.model.properties.value.change, () => { this.input_el.value = this.format_value; this.old_value = this.input_el.value; }); this.connect(this.model.properties.low.change, () => { const { value, low, high } = this.model; if (low != null && high != null) { assert(low <= high, "Invalid bounds, low must be inferior to high"); } if (value != null && low != null && value < low) { this.model.value = low; } }); this.connect(this.model.properties.high.change, () => { const { value, low, high } = this.model; if (low != null && high != null) { assert(high >= low, "Invalid bounds, high must be superior to low"); } if (value != null && high != null && value > high) { this.model.value = high; } }); this.connect(this.model.properties.high.change, () => this.input_el.placeholder = this.model.placeholder); this.connect(this.model.properties.disabled.change, () => this.input_el.disabled = this.model.disabled); this.connect(this.model.properties.placeholder.change, () => this.input_el.placeholder = this.model.placeholder); } get format_value() { return this.model.value != null ? this.model.pretty(this.model.value) : ""; } _set_input_filter(inputFilter) { this.input_el.addEventListener("input", () => { const { selectionStart, selectionEnd } = this.input_el; if (!inputFilter(this.input_el.value)) { // an invalid character is entered const difflen = this.old_value.length - this.input_el.value.length; this.input_el.value = this.old_value; if (selectionStart != null && selectionEnd != null) { this.input_el.setSelectionRange(selectionStart - 1, selectionEnd + difflen); } } else { this.old_value = this.input_el.value; } }); } _render_input() { return this.input_el = input({ type: "text", class: inputs.input, name: this.model.name, value: this.format_value, disabled: this.model.disabled, placeholder: this.model.placeholder, }); } render() { super.render(); this.old_value = this.format_value; this.set_input_filter(); this.input_el.addEventListener("change", () => this.change_input()); this.input_el.addEventListener("focusout", () => this.input_el.value = this.format_value); } set_input_filter() { const regex = this.model.mode == "int" ? int_regex : float_regex; this._set_input_filter((value) => regex.test(value)); } bound_value(value) { let output = value; const { low, high } = this.model; output = low != null ? Math.max(low, output) : output; output = high != null ? Math.min(high, output) : output; return output; } get value() { let value = this.input_el.value != "" ? Number(this.input_el.value) : null; if (value != null) { value = this.bound_value(value); } return value; } change_input() { if (this.value == null) { this.model.value = null; } else if (!Number.isNaN(this.value)) { this.model.value = this.value; } } } export class NumericInput extends InputWidget { static __name__ = "NumericInput"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = NumericInputView; this.define(({ Float, Str, Enum, Ref, Or, Nullable }) => ({ value: [Nullable(Float), null], placeholder: [Str, ""], mode: [Enum("int", "float"), "int"], format: [Nullable(Or(Str, Ref(TickFormatter))), null], low: [Nullable(Float), null], high: [Nullable(Float), null], })); } _formatter(value, format) { if (isString(format)) { return numbro.format(value, format); } else { return format.doFormat([value], { loc: 0 })[0]; } } pretty(value) { if (this.format != null) { return this._formatter(value, this.format); } else { return `${value}`; } } } //# sourceMappingURL=numeric_input.js.map