[Rt-commit] rt branch 5.0/cf-input-required-attr created. rt-5.0.5-45-gfd38390c5d

BPS Git Server git at git.bestpractical.com
Thu Nov 16 15:48:25 UTC 2023


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".

The branch, 5.0/cf-input-required-attr has been created
        at  fd38390c5deddc591e0bebd3d9bfb812d06fc5c6 (commit)

- Log -----------------------------------------------------------------
commit fd38390c5deddc591e0bebd3d9bfb812d06fc5c6
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Nov 3 13:27:24 2023 -0400

    Add "required" attribute for mandatory custom field inputs
    
    The attribute isn't enabled for "List" style of multi-value select
    custom fields: "required" means each "required" checkbox must be
    checked, but we want to allow to check just some of them.
    
    For mandatory select inputs, previously in a67e05ea49 we chose to keep
    "(no value)" as the initial state to force user to manually select one
    valid option. This commit implements the logic in js, and there is no
    need to keep the invalid "(no value)" option any more.

diff --git a/share/html/Admin/CustomFields/Modify.html b/share/html/Admin/CustomFields/Modify.html
index 6e35d8da72..904eaea04d 100644
--- a/share/html/Admin/CustomFields/Modify.html
+++ b/share/html/Admin/CustomFields/Modify.html
@@ -181,7 +181,7 @@ jQuery( function() {
 % if ( $CustomFieldObj->SupportDefaultValues ) {
 <&| /Elements/LabeledValue, Label => loc("Default [numerate,_1,value,values]", $CustomFieldObj->MaxValues),
     Class => $default_value_class &>
-  <& /Elements/EditCustomField, NamePrefix => 'Default-', CustomField => $CustomFieldObj, ShowEmptyOption => 1 &>
+  <& /Elements/EditCustomField, NamePrefix => 'Default-', CustomField => $CustomFieldObj, ShowEmptyOption => 1, Required => 0 &>
 </&>
 % }
 
diff --git a/share/html/Admin/Queues/DefaultValues.html b/share/html/Admin/Queues/DefaultValues.html
index 0cde0c46dd..3f69b0fb2e 100644
--- a/share/html/Admin/Queues/DefaultValues.html
+++ b/share/html/Admin/Queues/DefaultValues.html
@@ -68,6 +68,8 @@
       CustomFields => $queue->TicketCustomFields->LimitToDefaultValuesSupportedTypes,
       Grouping => 'Basics',
       CategoryObj => $queue,
+      ShowEmptyOption => 1,
+      Required => 0,
   &>
 
   <&| /Elements/LabeledValue, Label => loc('Article') &>
@@ -91,6 +93,8 @@
       CustomFields => $queue->TicketCustomFields->LimitToDefaultValuesSupportedTypes,
       Grouping => 'Dates',
       CategoryObj => $queue,
+      ShowEmptyOption => 1,
+      Required => 0,
   &>
   </&>
 </div>
@@ -103,6 +107,8 @@
       CustomFields => $queue->TicketCustomFields->LimitToDefaultValuesSupportedTypes,
       Grouping => 'People',
       CategoryObj => $queue,
+      ShowEmptyOption => 1,
+      Required => 0,
   &>
   </&>
 </div>
@@ -116,6 +122,8 @@
       CustomFields => $queue->TicketCustomFields->LimitToDefaultValuesSupportedTypes,
       Grouping => 'Links',
       CategoryObj => $queue,
+      ShowEmptyOption => 1,
+      Required => 0,
   &>
   </&>
 </div>
@@ -126,11 +134,13 @@
     Object => RT::Ticket->new($session{CurrentUser}),
     Groupings => \@groupings,
     CategoryObj => $queue,
+    ShowEmptyOption => 1,
+    Required => 0,
 &>
 
 <div class="ticket-info-cfs">
   <&|/Widgets/TitleBox, title => loc("Transaction Custom Fields"), content_class => 'mx-auto width-sm' &>
-  <& /Elements/EditCustomFields, CustomFields => $queue->TicketTransactionCustomFields->LimitToDefaultValuesSupportedTypes, Object => RT::Transaction->new($session{CurrentUser}), QueueObj => $queue, &>
+  <& /Elements/EditCustomFields, CustomFields => $queue->TicketTransactionCustomFields->LimitToDefaultValuesSupportedTypes, Object => RT::Transaction->new($session{CurrentUser}), QueueObj => $queue, ShowEmptyOption => 1, Required => 0 &>
   </&>
 </div>
 
diff --git a/share/html/Elements/EditCustomField b/share/html/Elements/EditCustomField
index c088917ee7..b2e7572064 100644
--- a/share/html/Elements/EditCustomField
+++ b/share/html/Elements/EditCustomField
@@ -162,4 +162,5 @@ $Rows        => 5
 $Cols        => 15
 $Default     => undef
 $DefaultsFromTopArguments => 1,
+$Required    => undef
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldAutocomplete b/share/html/Elements/EditCustomFieldAutocomplete
index 40104555ae..2acef923d7 100644
--- a/share/html/Elements/EditCustomFieldAutocomplete
+++ b/share/html/Elements/EditCustomFieldAutocomplete
@@ -53,6 +53,9 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
+% if ( $Required ) {
+required
+% }
 name="<% $name %>" id="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control"><% $Default || '' %></textarea>
 
 <script type="text/javascript">
@@ -78,7 +81,11 @@ jQuery('#'+id).autocomplete( {
 }
 );
 % } else {
-<input type="text" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control" value="<% $Default || '' %>"/>
+<input type="text" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control" value="<% $Default || '' %>"
+% if ( $Required ) {
+  required
+% }
+/>
 <script type="text/javascript">
 var id = <% $name |n,j%>;
 id = id.replace(/:/g,'\\:');
@@ -114,4 +121,5 @@ $Values      => undef
 $Multiple    => undef
 $Rows        => undef
 $Cols        => undef
+$Required    => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldBinary b/share/html/Elements/EditCustomFieldBinary
index 87f74913a4..60f3d88fac 100644
--- a/share/html/Elements/EditCustomFieldBinary
+++ b/share/html/Elements/EditCustomFieldBinary
@@ -68,7 +68,11 @@
 % }
 
 <div class="custom-file">
-  <input type="file" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input" />
+  <input type="file" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input"
+% if ( $Required ) {
+    required
+% }
+  />
   <label class="custom-file-label" for="<% $name %>"><&|/l&>Choose file</&></label>
 </div>
 
@@ -86,4 +90,5 @@ $Name   => undef
 $Default => undef
 $Values => undef
 $MaxValues => undef
+$Required => ( ( $Values && $Values->Count ) || $CustomField->MatchPattern('') ) ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldCombobox b/share/html/Elements/EditCustomFieldCombobox
index b0653885a1..5422ebb568 100644
--- a/share/html/Elements/EditCustomFieldCombobox
+++ b/share/html/Elements/EditCustomFieldCombobox
@@ -58,6 +58,7 @@
     Rows    => $Rows,
     Class   => "CF-".$CustomField->id."-Edit",
     Values  => [map {$_->Name} @{CachedCustomFieldValues($CustomField)->ItemsArrayRef}],
+    Required => $Required,
 &>
 
 <%INIT>
@@ -76,4 +77,5 @@ $Multiple => 0
 $Rows => undef
 $MaxValues => undef
 $Name => undef
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldDate b/share/html/Elements/EditCustomFieldDate
index 7b99dba0b0..cceacb1ba2 100644
--- a/share/html/Elements/EditCustomFieldDate
+++ b/share/html/Elements/EditCustomFieldDate
@@ -48,7 +48,7 @@
 % my $name = $Name || $NamePrefix.$CustomField->Id.'-Values';
 <div class="form-row">
   <div class="col-auto">
-    <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0, ShowTime => 0 &>
+    <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0, ShowTime => 0, Required => $Required, &>
   </div>
   <div class="col-auto">
     <span class="current-value form-control">(<%$DateObj->AsString(Time => 0, Timezone => 'utc')%>)</span>
@@ -66,4 +66,5 @@ $Default => undef
 $Values => undef
 $MaxValues => 1
 $Name => undef
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldDateTime b/share/html/Elements/EditCustomFieldDateTime
index ac41403e51..f3f8129ade 100644
--- a/share/html/Elements/EditCustomFieldDateTime
+++ b/share/html/Elements/EditCustomFieldDateTime
@@ -48,7 +48,7 @@
 % my $name = $Name || $NamePrefix.$CustomField->Id.'-Values';
 <div class="form-row">
     <div class="col-auto">
-        <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0 &>
+        <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0, Required => $Required, &>
     </div>
     <div class="col-auto">
         <span class="current-value form-control">(<%$DateObj->AsString%>)</span>
@@ -68,4 +68,5 @@ $Values => undef
 $MaxValues => 1
 $Name => undef
 $Format => 'unknown'
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldFreeform b/share/html/Elements/EditCustomFieldFreeform
index c7c5ed1874..85345f3de7 100644
--- a/share/html/Elements/EditCustomFieldFreeform
+++ b/share/html/Elements/EditCustomFieldFreeform
@@ -54,12 +54,18 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
+% if ( $Required ) {
+required
+% }
 name="<%$name%>" id="<%$name%>" wrap="off" class="CF-<%$CustomField->id%>-Edit form-control"><% defined($Default) ? $Default : '' %></textarea>
 % } else {
 <input type="text" name="<%$name%>" id="<%$name%>" \
 % if ( defined $Cols ) {
 size="<% $Cols %>" \
 % }
+% if ( $Required ) {
+required
+% }
 class="CF-<%$CustomField->id%>-Edit form-control" value="<% defined($Default) ? $Default : ''%>" />
 % }
 <%INIT>
