-
Notifications
You must be signed in to change notification settings - Fork 3
Honor date-only dates using the date picker (CFM-107) #49
Merged
+248
−113
Merged
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
fed6300
Align datepicker colors with Registry theme (CFM-107)
arlen 8c795f2
Honor date-only dates using the date picker (CFM-107)
arlen d503cdd
Allow date fields to be specified as type 'date', 'dateTime', and 'en…
arlen 302f0d0
Add the 'format' attribute to date/time fields to allow browsers to d…
arlen 0ad6579
Extend the min and max dates to provide a wide range of years in the …
arlen e17bd78
Add aria attributes and screenreader features to time picker. (CFM-107)
arlen acb754a
Refactor FieldHelper to include a dateControl() wrapper function. Set…
arlen 5705e09
Minor update to comments. (CFM-107)
arlen a7b649e
Clean up code conventions. (CFM-107)
arlen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
/** | ||
* COmanage Registry Date Type Enum, Standard Variant | ||
* | ||
* Portions licensed to the University Corporation for Advanced Internet | ||
* Development, Inc. ("UCAID") under one or more contributor license agreements. | ||
* See the NOTICE file distributed with this work for additional information | ||
* regarding copyright ownership. | ||
* | ||
* UCAID licenses this file to you under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with the | ||
* License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @link https://www.internet2.edu/comanage COmanage Project | ||
* @package registry | ||
* @since COmanage Registry v5.0.0 | ||
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | ||
*/ | ||
|
||
declare(strict_types = 1); | ||
|
||
namespace App\Lib\Enum; | ||
|
||
class DateTypeEnum extends StandardEnum { | ||
const Standard = 'standard'; | ||
const DateOnly = 'dateonly'; | ||
const FromTime = 'fromtime'; | ||
const ThroughTime = 'throughtime'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,8 @@ | |
|
||
use \Cake\Utility\Inflector; | ||
use Cake\View\Helper; | ||
use App\Lib\Enum\DateTypeEnum; | ||
use Cake\I18n\FrozenTime; | ||
|
||
class FieldHelper extends Helper { | ||
public $helpers = ['Form', 'Html', 'Url', 'Alert']; | ||
|
@@ -66,25 +68,29 @@ public function banner(string $info) { | |
* Emit a form control. | ||
* | ||
* @since COmanage Registry v5.0.0 | ||
* @param string $fieldName Form field | ||
* @param array $options FormHelper control options | ||
* @param string $labelText Label text (fieldName language key used by default) | ||
* @param array $config Custom FormHelper configuration options | ||
* @param string $fieldName Form field | ||
* @param array $options FormHelper control options | ||
* @param string $labelText Label text (fieldName language key used by default) | ||
* @param array $config Custom FormHelper configuration options | ||
* @param string $ctrlCode Control code passed in from wrapper functions | ||
* @param string $cssClass Start li css class passed in from wrapper functions | ||
* @return string HTML for control | ||
*/ | ||
|
||
public function control(string $fieldName, | ||
array $options=[], | ||
string $labelText=null, | ||
array $config=[]){ | ||
array $config=[], | ||
string $ctrlCode=null, | ||
string $cssClass=''){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be a return type in the function signature, eg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done - and also for consistency I carried this convention to every function in the FieldHelper.php file. |
||
$coptions = $options; | ||
$coptions['label'] = false; | ||
$coptions['readonly'] = !$this->editable || (isset($options['readonly']) && $options['readonly']); | ||
// Selects, Checkboxes, and Radio Buttons use "disabled" | ||
$coptions['disabled'] = $coptions['readonly']; | ||
|
||
// Generate HTML for the control itself | ||
$liClass = ""; | ||
// Specify a class on the <li> form control wrapper | ||
$liClass = $cssClass; | ||
|
||
// Remove prefix from field value | ||
if(isset($config['prefix'], $this->getView()->get('vv_obj')->$fieldName)) { | ||
|
@@ -94,50 +100,20 @@ public function control(string $fieldName, | |
$vv_obj->$fieldName = $fieldValueTemp; | ||
$this->getView()->set('vv_obj', $vv_obj); | ||
} | ||
|
||
// Handle datetime controls specially | ||
if($fieldName == 'valid_from' || $fieldName == 'valid_through') { | ||
// Append the timezone to the label | ||
$label = __d('field', $fieldName.".tz", [$this->_View->get('vv_tz')]); | ||
|
||
// A datetime field will be rendered as plain text input with adjacent date and time pickers | ||
// 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 | ||
$coptions['id'] = str_replace("_", "-", $fieldName); | ||
|
||
$entity = $this->getView()->get('vv_obj'); | ||
|
||
$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')); | ||
$pickerDate = $entity->$fieldName->i18nFormat("yyyy-MM-dd", $this->getView()->get('vv_tz')); | ||
} | ||
|
||
$date_args = [ | ||
'fieldName' => $fieldName, | ||
'pickerDate' => $pickerDate | ||
]; | ||
// Create a text field to hold our value. | ||
$controlCode = $this->Form->text($fieldName, $coptions) | ||
. $this->getView()->element('datePicker', $date_args); | ||
|
||
$liClass = "fields-datepicker"; | ||
} else { | ||
if($fieldName != 'status' | ||
&& !isset($options['empty']) | ||
&& (!isset($options['suppressBlank']) || !$options['suppressBlank'])) { | ||
// Cause any select (except status) to render with a blank option, even | ||
// if the field is required. This makes it clear when a value need to be set. | ||
// Note this will be ignored for non-select controls. | ||
$coptions['empty'] = true; | ||
} | ||
|
||
$controlCode = $this->Form->control($fieldName, $coptions); | ||
|
||
if($fieldName != 'status' | ||
&& !isset($options['empty']) | ||
&& (!isset($options['suppressBlank']) || !$options['suppressBlank'])) { | ||
// Cause any select (except status) to render with a blank option, even | ||
// if the field is required. This makes it clear when a value need to be set. | ||
// Note this will be ignored for non-select controls. | ||
$coptions['empty'] = true; | ||
} | ||
|
||
// Generate the form control or pass along the markup generated in a wrapper function | ||
$controlCode = empty($ctrlCode) ? $this->Form->control($fieldName, $coptions) : $ctrlCode; | ||
|
||
|
||
// Required fields are usually determined by the model validator, but for | ||
// related models the view (currently) has to pass the field as required in | ||
// $options. For fields of the form model.0.field, if $options['required'] | ||
|
@@ -159,6 +135,90 @@ public function control(string $fieldName, | |
. $this->endLine(); | ||
} | ||
|
||
/** | ||
* Emit a date/time form control. | ||
* This is a wrapper function for $this->control() | ||
* | ||
* @since COmanage Registry v5.0.0 | ||
* @param string $fieldName Form field | ||
* @param string $dateType Standard, DateOnly, FromTime, ThroughTime | ||
* | ||
* @return string HTML for control | ||
*/ | ||
|
||
public function dateControl(string $fieldName, string $dateType=DateTypeEnum::Standard) { | ||
// A datetime field will be rendered as a plain text input with adjacent date and time pickers | ||
// that will interact with the field value. Allowing direct access to the input field is for | ||
// accessibility purposes. | ||
|
||
$pickerType = $dateType; | ||
// Special-case the very common "valid_from" and "valid_through" fields so we won't need | ||
// to specify their types in fields.inc. | ||
if($fieldName == 'valid_from') { | ||
$pickerType = DateTypeEnum::FromTime; | ||
} | ||
if($fieldName == 'valid_through') { | ||
$pickerType = DateTypeEnum::ThroughTime; | ||
} | ||
|
||
// Append the timezone to the label -- TODO: see that the timezone gets output to the display | ||
$label = __d('field', $fieldName.".tz", [$this->_View->get('vv_tz')]); | ||
|
||
// Create the options array for the (text input) form control | ||
$coptions = []; | ||
$coptions['class'] = 'form-control datepicker'; | ||
|
||
if($pickerType == DateTypeEnum::DateOnly) { | ||
$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); | ||
|
||
$entity = $this->getView()->get('vv_obj'); | ||
|
||
// Default the picker date to today | ||
$now = FrozenTime::now(); | ||
$pickerDate = $now->i18nFormat('yyyy-MM-dd'); | ||
|
||
// Get the existing values, if present | ||
if(!empty($entity->$fieldName)) { | ||
// Adjust the time back to the user's timezone | ||
if($pickerType == DateTypeEnum::DateOnly) { | ||
$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')); | ||
} | ||
|
||
// Set the date picker floor year value (-100 years) | ||
$pickerDateFT = new FrozenTime($pickerDate); | ||
$pickerDateFT = $pickerDateFT->subYears(100); | ||
$pickerFloor = $pickerDateFT->i18nFormat("yyyy-MM-dd"); | ||
|
||
$date_picker_args = [ | ||
'fieldName' => $fieldName, | ||
'pickerDate' => $pickerDate, | ||
'pickerType' => $pickerType, | ||
'pickerFloor' => $pickerFloor | ||
]; | ||
|
||
// Create a text field to hold our value and call the datePicker | ||
$controlCode = $this->Form->text($fieldName, $coptions) | ||
. $this->getView()->element('datePicker', $date_picker_args); | ||
|
||
// Specify a class on the <li> form control wrapper | ||
$liClass = "fields-datepicker"; | ||
|
||
// Pass everything to the generic control() function | ||
return $this->control($fieldName, $coptions, '', [], $controlCode, $liClass); | ||
} | ||
|
||
/** | ||
* End a set of form controls. | ||
* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit, sort the
App
stuff together after theCake
stuff.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done - I also removed a preceding "\" on one of the Cake imports for consistency.