Start on converting date range to webcomponent

This commit is contained in:
nathan 2022-12-20 14:04:45 -07:00
parent 87bf5af8e4
commit 098fe647dc
3 changed files with 336 additions and 4 deletions

View File

@ -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)
}

View 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);

View File

@ -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';