From 86a908d3b9ed7b4374243f6c265a630a23e83221 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 15 Jun 2015 10:11:10 -0700 Subject: [PATCH] Date controls should respect user time preferences Summary: Ref T8362, Date controls should respect user time preferences Test Plan: Set user time preference to 24-hour format, create an event, type 23 in time input, 23:00 should be suggested. Saveing a 24-hour format time should save correctly. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T8362 Differential Revision: https://secure.phabricator.com/D13291 --- .../form/control/AphrontFormDateControl.php | 32 ++++++-- .../control/AphrontFormDateControlValue.php | 80 ++++++++++++------- .../rsrc/js/core/behavior-time-typeahead.js | 71 ++++++++++------ 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php index 4bf7619875..20172593e9 100644 --- a/src/view/form/control/AphrontFormDateControl.php +++ b/src/view/form/control/AphrontFormDateControl.php @@ -136,6 +136,14 @@ final class AphrontFormDateControl extends AphrontFormControl { return $date; } + private function getTimeFormat() { + $viewer = $this->getUser(); + $preferences = $viewer->loadPreferences(); + $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + + return $preferences->getPreference($pref_time_format, 'g:i A'); + } + private function getDateFormat() { $viewer = $this->getUser(); $preferences = $viewer->loadPreferences(); @@ -233,6 +241,7 @@ final class AphrontFormDateControl extends AphrontFormControl { 'startTimeID' => $time_id, 'endTimeID' => $this->endDateID, 'timeValues' => $values, + 'format' => $this->getTimeFormat(), )); @@ -335,20 +344,31 @@ final class AphrontFormDateControl extends AphrontFormControl { } private function getTimeTypeaheadValues() { + $time_format = $this->getTimeFormat(); $times = array(); - $am_pm_list = array('AM', 'PM'); - foreach ($am_pm_list as $am_pm) { - for ($hour = 0; $hour < 12; $hour++) { - $actual_hour = ($hour == 0) ? 12 : $hour; - $times[] = $actual_hour.':00 '.$am_pm; - $times[] = $actual_hour.':30 '.$am_pm; + if ($time_format == 'g:i A') { + $am_pm_list = array('AM', 'PM'); + + foreach ($am_pm_list as $am_pm) { + for ($hour = 0; $hour < 12; $hour++) { + $actual_hour = ($hour == 0) ? 12 : $hour; + $times[] = $actual_hour.':00 '.$am_pm; + $times[] = $actual_hour.':30 '.$am_pm; + } + } + } else if ($time_format == 'H:i') { + for ($hour = 0; $hour < 24; $hour++) { + $written_hour = ($hour > 9) ? $hour : '0'.$hour; + $times[] = $written_hour.':00'; + $times[] = $written_hour.':30'; } } foreach ($times as $key => $time) { $times[$key] = array($key, $time); } + return $times; } diff --git a/src/view/form/control/AphrontFormDateControlValue.php b/src/view/form/control/AphrontFormDateControlValue.php index c084eecf2a..c5d7e81852 100644 --- a/src/view/form/control/AphrontFormDateControlValue.php +++ b/src/view/form/control/AphrontFormDateControlValue.php @@ -66,12 +66,13 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = $value->getFormattedDateFromParts( - $year, - $month, - $day, - $value); - $value->valueTime = coalesce($time, '12:00 AM'); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromParts( + $year, + $month, + $day, + coalesce($time, '12:00 AM'), + $value); $value->valueEnabled = $enabled; return $value; @@ -81,11 +82,12 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $request->getViewer(); - $value->valueDate = $value->getFormattedDateFromDate( - $request->getStr($key.'_d'), - $value); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromDate( + $request->getStr($key.'_d'), + $request->getStr($key.'_t'), + $value); - $value->valueTime = $request->getStr($key.'_t'); $value->valueEnabled = $request->getStr($key.'_e'); return $value; } @@ -99,14 +101,15 @@ final class AphrontFormDateControlValue extends Phobject { $year = $readable[0]; $month = $readable[1]; $day = $readable[2]; + $time = $readable[3]; - $value->valueDate = $value->getFormattedDateFromParts( - $year, - $month, - $day, - $value); - $value->valueTime = $readable[3]; - + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromParts( + $year, + $month, + $day, + $time, + $value); return $value; } @@ -117,11 +120,12 @@ final class AphrontFormDateControlValue extends Phobject { $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueDate = $value->getFormattedDateFromDate( - idx($dictionary, 'd'), - $value); + list($value->valueDate, $value->valueTime) = + $value->getFormattedDateFromDate( + idx($dictionary, 'd'), + idx($dictionary, 't'), + $value); - $value->valueTime = idx($dictionary, 't'); $value->valueEnabled = idx($dictionary, 'e'); return $value; @@ -200,6 +204,13 @@ final class AphrontFormDateControlValue extends Phobject { return $value; } + private function getTimeFormat() { + $preferences = $this->viewer->loadPreferences(); + $pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + + return $preferences->getPreference($pref_time_format, 'g:i A'); + } + private function getDateFormat() { $preferences = $this->viewer->loadPreferences(); $pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT; @@ -207,7 +218,7 @@ final class AphrontFormDateControlValue extends Phobject { return $preferences->getPreference($pref_date_format, 'Y-m-d'); } - private function getFormattedDateFromDate($date, $value) { + private function getFormattedDateFromDate($date, $time, $value) { $original_input = $date; $zone = $value->getTimezone(); $separator = $value->getFormatSeparator(); @@ -216,17 +227,32 @@ final class AphrontFormDateControlValue extends Phobject { $date = id(new DateTime($date, $zone)); if ($date) { - return $date->format($value->getDateFormat()); + $date = $date->format($value->getDateFormat()); } else { - return $original_input; + $date = $original_input; } + + $date = id(new DateTime("{$date} {$time}", $zone)); + + return array( + $date->format($value->getDateFormat()), + $date->format($value->getTimeFormat()), + ); } - private function getFormattedDateFromParts($year, $month, $day, $value) { + private function getFormattedDateFromParts( + $year, + $month, + $day, + $time, + $value) { $zone = $value->getTimezone(); + $date_time = id(new DateTime("{$year}-{$month}-{$day} {$time}", $zone)); - return id(new DateTime("{$year}-{$month}-{$day}", $zone)) - ->format($value->getDateFormat()); + return array( + $date_time->format($value->getDateFormat()), + $date_time->format($value->getTimeFormat()), + ); } private function getFormatSeparator() { diff --git a/webroot/rsrc/js/core/behavior-time-typeahead.js b/webroot/rsrc/js/core/behavior-time-typeahead.js index 381eea7f36..bbd5e08699 100644 --- a/webroot/rsrc/js/core/behavior-time-typeahead.js +++ b/webroot/rsrc/js/core/behavior-time-typeahead.js @@ -11,6 +11,7 @@ JX.behavior('time-typeahead', function(config) { var start_date_control = JX.$(config.startTimeID); var end_date_control = config.endTimeID ? JX.$(config.endTimeID) : null; + var format = config.format; var end_date_tampered = false; @@ -79,7 +80,7 @@ JX.behavior('time-typeahead', function(config) { function getNewValue(time) { - var regex = /^([01]?\d)(?::([0-5]\d))?\s*((am|pm))?$/i; + var regex = /^([0-2]?\d)(?::([0-5]\d))?\s*((am|pm))?$/i; if (!regex.test(time)) { return null; @@ -90,32 +91,56 @@ JX.behavior('time-typeahead', function(config) { var minutes = parseInt(results[2], 10) ? parseInt(results[2], 10) : 0; var real_time = 0; + var end_value = ''; - if (/pm/i.test(results[3])) { - real_time = 12*60; - } else if (/am/i.test(results[3]) && hours == 12) { - hours = 0; + var end_hours; + var end_minutes; + + if (format === 'H:i' && hours < 23) { + end_hours = hours + 1; + + if (end_hours > 9) { + end_hours = end_hours.toString(); + } else { + end_hours = '0' + end_hours.toString(); + } + + if (minutes > 9) { + end_minutes = minutes.toString(); + } else { + end_minutes = '0' + minutes.toString(); + } + + end_value = end_hours + ':' + end_minutes; + } else if (format === 'g:i A') { + if (/pm/i.test(results[3])) { + real_time = 12*60; + } else if (/am/i.test(results[3]) && hours == 12) { + hours = 0; + } + + real_time = real_time + (hours * 60) + minutes; + + var end_time = real_time + 60; + + var end_meridian = 'AM'; + end_hours = Math.floor(end_time / 60); + + if (end_hours == 12) { + end_meridian = 'PM'; + } else if (end_hours > 12 && end_hours < 24) { + end_hours = end_hours - 12; + end_meridian = 'PM'; + } else if (end_hours == 24) { + end_hours = end_hours - 12; + } + + end_minutes = end_time%60; + end_minutes = (end_minutes < 9) ? end_minutes : ('0' + end_minutes); + end_value = end_hours + ':' + end_minutes + ' ' + end_meridian; } - real_time = real_time + (hours * 60) + minutes; - var end_time = real_time + 60; - - var end_meridian = 'AM'; - var end_hours = Math.floor(end_time / 60); - - if (end_hours == 12) { - end_meridian = 'PM'; - } else if (end_hours > 12 && end_hours < 24) { - end_hours = end_hours - 12; - end_meridian = 'PM'; - } else if (end_hours == 24) { - end_hours = end_hours - 12; - } - - var end_minutes = end_time%60; - end_minutes = (end_minutes > 9) ? end_minutes : ('0' + end_minutes); - var end_value = end_hours + ':' + end_minutes + ' ' + end_meridian; return end_value; }