This is an automated email from the ASF dual-hosted git repository. jleroux pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push: new 79e55dd6e1 Improved: Use browser validation for input element, support types (#862) 79e55dd6e1 is described below commit 79e55dd6e1790211f3a14710caa2947adb1ce5d3 Author: Florian Motteau <florian.mott...@nereide.fr> AuthorDate: Mon Dec 16 17:29:19 2024 +0100 Improved: Use browser validation for input element, support types (#862) * Improved: Use browser validation for input element, support types Rely on browser native validation for inputs, using the "required" attribute, instead of jQuery Validation plugin. Support "number", "email", "url" and "tel" input types. Support "pattern" attribute for input types that supports it. Fix boolean attributes uses in FTL macros ("readonly", "required"). Fix required behavior when "required-field-style" is not empty. Add "required" attribute on password fields. Add "required" attribute to inputs in login forms OFBIZ-13183 * Improved: Use input type=number for numeric fields OFBIZ-13183 * Adjust new input types appearance OFBIZ-13183 * Use input type "email" instead of "text" for email fields OFBIZ-13183 * Fix checkstyle issues OFBIZ-13183 * Fix XSD issue You can't have both type="xs:string" and a nested complexType for the same element. OFBIZ-13183 * Always add an asterisk on mandatory fields Even if we defined a "required-field-style" attribute OFBIZ-13183 * Fix test on required-field-style attribute OFBIZ-13183 * Update renderAsterisks macro declarations OFBIZ-13183 --- applications/accounting/widget/InvoiceForms.xml | 10 +- .../humanres/widget/forms/EmployeeForms.xml | 2 +- .../marketing/widget/sfa/forms/AccountForms.xml | 2 +- .../marketing/widget/sfa/forms/ContactForms.xml | 2 +- .../marketing/widget/sfa/forms/LeadForms.xml | 4 +- applications/order/template/entry/CustSettings.ftl | 2 +- .../party/template/party/EditContactMech.ftl | 2 +- .../widget/partymgr/CommunicationEventForms.xml | 2 +- .../product/template/facility/EditContactMech.ftl | 2 +- framework/widget/dtd/widget-form.xsd | 19 +++ .../apache/ofbiz/widget/model/ModelFormField.java | 32 ++++- .../ofbiz/widget/model/ModelFormFieldBuilder.java | 7 +- .../macro/RenderableFtlFormElementsBuilder.java | 33 +++-- .../RenderableFtlFormElementsBuilderTest.java | 148 +++++++++++++++++++++ themes/bluelight/webapp/bluelight/style.css | 3 +- themes/common-theme/template/Login.ftl | 4 +- .../template/macro/CsvFormMacroLibrary.ftl | 2 +- .../template/macro/FoFormMacroLibrary.ftl | 2 +- .../template/macro/HtmlFormMacroLibrary.ftl | 38 ++++-- .../template/macro/TextFormMacroLibrary.ftl | 2 +- .../template/macro/XlsFormMacroLibrary.ftl | 2 +- .../template/macro/XmlFormMacroLibrary.ftl | 2 +- .../webapp/common-theme/js/util/OfbizUtil.js | 4 - themes/helveticus/template/Login.ftl | 4 +- .../webapp/helveticus/helveticus-main-theme.less | 6 +- themes/rainbowstone/template/Login.ftl | 4 +- themes/tomahawk/webapp/tomahawk/css/style.css | 3 +- 27 files changed, 281 insertions(+), 62 deletions(-) diff --git a/applications/accounting/widget/InvoiceForms.xml b/applications/accounting/widget/InvoiceForms.xml index c14a7390ed..6035393580 100644 --- a/applications/accounting/widget/InvoiceForms.xml +++ b/applications/accounting/widget/InvoiceForms.xml @@ -636,11 +636,11 @@ under the License. </service> </actions> <field name="invoiceId"><hidden/></field> - <field name="emailAddressFrom" entry-name="mapFrom.emailAddress" parameter-name="sendFrom" use-when=""${invoice.invoiceTypeId}".equals("SALES_INVOICE")"><text/></field> - <field name="emailAddressFrom" entry-name="mapTo.emailAddress" parameter-name="sendFrom" use-when=""${invoice.invoiceTypeId}".equals("PURCHASE_INVOICE")"><text/></field> - <field name="emailAddressTo" entry-name="mapTo.emailAddress" parameter-name="sendTo" use-when=""${invoice.invoiceTypeId}".equals("SALES_INVOICE")"><text/></field> - <field name="emailAddressTo" entry-name="mapFrom.emailAddress" parameter-name="sendTo" use-when=""${invoice.invoiceTypeId}".equals("PURCHASE_INVOICE")"><text/></field> - <field name="emailAddressCc" entry-name="ccEmailAddress" parameter-name="sendCc"><text/></field> + <field name="emailAddressFrom" entry-name="mapFrom.emailAddress" parameter-name="sendFrom" use-when=""${invoice.invoiceTypeId}".equals("SALES_INVOICE")"><text type="email"/></field> + <field name="emailAddressFrom" entry-name="mapTo.emailAddress" parameter-name="sendFrom" use-when=""${invoice.invoiceTypeId}".equals("PURCHASE_INVOICE")"><text type="email"/></field> + <field name="emailAddressTo" entry-name="mapTo.emailAddress" parameter-name="sendTo" use-when=""${invoice.invoiceTypeId}".equals("SALES_INVOICE")"><text type="email"/></field> + <field name="emailAddressTo" entry-name="mapFrom.emailAddress" parameter-name="sendTo" use-when=""${invoice.invoiceTypeId}".equals("PURCHASE_INVOICE")"><text type="email"/></field> + <field name="emailAddressCc" entry-name="ccEmailAddress" parameter-name="sendCc"><text type="email"/></field> <field name="subject"><text default-value="Please find attached invoice."/></field> <field name="otherCurrency" entry-name="parameters.other" parameter-name="other"><check/></field> <field name="bodyText"><textarea/></field> diff --git a/applications/humanres/widget/forms/EmployeeForms.xml b/applications/humanres/widget/forms/EmployeeForms.xml index 8fd76ffc47..93724e031d 100644 --- a/applications/humanres/widget/forms/EmployeeForms.xml +++ b/applications/humanres/widget/forms/EmployeeForms.xml @@ -63,7 +63,7 @@ <field name="contactNumber" title="${uiLabelMap.PartyPhoneNumber}" required-field="true"><text size="15" maxlength="15"/></field> <field name="extension" title="${uiLabelMap.PartyContactExt}"><text size="6" maxlength="10"/></field> <field name="emailAddressTitle" title="${uiLabelMap.PartyEmailAddress}" title-area-style="group-label"><display/></field> - <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60"/></field> + <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60" type="email"/></field> <field name="submitButton" title="${uiLabelMap.CommonSave}" widget-style="smallSubmit"><submit button-type="button"/></field> </form> <form name="AddEmployeeSkills" type="single" target="createEmployeeSkill" default-map-name="partySkill"> diff --git a/applications/marketing/widget/sfa/forms/AccountForms.xml b/applications/marketing/widget/sfa/forms/AccountForms.xml index c1540527b0..b6f81d80d9 100644 --- a/applications/marketing/widget/sfa/forms/AccountForms.xml +++ b/applications/marketing/widget/sfa/forms/AccountForms.xml @@ -64,7 +64,7 @@ under the License. <field name="contactNumber" title="${uiLabelMap.PartyPhoneNumber}"><text size="15" maxlength="15"/></field> <field name="extension" title="${uiLabelMap.PartyContactExt}"><text size="6" maxlength="10"/></field> <field name="emailAddressTitle" title="${uiLabelMap.PartyEmailAddress}" title-area-style="group-label"><display/></field> - <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60"/></field> + <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60" type="email"/></field> <field name="submitButton" title="${uiLabelMap.CommonSave}" widget-style="smallSubmit"><submit button-type="button"/></field> </form> diff --git a/applications/marketing/widget/sfa/forms/ContactForms.xml b/applications/marketing/widget/sfa/forms/ContactForms.xml index 1ff65396a6..83f71885a5 100644 --- a/applications/marketing/widget/sfa/forms/ContactForms.xml +++ b/applications/marketing/widget/sfa/forms/ContactForms.xml @@ -141,7 +141,7 @@ under the License. <field name="contactNumber" title="${uiLabelMap.PartyPhoneNumber}"><text size="15" maxlength="15"/></field> <field name="extension" title="${uiLabelMap.PartyContactExt}"><text size="6" maxlength="10"/></field> <field name="emailAddressTitle" title="${uiLabelMap.PartyEmailAddress}" title-area-style="group-label"><display/></field> - <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60"/></field> + <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60" type="email"/></field> <field name="contactListTitle" title="${uiLabelMap.MarketingContactList}" title-area-style="group-label"><display/></field> <field name="contactListId" title="${uiLabelMap.MarketingContactList}"> <drop-down allow-empty="true"> diff --git a/applications/marketing/widget/sfa/forms/LeadForms.xml b/applications/marketing/widget/sfa/forms/LeadForms.xml index 59070b6a30..2db0fc9ec6 100644 --- a/applications/marketing/widget/sfa/forms/LeadForms.xml +++ b/applications/marketing/widget/sfa/forms/LeadForms.xml @@ -56,7 +56,7 @@ under the License. <field name="contactNumber" title="${uiLabelMap.PartyPhoneNumber}"><text size="15" maxlength="15"/></field> <field name="extension" title="${uiLabelMap.PartyContactExt}"><text size="6" maxlength="10"/></field> <field name="emailAddressTitle" title="${uiLabelMap.PartyEmailAddress}" title-area-style="group-label"><display/></field> - <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60"/></field> + <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="50" maxlength="60" type="email"/></field> <field name="leadSourceTitle" title="${uiLabelMap.SfaLeadSource}" title-area-style="group-label"><display/></field> <field name="dataSourceId" title="${uiLabelMap.SfaLeadSource}"> <drop-down allow-empty="true"> @@ -123,7 +123,7 @@ under the License. <field name="firstName" title="${uiLabelMap.PartyFirstName}" required-field="true"><text size="15"/></field> <field name="lastName" title="${uiLabelMap.PartyLastName}" required-field="true"><text size="15"/></field> <field name="groupName" title="${uiLabelMap.CommonGroup}"><text size="15"/></field> - <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="15"/></field> + <field name="emailAddress" title="${uiLabelMap.CommonEmail}"><text size="15" type="email"/></field> <field name="contactListId" title="${uiLabelMap.MarketingContactList}"> <drop-down allow-empty="true"> <entity-options entity-name="ContactList" key-field-name="contactListId" description="${groovy:contactListName.substring(0,Math.min(contactListName.length(), 12))}..."/> diff --git a/applications/order/template/entry/CustSettings.ftl b/applications/order/template/entry/CustSettings.ftl index 791a97ebb4..82542c3caa 100644 --- a/applications/order/template/entry/CustSettings.ftl +++ b/applications/order/template/entry/CustSettings.ftl @@ -107,7 +107,7 @@ under the License. <td width="26%" align="right"><div>${uiLabelMap.PartyEmailAddress}<br/>${uiLabelMap.OrderAllowSolicitation}</div></td> <td width="5"> </td> <td width="74%"> - <input type="text" name="emailAddress" value="" size="60" maxlength="255" /> + <input type="text" name="emailAddress" value="" size="60" maxlength="255" type="email"/> <br/> <select name="emailSol"> <#if ("Y" == ((requestParameters.emailSol)!""))><option value="Y">${uiLabelMap.CommonY}</option></#if> diff --git a/applications/party/template/party/EditContactMech.ftl b/applications/party/template/party/EditContactMech.ftl index f418ab3053..cfb9ebaded 100644 --- a/applications/party/template/party/EditContactMech.ftl +++ b/applications/party/template/party/EditContactMech.ftl @@ -203,7 +203,7 @@ under the License. <tr> <td class="label">${mechMap.contactMechType.get("description",locale)}</td> <td> - <input type="text" size="60" maxlength="255" name="emailAddress" value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}" /> + <input type="email" size="60" maxlength="255" name="emailAddress" value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}" /> </td> </tr> <#elseif "FTP_ADDRESS" = mechMap.contactMechTypeId!> diff --git a/applications/party/widget/partymgr/CommunicationEventForms.xml b/applications/party/widget/partymgr/CommunicationEventForms.xml index b526dda26b..f4d5a9effa 100644 --- a/applications/party/widget/partymgr/CommunicationEventForms.xml +++ b/applications/party/widget/partymgr/CommunicationEventForms.xml @@ -928,7 +928,7 @@ under the License. <field name="donePage"><hidden value="${donePage}"/></field> <field name="communicationEventId"><hidden value="${parameters.communicationEventId}"/></field> <field name="partyId" entry-name="dummy" tooltip="${uiLabelMap.PartyLeaveEmpty}"><lookup target-form-name="LookupPartyName"/></field> - <field name="emailAddress"><text/></field> + <field name="emailAddress"><text type="email"/></field> <field name="firstName" position="1"><text/></field> <field name="middleName" position="2"><text/></field> <field name="lastName"><text/></field> diff --git a/applications/product/template/facility/EditContactMech.ftl b/applications/product/template/facility/EditContactMech.ftl index 1ec648119e..356d133e1c 100644 --- a/applications/product/template/facility/EditContactMech.ftl +++ b/applications/product/template/facility/EditContactMech.ftl @@ -221,7 +221,7 @@ under the License. <tr> <td class="label">${uiLabelMap.PartyEmailAddress}</td> <td> - <input type="text" class="required" size="60" maxlength="255" name="emailAddress" value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}" /> + <input type="email" class="required" size="60" maxlength="255" name="emailAddress" value="${(mechMap.contactMech.infoString)?default(request.getParameter('emailAddress')!)}" /> *</td> </tr> <#else> diff --git a/framework/widget/dtd/widget-form.xsd b/framework/widget/dtd/widget-form.xsd index 76e9cda4f0..25993c66d7 100644 --- a/framework/widget/dtd/widget-form.xsd +++ b/framework/widget/dtd/widget-form.xsd @@ -1497,6 +1497,25 @@ under the License. <xs:documentation>Specifies a short hint that describes the expected value of an input field.</xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="type" default="text"> + <xs:annotation> + <xs:documentation>Controls the type attribute on the input element. Limited to a few types. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types</xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="text" /> + <xs:enumeration value="number" /> + <xs:enumeration value="email" /> + <xs:enumeration value="url" /> + <xs:enumeration value="tel" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="pattern" type="xs:string"> + <xs:annotation> + <xs:documentation>Controls the pattern attribute of the input element. See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern</xs:documentation> + </xs:annotation> + </xs:attribute> </xs:complexType> </xs:element> <xs:element name="textarea" substitutionGroup="AllFields"> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormField.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormField.java index fdb653f9f8..02b6b1de08 100644 --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormField.java +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormField.java @@ -5441,12 +5441,16 @@ public final class ModelFormField { private final boolean readonly; private final int size; private final SubHyperlink subHyperlink; + private final String type; + private final String pattern; public TextField(Element element, ModelFormField modelFormField) { super(element, modelFormField); this.clientAutocompleteField = !"false".equals(element.getAttribute("client-autocomplete-field")); this.defaultValue = FlexibleStringExpander.getInstance(element.getAttribute("default-value")); this.mask = element.getAttribute("mask"); + this.type = element.getAttribute("type"); + this.pattern = element.getAttribute("pattern"); Integer maxlength = null; String maxlengthStr = element.getAttribute("maxlength"); if (!maxlengthStr.isEmpty()) { @@ -5484,6 +5488,8 @@ public final class ModelFormField { this.clientAutocompleteField = true; this.defaultValue = FlexibleStringExpander.getInstance(""); this.mask = ""; + this.type = ""; + this.pattern = ""; this.maxlength = maxlength; this.placeholder = FlexibleStringExpander.getInstance(""); this.readonly = false; @@ -5491,11 +5497,13 @@ public final class ModelFormField { this.subHyperlink = null; } - protected TextField(int fieldSource, int size, Integer maxlength, ModelFormField modelFormField) { + protected TextField(int fieldSource, int size, Integer maxlength, String type, ModelFormField modelFormField) { super(fieldSource, FieldInfo.TEXT, modelFormField); this.clientAutocompleteField = true; this.defaultValue = FlexibleStringExpander.getInstance(""); this.mask = ""; + this.type = type; + this.pattern = ""; this.maxlength = maxlength; this.placeholder = FlexibleStringExpander.getInstance(""); this.readonly = false; @@ -5508,6 +5516,8 @@ public final class ModelFormField { this.clientAutocompleteField = true; this.defaultValue = FlexibleStringExpander.getInstance(""); this.mask = ""; + this.type = ""; + this.pattern = ""; this.maxlength = null; this.placeholder = FlexibleStringExpander.getInstance(""); this.readonly = false; @@ -5528,6 +5538,8 @@ public final class ModelFormField { this.clientAutocompleteField = original.clientAutocompleteField; this.defaultValue = original.defaultValue; this.mask = original.mask; + this.type = original.type; + this.pattern = original.pattern; this.placeholder = original.placeholder; this.size = original.size; this.maxlength = original.maxlength; @@ -5639,6 +5651,22 @@ public final class ModelFormField { throws IOException { formStringRenderer.renderTextField(writer, context, this); } + + /** + * Gets type. + * @return the type + */ + public String getType() { + return this.type; + } + + /** + * Gets pattern. + * @return the pattern + */ + public String getPattern() { + return this.pattern; + } } /** @@ -5666,7 +5694,7 @@ public final class ModelFormField { } public TextFindField(int fieldSource, int size, Integer maxlength, ModelFormField modelFormField) { - super(fieldSource, size, maxlength, modelFormField); + super(fieldSource, size, maxlength, "", modelFormField); this.defaultOption = UtilProperties.getPropertyValue("widget", "widget.form.defaultTextFindOption", "contains"); this.hideIgnoreCase = false; this.hideOptions = false; diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormFieldBuilder.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormFieldBuilder.java index 9647fa9641..d3429d8691 100644 --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormFieldBuilder.java +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormFieldBuilder.java @@ -803,10 +803,10 @@ public class ModelFormFieldBuilder { this.setFieldInfo(textareaField); } else if (TEXT_FIELD_TYPES.contains(fieldType)) { ModelFormField.TextField textField = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_ENTITY, - TEXT_SIZE_BY_FIELD_TYPES.get(fieldType), TEXT_MAX_SIZE_BY_FIELD_TYPES.get(fieldType), null); + TEXT_SIZE_BY_FIELD_TYPES.get(fieldType), TEXT_MAX_SIZE_BY_FIELD_TYPES.get(fieldType), "text", null); this.setFieldInfo(textField); } else if (NUMERIC_FIELD_TYPES.contains(fieldType)) { - ModelFormField.TextField textField = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_ENTITY, 6, null, null); + ModelFormField.TextField textField = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_ENTITY, 6, null, "number", null); this.setFieldInfo(textField); } else if (DATA_FIELD_TYPES.contains(fieldType)) { String type = fieldType; @@ -880,7 +880,7 @@ public class ModelFormFieldBuilder { if ("text".equals(modelParamFieldType)) { fieldInfo = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_SERVICE, null); } else if ("numeric".equals(modelParamFieldType)) { - fieldInfo = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_SERVICE, 6, null, null); + fieldInfo = new ModelFormField.TextField(FieldInfo.SOURCE_AUTO_SERVICE, 6, null, "number", null); } else if ("timestamp".equals(modelParamFieldType)) { fieldInfo = new ModelFormField.DateTimeField(FieldInfo.SOURCE_AUTO_SERVICE, "timestamp"); } else if ("date".equals(modelParamFieldType)) { @@ -1047,6 +1047,7 @@ public class ModelFormFieldBuilder { this.encodeOutput = builder.getEncodeOutput(); this.position = builder.getPosition(); this.requiredField = builder.getRequiredField(); + this.requiredFieldStyle = builder.getRequiredFieldStyle(); this.separateColumn = builder.getSeparateColumn(); this.disabled = builder.getDisabledSpec(); } diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java index 92e336131d..413132c09f 100644 --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java @@ -108,16 +108,13 @@ public final class RenderableFtlFormElementsBuilder { public RenderableFtl asterisks(final Map<String, Object> context, final ModelFormField modelFormField) { String requiredField = "false"; - String requiredStyle = ""; if (modelFormField.getRequiredField()) { requiredField = "true"; - requiredStyle = modelFormField.getRequiredFieldStyle(); } return RenderableFtlMacroCall.builder() .name("renderAsterisks") .stringParameter("requiredField", requiredField) - .stringParameter("requiredStyle", requiredStyle) .build(); } @@ -253,12 +250,20 @@ public final class RenderableFtlFormElementsBuilder { final boolean javaScriptEnabled) { ModelFormField modelFormField = textField.getModelFormField(); String name = modelFormField.getParameterName(context); - String className = ""; + String type = textField.getType(); + if (UtilValidate.isEmpty(type)) { + type = "text"; + } + String pattern = ""; + if (List.of("text", "email", "url", "tel").contains(type)) { + pattern = textField.getPattern(); + } + List<String> classes = new ArrayList<>(); String alert = "false"; String mask = ""; String placeholder = textField.getPlaceholder(context); if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) { - className = modelFormField.getWidgetStyle(); + classes.add(modelFormField.getWidgetStyle()); if (modelFormField.shouldBeRed(context)) { alert = "true"; } @@ -275,14 +280,13 @@ public final class RenderableFtlFormElementsBuilder { String clientAutocomplete = "false"; //check for required field style on single forms if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) { + // kept for backward compatibility with existing CSS/JS + // maybe unused if jQuery Validation is no longer used + // for styling we should rely on "required" attribute + classes.add("required"); String requiredStyle = modelFormField.getRequiredFieldStyle(); - if (UtilValidate.isEmpty(requiredStyle)) { - requiredStyle = "required"; - } - if (UtilValidate.isEmpty(className)) { - className = requiredStyle; - } else { - className = requiredStyle + " " + className; + if (UtilValidate.isNotEmpty(requiredStyle)) { + classes.add(requiredStyle); } } List<ModelForm.UpdateArea> updateAreas = modelFormField.getOnChangeUpdateAreas(); @@ -301,7 +305,9 @@ public final class RenderableFtlFormElementsBuilder { return RenderableFtlMacroCall.builder() .name("renderTextField") .stringParameter("name", name) - .stringParameter("className", className) + .stringParameter("className", String.join(" ", classes)) + .stringParameter("type", type) + .stringParameter("pattern", pattern) .stringParameter("alert", alert) .stringParameter("value", value) .stringParameter("textSize", textSize) @@ -311,6 +317,7 @@ public final class RenderableFtlFormElementsBuilder { .stringParameter("action", action != null ? action : "") .booleanParameter("disabled", disabled) .booleanParameter("readonly", readonly) + .booleanParameter("required", modelFormField.getRequiredField()) .stringParameter("clientAutocomplete", clientAutocomplete) .stringParameter("ajaxUrl", ajaxUrl) .booleanParameter("ajaxEnabled", ajaxEnabled) diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java index 80debaed87..c31b0a966d 100644 --- a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java +++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java @@ -240,6 +240,154 @@ public class RenderableFtlFormElementsBuilderTest { + "areaId2,http://host.domain/target2,"))); } + @Test + public void textFieldDefaultTypeIsText(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("type", "text"))); + } + + @Test + public void textFieldTypeNumber(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getType(); result = "number"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("type", "number"))); + } + + @Test + public void textFieldTypeEmail(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getType(); result = "email"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("type", "email"))); + } + + @Test + public void textFieldTypeUrl(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getType(); result = "url"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("type", "url"))); + } + + @Test + public void textFieldTypeTel(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getType(); result = "tel"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("type", "tel"))); + } + + @Test + public void textFieldNotRequired(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + modelFormField.getRequiredField(); result = false; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndBooleanValue("required", false))); + } + + @Test + public void textFieldRequiredWithoutRequiredStyle(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + modelFormField.getModelForm().getType(); result = "single"; + modelFormField.getRequiredField(); result = true; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndBooleanValue("required", true))); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("className", "required"))); + } + + @Test + public void textFieldRequiredWithRequiredStyle(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + modelFormField.getModelForm().getType(); result = "single"; + modelFormField.getRequiredField(); result = true; + modelFormField.getRequiredFieldStyle(); result = "someCssClass"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndBooleanValue("required", true))); + assertThat(renderableFtl, MacroCallMatcher.hasParameters( + MacroCallParameterMatcher.hasNameAndStringValue("className", "required someCssClass"))); + } + + @Test + public void textFieldPattern(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getPattern(); result = "\\d{4,4}"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("pattern", "\\d{4,4}"))); + } + + @Test + public void textFieldPatternOnInvalidType(@Mocked final ModelFormField.TextField textField) { + new Expectations() { + { + textField.getPattern(); result = "\\d{4,4}"; + textField.getType(); result = "number"; + httpSession.getAttribute("delegatorName"); result = "DelegatorName"; + } + }; + + textField.getPattern(); + final RenderableFtl renderableFtl = renderableFtlFormElementsBuilder.textField(Map.of("session", httpSession), textField, true); + + assertThat(renderableFtl, MacroCallMatcher.hasName("renderTextField")); + assertThat(renderableFtl, MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("pattern", ""))); + } + @Test public void textareaFieldSetsIdValueLengthAndSize(@Mocked final ModelFormField.TextareaField textareaField) { final int maxLength = 142; diff --git a/themes/bluelight/webapp/bluelight/style.css b/themes/bluelight/webapp/bluelight/style.css index ec7858f198..e64d8e6fea 100644 --- a/themes/bluelight/webapp/bluelight/style.css +++ b/themes/bluelight/webapp/bluelight/style.css @@ -106,7 +106,8 @@ input[type="radio"], input[type="checkbox"] { margin: 0.2em; } -input[type="text"], input[type="password"] { +input[type="text"], input[type="password"], input[type="number"], +input[type="email"], input[type="url"], input[type="tel"] { background-color: #ffffff; border: #999999 solid 0.1em; font-size: 1.1em; diff --git a/themes/common-theme/template/Login.ftl b/themes/common-theme/template/Login.ftl index 72ec964d06..98fe5cdd0f 100644 --- a/themes/common-theme/template/Login.ftl +++ b/themes/common-theme/template/Login.ftl @@ -36,11 +36,11 @@ under the License. <table class="basic-table" cellspacing="0"> <tr> <td class="label">${uiLabelMap.CommonUsername}</td> - <td><input type="text" name="USERNAME" value="${username}" size="20"/></td> + <td><input type="text" name="USERNAME" value="${username}" size="20" required/></td> </tr> <tr> <td class="label">${uiLabelMap.CommonPassword}</td> - <td><input type="password" name="PASSWORD" autocomplete="off" value="" size="20"/></td> + <td><input type="password" name="PASSWORD" autocomplete="off" value="" size="20" required/></td> </tr> <#if ("Y" == useMultitenant) > <#if !requestAttributes.userTenantId??> diff --git a/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl b/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl index 8b95d8d86e..379b8ae111 100644 --- a/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/CsvFormMacroLibrary.ftl @@ -117,7 +117,7 @@ under the License. <#macro renderHyperlinkTitle name title showSelectAll="N"></#macro> <#macro renderSortField style title linkUrl ajaxEnabled tooltip=""><@renderFieldTitle style title /></#macro> <#macro formatBoundaryComment boundaryType widgetType widgetName></#macro> -<#macro renderAsterisks requiredField requiredStyle></#macro> +<#macro renderAsterisks requiredField></#macro> <#macro makeHiddenFormLinkForm actionUrl name parameters targetWindow></#macro> <#macro makeHiddenFormLinkAnchor linkStyle hiddenFormName event action imgSrc description confirmation><@renderField description /></#macro> <#macro makeHyperlinkString hiddenFormName imgSrc imgTitle title alternate linkUrl description linkStyle="" event="" action="" targetParameters="" targetWindow="" confirmation="" uniqueItemName="" height="" width="" id=""><@renderField description />,<#rt/></#macro> diff --git a/themes/common-theme/template/macro/FoFormMacroLibrary.ftl b/themes/common-theme/template/macro/FoFormMacroLibrary.ftl index 15cc3c43f2..a48b69925b 100644 --- a/themes/common-theme/template/macro/FoFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/FoFormMacroLibrary.ftl @@ -145,5 +145,5 @@ under the License. <#macro makeHiddenFormLinkAnchor linkStyle hiddenFormName event action imgSrc description><@renderField description /></#macro> <#macro makeHyperlinkString hiddenFormName imgSrc imgTitle title alternate linkUrl description linkStyle="" event="" action="" targetParameters="" targetWindow="" confirmation="" uniqueItemName="" height="" width="" id=""><@makeBlock linkStyle description /></#macro> <#macro renderTooltip tooltip tooltipStyle></#macro> -<#macro renderAsterisks requiredField requiredStyle></#macro> +<#macro renderAsterisks requiredField></#macro> </#escape> diff --git a/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl b/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl index bccbb7eaea..0199d51da1 100644 --- a/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl @@ -43,8 +43,10 @@ under the License. </#macro> <#macro renderHyperlinkField></#macro> -<#macro renderTextField name className alert value="" textSize="" maxlength="" id="" event="" action="" disabled=false clientAutocomplete="" ajaxUrl="" ajaxEnabled="" mask="" tabindex="" readonly="" placeholder="" delegatorName="default"> - <input type="text" name="${name?default("")?html}"<#t/> +<#macro renderTextField type pattern name className alert value="" textSize="" maxlength="" id="" event="" action="" + disabled=false clientAutocomplete="" ajaxUrl="" ajaxEnabled="" mask="" tabindex="" readonly="" required=false + placeholder="" delegatorName="default"> + <input type="${type}" name="${name?default("")?html}"<#t/> <#if ajaxEnabled?has_content && ajaxEnabled && ajaxUrl?has_content> <#local defaultMinLength = modelTheme.getAutocompleterDefaultMinLength()> <#local defaultDelay = modelTheme.getAutocompleterDefaultDelay()> @@ -58,14 +60,15 @@ under the License. <#if value?has_content> value="${value}"</#if><#rt/> <#if textSize?has_content> size="${textSize}"</#if><#rt/> <#if maxlength?has_content> maxlength="${maxlength}"</#if><#rt/> - <#if readonly?has_content && readonly> readonly="readonly"</#if><#rt/> + <#if readonly?has_content && readonly> readonly</#if><#rt/> <#if mask?has_content> data-mask="${mask}"</#if><#rt/> <#if id?has_content> id="${id}"</#if><#rt/> <#if event?has_content && action?has_content> ${event}="${action}"</#if><#rt/> <#if clientAutocomplete?has_content && clientAutocomplete=="false"> autocomplete="off"</#if><#rt/> <#if placeholder?has_content> placeholder="${placeholder}"</#if><#rt/> <#if tabindex?has_content> tabindex="${tabindex}"</#if><#rt/> - require + <#if required?has_content && required> required</#if> + <#if pattern?has_content> pattern="${pattern}"</#if> /><#t/> </#macro> @@ -78,7 +81,7 @@ under the License. <#if cols?has_content> cols="${cols}"</#if><#rt/> <#if rows?has_content> rows="${rows}"</#if><#rt/> <#if id?has_content> id="${id}"</#if><#rt/> - <#if readonly?has_content && readonly=='readonly'> readonly="readonly"</#if><#rt/> + <#if readonly?has_content && readonly=='readonly'> readonly</#if><#rt/> <#if maxlength?has_content> maxlength="${maxlength}"</#if><#rt/> <#if tabindex?has_content> tabindex="${tabindex}"</#if><#rt/> <#if visualEditorEnable?has_content> data-toolbar="${buttons?default("maxi")}"</#if><#rt/> @@ -321,7 +324,15 @@ under the License. <#macro renderSingleFormFieldTitle></#macro> <#macro renderFormOpen linkUrl formType name viewIndexField viewSizeField viewIndex viewSize targetWindow="" containerId="" containerStyle="" autocomplete="" useRowSubmit="" focusFieldName="" hasRequiredField="" csrfNameValue=""> - <form method="post" action="${linkUrl}"<#if formType=="upload"> enctype="multipart/form-data"</#if><#if targetWindow?has_content> target="${targetWindow}"</#if><#if containerId?has_content> id="${containerId}"</#if> <#if focusFieldName?has_content> data-focus-field="${focusFieldName}"</#if> class="<#if containerStyle?has_content>${containerStyle}<#else>basic-form</#if><#if hasRequiredField?has_content> requireValidation</#if>" onsubmit="javascript:submitFormDisableSubmits(this)"<#if au [...] + <form method="post" action="${linkUrl}" + <#if formType=="upload"> enctype="multipart/form-data"</#if> + <#if targetWindow?has_content> target="${targetWindow}"</#if> + <#if containerId?has_content> id="${containerId}"</#if> + <#if focusFieldName?has_content> data-focus-field="${focusFieldName}"</#if> + class="<#if containerStyle?has_content>${containerStyle}<#else>basic-form</#if>" + onsubmit="javascript:submitFormDisableSubmits(this)" + <#if autocomplete?has_content> autocomplete="${autocomplete}"</#if> + name="${name}"><#lt/> <#if csrfNameValue?has_content> <#assign result = csrfNameValue?matches(r"(\w+) (\w+)")> <#if result> @@ -640,7 +651,11 @@ Parameter: lastViewName, String, optional - If the ajaxEnabled parameter is true Parameter: tabindex, String, optional - HTML tabindex number. Parameter: delegatorName, String, optional - name of the delegator in context. --> -<#macro renderLookupField name formName fieldFormName conditionGroup="" className="" alert="false" value="" size="" maxlength="" id="" event="" action="" readonly=false autocomplete="" descriptionFieldName="" targetParameterIter="" imgSrc="" ajaxUrl="" ajaxEnabled=javaScriptEnabled presentation="layer" width=modelTheme.getLookupWidth() height=modelTheme.getLookupHeight() position=modelTheme.getLookupPosition() fadeBackground="true" clearText="" showDescription="" initiallyCollapsed="" la [...] +<#macro renderLookupField name formName fieldFormName conditionGroup="" className="" alert="false" value="" size="" + maxlength="" id="" event="" action="" readonly=false autocomplete="" descriptionFieldName="" targetParameterIter="" + imgSrc="" ajaxUrl="" ajaxEnabled=javaScriptEnabled presentation="layer" width=modelTheme.getLookupWidth() + height=modelTheme.getLookupHeight() position=modelTheme.getLookupPosition() fadeBackground="true" clearText="" + showDescription="" initiallyCollapsed="" lastViewName="main" tabindex="" delegatorName="default" disabled=false> <#if Static["org.apache.ofbiz.widget.model.ModelWidget"].widgetBoundaryCommentsEnabled(context)><#-- context is always null here, but this is handled in widgetBoundaryCommentsEnabled --> <!-- @renderLookupField --> </#if> @@ -669,7 +684,7 @@ Parameter: delegatorName, String, optional - name of the delegator in context. <input type="text" <@renderClass className alert /> <@renderDisabled disabled /> <#if name?has_content> name="${name}"</#if><#if value?has_content> value="${value}"</#if><#if tabindex?has_content> tabindex="${tabindex}"</#if><#rt/> <#if size?has_content> size="${size}"</#if><#if maxlength?has_content> maxlength="${maxlength}"</#if><#if id?has_content> id="${id}"</#if><#rt/> - <#if readonly?has_content && readonly> readonly="readonly"</#if><#rt/><#if event?has_content && action?has_content> ${event}="${action}"</#if><#rt/> + <#if readonly?has_content && readonly> readonly</#if><#rt/><#if event?has_content && action?has_content> ${event}="${action}"</#if><#rt/> <#if autocomplete?has_content> autocomplete="off"</#if><#rt/> </#if> data-lookup-ajax-enabled="<#if ajaxEnabled?has_content>${ajaxEnabled?string}<#else>false</#if>" <#rt/> @@ -771,7 +786,8 @@ Parameter: delegatorName, String, optional - name of the delegator in context. <#if maxlength?has_content> maxlength="${maxlength}"</#if> <#if id?has_content> id="${id}"</#if> <#if autocomplete?has_content> autocomplete="off"</#if> - <#if tabindex?has_content> tabindex="${tabindex}"</#if>/><#rt/> + <#if tabindex?has_content> tabindex="${tabindex}"</#if> + required/><#rt/> </#macro> <#macro renderImageField action value="" description="" alternate="" style="" event=""><img<#if value?has_content> src="${value}"</#if><#if description?has_content> title="${description}"</#if> alt="<#if alternate?has_content>${alternate}"</#if><#if style?has_content> class="${style}"</#if><#if event?has_content> ${event?html}="${action}" </#if>/></#macro> @@ -827,8 +843,8 @@ Parameter: delegatorName, String, optional - name of the delegator in context. <#if className?has_content || (alert?has_content && alert=="true")> class="${className}<#if alert?has_content && alert=="true"> alert</#if>" </#if> </#macro> -<#macro renderAsterisks requiredField requiredStyle> - <#if requiredField=="true"><#if !requiredStyle?has_content>*</#if></#if> +<#macro renderAsterisks requiredField> + <#if requiredField=="true">*</#if> </#macro> <#macro renderDisabled disabled> diff --git a/themes/common-theme/template/macro/TextFormMacroLibrary.ftl b/themes/common-theme/template/macro/TextFormMacroLibrary.ftl index ad10a54c05..42cc065153 100644 --- a/themes/common-theme/template/macro/TextFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/TextFormMacroLibrary.ftl @@ -116,7 +116,7 @@ under the License. <#macro renderHyperlinkTitle name title showSelectAll="N"></#macro> <#macro renderSortField style title linkUrl ajaxEnabled tooltip=""><@renderFieldTitle style title /></#macro> <#macro formatBoundaryComment boundaryType widgetType widgetName></#macro> -<#macro renderAsterisks requiredField requiredStyle>*</#macro> +<#macro renderAsterisks requiredField>*</#macro> <#macro makeHiddenFormLinkForm actionUrl name parameters targetWindow></#macro> <#macro makeHiddenFormLinkAnchor linkStyle hiddenFormName event action imgSrc description confirmation><@renderField description /></#macro> <#macro makeHyperlinkString linkStyle hiddenFormName event action imgSrc title targetParameters alternate linkUrl targetWindow description confirmation uniqueItemName="" height="" width="" id=""><@renderField description /></#macro> diff --git a/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl b/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl index c8872e2f67..c5dd16e416 100644 --- a/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/XlsFormMacroLibrary.ftl @@ -150,7 +150,7 @@ under the License. <#macro renderClass className="" alert=""></#macro> -<#macro renderAsterisks requiredField requiredStyle></#macro> +<#macro renderAsterisks requiredField></#macro> <#macro makeHiddenFormLinkForm actionUrl name parameters targetWindow></#macro> <#macro makeHiddenFormLinkAnchor linkStyle hiddenFormName event action imgSrc description confirmation><td>${description!}</td></#macro> diff --git a/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl b/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl index 5678840d5b..3845880b1d 100644 --- a/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl +++ b/themes/common-theme/template/macro/XmlFormMacroLibrary.ftl @@ -118,4 +118,4 @@ under the License. <#macro makeHiddenFormLinkAnchor linkStyle hiddenFormName event action imgSrc description confirmation><@renderField description /></#macro> <#macro makeHyperlinkString linkStyle hiddenFormName event action imgSrc title targetParameters alternate linkUrl targetWindow description confirmation uniqueItemName="" height="" width="" id=""><@renderField description /></#macro> <#macro renderTooltip tooltip tooltipStyle></#macro> -<#macro renderAsterisks requiredField requiredStyle></#macro> +<#macro renderAsterisks requiredField></#macro> diff --git a/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js b/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js index 5f1942614c..fb1cb53f6c 100644 --- a/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js +++ b/themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js @@ -345,10 +345,6 @@ function bindObservers(bind_element) { var focusField = element.data("focus-field"); element.find("[name=" + focusField + "]").focus(); }); - jQuery(bind_element).find(".requireValidation").each(function () { - var element = jQuery(this); - element.validate(); - }); jQuery(bind_element).find(".date-time-picker").each(function () { initDateTimePicker(this); }); diff --git a/themes/helveticus/template/Login.ftl b/themes/helveticus/template/Login.ftl index 25434bf9dc..273d1ad7f0 100644 --- a/themes/helveticus/template/Login.ftl +++ b/themes/helveticus/template/Login.ftl @@ -36,14 +36,14 @@ under the License. <form method="post" action="<@ofbizUrl>login</@ofbizUrl>" name="loginform"> <label> ${uiLabelMap.CommonUsername} - <input type="text" name="USERNAME" value="${username}" tabindex="0"/> + <input type="text" name="USERNAME" value="${username}" tabindex="0" required/> </label> <label> <span> ${uiLabelMap.CommonPassword} </span> - <input type="password" name="PASSWORD" autocomplete="off" value="" tabindex="0"/> + <input type="password" name="PASSWORD" autocomplete="off" value="" tabindex="0" required/> <a href="<@ofbizUrl>forgotPassword</@ofbizUrl>">${uiLabelMap.CommonForgotYourPassword}</a> </label> diff --git a/themes/helveticus/webapp/helveticus/helveticus-main-theme.less b/themes/helveticus/webapp/helveticus/helveticus-main-theme.less index f9e7c7401f..c9d309ce35 100644 --- a/themes/helveticus/webapp/helveticus/helveticus-main-theme.less +++ b/themes/helveticus/webapp/helveticus/helveticus-main-theme.less @@ -1479,7 +1479,8 @@ i.hoverTooltip { } } - input[type="text"], input[type="password"] { + input[type="text"], input[type="password"], input[type="number"], + input[type="email"], input[type="url"], input[type="tel"] { border: none; background-color: @grey-light; padding: 1rem; @@ -1606,7 +1607,8 @@ i.hoverTooltip { } } - input[type="text"], input[type="password"] { + input[type="text"], input[type="password"], input[type="number"], + input[type="email"], input[type="url"], input[type="tel"] { border: none; background-color: @grey-light; padding: 1rem; diff --git a/themes/rainbowstone/template/Login.ftl b/themes/rainbowstone/template/Login.ftl index 44cee9552c..557b87fbd8 100644 --- a/themes/rainbowstone/template/Login.ftl +++ b/themes/rainbowstone/template/Login.ftl @@ -37,11 +37,11 @@ under the License. <table class="basic-table" cellspacing="0"> <tr> <td class="label">${uiLabelMap.CommonUsername}</td> - <td><input type="text" name="USERNAME" value="${username}" size="20"/></td> + <td><input type="text" name="USERNAME" value="${username}" size="20" required/></td> </tr> <tr> <td class="label">${uiLabelMap.CommonPassword}</td> - <td><input type="password" name="PASSWORD" autocomplete="off" value="" size="20"/></td> + <td><input type="password" name="PASSWORD" autocomplete="off" value="" size="20" required/></td> </tr> <#if ("Y" == useMultitenant) > <#if !requestAttributes.userTenantId??> diff --git a/themes/tomahawk/webapp/tomahawk/css/style.css b/themes/tomahawk/webapp/tomahawk/css/style.css index aecc9fbe06..0590fa66b7 100644 --- a/themes/tomahawk/webapp/tomahawk/css/style.css +++ b/themes/tomahawk/webapp/tomahawk/css/style.css @@ -102,7 +102,8 @@ input[type="radio"], input[type="checkbox"] { vertical-align: middle; } -input[type="text"], input[type="password"] { +input[type="text"], input[type="password"], input[type="number"], +input[type="email"], input[type="url"], input[type="tel"] { background-color: #fffcea; border: 0.1em solid #999999; font-size: 1.1em;