2022-03-06 19:14:53 +01:00
|
|
|
/**
|
|
|
|
* EGroupware eTemplate2 - Number widget (WebComponent)
|
|
|
|
*
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package etemplate
|
|
|
|
* @subpackage api
|
|
|
|
* @link https://www.egroupware.org
|
|
|
|
* @author Ralf Becker
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {Et2Textbox} from "./Et2Textbox";
|
2023-09-13 19:55:33 +02:00
|
|
|
import {css, html, render} from "lit";
|
2022-03-06 19:14:53 +01:00
|
|
|
|
|
|
|
export class Et2Number extends Et2Textbox
|
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
static get styles()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
...(super.styles ? (Array.isArray(super.styles) ? super.styles : [super.styles]) : []),
|
|
|
|
css`
|
|
|
|
/* Scroll buttons */
|
|
|
|
|
|
|
|
:host(:hover) ::slotted(et2-button-scroll) {
|
|
|
|
display: flex;
|
|
|
|
}
|
|
|
|
|
|
|
|
::slotted(et2-button-scroll) {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.input--medium .input__suffix ::slotted(et2-button-scroll) {
|
|
|
|
padding: 0px;
|
|
|
|
}
|
|
|
|
|
|
|
|
`,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2022-03-06 19:14:53 +01:00
|
|
|
static get properties()
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
...super.properties,
|
|
|
|
/**
|
|
|
|
* Minimum value
|
|
|
|
*/
|
|
|
|
min: Number,
|
|
|
|
/**
|
|
|
|
* Maximum value
|
|
|
|
*/
|
|
|
|
max: Number,
|
|
|
|
/**
|
|
|
|
* Step value
|
|
|
|
*/
|
|
|
|
step: Number,
|
|
|
|
/**
|
|
|
|
* Precision of float number or 0 for integer
|
|
|
|
*/
|
|
|
|
precision: Number,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-22 17:59:05 +01:00
|
|
|
|
|
|
|
constructor()
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.handleScroll = this.handleScroll.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
connectedCallback()
|
|
|
|
{
|
|
|
|
super.connectedCallback();
|
|
|
|
|
|
|
|
// Add spinners
|
|
|
|
render(this._incrementButtonTemplate(), this);
|
|
|
|
}
|
|
|
|
|
2022-03-06 19:14:53 +01:00
|
|
|
transformAttributes(attrs)
|
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
if(attrs.precision === 0 && typeof attrs.step === 'undefined')
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
|
|
|
attrs.step = 1;
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
if(typeof attrs.validator === 'undefined')
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
|
|
|
attrs.validator = attrs.precision === 0 ? '/^-?[0-9]*$/' : '/^-?[0-9]*[,.]?[0-9]*$/';
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
attrs.inputmode = "numeric";
|
2022-03-06 19:14:53 +01:00
|
|
|
super.transformAttributes(attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-07-22 09:03:54 +02:00
|
|
|
* Somehow the setter is not inherited from the parent, not defining it here leaves the validator a string!
|
2022-03-06 19:14:53 +01:00
|
|
|
*
|
|
|
|
* @param regexp
|
|
|
|
*/
|
|
|
|
set validator(regexp)
|
|
|
|
{
|
|
|
|
super.validator = regexp;
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
|
2022-03-06 19:14:53 +01:00
|
|
|
get validator()
|
|
|
|
{
|
|
|
|
return super.validator;
|
|
|
|
}
|
|
|
|
|
2023-03-22 17:59:05 +01:00
|
|
|
handleInput()
|
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
handleBlur()
|
|
|
|
{
|
|
|
|
this.value = this.input.value;
|
|
|
|
super.handleBlur();
|
|
|
|
}
|
|
|
|
|
|
|
|
set value(val)
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
if("" + val !== "")
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
// use decimal separator from user prefs
|
|
|
|
const format = this.egw().preference('number_format');
|
|
|
|
const sep = format ? format[0] : '.';
|
|
|
|
|
|
|
|
// Remove separator so parseFloat works
|
2023-04-24 17:42:09 +02:00
|
|
|
if(typeof val === 'string')
|
2023-03-22 17:59:05 +01:00
|
|
|
{
|
2023-04-24 17:42:09 +02:00
|
|
|
val = val.replace(",", '.');
|
2023-03-22 17:59:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(typeof this.precision !== 'undefined')
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
|
|
|
val = parseFloat(val).toFixed(this.precision);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
val = parseFloat(val);
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
// Put separator back in, if different
|
2022-03-06 19:14:53 +01:00
|
|
|
if(typeof val === 'string' && format && sep && sep !== '.')
|
|
|
|
{
|
|
|
|
val = val.replace('.', sep);
|
|
|
|
}
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
super.value = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
get value()
|
|
|
|
{
|
|
|
|
return super.value;
|
2022-03-06 19:14:53 +01:00
|
|
|
}
|
|
|
|
|
2023-03-22 17:59:05 +01:00
|
|
|
getValue() : any
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
// Needs to be string to pass validator
|
|
|
|
return "" + this.valueAsNumber;
|
|
|
|
}
|
2022-03-06 19:14:53 +01:00
|
|
|
|
2023-03-22 17:59:05 +01:00
|
|
|
get valueAsNumber() : number
|
|
|
|
{
|
|
|
|
let val = this.__value;
|
|
|
|
|
|
|
|
if("" + val !== "")
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
// remove decimal separator from user prefs
|
|
|
|
const format = this.egw().preference('number_format');
|
|
|
|
const sep = format ? format[0] : '.';
|
|
|
|
if(typeof val === 'string' && format && sep && sep !== '.')
|
2022-03-06 19:14:53 +01:00
|
|
|
{
|
2023-03-22 17:59:05 +01:00
|
|
|
val = val.replace(sep, '.');
|
|
|
|
}
|
|
|
|
if(typeof this.precision !== 'undefined')
|
|
|
|
{
|
|
|
|
val = parseFloat(parseFloat(val).toFixed(this.precision));
|
2022-03-06 19:14:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
val = parseFloat(val);
|
|
|
|
}
|
|
|
|
}
|
2023-03-22 17:59:05 +01:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
private handleScroll(e)
|
|
|
|
{
|
|
|
|
const old_value = this.value;
|
2024-01-08 22:32:25 +01:00
|
|
|
const min = parseFloat(this.min ?? Number.MIN_SAFE_INTEGER);
|
|
|
|
const max = parseFloat(this.max ?? Number.MAX_SAFE_INTEGER);
|
|
|
|
this.value = "" + Math.min(Math.max(this.valueAsNumber + e.detail * (parseFloat(this.step) || 1), min), max);
|
2023-03-22 17:59:05 +01:00
|
|
|
this.dispatchEvent(new CustomEvent("sl-change", {bubbles: true}));
|
|
|
|
this.requestUpdate("value", old_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected _incrementButtonTemplate()
|
|
|
|
{
|
|
|
|
// No increment buttons on mobile
|
|
|
|
if(typeof egwIsMobile == "function" && egwIsMobile())
|
|
|
|
{
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return html`
|
|
|
|
<et2-button-scroll class="et2-number__scrollbuttons" slot="suffix"
|
|
|
|
part="scroll"
|
|
|
|
@et2-scroll=${this.handleScroll}></et2-button-scroll>`;
|
2022-03-06 19:14:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// @ts-ignore TypeScript is not recognizing that Et2Textbox is a LitElement
|
|
|
|
customElements.define("et2-number", Et2Number);
|