mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
Remove Lion
This commit is contained in:
parent
2b90e9fc8d
commit
ba744d3292
@ -20,7 +20,7 @@ import {et2_selectbox} from "../../api/js/etemplate/et2_widget_selectbox";
|
||||
import {fetchAll, nm_action, nm_compare_field} from "../../api/js/etemplate/et2_extension_nextmatch_actions";
|
||||
import "./CRM";
|
||||
import {egw} from "../../api/js/jsapi/egw_global";
|
||||
import {LitElement} from "@lion/core";
|
||||
import {LitElement} from "lit";
|
||||
import {Et2SelectCountry} from "../../api/js/etemplate/Et2Select/Select/Et2SelectCountry";
|
||||
|
||||
import {Et2SelectState} from "../../api/js/etemplate/Et2Select/Select/Et2SelectState";
|
||||
|
@ -17,13 +17,13 @@ import {etemplate2} from "../../api/js/etemplate/etemplate2";
|
||||
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
|
||||
import {egw} from "../../api/js/jsapi/egw_global.js";
|
||||
import {egwAction, egwActionObject} from '../../api/js/egw_action/egw_action';
|
||||
import {LitElement} from "@lion/core";
|
||||
import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch";
|
||||
import {et2_DOMWidget} from "../../api/js/etemplate/et2_core_DOMWidget";
|
||||
import {Et2SelectAccount} from "../../api/js/etemplate/Et2Select/Select/Et2SelectAccount";
|
||||
import {EgwAction} from "../../api/js/egw_action/EgwAction";
|
||||
import {EgwActionObject} from "../../api/js/egw_action/EgwActionObject";
|
||||
import type {Et2Button} from "../../api/js/etemplate/Et2Button/Et2Button";
|
||||
import {LitElement} from "lit";
|
||||
|
||||
/**
|
||||
* UI for Admin
|
||||
|
@ -52,7 +52,6 @@ export class Et2Avatar extends Et2Widget(SlAvatar) implements et2_IDetachedDOM
|
||||
/**
|
||||
* The label of the image
|
||||
* Actually not used as label, but we put it as title
|
||||
* Added here as there's no Lion parent
|
||||
*/
|
||||
label: {
|
||||
type: String
|
||||
|
@ -9,20 +9,19 @@
|
||||
*/
|
||||
|
||||
|
||||
import {css, html} from "lit";
|
||||
import {css, html, nothing} from "lit";
|
||||
import 'lit-flatpickr';
|
||||
import {dateStyles} from "./DateStyles";
|
||||
import type {Instance} from 'flatpickr/dist/types/instance';
|
||||
import {default as scrollPlugin} from "flatpickr/dist/plugins/scrollPlugin.js";
|
||||
import {default as ShortcutButtonsPlugin} from "shortcut-buttons-flatpickr/dist/shortcut-buttons-flatpickr";
|
||||
import {default as ShortcutButtonsPlugin} from "shortcut-buttons-flatpickr/dist/shortcut-buttons-flatpickr.js";
|
||||
import flatpickr from "flatpickr";
|
||||
import {egw} from "../../jsapi/egw_global";
|
||||
import type {HTMLElementWithValue} from "@lion/form-core/types/FormControlMixinTypes";
|
||||
import {Et2Textbox} from "../Et2Textbox/Et2Textbox";
|
||||
import {FormControlMixin} from "@lion/form-core";
|
||||
import {LitFlatpickr} from "lit-flatpickr";
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import shoelace from "../Styles/shoelace";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
|
||||
// list of existing localizations from node_modules/flatpicker/dist/l10n directory:
|
||||
const l10n = [
|
||||
@ -224,7 +223,7 @@ export function parseDateTime(dateTimeString)
|
||||
* Format dates according to user preference
|
||||
*
|
||||
* @param {Date} date
|
||||
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available
|
||||
* @param [options] Intl options are available
|
||||
* set 'dateFormat': "Y-m-d" to specify a particular format
|
||||
* @returns {string}
|
||||
*/
|
||||
@ -261,7 +260,7 @@ export function formatDate(date : Date, options = {dateFormat: ""}) : string
|
||||
* Format dates according to user preference
|
||||
*
|
||||
* @param {Date} date
|
||||
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available
|
||||
* @param [options] Intl options are available
|
||||
* set 'timeFormat': "12" to specify a particular format
|
||||
* @returns {string}
|
||||
*/
|
||||
@ -305,8 +304,7 @@ export function formatDateTime(date : Date, options = {dateFormat: "", timeForma
|
||||
return formatDate(date, options) + " " + formatTime(date, options);
|
||||
}
|
||||
|
||||
// !!! ValidateMixin !!!
|
||||
export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
export class Et2Date extends Et2InputWidget(LitFlatpickr)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
@ -554,7 +552,7 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
options.onChange = this._updateValueOnChange;
|
||||
options.onReady = this._onReady;
|
||||
|
||||
// Remove Lion's inert attribute so we can work in Et2Dialog
|
||||
// Remove inert attribute so we can work in Et2Dialog
|
||||
options.onOpen = [() =>
|
||||
{
|
||||
this._instance.calendarContainer?.removeAttribute("inert")
|
||||
@ -968,17 +966,17 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
* This is an et2-textbox, which causes some problems with flatpickr
|
||||
* @protected
|
||||
*/
|
||||
get _inputNode() : HTMLElementWithValue
|
||||
get _inputNode() : Et2Textbox
|
||||
{
|
||||
return this.querySelector('[slot="input"]');
|
||||
return this.shadowRoot?.querySelector('et2-textbox');
|
||||
}
|
||||
|
||||
/**
|
||||
* The holder of value for flatpickr
|
||||
*/
|
||||
get _valueNode() : HTMLElementWithValue
|
||||
get _valueNode() : Et2Textbox
|
||||
{
|
||||
return this.querySelector('et2-textbox');
|
||||
return this.shadowRoot?.querySelector('et2-textbox');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1037,20 +1035,17 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
this.setDate(date, false, null);
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
return html`
|
||||
<div part="form-control" class="form-control">
|
||||
<div class="form-field__group-one" part="form-control-label">${this._groupOneTemplate()}</div>
|
||||
<div class="form-field__group-two" part="form-control-input">${this._groupTwoTemplate()}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected _inputGroupInputTemplate()
|
||||
protected _inputTemplate()
|
||||
{
|
||||
if(typeof egwIsMobile == "function" && egwIsMobile())
|
||||
{
|
||||
// Plain input for mobile
|
||||
return html`<input type=${this._mobileInputType()}></input>`;
|
||||
}
|
||||
// This element gets hidden and used for value, but copied by flatpickr and used for input
|
||||
return html`
|
||||
<slot name="input"></slot>
|
||||
<et2-textbox type="text" placeholder=${this.placeholder} ?required=${this.required}></et2-textbox>
|
||||
${this._incrementButtonTemplate()}
|
||||
`;
|
||||
}
|
||||
@ -1079,6 +1074,32 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
|
||||
</et2-button-icon>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
|
||||
const labelTemplate = this._labelTemplate();
|
||||
const helpTemplate = this._helpTextTemplate();
|
||||
|
||||
return html`
|
||||
${super.render()}
|
||||
<div
|
||||
part="form-control"
|
||||
class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--medium': true,
|
||||
'form-control--has-label': labelTemplate !== nothing,
|
||||
'form-control--has-help-text': helpTemplate !== nothing
|
||||
})}
|
||||
>
|
||||
${labelTemplate}
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
${this._inputTemplate()}
|
||||
</div>
|
||||
${helpTemplate}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement
|
||||
|
@ -9,12 +9,11 @@
|
||||
*/
|
||||
|
||||
|
||||
import {css, html, LitElement} from "lit";
|
||||
import {css, html, LitElement, nothing} from "lit";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {sprintf} from "../../egw_action/egw_action_common";
|
||||
import {dateStyles} from "./DateStyles";
|
||||
import {FormControlMixin} from "@lion/form-core";
|
||||
import shoelace from "../Styles/shoelace";
|
||||
|
||||
export interface formatOptions
|
||||
@ -112,7 +111,7 @@ export function formatDuration(value : number | string, options : formatOptions)
|
||||
* 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 Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement))
|
||||
export class Et2DateDuration extends Et2InputWidget(LitElement)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
@ -125,7 +124,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
.form-control-input {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
@ -399,35 +398,29 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
|
||||
|
||||
render()
|
||||
{
|
||||
return html`
|
||||
<div part="form-control" class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--has-label': this.label.split("%")[0] || false
|
||||
})}>
|
||||
<div class="form-field__group-one form-control__label" part="form-control-label">
|
||||
${this._groupOneTemplate()}
|
||||
</div>
|
||||
<div class="form-field__group-two" part="form-control-input">${this._groupTwoTemplate()}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {TemplateResult}
|
||||
* @protected
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_inputGroupInputTemplate()
|
||||
{
|
||||
const labelTemplate = this._labelTemplate();
|
||||
const helpTemplate = this._helpTextTemplate();
|
||||
|
||||
return html`
|
||||
<div class="input-group__input" @sl-change=${() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}}>
|
||||
<slot name="input">
|
||||
<div
|
||||
part="form-control"
|
||||
class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--medium': true,
|
||||
'form-control--has-label': labelTemplate !== nothing,
|
||||
'form-control--has-help-text': helpTemplate !== nothing
|
||||
})}
|
||||
>
|
||||
${labelTemplate}
|
||||
<div part="form-control-input" class="form-control-input" @sl-change=${() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}}>
|
||||
${this._inputTemplate()}
|
||||
${this._formatTemplate()}
|
||||
</slot>
|
||||
</div>
|
||||
${helpTemplate}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {FormControlMixin} from "@lion/form-core";
|
||||
import {css, html, LitElement, TemplateResult} from "lit";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
import {ifDefined} from "lit/directives/if-defined.js";
|
||||
@ -14,7 +13,7 @@ import {egw} from "../../jsapi/egw_global";
|
||||
* 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))
|
||||
export class Et2DateRange extends Et2InputWidget(LitElement)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
|
@ -28,7 +28,6 @@ export class Et2DateTimeToday extends Et2DateReadonly
|
||||
* If the date is today, we show just the time. Otherwise, the date.
|
||||
*
|
||||
* @param {Date} date
|
||||
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available
|
||||
* @returns {string}
|
||||
*/
|
||||
formatDateTime(date : Date, options = {dateFormat: "", timeFormat: ""}) : string
|
||||
|
@ -15,7 +15,6 @@ import {classMap} from "lit/directives/class-map.js";
|
||||
import {ifDefined} from "lit/directives/if-defined.js";
|
||||
import {repeat} from "lit/directives/repeat.js";
|
||||
import {styleMap} from "lit/directives/style-map.js";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {et2_template} from "../et2_widget_template";
|
||||
import type {etemplate2} from "../etemplate2";
|
||||
import {egw, IegwAppLocal} from "../../jsapi/egw_global";
|
||||
@ -126,7 +125,7 @@ export interface DialogButton
|
||||
*
|
||||
* Customize initial focus by setting the "autofocus" attribute on a control, otherwise first input will have focus
|
||||
*/
|
||||
export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
|
||||
export class Et2Dialog extends Et2Widget(SlDialog)
|
||||
{
|
||||
/**
|
||||
* Dialogs don't always get added to an etemplate, so we keep our own egw
|
||||
@ -334,21 +333,6 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
|
||||
}
|
||||
}
|
||||
|
||||
get slots()
|
||||
{
|
||||
return {
|
||||
...super.slots,
|
||||
'': () =>
|
||||
{
|
||||
// to fix problem with Safari 16.2 of NOT displaying the content, we have to use the following,
|
||||
// instead of just return this._contentTemplate()
|
||||
let div = document.createElement("div");
|
||||
render(this._contentTemplate(), div);
|
||||
return div.children[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* List of properties that get translated
|
||||
* Done separately to not interfere with properties - if we re-define label property,
|
||||
@ -525,9 +509,11 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
|
||||
}
|
||||
}
|
||||
|
||||
firstUpdated()
|
||||
firstUpdated(changedProperties)
|
||||
{
|
||||
super.firstUpdated();
|
||||
super.firstUpdated(changedProperties);
|
||||
|
||||
render(this._contentTemplate(), this);
|
||||
|
||||
// If we start open, fire handler to get setup done
|
||||
if(this.open)
|
||||
@ -764,7 +750,7 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
|
||||
}
|
||||
if(changedProperties.has("buttons"))
|
||||
{
|
||||
render(this._buttonsTemplate(), this);
|
||||
//render(this._buttonsTemplate(), this);
|
||||
this.requestUpdate();
|
||||
}
|
||||
if(changedProperties.has("width"))
|
||||
@ -904,7 +890,7 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
|
||||
<slot>${this.message}</slot>`
|
||||
}
|
||||
|
||||
</div>`;
|
||||
</div>${this._buttonsTemplate()}`;
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ import {waitForEvent} from "../Et2Widget/event";
|
||||
import styles from "./Et2Email.styles";
|
||||
import {SelectOption} from "../Et2Select/FindSelectOptions";
|
||||
import {IsEmail} from "../Validators/IsEmail";
|
||||
import {Validator} from "@lion/form-core";
|
||||
import Sortable from "sortablejs/modular/sortable.complete.esm.js";
|
||||
import {SearchMixinInterface} from "../Et2Widget/SearchMixin";
|
||||
|
||||
|
@ -186,7 +186,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
|
||||
}
|
||||
|
||||
|
||||
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
||||
/** @param changedProperties */
|
||||
updated(changedProperties : PropertyValues)
|
||||
{
|
||||
super.updated(changedProperties);
|
||||
|
@ -10,10 +10,9 @@
|
||||
|
||||
|
||||
import {css, html, LitElement} from "lit";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||
|
||||
export class Et2Iframe extends Et2Widget(SlotMixin(LitElement))
|
||||
export class Et2Iframe extends Et2Widget(LitElement)
|
||||
{
|
||||
|
||||
static get styles()
|
||||
|
@ -29,4 +29,5 @@ export class Et2AppIcon extends Et2Image
|
||||
return super.parse_href(src);
|
||||
}
|
||||
}
|
||||
customElements.define("et2-appicon", Et2AppIcon as any, {extends: 'img'});
|
||||
|
||||
customElements.define("et2-appicon", Et2AppIcon as any);
|
@ -9,29 +9,29 @@
|
||||
*/
|
||||
|
||||
import {css, html, LitElement, render} from "lit";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||
import {et2_IDetachedDOM} from "../et2_core_interfaces";
|
||||
|
||||
export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_IDetachedDOM
|
||||
export class Et2Image extends Et2Widget(LitElement) implements et2_IDetachedDOM
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
...super.styles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
::slotted(img) {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
:host([icon]) {
|
||||
height: 1.3rem;
|
||||
}
|
||||
`,
|
||||
];
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
::slotted(img) {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
:host([icon]) {
|
||||
height: 1.3rem;
|
||||
}
|
||||
`];
|
||||
}
|
||||
|
||||
static get properties()
|
||||
@ -42,7 +42,6 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
|
||||
/**
|
||||
* The label of the image
|
||||
* Actually not used as label, but we put it as title
|
||||
* Added here as there's no Lion parent
|
||||
*/
|
||||
label: {
|
||||
type: String
|
||||
@ -80,16 +79,6 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
|
||||
}
|
||||
}
|
||||
|
||||
get slots()
|
||||
{
|
||||
return {
|
||||
'': () =>
|
||||
{
|
||||
return this._imageTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
@ -248,4 +237,4 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("et2-image", Et2Image, {extends: 'img'});
|
||||
customElements.define("et2-image", Et2Image)//, {extends: 'img'});
|
@ -1,15 +1,15 @@
|
||||
import {css, html, LitElement, nothing, PropertyValues, TemplateResult} from "lit";
|
||||
import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "../et2_core_interfaces";
|
||||
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||
import {css, LitElement, PropertyValues} from "lit";
|
||||
import {Required} from "../Validators/Required";
|
||||
import {ManualMessage} from "../Validators/ManualMessage";
|
||||
import {LionValidationFeedback, Validator} from "@lion/form-core";
|
||||
import {HasSlotController} from "../Et2Widget/slot";
|
||||
import {et2_csvSplit} from "../et2_core_common";
|
||||
import {dedupeMixin} from "@lion/core";
|
||||
import {property} from "lit/decorators/property.js";
|
||||
import {Validator} from "../Validators/Validator";
|
||||
import {ManualMessage} from "../Validators/ManualMessage";
|
||||
import {Required} from "../Validators/Required";
|
||||
import {EgwValidationFeedback} from "../Validators/EgwValidationFeedback";
|
||||
import {dedupeMixin} from "@open-wc/dedupe-mixin";
|
||||
|
||||
// LionValidationFeedback needs to be registered manually
|
||||
window.customElements.define('lion-validation-feedback', LionValidationFeedback);
|
||||
|
||||
/**
|
||||
* This mixin will allow any LitElement to become an Et2InputWidget
|
||||
@ -69,6 +69,9 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
|
||||
protected isSlComponent = false;
|
||||
|
||||
// Allows us to check to see if label or help-text is set. Override to check additional slots.
|
||||
protected readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
||||
|
||||
/** WebComponent **/
|
||||
static get styles()
|
||||
{
|
||||
@ -95,6 +98,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
|
||||
.form-control__help-text {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
`
|
||||
];
|
||||
@ -111,11 +115,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
label: {
|
||||
type: String, noAccessor: true
|
||||
},
|
||||
// readOnly is what the property is in Lion, readonly is the attribute
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
attribute: 'readonly',
|
||||
},
|
||||
|
||||
// readonly is what is in the templates
|
||||
// I put this in here so loadWebComponent finds it when it tries to set it from the template
|
||||
readonly: {
|
||||
@ -341,7 +341,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
// Remove all messages. Manual will be explicitly replaced, other validators will be re-run on blur.
|
||||
this.querySelectorAll("lion-validation-feedback").forEach(e => e.remove());
|
||||
this.querySelectorAll("egw-validation-feedback").forEach(e => e.remove());
|
||||
});
|
||||
}
|
||||
|
||||
@ -400,6 +400,11 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
return this.__readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was from early days (Lion)
|
||||
* @deprecated
|
||||
* @param {boolean} new_value
|
||||
*/
|
||||
set readOnly(new_value)
|
||||
{
|
||||
this.readonly = new_value;
|
||||
@ -582,7 +587,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
let fieldName = this.id;
|
||||
let feedbackData = [];
|
||||
let resultPromises = [];
|
||||
this.querySelector("lion-validation-feedback")?.remove();
|
||||
(<EgwValidationFeedback>this.querySelector("egw-validation-feedback"))?.remove();
|
||||
|
||||
// Collect message of a (failing) validator
|
||||
const doValidate = async function(validator, value)
|
||||
@ -653,7 +658,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
// Show feedback from all failing validators
|
||||
if(feedbackData.length > 0)
|
||||
{
|
||||
let feedback = <LionValidationFeedback>document.createElement("lion-validation-feedback");
|
||||
let feedback = document.createElement("egw-validation-feedback");
|
||||
feedback.feedbackData = feedbackData;
|
||||
feedback.slot = "help-text";
|
||||
this.append(feedback);
|
||||
@ -719,7 +724,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
*/
|
||||
public get hasFeedbackFor() : string[]
|
||||
{
|
||||
let feedback = (<LionValidationFeedback>this.querySelector("lion-validation-feedback"))?.feedbackData || [];
|
||||
let feedback = (this.querySelector("egw-validation-feedback"))?.feedbackData || [];
|
||||
return feedback.map((f) => f.type);
|
||||
}
|
||||
|
||||
@ -734,7 +739,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
{
|
||||
this.submitted = true;
|
||||
|
||||
// If using Lion validators, run them now
|
||||
// If using validators, run them now
|
||||
if(this.validate)
|
||||
{
|
||||
// Force update now
|
||||
@ -745,6 +750,47 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common sub-template to add a label.
|
||||
* This goes inside the form control wrapper div, before and at the same depth as the input controls.
|
||||
*
|
||||
*
|
||||
* @returns {TemplateResult} Either a TemplateResult or nothing (the object). Check for nothing to set
|
||||
* 'form-control--has-label' class on the wrapper div.
|
||||
* @protected
|
||||
*/
|
||||
protected _labelTemplate() : TemplateResult | typeof nothing
|
||||
{
|
||||
const hasLabelSlot = this.hasSlotController?.test('label');
|
||||
const hasLabel = this.label ? true : !!hasLabelSlot;
|
||||
return hasLabel ? html`
|
||||
<label
|
||||
id="label"
|
||||
part="form-control-label"
|
||||
class="form-control__label"
|
||||
aria-hidden=${hasLabel ? 'false' : 'true'}
|
||||
@click=${typeof this.handleLabelClick == "function" ? this.handleLabelClick : nothing}
|
||||
>
|
||||
<slot name="label">${this.label}</slot>
|
||||
</label>
|
||||
` : nothing;
|
||||
}
|
||||
|
||||
protected _helpTextTemplate() : TemplateResult | typeof nothing
|
||||
{
|
||||
const hasHelpTextSlot = this.hasSlotController?.test('help-text');
|
||||
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
|
||||
return hasHelpText ? html`
|
||||
<div
|
||||
part="form-control-help-text"
|
||||
id="help-text"
|
||||
class="form-control__help-text"
|
||||
aria-hidden=${hasHelpText ? 'false' : 'true'}
|
||||
>
|
||||
<slot name="help-text">${this.helpText}</slot>
|
||||
</div>` : nothing;
|
||||
}
|
||||
}
|
||||
|
||||
return Et2InputWidgetClass as Constructor & T;
|
||||
|
@ -1,7 +1,5 @@
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {css, html, LitElement, PropertyValues} from "lit";
|
||||
import {FormControlMixin, ValidateMixin} from "@lion/form-core";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {Et2LinkAppSelect} from "./Et2LinkAppSelect";
|
||||
import {LinkInfo} from "./Et2Link";
|
||||
import {Et2Button} from "../Et2Button/Et2Button";
|
||||
@ -11,7 +9,7 @@ import {Et2Button} from "../Et2Button/Et2Button";
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(SlotMixin(LitElement))))
|
||||
export class Et2LinkAdd extends Et2InputWidget(LitElement)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
|
@ -6,37 +6,38 @@
|
||||
* @link https://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
*/
|
||||
import {css, html, LitElement, PropertyValues} from "lit";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {css, html, LitElement, nothing} from "lit";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
import {Et2LinkAppSelect} from "./Et2LinkAppSelect";
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {FormControlMixin} from "@lion/form-core";
|
||||
import {Et2LinkSearch} from "./Et2LinkSearch";
|
||||
import {Et2Link, LinkInfo} from "./Et2Link";
|
||||
import {HasSlotController} from "../Et2Widget/slot";
|
||||
|
||||
/**
|
||||
* Find and select a single entry using the link system.
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitElement)))
|
||||
export class Et2LinkEntry extends Et2InputWidget(LitElement)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
...super.styles,
|
||||
css`
|
||||
:host {
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
:host(.hideApp) ::slotted([slot="app"]) {
|
||||
:host(.hideApp) ::slotted([slot="app"]) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group__input {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.form-control-input {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
`
|
||||
];
|
||||
@ -83,52 +84,17 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
}
|
||||
}
|
||||
|
||||
get slots()
|
||||
{
|
||||
return {
|
||||
...super.slots,
|
||||
app: () =>
|
||||
{
|
||||
const app = <Et2LinkAppSelect>document.createElement("et2-link-apps")
|
||||
if(this.__onlyApp)
|
||||
{
|
||||
app.onlyApp = this.__onlyApp;
|
||||
}
|
||||
else if(typeof this._value !== "undefined" && this._value.app)
|
||||
{
|
||||
app.value = this._value.app;
|
||||
}
|
||||
return app;
|
||||
},
|
||||
select: () =>
|
||||
{
|
||||
const select = <Et2LinkSearch><unknown>document.createElement("et2-link-search");
|
||||
if(typeof this._value !== "undefined" && this._value.id)
|
||||
{
|
||||
if(this._value.title)
|
||||
{
|
||||
select.select_options = [{value: this._value.id, label: this._value.title}]
|
||||
}
|
||||
select.app = this._value.app;
|
||||
select.value = this._value.id;
|
||||
}
|
||||
return select;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We only care about this value until render. After the sub-nodes are created,
|
||||
* we take their "live" values for our value.
|
||||
*
|
||||
* N.B.: Single underscore! Otherwise we conflict with parent __value
|
||||
*
|
||||
* @type {LinkInfo}
|
||||
* @private
|
||||
*/
|
||||
private _value : LinkInfo;
|
||||
private __value : LinkInfo = {app: "", id: ""};
|
||||
|
||||
protected __onlyApp : string;
|
||||
protected readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
||||
|
||||
constructor()
|
||||
{
|
||||
@ -139,18 +105,18 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
{
|
||||
super.connectedCallback();
|
||||
|
||||
this._handleAppChange = this._handleAppChange.bind(this);
|
||||
this._handleEntrySelect = this._handleEntrySelect.bind(this);
|
||||
this._handleEntryClear = this._handleEntryClear.bind(this);
|
||||
this._handleShow = this._handleShow.bind(this);
|
||||
this._handleHide = this._handleHide.bind(this);
|
||||
|
||||
// Clear initial value
|
||||
this._value = undefined;
|
||||
this.__value = undefined;
|
||||
|
||||
if(!this.readonly)
|
||||
{
|
||||
this._bindListeners();
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this._bindListeners();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,41 +126,14 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
this._unbindListeners();
|
||||
}
|
||||
|
||||
updated(changedProperties : PropertyValues)
|
||||
{
|
||||
super.updated(changedProperties);
|
||||
if(changedProperties.has("required"))
|
||||
{
|
||||
this._searchNode.required = this.required;
|
||||
}
|
||||
if(changedProperties.has("readonly"))
|
||||
{
|
||||
this._appNode.readonly = this._appNode.disabled = this.readonly;
|
||||
this._searchNode.readonly = this.readonly;
|
||||
}
|
||||
// Pass some properties on to app selection
|
||||
if(changedProperties.has("onlyApp"))
|
||||
{
|
||||
this._appNode.onlyApp = this.onlyApp;
|
||||
}
|
||||
if(changedProperties.has("applicationList"))
|
||||
{
|
||||
this._appNode.applicationList = this.applicationList;
|
||||
}
|
||||
if(changedProperties.has("appIcons"))
|
||||
{
|
||||
this._appNode.appIcons = this.appIcons;
|
||||
}
|
||||
}
|
||||
|
||||
set onlyApp(app)
|
||||
{
|
||||
this.__onlyApp = app || "";
|
||||
|
||||
// If initial value got set before onlyApp, it still needs app in pre-render value
|
||||
if(this._value && app)
|
||||
if(this.__value && app)
|
||||
{
|
||||
this._value.app = this.__onlyApp;
|
||||
this.__value.app = this.__onlyApp;
|
||||
}
|
||||
if(app)
|
||||
{
|
||||
@ -213,16 +152,20 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
|
||||
set app(app)
|
||||
{
|
||||
this.updateComplete.then(() =>
|
||||
if(typeof this.__value !== "object" || this.__value == null)
|
||||
{
|
||||
this._appNode.value = app;
|
||||
this._searchNode.app = app;
|
||||
});
|
||||
this.__value = <LinkInfo>{app: app}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.__value.app = app;
|
||||
}
|
||||
this.requestUpdate("value");
|
||||
}
|
||||
|
||||
get app()
|
||||
{
|
||||
return this._appNode?.value || "";
|
||||
return this.__value?.app || "";
|
||||
}
|
||||
|
||||
set searchOptions(options)
|
||||
@ -240,12 +183,12 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
|
||||
get _appNode() : Et2LinkAppSelect
|
||||
{
|
||||
return this.querySelector("[slot='app']");
|
||||
return this.shadowRoot?.querySelector("et2-link-apps");
|
||||
}
|
||||
|
||||
get _searchNode() : Et2LinkSearch
|
||||
{
|
||||
return this.querySelector("[slot='select']");
|
||||
return <Et2LinkSearch>this.shadowRoot?.querySelector("et2-link-search");
|
||||
}
|
||||
|
||||
get placeholder() : string
|
||||
@ -263,48 +206,32 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
|
||||
protected _bindListeners()
|
||||
{
|
||||
this._appNode.addEventListener("change", this._handleAppChange);
|
||||
this._searchNode.addEventListener("change", this._handleEntrySelect);
|
||||
this._searchNode.addEventListener("sl-clear", this._handleEntryClear);
|
||||
this.addEventListener("sl-show", this._handleShow);
|
||||
this.addEventListener("sl-hide", this._handleHide);
|
||||
}
|
||||
|
||||
protected _unbindListeners()
|
||||
{
|
||||
this._appNode.removeEventListener("change", this._handleAppChange);
|
||||
this.removeEventListener("sl-select", this._handleEntrySelect);
|
||||
this.removeEventListener("sl-clear", this._handleEntryClear);
|
||||
this.removeEventListener("sl-show", this._handleShow);
|
||||
this.removeEventListener("sl-hide", this._handleHide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the search node's app & clear selected value when
|
||||
* selected app changes.
|
||||
* @param event
|
||||
* @protected
|
||||
*/
|
||||
protected _handleAppChange(event)
|
||||
{
|
||||
this._searchNode.app = this._appNode.value;
|
||||
this._searchNode.value = "";
|
||||
this._searchNode.clearSearch();
|
||||
this._searchNode.focus();
|
||||
|
||||
this.requestUpdate('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide app selection when there's an entry
|
||||
* @param event
|
||||
* @protected
|
||||
*/
|
||||
protected _handleEntrySelect(event)
|
||||
protected handleEntrySelect(event)
|
||||
{
|
||||
event.stopPropagation();
|
||||
this.value = <string>this._searchNode.value ?? "";
|
||||
this.classList.toggle("hideApp", Boolean(typeof this.value == "object" ? this.value?.id : this.value));
|
||||
this.dispatchEvent(new Event("change"));
|
||||
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change"));
|
||||
});
|
||||
this.requestUpdate('value');
|
||||
|
||||
this.validate();
|
||||
@ -316,13 +243,17 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
* @param event
|
||||
* @protected
|
||||
*/
|
||||
protected _handleEntryClear(event)
|
||||
protected handleEntryClear(event)
|
||||
{
|
||||
this.value = ""
|
||||
this.classList.remove("hideApp")
|
||||
this._searchNode.value = "";
|
||||
this._searchNode.focus();
|
||||
|
||||
this.dispatchEvent(new Event("change"));
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change"));
|
||||
});
|
||||
this.requestUpdate('value');
|
||||
|
||||
this.validate();
|
||||
@ -362,16 +293,12 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
{
|
||||
return <string>this._searchNode?.value ?? "";
|
||||
}
|
||||
return this._searchNode ? <LinkInfo>{
|
||||
id: this._searchNode.value,
|
||||
app: this.app,
|
||||
//search: this._searchNode... // content of search field
|
||||
} : this._value;
|
||||
return this.__value;
|
||||
}
|
||||
|
||||
set value(val : LinkInfo | string | number)
|
||||
{
|
||||
let value : LinkInfo = {app: this.onlyApp || this.app, id: ""};
|
||||
let value : LinkInfo = {app: this.onlyApp || (this.app || this._appNode?.value), id: ""};
|
||||
|
||||
if(typeof val === 'string' && val.length > 0)
|
||||
{
|
||||
@ -399,30 +326,79 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
|
||||
value = (<LinkInfo>val);
|
||||
}
|
||||
|
||||
// If the searchNode is not there yet, hold value. We'll use these values when we create the
|
||||
// slotted searchNode.
|
||||
if(this._searchNode == null)
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.app = this._searchNode.app = value.app;
|
||||
this._searchNode.value = value.id;
|
||||
}
|
||||
this.classList.toggle("hideApp", Boolean(value.id));
|
||||
const oldValue = this.__value;
|
||||
this.__value = value;
|
||||
|
||||
this.classList.toggle("hideApp", Boolean(this.__value.id));
|
||||
this.requestUpdate("value", oldValue);
|
||||
}
|
||||
|
||||
protected handleLabelClick()
|
||||
{
|
||||
this._searchNode.focus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {TemplateResult}
|
||||
* Update the search node's app & clear selected value when
|
||||
* selected app changes.
|
||||
* @param event
|
||||
* @protected
|
||||
*/
|
||||
_inputGroupInputTemplate()
|
||||
protected handleAppChange(e)
|
||||
{
|
||||
this.app = this._appNode.value;
|
||||
this._searchNode.app = this._appNode.value;
|
||||
this._searchNode.value = "";
|
||||
this._searchNode.clearSearch();
|
||||
this._searchNode.focus();
|
||||
|
||||
this.requestUpdate('value');
|
||||
}
|
||||
|
||||
|
||||
render()
|
||||
{
|
||||
const labelTemplate = this._labelTemplate();
|
||||
const helpTemplate = this._helpTextTemplate();
|
||||
|
||||
return html`
|
||||
<div class="input-group__input" part="control">
|
||||
<slot name="app"></slot>
|
||||
<slot name="select"></slot>
|
||||
<div
|
||||
part="form-control"
|
||||
class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--medium': true,
|
||||
'form-control--has-label': labelTemplate !== nothing,
|
||||
'form-control--has-help-text': helpTemplate !== nothing
|
||||
})}
|
||||
>
|
||||
${labelTemplate}
|
||||
<div part="form-control-input" class="form-control-input">
|
||||
<et2-link-apps
|
||||
onlyApp=${this.onlyApp ? this.onlyApp : nothing}
|
||||
?appIcons=${this.appIcons}
|
||||
?applicationList=${this.applicationList}
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.disabled}
|
||||
.value=${this.__value?.app ? this.__value.app : nothing}
|
||||
@change=${this.handleAppChange}
|
||||
></et2-link-apps>
|
||||
<et2-link-search
|
||||
?placeholder=${this.placeholder}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
.app=${this.__value?.app || nothing}
|
||||
.value=${this.__value?.id || nothing}
|
||||
@change=${this.handleEntrySelect}
|
||||
@sl-clear=${this.handleEntryClear}
|
||||
>
|
||||
${(this.__value?.title) ? html`
|
||||
<option value=${this.__value.id}>${this.__value.title}</option>
|
||||
` : nothing}
|
||||
</et2-link-search>
|
||||
</div>
|
||||
${helpTemplate}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -335,5 +335,4 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
|
||||
}
|
||||
};
|
||||
|
||||
// @ts-ignore TypeScript says there's something wrong with types
|
||||
customElements.define("et2-link-string", Et2LinkString, {extends: 'ul'});
|
||||
customElements.define("et2-link-string", Et2LinkString);
|
@ -11,21 +11,19 @@
|
||||
|
||||
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {FormControlMixin, ValidateMixin} from "@lion/form-core";
|
||||
import {css, html, LitElement, nothing} from "lit";
|
||||
import {ScopedElementsMixin} from "@lion/core";
|
||||
import {et2_createWidget, et2_widget} from "../et2_core_widget";
|
||||
import {et2_file} from "../et2_widget_file";
|
||||
import {Et2Button} from "../Et2Button/Et2Button";
|
||||
import {Et2LinkEntry} from "./Et2LinkEntry";
|
||||
import {egw} from "../../jsapi/egw_global";
|
||||
import {LinkInfo} from "./Et2Link";
|
||||
import type {ValidationType} from "@lion/form-core/types/validate/ValidateMixinTypes";
|
||||
import {ManualMessage} from "../Validators/ManualMessage";
|
||||
import {Et2Tabs} from "../Layout/Et2Tabs/Et2Tabs";
|
||||
import {Et2VfsSelectButton} from "../Et2Vfs/Et2VfsSelectButton";
|
||||
import {Et2LinkPasteDialog, getClipboardFiles} from "./Et2LinkPasteDialog";
|
||||
import {waitForEvent} from "../Et2Widget/event";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
|
||||
/**
|
||||
* Choose an existing entry, VFS file or local file, and link it to the current entry.
|
||||
@ -33,7 +31,7 @@ import {waitForEvent} from "../Et2Widget/event";
|
||||
* If there is no "current entry", link information will be stored for submission instead
|
||||
* of being directly linked.
|
||||
*/
|
||||
export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMixin(ValidateMixin(LitElement))))
|
||||
export class Et2LinkTo extends Et2InputWidget(LitElement)
|
||||
{
|
||||
static get properties()
|
||||
{
|
||||
@ -73,15 +71,12 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
|
||||
.input-group__container {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.input-group {
|
||||
|
||||
.form-control-input {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.input-group__before {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
::slotted(.et2_file) {
|
||||
width: 30px;
|
||||
}
|
||||
@ -160,13 +155,17 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
|
||||
return html`
|
||||
<slot name="before"></slot>
|
||||
<et2-vfs-select
|
||||
id="link"
|
||||
?readonly=${this.readonly}
|
||||
method=${method || nothing}
|
||||
method-id=${method_id || nothing}
|
||||
multiple
|
||||
title=${this.egw().lang("select file(s) from vfs")}
|
||||
.buttonLabel=${this.egw().lang('Link')}
|
||||
.onchange=${this.handleVfsSelected}
|
||||
@change=${async() =>
|
||||
{
|
||||
this.handleVfsSelected(await this.shadowRoot.getElementById("link")._dialog.getComplete());
|
||||
}}
|
||||
>
|
||||
<et2-button slot="footer" image="copy" id="copy" style="order:3" noSubmit="true"
|
||||
label=${this.egw().lang("copy")}></et2-button>
|
||||
@ -586,6 +585,35 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
|
||||
{
|
||||
return ['error', 'success'];
|
||||
}
|
||||
|
||||
|
||||
render()
|
||||
{
|
||||
const labelTemplate = this._labelTemplate();
|
||||
const helpTemplate = this._helpTextTemplate();
|
||||
|
||||
return html`
|
||||
<div
|
||||
part="form-control"
|
||||
class=${classMap({
|
||||
'form-control': true,
|
||||
'form-control--medium': true,
|
||||
'form-control--has-label': labelTemplate !== nothing,
|
||||
'form-control--has-help-text': helpTemplate !== nothing
|
||||
})}
|
||||
>
|
||||
${labelTemplate}
|
||||
<div part="form-control-input" class="form-control-input" @sl-change=${() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}}>
|
||||
${this._inputGroupBeforeTemplate()}
|
||||
${this._inputGroupInputTemplate()}
|
||||
</div>
|
||||
${helpTemplate}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
|
||||
|
@ -546,7 +546,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
|
||||
this.updateComplete.then(() => this.fix_bad_value());
|
||||
}
|
||||
|
||||
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
||||
/** @param changedProperties */
|
||||
willUpdate(changedProperties : PropertyValues)
|
||||
{
|
||||
super.willUpdate(changedProperties);
|
||||
|
@ -44,7 +44,6 @@ import {SearchMixinInterface} from "../Et2Widget/SearchMixin";
|
||||
*
|
||||
* Optionally, you can override:
|
||||
* - _emptyLabelTemplate(): How to render the empty label
|
||||
* - slots(): Most Lion components have an input slot where the <input> tag is created.
|
||||
* You can specify something else, or return {} to do your own thing. This is a little more complicated. You should
|
||||
* also override _inputGroupInputTemplate() to do what you normally would in render().
|
||||
*
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
import {css, CSSResultGroup, html, LitElement, nothing, TemplateResult} from "lit";
|
||||
import {cleanSelectOptions, SelectOption} from "./FindSelectOptions";
|
||||
import {Validator} from "@lion/form-core";
|
||||
import {Et2Tag} from "./Tag/Et2Tag";
|
||||
import {StaticOptions} from "./StaticOptions";
|
||||
import {dedupeMixin} from "@open-wc/dedupe-mixin";
|
||||
@ -17,6 +16,7 @@ import {SlOption} from "@shoelace-style/shoelace";
|
||||
import {Et2Textbox} from "../Et2Textbox/Et2Textbox";
|
||||
import {until} from "lit/directives/until.js";
|
||||
import {waitForEvent} from "../Et2Widget/event";
|
||||
import {Validator} from "../Validators/Validator";
|
||||
|
||||
// Otherwise import gets stripped
|
||||
let keep_import : Et2Tag;
|
||||
|
@ -8,8 +8,7 @@
|
||||
* @author Hadi Nategh
|
||||
*/
|
||||
|
||||
import {css, html} from "lit";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {css, html, render} from "lit";
|
||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||
import '../Et2Image/Et2Image';
|
||||
import {SlSwitch} from "@shoelace-style/shoelace";
|
||||
@ -21,7 +20,7 @@ import shoelace from "../Styles/shoelace";
|
||||
* Add "et2SlideSwitch" class to use an alternate UI with images. Use CSS to set the images:
|
||||
*
|
||||
*/
|
||||
export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch))
|
||||
export class Et2Switch extends Et2InputWidget(SlSwitch)
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
@ -104,17 +103,6 @@ export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch))
|
||||
}
|
||||
}
|
||||
|
||||
get slots()
|
||||
{
|
||||
return {
|
||||
...super.slots,
|
||||
'': () =>
|
||||
{
|
||||
return this.labelTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
@ -125,6 +113,7 @@ export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch))
|
||||
|
||||
updated(changedProperties)
|
||||
{
|
||||
render(this.labelTemplate(), this);
|
||||
if(changedProperties.has("toggleOn") || changedProperties.has("toggleOff") || changedProperties.has("label"))
|
||||
{
|
||||
if(!this.toggleOn && !this.toggleOff && this._labelNode)
|
||||
|
@ -69,7 +69,7 @@ export class Et2Textbox extends Et2InputWidget(SlInput)
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
||||
/** @param changedProperties */
|
||||
updated(changedProperties : PropertyValues)
|
||||
{
|
||||
super.updated(changedProperties);
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import {css, html, LitElement} from 'lit';
|
||||
import {dedupeMixin, SlotMixin} from '@lion/core';
|
||||
import {Et2InputWidget, Et2InputWidgetInterface} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {colorsDefStyles} from "../Styles/colorsDefStyles";
|
||||
import {dedupeMixin} from "@open-wc/dedupe-mixin";
|
||||
|
||||
/**
|
||||
* Invoker mixing adds an invoker button to a widget to trigger some action, e.g.:
|
||||
@ -25,7 +25,7 @@ import {colorsDefStyles} from "../Styles/colorsDefStyles";
|
||||
type Constructor<T = Et2InputWidgetInterface> = new (...args : any[]) => T;
|
||||
export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(superclass : T) =>
|
||||
{
|
||||
class Et2Invoker extends SlotMixin(Et2InputWidget(superclass))
|
||||
class Et2Invoker extends Et2InputWidget(superclass)
|
||||
{
|
||||
/** @type {any} */
|
||||
static get properties()
|
||||
@ -193,7 +193,7 @@ export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(s
|
||||
return super._oldChange(_ev);
|
||||
}
|
||||
|
||||
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
||||
/** @param changedProperties */
|
||||
firstUpdated(changedProperties)
|
||||
{
|
||||
super.firstUpdated(changedProperties);
|
||||
|
@ -259,4 +259,4 @@ export class Et2VfsMime extends Et2ImageExpose
|
||||
|
||||
}
|
||||
|
||||
customElements.define("et2-vfs-mime", Et2VfsMime as any, {extends: 'img'});
|
||||
customElements.define("et2-vfs-mime", Et2VfsMime as any);
|
@ -9,7 +9,7 @@ import type {IegwAppLocal} from "../../jsapi/egw_global";
|
||||
import {egw} from "../../jsapi/egw_global";
|
||||
import {ClassWithAttributes, ClassWithInterfaces} from "../et2_core_inheritance";
|
||||
import {css, LitElement, PropertyValues, unsafeCSS} from "lit";
|
||||
import {dedupeMixin} from "@lion/core";
|
||||
import {dedupeMixin} from "@open-wc/dedupe-mixin";
|
||||
import type {et2_container} from "../et2_core_baseWidget";
|
||||
import type {et2_DOMWidget} from "../et2_core_DOMWidget";
|
||||
|
||||
@ -495,7 +495,7 @@ const Et2WidgetMixin = <T extends Constructor>(superClass : T) =>
|
||||
* A property has changed, and we want to make adjustments to other things
|
||||
* based on that
|
||||
*
|
||||
* @param {import('@lion/core').PropertyValues } changedProperties
|
||||
* @param changedProperties
|
||||
*/
|
||||
updated(changedProperties : PropertyValues)
|
||||
{
|
||||
|
@ -13,12 +13,10 @@ import {SlSplitPanel} from "@shoelace-style/shoelace";
|
||||
import {et2_IDOMNode, et2_IResizeable} from "../../et2_core_interfaces";
|
||||
import {et2_DOMWidget} from "../../et2_core_DOMWidget";
|
||||
import {css, html} from "lit";
|
||||
import {SlotMixin} from "@lion/core";
|
||||
import {colorsDefStyles} from "../../Styles/colorsDefStyles";
|
||||
|
||||
export class Et2Split extends Et2Widget(SlotMixin(SlSplitPanel))
|
||||
export class Et2Split extends Et2Widget(SlSplitPanel)
|
||||
{
|
||||
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
|
72
api/js/etemplate/Validators/EgwValidationFeedback.ts
Normal file
72
api/js/etemplate/Validators/EgwValidationFeedback.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import {customElement} from "lit/decorators/custom-element.js";
|
||||
import {property} from "lit/decorators/property.js";
|
||||
import {html, LitElement} from "lit";
|
||||
|
||||
|
||||
/**
|
||||
* @desc Takes care of accessible rendering of error messages
|
||||
* Should be used in conjunction with FormControl having ValidateMixin applied
|
||||
*
|
||||
* Based on Lion
|
||||
*/
|
||||
@customElement("egw-validation-feedback")
|
||||
export class EgwValidationFeedback extends LitElement
|
||||
{
|
||||
@property({type: Array, attribute: false})
|
||||
feedbackData = [];
|
||||
|
||||
/**
|
||||
* @overridable
|
||||
* @param {Object} opts
|
||||
* @param {string | Node | TemplateResult } opts.message message or feedback node or TemplateResult
|
||||
* @param {string} [opts.type]
|
||||
* @param {Validator} [opts.validator]
|
||||
* @protected
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_messageTemplate({message})
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param changedProperties
|
||||
*/
|
||||
updated(changedProperties)
|
||||
{
|
||||
super.updated(changedProperties);
|
||||
if(this.feedbackData && this.feedbackData[0])
|
||||
{
|
||||
this.setAttribute('type', this.feedbackData[0].type);
|
||||
this.currentType = this.feedbackData[0].type;
|
||||
window.clearTimeout(this.removeMessage);
|
||||
// TODO: this logic should be in ValidateMixin, so that [show-feedback-for] is in sync,
|
||||
// plus duration should be configurable
|
||||
if(this.currentType === 'success')
|
||||
{
|
||||
this.removeMessage = window.setTimeout(() =>
|
||||
{
|
||||
this.removeAttribute('type');
|
||||
/** @type {messageMap[]} */
|
||||
this.feedbackData = [];
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
else if(this.currentType !== 'success')
|
||||
{
|
||||
this.removeAttribute('type');
|
||||
}
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
return html`
|
||||
${this.feedbackData &&
|
||||
this.feedbackData.map(
|
||||
({message, type, validator}) => html`
|
||||
${this._messageTemplate({message, type, validator})}
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import {Pattern} from "@lion/form-core";
|
||||
import {Pattern} from "./StringValidators";
|
||||
|
||||
export class IsEmail extends Pattern
|
||||
{
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {ResultValidator} from "@lion/form-core";
|
||||
import {Validator} from "./Validator";
|
||||
|
||||
/**
|
||||
* Manual validator for server-side validation messages passed
|
||||
* from Etemplate. It just gives whatever message is passed in when created.
|
||||
*
|
||||
*/
|
||||
export class ManualMessage extends ResultValidator
|
||||
export class ManualMessage extends Validator
|
||||
{
|
||||
static get validatorName()
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Pattern} from "@lion/form-core";
|
||||
import {Pattern} from "./StringValidators"
|
||||
|
||||
export class Regex extends Pattern
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Required as LionRequired} from "@lion/form-core";
|
||||
import {Validator} from "./Validator";
|
||||
|
||||
export class Required extends LionRequired
|
||||
export class Required extends Validator
|
||||
{
|
||||
/**
|
||||
* Returns a Boolean. True if the test fails
|
||||
|
110
api/js/etemplate/Validators/StringValidators.ts
Normal file
110
api/js/etemplate/Validators/StringValidators.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import {Validator} from './Validator';
|
||||
|
||||
/**
|
||||
* @param {?} value
|
||||
*/
|
||||
const isString = value => typeof value === 'string';
|
||||
|
||||
export class IsString extends Validator {
|
||||
static get validatorName() {
|
||||
return 'IsString';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?} value
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
execute(value) {
|
||||
let hasError = false;
|
||||
if (!isString(value)) {
|
||||
hasError = true;
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
}
|
||||
|
||||
export class EqualsLength extends Validator {
|
||||
static get validatorName() {
|
||||
return 'EqualsLength';
|
||||
}
|
||||
|
||||
|
||||
execute(value, length = this.param) {
|
||||
let hasError = false;
|
||||
if (!isString(value) || value.length !== length) {
|
||||
hasError = true;
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
}
|
||||
|
||||
export class MinLength extends Validator {
|
||||
static get validatorName() {
|
||||
return 'MinLength';
|
||||
}
|
||||
|
||||
|
||||
execute(value, min = this.param) {
|
||||
let hasError = false;
|
||||
if (!isString(value) || value.length < min) {
|
||||
hasError = true;
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
}
|
||||
|
||||
export class MaxLength extends Validator {
|
||||
static get validatorName() {
|
||||
return 'MaxLength';
|
||||
}
|
||||
|
||||
execute(value, max = this.param) {
|
||||
let hasError = false;
|
||||
if (!isString(value) || value.length > max) {
|
||||
hasError = true;
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
}
|
||||
|
||||
export class MinMaxLength extends Validator {
|
||||
static get validatorName() {
|
||||
return 'MinMaxLength';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?} value
|
||||
*/
|
||||
execute(value, { min = 0, max = 0 } = this.param) {
|
||||
let hasError = false;
|
||||
if (!isString(value) || value.length < min || value.length > max) {
|
||||
hasError = true;
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?} value
|
||||
* @param {RegExp} pattern
|
||||
*/
|
||||
const hasPattern = (value, pattern) => pattern.test(value);
|
||||
export class Pattern extends Validator {
|
||||
static get validatorName() {
|
||||
return 'Pattern';
|
||||
}
|
||||
|
||||
execute(value, pattern = this.param) {
|
||||
if (!(pattern instanceof RegExp)) {
|
||||
throw new Error(
|
||||
'Psst... Pattern validator expects RegExp object as parameter e.g, new Pattern(/#LionRocks/) or new Pattern(RegExp("#LionRocks")',
|
||||
);
|
||||
}
|
||||
let hasError = false;
|
||||
if (!isString(value) || !hasPattern(value, pattern)) {
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
return hasError;
|
||||
}
|
||||
}
|
102
api/js/etemplate/Validators/Validator.ts
Normal file
102
api/js/etemplate/Validators/Validator.ts
Normal file
@ -0,0 +1,102 @@
|
||||
export class Validator
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param {?} [param]
|
||||
* @param {Object.<string,?>} [config]
|
||||
*/
|
||||
constructor(param, config)
|
||||
{
|
||||
|
||||
/** @type {?} */
|
||||
this.__param = param;
|
||||
|
||||
/** @type {Object.<string,?>} */
|
||||
this.__config = config || {};
|
||||
this.type = (config && config.type) || 'error'; // Default type supported by ValidateMixin
|
||||
}
|
||||
|
||||
static get validatorName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc The function that returns a Boolean
|
||||
* @param {?} [modelValue]
|
||||
* @param {?} [param]
|
||||
* @param {{}} [config]
|
||||
* @returns {Boolean|Promise<Boolean>}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars, class-methods-use-this
|
||||
execute(modelValue, param, config) : boolean | Promise<boolean>
|
||||
{
|
||||
const ctor = /** @type {typeof Validator} */ (this.constructor);
|
||||
if(!ctor.validatorName)
|
||||
{
|
||||
throw new Error(
|
||||
'A validator needs to have a name! Please set it via "static get validatorName() { return \'IsCat\'; }"',
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
set param(p)
|
||||
{
|
||||
this.__param = p;
|
||||
if(this.dispatchEvent)
|
||||
{
|
||||
this.dispatchEvent(new Event('param-changed'));
|
||||
}
|
||||
}
|
||||
|
||||
get param()
|
||||
{
|
||||
return this.__param;
|
||||
}
|
||||
|
||||
set config(c)
|
||||
{
|
||||
this.__config = c;
|
||||
if(this.dispatchEvent)
|
||||
{
|
||||
this.dispatchEvent(new Event('config-changed'));
|
||||
}
|
||||
}
|
||||
|
||||
get config()
|
||||
{
|
||||
return this.__config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @overridable
|
||||
* @param {MessageData} [data]
|
||||
* @returns {Promise<string|Node>}
|
||||
* @protected
|
||||
*/
|
||||
async _getMessage(data)
|
||||
{
|
||||
const ctor = /** @type {typeof Validator} */ (this.constructor);
|
||||
const composedData = {
|
||||
name: ctor.validatorName,
|
||||
type: this.type,
|
||||
params: this.param,
|
||||
config: this.config,
|
||||
...data,
|
||||
};
|
||||
if(this.config.getMessage)
|
||||
{
|
||||
if(typeof this.config.getMessage === 'function')
|
||||
{
|
||||
return this.config.getMessage(composedData);
|
||||
}
|
||||
throw new Error(
|
||||
`You must provide a value for getMessage of type 'function', you provided a value of type: ${typeof this
|
||||
.config.getMessage}`,
|
||||
);
|
||||
}
|
||||
return ctor.getMessage(composedData);
|
||||
}
|
||||
|
||||
}
|
@ -102,6 +102,7 @@ import "./Et2Vfs/Et2VfsSelectButton";
|
||||
import "./Et2Vfs/Et2VfsSelectDialog";
|
||||
import "./Et2Vfs/Et2VfsSelectRow";
|
||||
import "./Et2Vfs/Et2VfsUid";
|
||||
import "./Validators/EgwValidationFeedback";
|
||||
import "./Et2Textbox/Et2Password";
|
||||
import './Et2Textbox/Et2Searchbox';
|
||||
import "./Et2Tree/Et2Tree";
|
||||
|
@ -2112,7 +2112,7 @@ table.et2_grid tbody.ui-sortable:not(.ui-sortable-disabled) > tr:not(.th) {
|
||||
* Message styles
|
||||
*/
|
||||
/* Style used for a generic message (such as success messages or validation errors) */
|
||||
div.message, lion-validation-feedback[type] {
|
||||
div.message, egw-validation-feedback[type] {
|
||||
display: block;
|
||||
border: 1px solid;
|
||||
border-color: var(--primary-color, gray);
|
||||
@ -2124,7 +2124,7 @@ div.message, lion-validation-feedback[type] {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
div.message.floating, lion-validation-feedback[type] {
|
||||
div.message.floating, egw-validation-feedback[type] {
|
||||
position: absolute;
|
||||
margin: 0px;
|
||||
z-index: 1;
|
||||
@ -2132,14 +2132,14 @@ div.message.floating, lion-validation-feedback[type] {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
lion-validation-feedback[type] {
|
||||
egw-validation-feedback[type] {
|
||||
top: initial;
|
||||
margin-top: calc(-0.2 * var(--sl-input-height-medium));
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.message.validation_error, lion-validation-feedback[type="error"] {
|
||||
.message.validation_error, egw-validation-feedback[type="error"] {
|
||||
color: var(--error-color);
|
||||
border-color: var(--error-color);
|
||||
background-repeat: no-repeat;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import {css} from "@lion/core";
|
||||
import {css} from "lit";
|
||||
import {Et2PortletFavorite} from "../../home/js/Et2PortletFavorite";
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {Et2Date, parseDate} from "../../api/js/etemplate/Et2Date/Et2Date";
|
||||
import {css} from "@lion/core";
|
||||
import {CalendarApp} from "./app";
|
||||
import {css, html, render} from "lit";
|
||||
import {app} from "../../api/js/jsapi/egw_global";
|
||||
|
||||
export class SidemenuDate extends Et2Date
|
||||
{
|
||||
@ -35,20 +36,6 @@ export class SidemenuDate extends Et2Date
|
||||
];
|
||||
}
|
||||
|
||||
get slots()
|
||||
{
|
||||
return {
|
||||
...super.slots,
|
||||
input: () =>
|
||||
{
|
||||
// This element gets hidden and used for value - overridden from parent
|
||||
const text = document.createElement('input');
|
||||
text.type = "text";
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
@ -60,8 +47,10 @@ export class SidemenuDate extends Et2Date
|
||||
this._handleHeaderChange = this._handleHeaderChange.bind(this);
|
||||
}
|
||||
|
||||
|
||||
async connectedCallback()
|
||||
{
|
||||
render(this._inputTemplate(), this);
|
||||
super.connectedCallback();
|
||||
|
||||
this.removeEventListener("change", this._oldChange);
|
||||
@ -360,7 +349,22 @@ export class SidemenuDate extends Et2Date
|
||||
// Go directly
|
||||
app.calendar.update_state(update);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interactive (form) element.
|
||||
* @protected
|
||||
*/
|
||||
get _inputNode()
|
||||
{
|
||||
return this.querySelector('input');
|
||||
}
|
||||
|
||||
protected _inputTemplate()
|
||||
{
|
||||
// Plain input
|
||||
return html`
|
||||
<input type="text"></input>`;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement
|
||||
customElements.define("calendar-date", SidemenuDate);
|
@ -1,10 +1,11 @@
|
||||
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||
import {classMap, css, html} from "@lion/core";
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import {etemplate2} from "../../api/js/etemplate/etemplate2";
|
||||
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
|
||||
import {Et2Favorites} from "../../api/js/etemplate/Et2Favorites/Et2Favorites";
|
||||
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
|
||||
import {css, html} from "lit";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
|
||||
export class Et2PortletFavorite extends Et2Portlet
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import {css} from "@lion/core";
|
||||
import {css} from "lit";
|
||||
import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
|
||||
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||
import {et2_createWidget} from "../../api/js/etemplate/et2_core_widget";
|
||||
import {css, html, TemplateResult} from "@lion/core";
|
||||
import {css, html, TemplateResult} from "lit";
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
|
||||
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
|
||||
|
@ -1,7 +1,8 @@
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import {css, html, TemplateResult, unsafeHTML} from "@lion/core";
|
||||
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
|
||||
import {css, html, TemplateResult} from "lit";
|
||||
import {unsafeHTML} from "lit/directives/unsafe-html.js"
|
||||
|
||||
/**
|
||||
* Home portlet to show a note
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
|
||||
import {classMap, css, html, nothing, repeat, TemplateResult} from "@lion/core";
|
||||
import shoelace from "../../api/js/etemplate/Styles/shoelace";
|
||||
import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
|
||||
import {css, html, nothing, TemplateResult} from "lit";
|
||||
import {classMap} from "lit/directives/class-map.js";
|
||||
import {repeat} from "lit/directives/repeat.js";
|
||||
|
||||
/**
|
||||
* Show current and forecast weather
|
||||
|
72
package-lock.json
generated
72
package-lock.json
generated
@ -10,8 +10,6 @@
|
||||
"license": "GPL-2.0",
|
||||
"dependencies": {
|
||||
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
|
||||
"@lion/core": "^0.21.1",
|
||||
"@lion/form-core": "^0.16.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@shoelace-style/shoelace": "2.15.0",
|
||||
"@types/jquery": "^3.5.29",
|
||||
@ -2295,11 +2293,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bundled-es-modules/message-format": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/message-format/-/message-format-6.0.4.tgz",
|
||||
"integrity": "sha512-NGUoPxqsBzDwvRhY3A3L/AhS1hzS9OWappfyDOyCwE7G3W4ua28gau7QwvJz7QzA6ArbAdeb8c1mLjvd1WUFAA=="
|
||||
},
|
||||
"node_modules/@bundled-es-modules/pdfjs-dist": {
|
||||
"version": "2.5.207-rc1",
|
||||
"resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.5.207-rc1.tgz",
|
||||
@ -3061,35 +3054,6 @@
|
||||
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@lion/core": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@lion/core/-/core-0.21.1.tgz",
|
||||
"integrity": "sha512-6lCJ7ZLHQBcsZu/XBOEePG4KxxNFI1OD+1wSA4f9KMyHJVA4+FXZEv1mYniWVsfdPXyyAgKnmfB23xD4Z3kwng==",
|
||||
"dependencies": {
|
||||
"@open-wc/dedupe-mixin": "^1.3.0",
|
||||
"@open-wc/scoped-elements": "^2.0.1",
|
||||
"lit": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@lion/form-core": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@lion/form-core/-/form-core-0.16.0.tgz",
|
||||
"integrity": "sha512-b3Tw0y/5eoIkfowJUqH4JIPvleFOsN09MM6Pb8j7QIyweRk/YlSMbirAlEYmdeTo8aOgGRJhbmrOKmukpsPA/g==",
|
||||
"dependencies": {
|
||||
"@lion/core": "^0.21.0",
|
||||
"@lion/localize": "^0.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lion/localize": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@lion/localize/-/localize-0.23.0.tgz",
|
||||
"integrity": "sha512-pGN2JzEPukvgtB3+BpeT13KZnI7mCqyq7m/a+A973XFhH1PJlAyEXdkv3bVJsIpNolqXRVP0lU4vgisMsO8IkQ==",
|
||||
"dependencies": {
|
||||
"@bundled-es-modules/message-format": "6.0.4",
|
||||
"@lion/core": "^0.21.0",
|
||||
"singleton-manager": "^1.4.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@lit-labs/ssr-dom-shim": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
|
||||
@ -3171,12 +3135,14 @@
|
||||
"node_modules/@open-wc/dedupe-mixin": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@open-wc/dedupe-mixin/-/dedupe-mixin-1.3.0.tgz",
|
||||
"integrity": "sha512-UfdK1MPnR6T7f3svzzYBfu3qBkkZ/KsPhcpc3JYhsUY4hbpwNF9wEQtD4Z+/mRqMTJrKg++YSxIxE0FBhY3RIw=="
|
||||
"integrity": "sha512-UfdK1MPnR6T7f3svzzYBfu3qBkkZ/KsPhcpc3JYhsUY4hbpwNF9wEQtD4Z+/mRqMTJrKg++YSxIxE0FBhY3RIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@open-wc/scoped-elements": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@open-wc/scoped-elements/-/scoped-elements-2.0.1.tgz",
|
||||
"integrity": "sha512-JS6ozxUFwFX3+Er91v9yQzNIaFn7OnE0iESKTbFvkkKdNwvAPtp1fpckBKIvWk8Ae9ZcoI9DYZuT2DDbMPcadA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^1.0.0",
|
||||
"@open-wc/dedupe-mixin": "^1.3.0",
|
||||
@ -3891,12 +3857,6 @@
|
||||
"integrity": "sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
@ -3909,16 +3869,6 @@
|
||||
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.72",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.72.tgz",
|
||||
"integrity": "sha512-/e7GWxGzXQF7OJAua7UAYqYi/4VpXEfbGtmYQcAQwP3SjjjAXfybTf/JK5S+SaetB/ChXl8Y2g1hCsj7jDXxcg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
|
||||
@ -5190,7 +5140,8 @@
|
||||
"node_modules/@webcomponents/scoped-custom-element-registry": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@webcomponents/scoped-custom-element-registry/-/scoped-custom-element-registry-0.0.3.tgz",
|
||||
"integrity": "sha512-lpSzgDCGbM99dytb3+J3Suo4+Bk1E13MPnWB42JK8GwxSAxFz+tC7TTv2hhDSIE2IirGNKNKCf3m08ecu6eAsQ=="
|
||||
"integrity": "sha512-lpSzgDCGbM99dytb3+J3Suo4+Bk1E13MPnWB42JK8GwxSAxFz+tC7TTv2hhDSIE2IirGNKNKCf3m08ecu6eAsQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
@ -7138,12 +7089,6 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/custom-element-jet-brains-integration": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/custom-element-jet-brains-integration/-/custom-element-jet-brains-integration-1.2.1.tgz",
|
||||
@ -12995,7 +12940,7 @@
|
||||
"version": "2.79.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
|
||||
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
@ -13459,11 +13404,6 @@
|
||||
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/singleton-manager": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/singleton-manager/-/singleton-manager-1.4.3.tgz",
|
||||
"integrity": "sha512-Jy1Ib9cO9xCQ6UZ/vyFOqqWMnSpfZ8/Sc2vme944aWsCLO+lMPiFG9kGZGpyiRT9maYeI0JyZH1CGgjmkSN8VA=="
|
||||
},
|
||||
"node_modules/sinon": {
|
||||
"version": "11.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz",
|
||||
|
@ -82,8 +82,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
|
||||
"@lion/core": "^0.21.1",
|
||||
"@lion/form-core": "^0.16.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@shoelace-style/shoelace": "2.15.0",
|
||||
"@types/jquery": "^3.5.29",
|
||||
|
Loading…
Reference in New Issue
Block a user