@@ -80,4 +86,5 @@ $Values => undef
 $Multiple => undef
 $Cols
 $Rows
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldHTML b/share/html/Elements/EditCustomFieldHTML
index 90200b6bdf..2f74612ca1 100644
--- a/share/html/Elements/EditCustomFieldHTML
+++ b/share/html/Elements/EditCustomFieldHTML
@@ -64,6 +64,9 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
+% if ( $Required ) {
+required
+% }
 name="<%$name%>" class="CF-<%$CustomField->id%>-Edit form-control richtext"><% $Default %></textarea>
 % }
 <%INIT>
@@ -81,4 +84,5 @@ $Values => undef
 $MaxValues => undef
 $Cols
 $Rows
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldImage b/share/html/Elements/EditCustomFieldImage
index 478bade2f6..5efac3f9c0 100644
--- a/share/html/Elements/EditCustomFieldImage
+++ b/share/html/Elements/EditCustomFieldImage
@@ -60,7 +60,11 @@
 % }
 
 <div class="custom-file">
-  <input type="file" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input" />
+  <input type="file" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input"
+% if ( $Required ) {
+    required
+% }
+  />
   <label class="custom-file-label" for="<% $name %>"><&|/l&>Choose file</&></label>
 </div>
 
@@ -78,4 +82,5 @@ $Name => undef
 $Default => undef
 $Values => undef
 $MaxValues => undef
