From fed63006404722dc7f01c2595dda358f3ea257d7 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Tue, 30 Aug 2022 16:40:49 -0400 Subject: [PATCH 1/9] Align datepicker colors with Registry theme (CFM-107) --- app/webroot/css/co-color.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/webroot/css/co-color.css b/app/webroot/css/co-color.css index 02412bea4..1576ec0f0 100644 --- a/app/webroot/css/co-color.css +++ b/app/webroot/css/co-color.css @@ -81,14 +81,14 @@ --cmg-color-black: #000; /* black */ /* Duet Date Picker Colors */ - --duet-color-primary: #005fcc; - --duet-color-text: #333; + --duet-color-primary: #06c; + --duet-color-text: #222; --duet-color-text-active: #fff; --duet-color-placeholder: #666; --duet-color-button: #f5f5f5; --duet-color-surface: #fff; --duet-color-overlay: rgba(0, 0, 0, 0.8); - --duet-color-border: #333; + --duet-color-border: #222; --duet-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; --duet-font-normal: 400; From 8c795f2c386854288b2645f8153d4d8a11ffee0b Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 31 Aug 2022 16:48:07 -0400 Subject: [PATCH 2/9] Honor date-only dates using the date picker (CFM-107) --- app/src/View/Helper/FieldHelper.php | 20 ++++++++--- app/templates/People/fields.inc | 2 +- app/templates/element/datePicker.php | 2 +- .../datepicker/cm-datetimepicker.js | 35 +++++++++++-------- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index a1c04693f..9655e0257 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -96,7 +96,7 @@ public function control(string $fieldName, } // Handle datetime controls specially - if($fieldName == 'valid_from' || $fieldName == 'valid_through') { + if($fieldName == 'valid_from' || $fieldName == 'valid_through' || $fieldName == 'date_of_birth') { // Append the timezone to the label $label = __d('field', $fieldName.".tz", [$this->_View->get('vv_tz')]); @@ -104,7 +104,14 @@ public function control(string $fieldName, // that will interact with the field value. Allowing direct access to the input field is for // accessibility purposes. $coptions['class'] = 'form-control datepicker'; - $coptions['placeholder'] = 'YYYY-MM-DD HH:MM:SS'; // TODO: test for date-only inputs and send only the date + + if(isset($config['dateonly']) && $config['dateonly']) { + $coptions['placeholder'] = 'YYYY-MM-DD'; + $pickerTimed = false; + } else { + $coptions['placeholder'] = 'YYYY-MM-DD HH:MM:SS'; + $pickerTimed = true; + } $coptions['id'] = str_replace("_", "-", $fieldName); $entity = $this->getView()->get('vv_obj'); @@ -112,13 +119,18 @@ public function control(string $fieldName, $pickerDate = ''; if(!empty($entity->$fieldName)) { // Adjust the time back to the user's timezone - $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd HH:mm:ss", $this->getView()->get('vv_tz')); + if($pickerTimed) { + $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd HH:mm:ss", $this->getView()->get('vv_tz')); + } else { + $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd", $this->getView()->get('vv_tz')); + } $pickerDate = $entity->$fieldName->i18nFormat("yyyy-MM-dd", $this->getView()->get('vv_tz')); } $date_args = [ 'fieldName' => $fieldName, - 'pickerDate' => $pickerDate + 'pickerDate' => $pickerDate, + 'pickerTimed' => $pickerTimed ]; // Create a text field to hold our value. $controlCode = $this->Form->text($fieldName, $coptions) diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc index ccb3e0a11..c38570557 100644 --- a/app/templates/People/fields.inc +++ b/app/templates/People/fields.inc @@ -165,5 +165,5 @@ if($vv_action == 'add') { if($vv_action == 'add' || $vv_action == 'edit') { print $this->Field->control('status', ['empty' => false]); - print $this->Field->control('date_of_birth'); + print $this->Field->control('date_of_birth', [], '', ['dateonly' => true]); } \ No newline at end of file diff --git a/app/templates/element/datePicker.php b/app/templates/element/datePicker.php index 077242672..ff2b2357f 100644 --- a/app/templates/element/datePicker.php +++ b/app/templates/element/datePicker.php @@ -10,7 +10,7 @@ // like the models that use the Tree behavior and have the column parent_id $pickerId = 'datepicker-' . str_replace("_", "-", $fieldName); $pickerTarget = str_replace("_", "-", $fieldName); -$pickerTimed = $pickerTimed ?? true; // TODO: set false if date-only +$pickerTimed = $pickerTimed ?? true; $pickerAmPm = $pickerAmPm ?? false; // TODO: allow change between AM/PM and 24-hour mode ?> diff --git a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js index f038808b5..5178f9956 100644 --- a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js +++ b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js @@ -46,19 +46,24 @@ export default { const dateField = document.getElementById(this.target); if(dateField.value === '') { // There's no existing value, so just format what's given. - dateField.value = date + " 00:00:00"; - // If using a Date object, use the following instead: - // dateField.value = this.formatDate(date); + dateField.value = date; + if(this.timed) { + dateField.value += " 00:00:00"; + } } else { - // We need to apply the given date to our existing field value so we can retain the time. - const dateTime = dateField.value.split(' '); - dateTime[0] = date; - // A sanity check to see if someone messed up the field. - // XXX Pattern should also be enforced by the browser. - if(dateTime[1] === undefined || dateTime[1] === '') { - dateTime[1] = '00:00:00'; + if(this.timed) { + // We need to apply the given date to our existing field value so we can retain the time. + const dateTime = dateField.value.split(' '); + dateTime[0] = date; + // A sanity check to see if someone messed up the field. + // XXX Pattern should also be enforced by the browser. + if(dateTime[1] === undefined || dateTime[1] === '') { + dateTime[1] = '00:00:00'; + } + dateField.value = dateTime.join(' '); + } else { + dateField.value = date; } - dateField.value = dateTime.join(' '); } }, formatDate(date) { @@ -67,9 +72,11 @@ export default { let formattedDate = date.getFullYear(); formattedDate += '-' + ('0' + (date.getMonth()+1)).slice(-2); formattedDate += '-' + ('0' + date.getDate()).slice(-2); - formattedDate += ' ' + ('0' + date.getHours()).slice(-2); - formattedDate += ':' + ('0' + date.getMinutes()).slice(-2); - formattedDate += ':' + ('0' + date.getSeconds()).slice(-2); + if(this.timed) { + formattedDate += ' ' + ('0' + date.getHours()).slice(-2); + formattedDate += ':' + ('0' + date.getMinutes()).slice(-2); + formattedDate += ':' + ('0' + date.getSeconds()).slice(-2); + } return(formattedDate); }, showTimePicker() { From d503cddfbdb63b342ccb2bdbd302f764097d45dd Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 31 Aug 2022 18:18:50 -0400 Subject: [PATCH 3/9] Allow date fields to be specified as type 'date', 'dateTime', and 'endDateTime'. Ensure that the default times for endDateTime fields are set to '23:59:59'. (CFM-107) --- app/src/View/Helper/FieldHelper.php | 15 +++++++-------- app/templates/ApiUsers/fields.inc | 4 ++-- app/templates/ExternalIdentities/fields.inc | 2 +- app/templates/ExternalIdentityRoles/fields.inc | 8 ++------ app/templates/GroupMembers/fields.inc | 5 ++--- app/templates/People/fields.inc | 2 +- app/templates/PersonRoles/fields.inc | 8 ++------ app/templates/element/datePicker.php | 6 +++--- .../components/datepicker/cm-datetimepicker.js | 17 ++++++++++------- 9 files changed, 30 insertions(+), 37 deletions(-) diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 9655e0257..5485ce6f9 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -96,7 +96,7 @@ public function control(string $fieldName, } // Handle datetime controls specially - if($fieldName == 'valid_from' || $fieldName == 'valid_through' || $fieldName == 'date_of_birth') { + if(isset($config['dateField'])) { // Append the timezone to the label $label = __d('field', $fieldName.".tz", [$this->_View->get('vv_tz')]); @@ -105,12 +105,11 @@ public function control(string $fieldName, // accessibility purposes. $coptions['class'] = 'form-control datepicker'; - if(isset($config['dateonly']) && $config['dateonly']) { + $pickerType = $config['dateField']; + if($pickerType == 'date') { $coptions['placeholder'] = 'YYYY-MM-DD'; - $pickerTimed = false; } else { $coptions['placeholder'] = 'YYYY-MM-DD HH:MM:SS'; - $pickerTimed = true; } $coptions['id'] = str_replace("_", "-", $fieldName); @@ -119,10 +118,10 @@ public function control(string $fieldName, $pickerDate = ''; if(!empty($entity->$fieldName)) { // Adjust the time back to the user's timezone - if($pickerTimed) { - $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd HH:mm:ss", $this->getView()->get('vv_tz')); - } else { + if($pickerType == 'date') { $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd", $this->getView()->get('vv_tz')); + } else { + $coptions['value'] = $entity->$fieldName->i18nFormat("yyyy-MM-dd HH:mm:ss", $this->getView()->get('vv_tz')); } $pickerDate = $entity->$fieldName->i18nFormat("yyyy-MM-dd", $this->getView()->get('vv_tz')); } @@ -130,7 +129,7 @@ public function control(string $fieldName, $date_args = [ 'fieldName' => $fieldName, 'pickerDate' => $pickerDate, - 'pickerTimed' => $pickerTimed + 'pickerType' => $pickerType ]; // Create a text field to hold our value. $controlCode = $this->Form->text($fieldName, $coptions) diff --git a/app/templates/ApiUsers/fields.inc b/app/templates/ApiUsers/fields.inc index e4eb9bc02..1d7632462 100644 --- a/app/templates/ApiUsers/fields.inc +++ b/app/templates/ApiUsers/fields.inc @@ -56,9 +56,9 @@ if($vv_action == 'add' || $vv_action == 'edit') { print $this->Field->control('status', ['empty' => false]); - print $this->Field->control('valid_from'); + print $this->Field->control('valid_from', [], '', ['dateField' => 'dateTime']); - print $this->Field->control('valid_through'); + print $this->Field->control('valid_through', [], '', ['dateField' => 'endDateTime']); print $this->Field->control('remote_ip'); diff --git a/app/templates/ExternalIdentities/fields.inc b/app/templates/ExternalIdentities/fields.inc index 961774364..08ee448bc 100644 --- a/app/templates/ExternalIdentities/fields.inc +++ b/app/templates/ExternalIdentities/fields.inc @@ -30,7 +30,7 @@ if($vv_action == 'add' || $vv_action == 'edit') { // XXX sync status? print $this->Field->control('status', ['empty' => false]); - print $this->Field->control('date_of_birth'); + print $this->Field->control('date_of_birth', [], '', ['dateField' => 'date']); } // XXX This is a placeholder for canvas... maybe it should become a separate page diff --git a/app/templates/ExternalIdentityRoles/fields.inc b/app/templates/ExternalIdentityRoles/fields.inc index 1bd58b465..890936654 100644 --- a/app/templates/ExternalIdentityRoles/fields.inc +++ b/app/templates/ExternalIdentityRoles/fields.inc @@ -44,13 +44,9 @@ if($vv_action == 'add' || $vv_action == 'edit') { print $this->Field->control('manager_identifier', [], __d('field', 'manager')); -// XXX these need to render date pickers -// - we specifically have code in FieldHelper that checks for these two, but not date_of_birth -// - can FieldHelper introspect the date type rather than require a hard coded list of fields? -// though note valid_from/through uses special logic for 00:00:00 and 23:59:59 - print $this->Field->control('valid_from'); + print $this->Field->control('valid_from', [], '', ['dateField' => 'dateTime']); - print $this->Field->control('valid_through'); + print $this->Field->control('valid_through', [], '', ['dateField' => 'endDateTime']); } // XXX This is a placeholder for canvas... maybe it should become a separate page diff --git a/app/templates/GroupMembers/fields.inc b/app/templates/GroupMembers/fields.inc index 559a946a2..f10945918 100644 --- a/app/templates/GroupMembers/fields.inc +++ b/app/templates/GroupMembers/fields.inc @@ -32,9 +32,8 @@ if($vv_action == 'add') { print $this->Form->hidden('person_id'); } -// XXX valid from should default to 00:00:00 time, valid through to 23:59:59 -print $this->Field->control('valid_from'); +print $this->Field->control('valid_from', [], '', ['dateField' => 'dateTime']); -print $this->Field->control('valid_through'); +print $this->Field->control('valid_through', [], '', ['dateField' => 'endDateTime']); // XXX RFE: Add links to EIS or Nesting info \ No newline at end of file diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc index c38570557..12bcc4245 100644 --- a/app/templates/People/fields.inc +++ b/app/templates/People/fields.inc @@ -165,5 +165,5 @@ if($vv_action == 'add') { if($vv_action == 'add' || $vv_action == 'edit') { print $this->Field->control('status', ['empty' => false]); - print $this->Field->control('date_of_birth', [], '', ['dateonly' => true]); + print $this->Field->control('date_of_birth', [], '', ['dateField' => 'date']); } \ No newline at end of file diff --git a/app/templates/PersonRoles/fields.inc b/app/templates/PersonRoles/fields.inc index b163efe3c..629ac8951 100644 --- a/app/templates/PersonRoles/fields.inc +++ b/app/templates/PersonRoles/fields.inc @@ -57,13 +57,9 @@ if($vv_action == 'add' || $vv_action == 'edit') { print $this->Field->statusControl($f.'_person_id', $fname, $flink, __d('field', $f)); } -// XXX these need to render date pickers -// - we specifically have code in FieldHelper that checks for these two, but not date_of_birth -// - can FieldHelper introspect the date type rather than require a hard coded list of fields? -// though note valid_from/through uses special logic for 00:00:00 and 23:59:59 - print $this->Field->control('valid_from'); + print $this->Field->control('valid_from', [], '', ['dateField' => 'dateTime']); - print $this->Field->control('valid_through'); + print $this->Field->control('valid_through', [], '', ['dateField' => 'endDateTime']); } // XXX This is a placeholder for canvas... maybe it should become a separate page diff --git a/app/templates/element/datePicker.php b/app/templates/element/datePicker.php index ff2b2357f..e1f38f041 100644 --- a/app/templates/element/datePicker.php +++ b/app/templates/element/datePicker.php @@ -2,6 +2,7 @@ // Get parameters $fieldName = $fieldName ?? ""; $pickerDate = $pickerDate ?? ""; +$pickerType = $pickerType ?? 'dateTime'; // Create a date/time picker. The yyyy-MM-dd format is set above in $pickerDate. @@ -10,7 +11,6 @@ // like the models that use the Tree behavior and have the column parent_id $pickerId = 'datepicker-' . str_replace("_", "-", $fieldName); $pickerTarget = str_replace("_", "-", $fieldName); -$pickerTimed = $pickerTimed ?? true; $pickerAmPm = $pickerAmPm ?? false; // TODO: allow change between AM/PM and 24-hour mode ?> @@ -24,7 +24,7 @@ id: "", target: "", date: "", - timed: , + type: "", ampm: , txt: { hour: "", @@ -63,7 +63,7 @@ :id="id" :target="target" :date="date" - :timed="timed" + :type="type" :ampm="ampm" :txt="txt"> diff --git a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js index 5178f9956..ec9ebc09c 100644 --- a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js +++ b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js @@ -29,7 +29,7 @@ export default { id: String, target: String, date: String, - timed: Boolean, + type: String, ampm: Boolean, txt: Object }, @@ -47,11 +47,16 @@ export default { if(dateField.value === '') { // There's no existing value, so just format what's given. dateField.value = date; - if(this.timed) { + if(this.type == 'dateTime') { dateField.value += " 00:00:00"; } + if(this.type == 'endDateTime') { + dateField.value += " 23:59:59"; + } } else { - if(this.timed) { + if(this.type == 'date') { + dateField.value = date; + } else { // We need to apply the given date to our existing field value so we can retain the time. const dateTime = dateField.value.split(' '); dateTime[0] = date; @@ -61,8 +66,6 @@ export default { dateTime[1] = '00:00:00'; } dateField.value = dateTime.join(' '); - } else { - dateField.value = date; } } }, @@ -72,7 +75,7 @@ export default { let formattedDate = date.getFullYear(); formattedDate += '-' + ('0' + (date.getMonth()+1)).slice(-2); formattedDate += '-' + ('0' + date.getDate()).slice(-2); - if(this.timed) { + if(this.type == 'dateTime' || this.type == 'endDateTime') { formattedDate += ' ' + ('0' + date.getHours()).slice(-2); formattedDate += ':' + ('0' + date.getMinutes()).slice(-2); formattedDate += ':' + ('0' + date.getSeconds()).slice(-2); @@ -171,7 +174,7 @@ export default { @duetChange="setFieldDate" ref="curDuetPicker"> -
+
From 302f0d0a6b90024ddd21e1217ef51fe7cb8ea670 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 31 Aug 2022 18:55:33 -0400 Subject: [PATCH 4/9] Add the 'format' attribute to date/time fields to allow browsers to do simple client-side validation. Titles also included for accessibility. (CFM-107) --- app/resources/locales/en_US/field.po | 6 ++++++ app/src/View/Helper/FieldHelper.php | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po index 61c272bb5..5d776c69e 100644 --- a/app/resources/locales/en_US/field.po +++ b/app/resources/locales/en_US/field.po @@ -98,6 +98,12 @@ msgstr "Created" msgid "datepicker.am" msgstr "AM" +msgid "datepicker.enterDate" +msgstr "Enter a date in YYYY-MM-DD format" + +msgid "datepicker.enterDateTime" +msgstr "Enter a date in YYYY-MM-DD HH:MM:SS format" + msgid "datepicker.hour" msgstr "Hour" diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 5485ce6f9..604542a14 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -108,8 +108,12 @@ public function control(string $fieldName, $pickerType = $config['dateField']; if($pickerType == 'date') { $coptions['placeholder'] = 'YYYY-MM-DD'; + $coptions['pattern'] = '\d{4}-\d{2}-\d{2}'; + $coptions['title'] = __d('field', 'datepicker.enterDate'); } else { $coptions['placeholder'] = 'YYYY-MM-DD HH:MM:SS'; + $coptions['pattern'] = '\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'; + $coptions['title'] = __d('field', 'datepicker.enterDateTime'); } $coptions['id'] = str_replace("_", "-", $fieldName); From 0ad65798d5ba1cc63140b33d35005d5ae42e122d Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 31 Aug 2022 21:51:25 -0400 Subject: [PATCH 5/9] Extend the min and max dates to provide a wide range of years in the datepicker widget. (CFM-107) --- app/templates/element/datePicker.php | 9 +++++++++ .../comanage/components/datepicker/cm-datetimepicker.js | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/templates/element/datePicker.php b/app/templates/element/datePicker.php index e1f38f041..f9fc9a813 100644 --- a/app/templates/element/datePicker.php +++ b/app/templates/element/datePicker.php @@ -13,6 +13,11 @@ $pickerTarget = str_replace("_", "-", $fieldName); $pickerAmPm = $pickerAmPm ?? false; // TODO: allow change between AM/PM and 24-hour mode +// Set the min and max dates to allow for a wide range of year selections in the datepicker. +// XXX For now, just hard code these to provide a wide but reasonable range of values. +$pickerDateMin = '1900-01-01'; +$pickerDateMax = '2100-01-01'; + ?>