forked from extern/egroupware
Start on converting date range to webcomponent
This commit is contained in:
parent
87bf5af8e4
commit
098fe647dc
@ -518,7 +518,7 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
// Remove Lion's inert attribute so we can work in Et2Dialog
|
||||
options.onOpen = [() =>
|
||||
{
|
||||
this._instance.calendarContainer.removeAttribute("inert")
|
||||
this._instance.calendarContainer?.removeAttribute("inert")
|
||||
}];
|
||||
|
||||
return options;
|
||||
@ -682,7 +682,7 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
let parsedDate = null
|
||||
try
|
||||
{
|
||||
parsedDate = this._instance.parseDate(value, this._instance.config.altFormat)
|
||||
parsedDate = this._instance.parseDate(value, this.getOptions().altFormat)
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
@ -691,10 +691,10 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
// If they typed a valid date/time, try to update flatpickr
|
||||
if(parsedDate)
|
||||
{
|
||||
const formattedDate = this._instance.formatDate(parsedDate, this._instance.config.altFormat)
|
||||
const formattedDate = this._instance.formatDate(parsedDate, this.getOptions().altFormat)
|
||||
if(value === formattedDate &&
|
||||
// Avoid infinite loop of setting the same value back triggering another change
|
||||
this._instance.input.value !== this._instance.formatDate(parsedDate, this._instance.config.dateFormat))
|
||||
this._instance.input.value !== this._instance.formatDate(parsedDate, this.getOptions().dateFormat))
|
||||
{
|
||||
this._instance.setDate(value, true, this._instance.config.altFormat)
|
||||
}
|
||||
|
331
api/js/etemplate/Et2Date/Et2DateRange.ts
Normal file
331
api/js/etemplate/Et2Date/Et2DateRange.ts
Normal file
@ -0,0 +1,331 @@
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {FormControlMixin} from "@lion/form-core";
|
||||
import {classMap, css, html, ifDefined, LitElement, render, TemplateResult} from "@lion/core";
|
||||
import shoelace from "../Styles/shoelace";
|
||||
import {dateStyles} from "./DateStyles";
|
||||
import flatpickr from "flatpickr";
|
||||
import "flatpickr/dist/plugins/rangePlugin";
|
||||
import {Et2Date, formatDate, parseDate} from "./Et2Date";
|
||||
import {egw} from "../../jsapi/egw_global";
|
||||
|
||||
/**
|
||||
* Display a time duration (eg: 3 days, 6 hours)
|
||||
*
|
||||
* If not specified, the time is in assumed to be minutes and will be displayed with a calculated unit
|
||||
* but this can be specified with the properties.
|
||||
*/
|
||||
export class Et2DateRange extends Et2InputWidget(FormControlMixin(LitElement))
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
...super.styles,
|
||||
shoelace,
|
||||
...dateStyles,
|
||||
css`
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: baseline;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
static get properties()
|
||||
{
|
||||
return {
|
||||
...super.properties,
|
||||
/**
|
||||
* Is the date range relative (this week) or absolute (2016-02-15 - 2016-02-21). This will affect the value returned.
|
||||
*/
|
||||
relative: {type: Boolean},
|
||||
|
||||
/**
|
||||
* An object with keys 'from' and 'to' for absolute ranges, or a relative range string
|
||||
*/
|
||||
value: {type: Object}
|
||||
}
|
||||
}
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
getUpdateComplete() {
|
||||
const p = super.getUpdateComplete();
|
||||
if(!this.relative)
|
||||
{
|
||||
p.then(() => this.setupFlatpickr());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
protected setupFlatpickr()
|
||||
{
|
||||
if(!this.fromElement || !this.fromElement._inputElement) return;
|
||||
|
||||
this.fromElement._instance = flatpickr((<Et2Date>this.fromElement).findInputField(), {
|
||||
...(<Et2Date>this.fromElement).getOptions(),
|
||||
...{
|
||||
plugins: [
|
||||
// @ts-ignore ts can't find rangePlugin in IDE
|
||||
rangePlugin({
|
||||
input: this.toElement
|
||||
})
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const hasLabel = this.label ? true : false
|
||||
const hasHelpText = this.helpText ? true : false;
|
||||
|
||||
return html`
|
||||
<div part="form-control" class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--has-label': this.label.split("%")[0] || false
|
||||
})}>
|
||||
<div class="form-control__label" part="form-control-label">
|
||||
<label
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
for="input"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-control-input" part="form-control-input">${this._inputGroupTemplate()}</div>
|
||||
<slot
|
||||
name="help-text"
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
>
|
||||
${this.helpText}
|
||||
</slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected _inputGroupTemplate() : TemplateResult
|
||||
{
|
||||
return html`
|
||||
<slot name="prefix" part="prefix" class="input__prefix"></slot>
|
||||
${this.relative ? this._inputRelativeTemplate() : this._inputAbsoluteTemplate()}
|
||||
<slot name="suffix" part="suffix" class="input__suffix"></slot>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're doing a relative date range, show the relative options
|
||||
* @returns {TemplateResult}
|
||||
* @protected
|
||||
*/
|
||||
protected _inputRelativeTemplate() : TemplateResult
|
||||
{
|
||||
return html`<et2-select
|
||||
name="relative"
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.required}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
.select_options=${Et2DateRange.relative_dates}></et2-select>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're doing an absolute date range, we need start and end dates
|
||||
*
|
||||
* @returns {TemplateResult}
|
||||
* @protected
|
||||
*/
|
||||
protected _inputAbsoluteTemplate() : TemplateResult
|
||||
{
|
||||
return html`
|
||||
<et2-date
|
||||
name="from"
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.required}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
defaultDate=${ifDefined(this.value?.from)}
|
||||
></et2-date>
|
||||
<et2-textbox
|
||||
name="to"
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.required}
|
||||
placeholder=${ifDefined(this.placeholder)}
|
||||
value=${ifDefined(this.value?.to)}
|
||||
></et2-textbox>
|
||||
`;
|
||||
}
|
||||
|
||||
public get fromElement() : HTMLElement
|
||||
{
|
||||
return this.shadowRoot?.querySelector("[name='from']");
|
||||
}
|
||||
public get toElement() : HTMLElement
|
||||
{
|
||||
return this.shadowRoot?.querySelector("[name='to']");
|
||||
}
|
||||
public get relativeElement() : HTMLElement
|
||||
{
|
||||
return this.shadowRoot?.querySelector("[name='relative']");
|
||||
}
|
||||
|
||||
public get value() : {to:string,from:string}|string
|
||||
{
|
||||
if(this.relative)
|
||||
{
|
||||
return this.relativeElement?.value || "";
|
||||
}
|
||||
let val = {
|
||||
from: this.fromElement?.findInputField()?.value || null,
|
||||
to: this.toElement?.value || null
|
||||
}
|
||||
if(val.from) val.from = formatDate(parseDate(val.from), {dateFormat:"Y-m-dT00:00:00Z"});
|
||||
if(val.to) val.to = formatDate(parseDate(val.to), {dateFormat:"Y-m-dT00:00:00Z"});
|
||||
return (val.from || val.to) ? val : null;
|
||||
}
|
||||
|
||||
public set value(new_value : {to:string,from:string}|string)
|
||||
{
|
||||
if(this.relative)
|
||||
{
|
||||
this.relativeElement.value = new_value;
|
||||
}
|
||||
else if (this.fromElement && this.toElement)
|
||||
{
|
||||
this.fromElement._instance.setDate( [new_value?.from, new_value?.to],true);
|
||||
}
|
||||
}
|
||||
|
||||
// Class Constants
|
||||
static readonly relative_dates = [
|
||||
// Start and end are relative offsets, see et2_date.set_min()
|
||||
// or Date objects
|
||||
{
|
||||
value: 'Today',
|
||||
label: egw.lang('Today'),
|
||||
from(date) {return date;},
|
||||
to(date) {return date;}
|
||||
},
|
||||
{
|
||||
label: egw.lang('Yesterday'),
|
||||
value: 'Yesterday',
|
||||
from(date) {
|
||||
date.setUTCDate(date.getUTCDate() - 1);
|
||||
return date;
|
||||
},
|
||||
to: ''
|
||||
},
|
||||
{
|
||||
label: egw.lang('This week'),
|
||||
value: 'This week',
|
||||
from(date) {return egw.week_start(date);},
|
||||
to(date) {
|
||||
date.setUTCDate(date.getUTCDate() + 6);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('Last week'),
|
||||
value: 'Last week',
|
||||
from(date) {
|
||||
var d = egw.week_start(date);
|
||||
d.setUTCDate(d.getUTCDate() - 7);
|
||||
return d;
|
||||
},
|
||||
to(date) {
|
||||
date.setUTCDate(date.getUTCDate() + 6);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('This month'),
|
||||
value: 'This month',
|
||||
from(date)
|
||||
{
|
||||
date.setUTCDate(1);
|
||||
return date;
|
||||
},
|
||||
to(date)
|
||||
{
|
||||
date.setUTCMonth(date.getUTCMonth()+1);
|
||||
date.setUTCDate(0);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('Last month'),
|
||||
value: 'Last month',
|
||||
from(date)
|
||||
{
|
||||
date.setUTCMonth(date.getUTCMonth() - 1);
|
||||
date.setUTCDate(1);
|
||||
return date;
|
||||
},
|
||||
to(date)
|
||||
{
|
||||
date.setUTCMonth(date.getUTCMonth()+1);
|
||||
date.setUTCDate(0);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('Last 3 months'),
|
||||
value: 'Last 3 months',
|
||||
from(date)
|
||||
{
|
||||
date.setUTCMonth(date.getUTCMonth() - 2);
|
||||
date.setUTCDate(1);
|
||||
return date;
|
||||
},
|
||||
to(date)
|
||||
{
|
||||
date.setUTCMonth(date.getUTCMonth()+3);
|
||||
date.setUTCDate(0);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('This year'),
|
||||
value: 'This year',
|
||||
from(d) {
|
||||
d.setUTCMonth(0);
|
||||
d.setUTCDate(1);
|
||||
return d;
|
||||
},
|
||||
to(d) {
|
||||
d.setUTCMonth(11);
|
||||
d.setUTCDate(31);
|
||||
return d;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: egw.lang('Last year'),
|
||||
value: 'Last year',
|
||||
from(d) {
|
||||
d.setUTCMonth(0);
|
||||
d.setUTCDate(1);
|
||||
d.setUTCYear(d.getUTCYear() - 1);
|
||||
return d;
|
||||
},
|
||||
to(d) {
|
||||
d.setUTCMonth(11);
|
||||
d.setUTCDate(31);
|
||||
d.setUTCYear(d.getUTCYear() - 1);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
customElements.define("et2-date-range", Et2DateRange);
|
@ -37,6 +37,7 @@ import './Et2Checkbox/Et2CheckboxReadonly';
|
||||
import './Et2Date/Et2Date';
|
||||
import './Et2Date/Et2DateDuration';
|
||||
import './Et2Date/Et2DateDurationReadonly';
|
||||
import './Et2Date/Et2DateRange';
|
||||
import './Et2Date/Et2DateReadonly';
|
||||
import './Et2Date/Et2DateSinceReadonly';
|
||||
import './Et2Date/Et2DateTime';
|
||||
|
Loading…
Reference in New Issue
Block a user