+$Required => ( ( $Values && $Values->Count ) || $CustomField->MatchPattern('') ) ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldSelect b/share/html/Elements/EditCustomFieldSelect
index 9921e5e965..8caf1c1355 100644
--- a/share/html/Elements/EditCustomFieldSelect
+++ b/share/html/Elements/EditCustomFieldSelect
@@ -72,7 +72,7 @@
 %     my $content = $value->Name;
 %     my $labelid = "$name-". $value->id;
 <div data-name="<% $value->Category || '' %>" class="custom-control custom-<% $checktype %>">
-  <input class="custom-control-input"  type="<% $checktype %>" name="<% $name %>" id="<% $labelid %>" value="<% $content %>" <% $default{ lc $content }? ' checked="checked"' : '' |n%> />
+  <input class="custom-control-input"  type="<% $checktype %>" name="<% $name %>" id="<% $labelid %>" value="<% $content %>" <% $default{ lc $content }? ' checked="checked"' : '' |n%> <% $checktype eq 'radio' && $Required ? 'required' : '' %>/>
   <label class="custom-control-label" for="<% $labelid %>"><% $content %></label><br />
 </div>
 %   }
@@ -85,7 +85,7 @@
 %   my $TrueValue  = ( $checkbox_value = $CFVs->Next ) ? $checkbox_value->Name : 'True';
 %   my $isChecked = (scalar keys %default) && (not exists $default{lc $FalseValue});
   <div class="custom-control custom-checkbox">
