diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php --- a/src/view/form/control/AphrontFormDateControl.php +++ b/src/view/form/control/AphrontFormDateControl.php @@ -5,9 +5,7 @@ private $initialTime; private $zone; - private $valueDay; - private $valueMonth; - private $valueYear; + private $valueDate; private $valueTime; private $allowNull; private $continueOnInvalidDate = false; @@ -41,9 +39,7 @@ } public function readValueFromRequest(AphrontRequest $request) { - $day = $request->getInt($this->getDayInputName()); - $month = $request->getInt($this->getMonthInputName()); - $year = $request->getInt($this->getYearInputName()); + $date = $request->getStr($this->getDateInputName()); $time = $request->getStr($this->getTimeInputName()); $enabled = $request->getBool($this->getCheckboxInputName()); @@ -55,10 +51,8 @@ $err = $this->getError(); - if ($day || $month || $year || $time) { - $this->valueDay = $day; - $this->valueMonth = $month; - $this->valueYear = $year; + if ($date || $time) { + $this->valueDate = $date; $this->valueTime = $time; // Assume invalid. @@ -67,8 +61,8 @@ $zone = $this->getTimezone(); try { - $date = new DateTime("{$year}-{$month}-{$day} {$time}", $zone); - $value = $date->format('U'); + $datetime = new DateTime("{$date} {$time}", $zone); + $value = $datetime->format('U'); } catch (Exception $ex) { $value = null; } @@ -100,9 +94,7 @@ public function setValue($epoch) { if ($epoch instanceof AphrontFormDateControlValue) { $this->continueOnInvalidDate = true; - $this->valueYear = $epoch->getValueYear(); - $this->valueMonth = $epoch->getValueMonth(); - $this->valueDay = $epoch->getValueDay(); + $this->valueDate = $epoch->getValueDate(); $this->valueTime = $epoch->getValueTime(); $this->allowNull = $epoch->getOptional(); $this->isDisabled = $epoch->isDisabled(); @@ -119,42 +111,18 @@ $readable = $this->formatTime($epoch, 'Y!m!d!g:i A'); $readable = explode('!', $readable, 4); - $this->valueYear = $readable[0]; - $this->valueMonth = $readable[1]; - $this->valueDay = $readable[2]; + $year = $readable[0]; + $month = $readable[1]; + $day = $readable[2]; + + $this->valueDate = $month.'/'.$day.'/'.$year; $this->valueTime = $readable[3]; return $result; } - private function getMinYear() { - $cur_year = $this->formatTime( - time(), - 'Y'); - $val_year = $this->getYearInputValue(); - - return min($cur_year, $val_year) - 3; - } - - private function getMaxYear() { - $cur_year = $this->formatTime( - time(), - 'Y'); - $val_year = $this->getYearInputValue(); - - return max($cur_year, $val_year) + 3; - } - - private function getDayInputValue() { - return $this->valueDay; - } - - private function getMonthInputValue() { - return $this->valueMonth; - } - - private function getYearInputValue() { - return $this->valueYear; + private function getDateInputValue() { + return $this->valueDate; } private function getTimeInputValue() { @@ -168,18 +136,10 @@ $fmt); } - private function getDayInputName() { + private function getDateInputName() { return $this->getName().'_d'; } - private function getMonthInputName() { - return $this->getName().'_m'; - } - - private function getYearInputName() { - return $this->getName().'_y'; - } - private function getTimeInputName() { return $this->getName().'_t'; } @@ -202,27 +162,6 @@ $disabled = 'disabled'; } - $min_year = $this->getMinYear(); - $max_year = $this->getMaxYear(); - - $days = range(1, 31); - $days = array_fuse($days); - - $months = array( - 1 => pht('Jan'), - 2 => pht('Feb'), - 3 => pht('Mar'), - 4 => pht('Apr'), - 5 => pht('May'), - 6 => pht('Jun'), - 7 => pht('Jul'), - 8 => pht('Aug'), - 9 => pht('Sep'), - 10 => pht('Oct'), - 11 => pht('Nov'), - 12 => pht('Dec'), - ); - $checkbox = null; if ($this->allowNull) { $checkbox = javelin_tag( @@ -237,32 +176,24 @@ )); } - $years = range($this->getMinYear(), $this->getMaxYear()); - $years = array_fuse($years); - - $days_sel = AphrontFormSelectControl::renderSelectTag( - $this->getDayInputValue(), - $days, - array( - 'name' => $this->getDayInputName(), - 'sigil' => 'day-input', - )); - - $months_sel = AphrontFormSelectControl::renderSelectTag( - $this->getMonthInputValue(), - $months, + $date_sel = javelin_tag( + 'input', array( - 'name' => $this->getMonthInputName(), - 'sigil' => 'month-input', - )); + 'autocomplete' => 'off', + 'name' => $this->getDateInputName(), + 'sigil' => 'date-input', + 'value' => $this->getDateInputValue(), + 'type' => 'text', + 'class' => 'aphront-form-date-time-input', + ), + ''); - $years_sel = AphrontFormSelectControl::renderSelectTag( - $this->getYearInputValue(), - $years, + $date_div = javelin_tag( + 'div', array( - 'name' => $this->getYearInputName(), - 'sigil' => 'year-input', - )); + 'class' => 'aphront-form-date-time-input-container', + ), + $date_sel); $cicon = id(new PHUIIconView()) ->setIconFont('fa-calendar'); @@ -329,9 +260,7 @@ ), array( $checkbox, - $days_sel, - $months_sel, - $years_sel, + $date_div, $cal_icon, $time_div, )); diff --git a/src/view/form/control/AphrontFormDateControlValue.php b/src/view/form/control/AphrontFormDateControlValue.php --- a/src/view/form/control/AphrontFormDateControlValue.php +++ b/src/view/form/control/AphrontFormDateControlValue.php @@ -2,9 +2,7 @@ final class AphrontFormDateControlValue extends Phobject { - private $valueDay; - private $valueMonth; - private $valueYear; + private $valueDate; private $valueTime; private $valueEnabled; @@ -12,16 +10,8 @@ private $zone; private $optional; - public function getValueDay() { - return $this->valueDay; - } - - public function getValueMonth() { - return $this->valueMonth; - } - - public function getValueYear() { - return $this->valueYear; + public function getValueDate() { + return $this->valueDate; } public function getValueTime() { @@ -36,15 +26,7 @@ } public function isEmpty() { - if ($this->valueDay) { - return false; - } - - if ($this->valueMonth) { - return false; - } - - if ($this->valueYear) { + if ($this->valueDate) { return false; } @@ -83,9 +65,7 @@ $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueYear = $year; - $value->valueMonth = $month; - $value->valueDay = $day; + $value->valueDate = $month.'/'.$day.'/'.$year; $value->valueTime = coalesce($time, '12:00 AM'); $value->valueEnabled = $enabled; @@ -95,10 +75,7 @@ public static function newFromRequest(AphrontRequest $request, $key) { $value = new AphrontFormDateControlValue(); $value->viewer = $request->getViewer(); - - $value->valueDay = $request->getInt($key.'_d'); - $value->valueMonth = $request->getInt($key.'_m'); - $value->valueYear = $request->getInt($key.'_y'); + $value->valueDate = $request->getStr($key.'_d'); $value->valueTime = $request->getStr($key.'_t'); $value->valueEnabled = $request->getStr($key.'_e'); @@ -111,11 +88,14 @@ $readable = $value->formatTime($epoch, 'Y!m!d!g:i A'); $readable = explode('!', $readable, 4); - $value->valueYear = $readable[0]; - $value->valueMonth = $readable[1]; - $value->valueDay = $readable[2]; + $year = $readable[0]; + $month = $readable[1]; + $day = $readable[2]; + + $value->valueDate = $month.'/'.$day.'/'.$year; $value->valueTime = $readable[3]; + return $value; } @@ -125,9 +105,7 @@ $value = new AphrontFormDateControlValue(); $value->viewer = $viewer; - $value->valueYear = idx($dictionary, 'y'); - $value->valueMonth = idx($dictionary, 'm'); - $value->valueDay = idx($dictionary, 'd'); + $value->valueDate = idx($dictionary, 'd'); $value->valueTime = idx($dictionary, 't'); $value->valueEnabled = idx($dictionary, 'e'); @@ -149,9 +127,7 @@ public function getDictionary() { return array( - 'y' => $this->valueYear, - 'm' => $this->valueMonth, - 'd' => $this->valueDay, + 'd' => $this->valueDate, 't' => $this->valueTime, 'e' => $this->valueEnabled, ); @@ -176,9 +152,7 @@ return null; } - $year = $this->valueYear; - $month = $this->valueMonth; - $day = $this->valueDay; + $date = $this->valueDate; $time = $this->valueTime; $zone = $this->getTimezone(); @@ -203,8 +177,8 @@ } try { - $date = new DateTime("{$year}-{$month}-{$day} {$time}", $zone); - $value = $date->format('U'); + $datetime = new DateTime("{$date} {$time}", $zone); + $value = $datetime->format('U'); } catch (Exception $ex) { $value = null; } diff --git a/src/view/phui/calendar/PHUICalendarDayView.php b/src/view/phui/calendar/PHUICalendarDayView.php --- a/src/view/phui/calendar/PHUICalendarDayView.php +++ b/src/view/phui/calendar/PHUICalendarDayView.php @@ -90,10 +90,7 @@ } $this->events = msort($this->events, 'getEpochStart'); - - if (!$this->events) { - $first_event_hour = $this->getDateTime()->setTime(8, 0, 0); - } + $first_event_hour = $this->getDateTime()->setTime(8, 0, 0); foreach ($this->events as $event) { if ($event->getIsAllDay()) { diff --git a/src/view/phui/calendar/PHUICalendarListView.php b/src/view/phui/calendar/PHUICalendarListView.php --- a/src/view/phui/calendar/PHUICalendarListView.php +++ b/src/view/phui/calendar/PHUICalendarListView.php @@ -150,8 +150,11 @@ $this->getUser(), $event->getEpochEnd())); + $start_date = $start->getDateTime()->format('m d Y'); + $end_date = $end->getDateTime()->format('m d Y'); + if ($event->getIsAllDay()) { - if ($start->getValueDay() == $end->getValueDay()) { + if ($start_date == $end_date) { $tip = pht('All day'); } else { $tip = pht( @@ -160,9 +163,7 @@ $end->getValueAsFormat('M j, Y')); } } else { - if ($start->getValueDay() == $end->getValueDay() && - $start->getValueMonth() == $end->getValueMonth() && - $start->getValueYear() == $end->getValueYear()) { + if ($start->getValueDate() == $end->getValueDate()) { $tip = pht( '%s - %s', $start->getValueAsFormat('g:i A'), diff --git a/webroot/rsrc/js/core/behavior-fancy-datepicker.js b/webroot/rsrc/js/core/behavior-fancy-datepicker.js --- a/webroot/rsrc/js/core/behavior-fancy-datepicker.js +++ b/webroot/rsrc/js/core/behavior-fancy-datepicker.js @@ -78,25 +78,23 @@ var get_inputs = function() { return { - y: JX.DOM.find(root, 'select', 'year-input'), - m: JX.DOM.find(root, 'select', 'month-input'), - d: JX.DOM.find(root, 'select', 'day-input'), + d: JX.DOM.find(root, 'input', 'date-input'), t: JX.DOM.find(root, 'input', 'time-input') }; }; var read_date = function() { var i = get_inputs(); - value_y = +i.y.value; - value_m = +i.m.value; - value_d = +i.d.value; + var date = i.d.value; + var parts = date.split('/'); + value_y = +parts[2]; + value_m = +parts[0]; + value_d = +parts[1]; }; var write_date = function() { var i = get_inputs(); - i.y.value = value_y; - i.m.value = value_m; - i.d.value = value_d; + i.d.value = value_m + '/' + value_d + '/' + value_y; }; var render = function() { @@ -133,9 +131,12 @@ return JX.$N('td', {meta: {value: value}, className: class_name}, label); }; - // Render the top bar which allows you to pick a month and year. var render_month = function() { + var valid_date = getValidDate(); + var month = valid_date.getMonth(); + var year = valid_date.getYear() + 1900; + var months = [ 'January', 'February', @@ -152,7 +153,7 @@ var buttons = [ cell('\u25C0', 'm:-1', false, 'lrbutton'), - cell(months[value_m - 1] + ' ' + value_y, null), + cell(months[month] + ' ' + year, null), cell('\u25B6', 'm:1', false, 'lrbutton')]; return JX.$N( @@ -161,9 +162,21 @@ JX.$N('tr', {}, buttons)); }; + function getValidDate() { + var written_date = new Date(value_y, value_m-1, value_d); + if (isNaN(written_date.getTime())) { + return new Date(); + } else { + return written_date; + } + } + // Render the day-of-week and calendar views. var render_day = function() { + var today = new Date(); + var valid_date = getValidDate(); + var weeks = []; // First, render the weekday names. @@ -179,16 +192,21 @@ // Render the calendar itself. NOTE: Javascript uses 0-based month indexes // while we use 1-based month indexes, so we have to adjust for that. var days = []; - var start = new Date(value_y, value_m - 1, 1).getDay(); + var start = new Date( + valid_date.getYear() + 1900, + valid_date.getMonth(), + 1).getDay(); + while (start--) { days.push(cell('', null, false, 'day-placeholder')); } - var today = new Date(); - for (ii = 1; ii <= 31; ii++) { - var date = new Date(value_y, value_m - 1, ii); - if (date.getMonth() != (value_m - 1)) { + var date = new Date( + valid_date.getYear() + 1900, + valid_date.getMonth(), + ii); + if (date.getMonth() != (valid_date.getMonth())) { // We've spilled over into the next month, so stop rendering. break; } @@ -206,7 +224,11 @@ classes.push('weekend'); } - days.push(cell(ii, 'd:'+ii, value_d == ii, classes.join(' '))); + days.push(cell( + ii, + 'd:'+ii, + valid_date.getDate() == ii, + classes.join(' '))); } // Slice the days into weeks. @@ -263,4 +285,11 @@ render(); }); + JX.Stratcom.listen('click', null, function(e){ + if (e.getNode('phabricator-datepicker')) { + return; + } + onclose(); + }); + });