forked from extern/egroupware
Switch Et2Template to extend SlInput instead of LionInput
Also includes changes to how validation messages are handled to use our own stuff
This commit is contained in:
parent
e4f8c88e1e
commit
379ceeb3e5
@ -1,8 +1,9 @@
|
|||||||
import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "../et2_core_interfaces";
|
import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "../et2_core_interfaces";
|
||||||
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||||
import {css, dedupeMixin, LitElement, PropertyValues} from "@lion/core";
|
import {css, dedupeMixin, LitElement, PropertyValues} from "@lion/core";
|
||||||
import {ManualMessage} from "../Validators/ManualMessage";
|
|
||||||
import {Required} from "../Validators/Required";
|
import {Required} from "../Validators/Required";
|
||||||
|
import {ManualMessage} from "../Validators/ManualMessage";
|
||||||
|
import {LionValidationFeedback} from "@lion/form-core";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mixin will allow any LitElement to become an Et2InputWidget
|
* This mixin will allow any LitElement to become an Et2InputWidget
|
||||||
@ -320,9 +321,100 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Massively simplified validate, as compared to what ValidatorMixin gives us, since ValidatorMixin extends
|
||||||
|
* FormControlMixin which breaks SlSelect's render()
|
||||||
|
*/
|
||||||
|
async validate()
|
||||||
|
{
|
||||||
|
let validators = [...(this.validators || []), ...(this.defaultValidators || [])];
|
||||||
|
let fieldName = this.id;
|
||||||
|
let feedbackData = [];
|
||||||
|
let resultPromises = [];
|
||||||
|
this.querySelector("lion-validation-feedback")?.remove();
|
||||||
|
const doValidate = async function(validator, value)
|
||||||
|
{
|
||||||
|
if(validator.config.fieldName)
|
||||||
|
{
|
||||||
|
fieldName = await validator.config.fieldName;
|
||||||
|
}
|
||||||
|
// @ts-ignore [allow-protected]
|
||||||
|
return validator._getMessage({
|
||||||
|
modelValue: value,
|
||||||
|
formControl: this,
|
||||||
|
fieldName,
|
||||||
|
}).then((message) =>
|
||||||
|
{
|
||||||
|
feedbackData.push({message, type: validator.type, validator});
|
||||||
|
});
|
||||||
|
}.bind(this);
|
||||||
|
const doCheck = async(value, validator) =>
|
||||||
|
{
|
||||||
|
const result = validator.execute(value, validator.param, {node: this});
|
||||||
|
if(result === true)
|
||||||
|
{
|
||||||
|
resultPromises.push(doValidate(validator, value));
|
||||||
|
}
|
||||||
|
else if(result !== false && typeof result.then === 'function')
|
||||||
|
{
|
||||||
|
result.then(doValidate(validator, value));
|
||||||
|
resultPromises.push(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
validators.map(async validator =>
|
||||||
|
{
|
||||||
|
let values = this.value;
|
||||||
|
if(!Array.isArray(values))
|
||||||
|
{
|
||||||
|
values = [values];
|
||||||
|
}
|
||||||
|
if(!values.length)
|
||||||
|
{
|
||||||
|
values = [''];
|
||||||
|
} // so required validation works
|
||||||
|
|
||||||
|
// Run manual validation messages just once, doesn't usually matter what the value is
|
||||||
|
if(validator instanceof ManualMessage)
|
||||||
|
{
|
||||||
|
doCheck(values, validator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Validate each individual item
|
||||||
|
values.forEach((value) => doCheck(value, validator));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Promise.all(resultPromises);
|
||||||
|
|
||||||
|
if(feedbackData.length > 0)
|
||||||
|
{
|
||||||
|
let feedback = <LionValidationFeedback>document.createElement("lion-validation-feedback");
|
||||||
|
feedback.feedbackData = feedbackData;
|
||||||
|
feedback.slot = "help-text";
|
||||||
|
this.append(feedback);
|
||||||
|
// Not always visible?
|
||||||
|
(<HTMLElement>this.shadowRoot.querySelector("#help-text")).style.display = "initial";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
set_validation_error(err : string | false)
|
set_validation_error(err : string | false)
|
||||||
{
|
{
|
||||||
// ToDo - implement Lion validators properly, most likely by adding to this.validators
|
/* Shoelace uses constraint validation API
|
||||||
|
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api
|
||||||
|
|
||||||
|
if(err === false && this.setCustomValidity)
|
||||||
|
{
|
||||||
|
// Remove custom validity
|
||||||
|
this.setCustomValidity('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setCustomValidity(err);
|
||||||
|
|
||||||
|
// must call reportValidity() or nothing will happen
|
||||||
|
this.reportValidity();
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
if(err === false)
|
if(err === false)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,6 @@ import {Et2WithSearchMixin} from "./SearchMixin";
|
|||||||
import {Et2Tag} from "./Tag/Et2Tag";
|
import {Et2Tag} from "./Tag/Et2Tag";
|
||||||
import {LionValidationFeedback} from "@lion/form-core";
|
import {LionValidationFeedback} from "@lion/form-core";
|
||||||
import {RowLimitedMixin} from "../Layout/RowLimitedMixin";
|
import {RowLimitedMixin} from "../Layout/RowLimitedMixin";
|
||||||
import {ManualMessage} from "../Validators/ManualMessage";
|
|
||||||
|
|
||||||
// export Et2WidgetWithSelect which is used as type in other modules
|
// export Et2WidgetWithSelect which is used as type in other modules
|
||||||
export class Et2WidgetWithSelect extends RowLimitedMixin(Et2widgetWithSelectMixin(SlSelect))
|
export class Et2WidgetWithSelect extends RowLimitedMixin(Et2widgetWithSelectMixin(SlSelect))
|
||||||
@ -437,83 +436,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
|
|||||||
return [...this.querySelectorAll<SlMenuItem>(this.optionTag)];
|
return [...this.querySelectorAll<SlMenuItem>(this.optionTag)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Massively simplified validate, as compared to what ValidatorMixin gives us, since ValidatorMixin extends
|
|
||||||
* FormControlMixin which breaks SlSelect's render()
|
|
||||||
*/
|
|
||||||
async validate()
|
|
||||||
{
|
|
||||||
let validators = [...(this.validators || []), ...(this.defaultValidators || [])];
|
|
||||||
let fieldName = this.id;
|
|
||||||
let feedbackData = [];
|
|
||||||
let resultPromises = [];
|
|
||||||
this.querySelector("lion-validation-feedback")?.remove();
|
|
||||||
const doValidate = async function(validator, value)
|
|
||||||
{
|
|
||||||
if(validator.config.fieldName)
|
|
||||||
{
|
|
||||||
fieldName = await validator.config.fieldName;
|
|
||||||
}
|
|
||||||
// @ts-ignore [allow-protected]
|
|
||||||
return validator._getMessage({
|
|
||||||
modelValue: value,
|
|
||||||
formControl: this,
|
|
||||||
fieldName,
|
|
||||||
}).then((message) =>
|
|
||||||
{
|
|
||||||
feedbackData.push({message, type: validator.type, validator});
|
|
||||||
});
|
|
||||||
}.bind(this);
|
|
||||||
const doCheck = async(value, validator) =>
|
|
||||||
{
|
|
||||||
const result = validator.execute(value, validator.param, {node: this});
|
|
||||||
if(result === true)
|
|
||||||
{
|
|
||||||
resultPromises.push(doValidate(validator, value));
|
|
||||||
}
|
|
||||||
else if(result !== false && typeof result.then === 'function')
|
|
||||||
{
|
|
||||||
result.then(doValidate(validator, value));
|
|
||||||
resultPromises.push(result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
validators.map(async validator =>
|
|
||||||
{
|
|
||||||
let values = this.value;
|
|
||||||
if(!Array.isArray(values))
|
|
||||||
{
|
|
||||||
values = [values];
|
|
||||||
}
|
|
||||||
if(!values.length)
|
|
||||||
{
|
|
||||||
values = [''];
|
|
||||||
} // so required validation works
|
|
||||||
|
|
||||||
// Run manual validation messages just once, doesn't usually matter what the value is
|
|
||||||
if(validator instanceof ManualMessage)
|
|
||||||
{
|
|
||||||
doCheck(values, validator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Validate each individual item
|
|
||||||
values.forEach((value) => doCheck(value, validator));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await Promise.all(resultPromises);
|
|
||||||
|
|
||||||
if(feedbackData.length > 0)
|
|
||||||
{
|
|
||||||
let feedback = <LionValidationFeedback>document.createElement("lion-validation-feedback");
|
|
||||||
feedback.feedbackData = feedbackData;
|
|
||||||
feedback.slot = "help-text";
|
|
||||||
this.append(feedback);
|
|
||||||
// Not always visible?
|
|
||||||
(<HTMLElement>this.shadowRoot.querySelector("#help-text")).style.display = "initial";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override parent to always call validate(), as our simple implementation needs to validate on clear as well.
|
* Override parent to always call validate(), as our simple implementation needs to validate on clear as well.
|
||||||
*
|
*
|
||||||
|
@ -10,22 +10,30 @@
|
|||||||
|
|
||||||
|
|
||||||
import {css, PropertyValues} from "@lion/core";
|
import {css, PropertyValues} from "@lion/core";
|
||||||
import {LionInput} from "@lion/input";
|
|
||||||
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
|
||||||
import {Regex} from "../Validators/Regex";
|
import {Regex} from "../Validators/Regex";
|
||||||
|
import {SlInput} from "@shoelace-style/shoelace";
|
||||||
|
import shoelace from "../Styles/shoelace";
|
||||||
|
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
|
||||||
|
|
||||||
export class Et2Textbox extends Et2InputWidget(LionInput)
|
export class Et2Textbox extends Et2InputWidget(SlInput)
|
||||||
{
|
{
|
||||||
|
|
||||||
static get styles()
|
static get styles()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
...shoelace,
|
||||||
...super.styles,
|
...super.styles,
|
||||||
css`
|
css`
|
||||||
:host([type="hidden"]) {
|
:host([type="hidden"]) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
`,
|
.input__control {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.input:hover:not(.input--disabled) .input__control {
|
||||||
|
color: var(--input-text-color, inherit);
|
||||||
|
}
|
||||||
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ registerIconLibrary('default', {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Customise shoelace styles to match our stuff
|
* Customise shoelace styles to match our stuff
|
||||||
* External CSS will override this
|
* External CSS & widget styles will override this
|
||||||
*/
|
*/
|
||||||
export default [sl_css, css`
|
export default [sl_css, css`
|
||||||
:root,
|
:root,
|
||||||
|
@ -2102,6 +2102,8 @@ div.message.floating, lion-validation-feedback[type] {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
top: 100%;
|
||||||
|
left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message.validation_error, lion-validation-feedback[type="error"] {
|
.message.validation_error, lion-validation-feedback[type="error"] {
|
||||||
|
Loading…
Reference in New Issue
Block a user