-    <input id="<% $name . '-Display' %>" type="checkbox" class="custom-control-input" data-checked-value="<% $TrueValue %>" data-unchecked-value="<% $FalseValue %>" value-target="#<% $name %>" <% $isChecked ? "checked" : "" %> />
+    <input id="<% $name . '-Display' %>" type="checkbox" class="custom-control-input" data-checked-value="<% $TrueValue %>" data-unchecked-value="<% $FalseValue %>" value-target="#<% $name %>" <% $isChecked ? "checked" : "" %> <% $Required && !$CustomField->MatchPattern($FalseValue) ? 'required' : '' %> />
     <label class="custom-control-label" for="<% $name . '-Display' %>"></label>
     <input type="hidden" id="<% $name %>" name="<% $name %>" class="custom-control" value="<% $isChecked ? $TrueValue : $FalseValue %>" />
   </div>
@@ -123,6 +123,9 @@
 % if ( $size > 1 ) {
   size="<% $Rows %>"
 % }
+% if ( $Required ) {
+  required
+% }
 <% $Multiple && qq[multiple="multiple"] |n %> >
 % if ( $show_empty_option ) {
 <option value=""<% !$selected && qq[ selected="selected"] |n %>><&|/l&>(no value)</&></option>
@@ -164,11 +167,6 @@ else {
     if ( $CustomField->MatchPattern('') ) {
         $show_empty_option = 1;
     }
-    elsif ( $CustomField->SupportDefaultValues ) {
-        my ( $on ) = grep { $_->isa( $CustomField->RecordClassFromLookupType ) } $CustomField->ACLEquivalenceObjects;
-        my $default_values = $CustomField->DefaultValues( Object => $on || RT->System );
-        $show_empty_option = 1 unless defined $default_values && length $default_values;
-    }
 }
 
 my $use_chosen = CachedCustomFieldValues($CustomField)->Count >= 10 ? 1 : 0;
@@ -191,6 +189,7 @@ $Rows => undef
 $HideCategory => 0
 $RenderType => undef
 $MaxValues => 1
+$Required => $CustomField->MatchPattern('') ? 0 : 1,
 </%ARGS>
 
 <%METHOD options>
diff --git a/share/html/Elements/EditCustomFieldText b/share/html/Elements/EditCustomFieldText
index ac365b6ad4..eea620a927 100644
--- a/share/html/Elements/EditCustomFieldText
+++ b/share/html/Elements/EditCustomFieldText
@@ -63,6 +63,9 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
+% if ( $Required ) {
+required
+% }
 name="<%$name%>" class="CF-<%$CustomField->id%>-Edit form-control"><% defined($Default) ? $Default : '' %></textarea>
 % }
 <%INIT>
@@ -80,4 +83,5 @@ $Values => undef
 $MaxValues => undef
 $Cols
 $Rows
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFieldWikitext b/share/html/Elements/EditCustomFieldWikitext
index d28add1c2b..27fe152194 100644
--- a/share/html/Elements/EditCustomFieldWikitext
+++ b/share/html/Elements/EditCustomFieldWikitext
@@ -63,6 +63,9 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
+% if ( $Required ) {
+required
+% }
 name="<%$name%>" class="CF-<%$CustomField->id%>-Edit form-control"><% $Default %></textarea>
 % }
 <%INIT>
@@ -80,4 +83,5 @@ $Values => undef
 $MaxValues => undef
 $Cols
 $Rows
+$Required => $CustomField->MatchPattern('') ? 0 : 1
 </%ARGS>
diff --git a/share/html/Elements/EditCustomFields b/share/html/Elements/EditCustomFields
index fdecf23507..12f76cd6a6 100644
--- a/share/html/Elements/EditCustomFields
+++ b/share/html/Elements/EditCustomFields
@@ -125,4 +125,5 @@ $LabelCols => 3
 $ValueCols => 9
 $ShowHints => 1
 $ForCreation => 0
+$Required => undef
 </%ARGS>
diff --git a/share/html/Elements/SelectDate b/share/html/Elements/SelectDate
index 1425e1bcef..af7e047654 100644
--- a/share/html/Elements/SelectDate
+++ b/share/html/Elements/SelectDate
@@ -49,6 +49,9 @@
 <input type="text" class="datepicker<% $ShowTime ? ' withtime' : '' %> form-control"
 % if ( $id ) {
  id="<% $id %>"
+% }
+% if ( $Required ) {
+required
 % }
  name="<% $Name %>" value="<% $Default %>" size="<% $Size %>" autocomplete="off" />
 % $m->callback( %ARGS, Name => $Name, CallbackName => 'AfterDateInput', Object => $Object, ARGSRef => $ARGSRef, );
@@ -78,4 +81,5 @@ $Size        => 16
 $Object      => undef
 $ARGSRef     => undef
 $id          => undef
+$Required    => undef
 </%args>
diff --git a/share/html/Widgets/ComboBox b/share/html/Widgets/ComboBox
index 681e763ce6..9c3c7cfbd5 100644
--- a/share/html/Widgets/ComboBox
+++ b/share/html/Widgets/ComboBox
@@ -51,7 +51,7 @@ my $z_index = 9999;
 </%once>
 
 <div class="combobox-wrapper" data-name="<% $Name %>" data-value="<% $Default // '' %>">
-  <select class="form-control combobox" size="<% $Rows %>">
+  <select class="form-control combobox" size="<% $Rows %>" <% $Required ? 'required' : '' %>>
     <option value=""></option>
 % for my $value (@Values) {
     <option value="<% $value %>" <% ($Default // '') eq $value ? 'selected="selected"' : '' %>><% $value%></option>
@@ -65,4 +65,5 @@ $Rows    => 5
 $Default => ''
 @Values  => ()
 $Class   => ''
+$Required => undef
 </%ARGS>
diff --git a/share/static/js/cascaded.js b/share/static/js/cascaded.js
index d9596cbd5d..c18850cfed 100644
--- a/share/static/js/cascaded.js
+++ b/share/static/js/cascaded.js
@@ -79,6 +79,11 @@ function filter_cascade_select (select, complete_select, vals) {
         }
     }
 
+    // Do not automatically select the first option for required selects as they don't have empty option
+    if ( jQuery(select).is('[required]') && !jQuery(select).find('option[selected]').length ) {
+        jQuery(select).val(null);
+    }
+
     if ( jQuery(select).closest('div.bootstrap-select').length ) {
         refreshSelectpicker(jQuery(select));
     }
diff --git a/share/static/js/util.js b/share/static/js/util.js
index d349bd6dcc..a7dd4192f9 100644
--- a/share/static/js/util.js
+++ b/share/static/js/util.js
@@ -1021,6 +1021,16 @@ jQuery(function() {
             form.addClass('rt-form-submitted');
         });
     });
+
+    // Do not automatically select the first option for required selects as they don't have empty option
+    jQuery('select[required]').each(function () {
+        if ( !jQuery(this).find('option[selected]').length ) {
+            jQuery(this).val(null);
+            if ( jQuery(this).closest('div.bootstrap-select').length ) {
+                refreshSelectpicker(jQuery(this));
+            }
+        }
+    });
 });
 
 function filterSearchResults () {

-----------------------------------------------------------------------


hooks/post-receive
-- 
rt


More information about the rt-commit mailing list