@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Convert date control dropdowns to an input for date

Summary: Ref T8060, Convert date control dropdowns to an input for date

Test Plan: Create new Calendar event, use US time format to enter a date or use datepicker, confirm dates are interpreted correctly.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T8060

Differential Revision: https://secure.phabricator.com/D13010

+100 -170
+31 -102
src/view/form/control/AphrontFormDateControl.php
··· 5 5 private $initialTime; 6 6 private $zone; 7 7 8 - private $valueDay; 9 - private $valueMonth; 10 - private $valueYear; 8 + private $valueDate; 11 9 private $valueTime; 12 10 private $allowNull; 13 11 private $continueOnInvalidDate = false; ··· 41 39 } 42 40 43 41 public function readValueFromRequest(AphrontRequest $request) { 44 - $day = $request->getInt($this->getDayInputName()); 45 - $month = $request->getInt($this->getMonthInputName()); 46 - $year = $request->getInt($this->getYearInputName()); 42 + $date = $request->getStr($this->getDateInputName()); 47 43 $time = $request->getStr($this->getTimeInputName()); 48 44 $enabled = $request->getBool($this->getCheckboxInputName()); 49 45 ··· 55 51 56 52 $err = $this->getError(); 57 53 58 - if ($day || $month || $year || $time) { 59 - $this->valueDay = $day; 60 - $this->valueMonth = $month; 61 - $this->valueYear = $year; 54 + if ($date || $time) { 55 + $this->valueDate = $date; 62 56 $this->valueTime = $time; 63 57 64 58 // Assume invalid. ··· 67 61 $zone = $this->getTimezone(); 68 62 69 63 try { 70 - $date = new DateTime("{$year}-{$month}-{$day} {$time}", $zone); 71 - $value = $date->format('U'); 64 + $datetime = new DateTime("{$date} {$time}", $zone); 65 + $value = $datetime->format('U'); 72 66 } catch (Exception $ex) { 73 67 $value = null; 74 68 } ··· 100 94 public function setValue($epoch) { 101 95 if ($epoch instanceof AphrontFormDateControlValue) { 102 96 $this->continueOnInvalidDate = true; 103 - $this->valueYear = $epoch->getValueYear(); 104 - $this->valueMonth = $epoch->getValueMonth(); 105 - $this->valueDay = $epoch->getValueDay(); 97 + $this->valueDate = $epoch->getValueDate(); 106 98 $this->valueTime = $epoch->getValueTime(); 107 99 $this->allowNull = $epoch->getOptional(); 108 100 $this->isDisabled = $epoch->isDisabled(); ··· 119 111 $readable = $this->formatTime($epoch, 'Y!m!d!g:i A'); 120 112 $readable = explode('!', $readable, 4); 121 113 122 - $this->valueYear = $readable[0]; 123 - $this->valueMonth = $readable[1]; 124 - $this->valueDay = $readable[2]; 114 + $year = $readable[0]; 115 + $month = $readable[1]; 116 + $day = $readable[2]; 117 + 118 + $this->valueDate = $month.'/'.$day.'/'.$year; 125 119 $this->valueTime = $readable[3]; 126 120 127 121 return $result; 128 122 } 129 123 130 - private function getMinYear() { 131 - $cur_year = $this->formatTime( 132 - time(), 133 - 'Y'); 134 - $val_year = $this->getYearInputValue(); 135 - 136 - return min($cur_year, $val_year) - 3; 137 - } 138 - 139 - private function getMaxYear() { 140 - $cur_year = $this->formatTime( 141 - time(), 142 - 'Y'); 143 - $val_year = $this->getYearInputValue(); 144 - 145 - return max($cur_year, $val_year) + 3; 146 - } 147 - 148 - private function getDayInputValue() { 149 - return $this->valueDay; 150 - } 151 - 152 - private function getMonthInputValue() { 153 - return $this->valueMonth; 154 - } 155 - 156 - private function getYearInputValue() { 157 - return $this->valueYear; 124 + private function getDateInputValue() { 125 + return $this->valueDate; 158 126 } 159 127 160 128 private function getTimeInputValue() { ··· 168 136 $fmt); 169 137 } 170 138 171 - private function getDayInputName() { 139 + private function getDateInputName() { 172 140 return $this->getName().'_d'; 173 141 } 174 142 175 - private function getMonthInputName() { 176 - return $this->getName().'_m'; 177 - } 178 - 179 - private function getYearInputName() { 180 - return $this->getName().'_y'; 181 - } 182 - 183 143 private function getTimeInputName() { 184 144 return $this->getName().'_t'; 185 145 } ··· 202 162 $disabled = 'disabled'; 203 163 } 204 164 205 - $min_year = $this->getMinYear(); 206 - $max_year = $this->getMaxYear(); 207 - 208 - $days = range(1, 31); 209 - $days = array_fuse($days); 210 - 211 - $months = array( 212 - 1 => pht('Jan'), 213 - 2 => pht('Feb'), 214 - 3 => pht('Mar'), 215 - 4 => pht('Apr'), 216 - 5 => pht('May'), 217 - 6 => pht('Jun'), 218 - 7 => pht('Jul'), 219 - 8 => pht('Aug'), 220 - 9 => pht('Sep'), 221 - 10 => pht('Oct'), 222 - 11 => pht('Nov'), 223 - 12 => pht('Dec'), 224 - ); 225 - 226 165 $checkbox = null; 227 166 if ($this->allowNull) { 228 167 $checkbox = javelin_tag( ··· 237 176 )); 238 177 } 239 178 240 - $years = range($this->getMinYear(), $this->getMaxYear()); 241 - $years = array_fuse($years); 242 - 243 - $days_sel = AphrontFormSelectControl::renderSelectTag( 244 - $this->getDayInputValue(), 245 - $days, 246 - array( 247 - 'name' => $this->getDayInputName(), 248 - 'sigil' => 'day-input', 249 - )); 250 - 251 - $months_sel = AphrontFormSelectControl::renderSelectTag( 252 - $this->getMonthInputValue(), 253 - $months, 179 + $date_sel = javelin_tag( 180 + 'input', 254 181 array( 255 - 'name' => $this->getMonthInputName(), 256 - 'sigil' => 'month-input', 257 - )); 182 + 'autocomplete' => 'off', 183 + 'name' => $this->getDateInputName(), 184 + 'sigil' => 'date-input', 185 + 'value' => $this->getDateInputValue(), 186 + 'type' => 'text', 187 + 'class' => 'aphront-form-date-time-input', 188 + ), 189 + ''); 258 190 259 - $years_sel = AphrontFormSelectControl::renderSelectTag( 260 - $this->getYearInputValue(), 261 - $years, 191 + $date_div = javelin_tag( 192 + 'div', 262 193 array( 263 - 'name' => $this->getYearInputName(), 264 - 'sigil' => 'year-input', 265 - )); 194 + 'class' => 'aphront-form-date-time-input-container', 195 + ), 196 + $date_sel); 266 197 267 198 $cicon = id(new PHUIIconView()) 268 199 ->setIconFont('fa-calendar'); ··· 329 260 ), 330 261 array( 331 262 $checkbox, 332 - $days_sel, 333 - $months_sel, 334 - $years_sel, 263 + $date_div, 335 264 $cal_icon, 336 265 $time_div, 337 266 ));
+17 -43
src/view/form/control/AphrontFormDateControlValue.php
··· 2 2 3 3 final class AphrontFormDateControlValue extends Phobject { 4 4 5 - private $valueDay; 6 - private $valueMonth; 7 - private $valueYear; 5 + private $valueDate; 8 6 private $valueTime; 9 7 private $valueEnabled; 10 8 ··· 12 10 private $zone; 13 11 private $optional; 14 12 15 - public function getValueDay() { 16 - return $this->valueDay; 17 - } 18 - 19 - public function getValueMonth() { 20 - return $this->valueMonth; 21 - } 22 - 23 - public function getValueYear() { 24 - return $this->valueYear; 13 + public function getValueDate() { 14 + return $this->valueDate; 25 15 } 26 16 27 17 public function getValueTime() { ··· 36 26 } 37 27 38 28 public function isEmpty() { 39 - if ($this->valueDay) { 40 - return false; 41 - } 42 - 43 - if ($this->valueMonth) { 44 - return false; 45 - } 46 - 47 - if ($this->valueYear) { 29 + if ($this->valueDate) { 48 30 return false; 49 31 } 50 32 ··· 83 65 84 66 $value = new AphrontFormDateControlValue(); 85 67 $value->viewer = $viewer; 86 - $value->valueYear = $year; 87 - $value->valueMonth = $month; 88 - $value->valueDay = $day; 68 + $value->valueDate = $month.'/'.$day.'/'.$year; 89 69 $value->valueTime = coalesce($time, '12:00 AM'); 90 70 $value->valueEnabled = $enabled; 91 71 ··· 95 75 public static function newFromRequest(AphrontRequest $request, $key) { 96 76 $value = new AphrontFormDateControlValue(); 97 77 $value->viewer = $request->getViewer(); 98 - 99 - $value->valueDay = $request->getInt($key.'_d'); 100 - $value->valueMonth = $request->getInt($key.'_m'); 101 - $value->valueYear = $request->getInt($key.'_y'); 78 + $value->valueDate = $request->getStr($key.'_d'); 102 79 $value->valueTime = $request->getStr($key.'_t'); 103 80 $value->valueEnabled = $request->getStr($key.'_e'); 104 81 ··· 111 88 $readable = $value->formatTime($epoch, 'Y!m!d!g:i A'); 112 89 $readable = explode('!', $readable, 4); 113 90 114 - $value->valueYear = $readable[0]; 115 - $value->valueMonth = $readable[1]; 116 - $value->valueDay = $readable[2]; 91 + $year = $readable[0]; 92 + $month = $readable[1]; 93 + $day = $readable[2]; 94 + 95 + $value->valueDate = $month.'/'.$day.'/'.$year; 117 96 $value->valueTime = $readable[3]; 97 + 118 98 119 99 return $value; 120 100 } ··· 125 105 $value = new AphrontFormDateControlValue(); 126 106 $value->viewer = $viewer; 127 107 128 - $value->valueYear = idx($dictionary, 'y'); 129 - $value->valueMonth = idx($dictionary, 'm'); 130 - $value->valueDay = idx($dictionary, 'd'); 108 + $value->valueDate = idx($dictionary, 'd'); 131 109 $value->valueTime = idx($dictionary, 't'); 132 110 $value->valueEnabled = idx($dictionary, 'e'); 133 111 ··· 149 127 150 128 public function getDictionary() { 151 129 return array( 152 - 'y' => $this->valueYear, 153 - 'm' => $this->valueMonth, 154 - 'd' => $this->valueDay, 130 + 'd' => $this->valueDate, 155 131 't' => $this->valueTime, 156 132 'e' => $this->valueEnabled, 157 133 ); ··· 176 152 return null; 177 153 } 178 154 179 - $year = $this->valueYear; 180 - $month = $this->valueMonth; 181 - $day = $this->valueDay; 155 + $date = $this->valueDate; 182 156 $time = $this->valueTime; 183 157 $zone = $this->getTimezone(); 184 158 ··· 203 177 } 204 178 205 179 try { 206 - $date = new DateTime("{$year}-{$month}-{$day} {$time}", $zone); 207 - $value = $date->format('U'); 180 + $datetime = new DateTime("{$date} {$time}", $zone); 181 + $value = $datetime->format('U'); 208 182 } catch (Exception $ex) { 209 183 $value = null; 210 184 }
+1 -4
src/view/phui/calendar/PHUICalendarDayView.php
··· 90 90 } 91 91 92 92 $this->events = msort($this->events, 'getEpochStart'); 93 - 94 - if (!$this->events) { 95 - $first_event_hour = $this->getDateTime()->setTime(8, 0, 0); 96 - } 93 + $first_event_hour = $this->getDateTime()->setTime(8, 0, 0); 97 94 98 95 foreach ($this->events as $event) { 99 96 if ($event->getIsAllDay()) {
+5 -4
src/view/phui/calendar/PHUICalendarListView.php
··· 150 150 $this->getUser(), 151 151 $event->getEpochEnd())); 152 152 153 + $start_date = $start->getDateTime()->format('m d Y'); 154 + $end_date = $end->getDateTime()->format('m d Y'); 155 + 153 156 if ($event->getIsAllDay()) { 154 - if ($start->getValueDay() == $end->getValueDay()) { 157 + if ($start_date == $end_date) { 155 158 $tip = pht('All day'); 156 159 } else { 157 160 $tip = pht( ··· 160 163 $end->getValueAsFormat('M j, Y')); 161 164 } 162 165 } else { 163 - if ($start->getValueDay() == $end->getValueDay() && 164 - $start->getValueMonth() == $end->getValueMonth() && 165 - $start->getValueYear() == $end->getValueYear()) { 166 + if ($start->getValueDate() == $end->getValueDate()) { 166 167 $tip = pht( 167 168 '%s - %s', 168 169 $start->getValueAsFormat('g:i A'),
+46 -17
webroot/rsrc/js/core/behavior-fancy-datepicker.js
··· 78 78 79 79 var get_inputs = function() { 80 80 return { 81 - y: JX.DOM.find(root, 'select', 'year-input'), 82 - m: JX.DOM.find(root, 'select', 'month-input'), 83 - d: JX.DOM.find(root, 'select', 'day-input'), 81 + d: JX.DOM.find(root, 'input', 'date-input'), 84 82 t: JX.DOM.find(root, 'input', 'time-input') 85 83 }; 86 84 }; 87 85 88 86 var read_date = function() { 89 87 var i = get_inputs(); 90 - value_y = +i.y.value; 91 - value_m = +i.m.value; 92 - value_d = +i.d.value; 88 + var date = i.d.value; 89 + var parts = date.split('/'); 90 + value_y = +parts[2]; 91 + value_m = +parts[0]; 92 + value_d = +parts[1]; 93 93 }; 94 94 95 95 var write_date = function() { 96 96 var i = get_inputs(); 97 - i.y.value = value_y; 98 - i.m.value = value_m; 99 - i.d.value = value_d; 97 + i.d.value = value_m + '/' + value_d + '/' + value_y; 100 98 }; 101 99 102 100 var render = function() { ··· 133 131 return JX.$N('td', {meta: {value: value}, className: class_name}, label); 134 132 }; 135 133 136 - 137 134 // Render the top bar which allows you to pick a month and year. 138 135 var render_month = function() { 136 + var valid_date = getValidDate(); 137 + var month = valid_date.getMonth(); 138 + var year = valid_date.getYear() + 1900; 139 + 139 140 var months = [ 140 141 'January', 141 142 'February', ··· 152 153 153 154 var buttons = [ 154 155 cell('\u25C0', 'm:-1', false, 'lrbutton'), 155 - cell(months[value_m - 1] + ' ' + value_y, null), 156 + cell(months[month] + ' ' + year, null), 156 157 cell('\u25B6', 'm:1', false, 'lrbutton')]; 157 158 158 159 return JX.$N( ··· 160 161 {className: 'month-table'}, 161 162 JX.$N('tr', {}, buttons)); 162 163 }; 164 + 165 + function getValidDate() { 166 + var written_date = new Date(value_y, value_m-1, value_d); 167 + if (isNaN(written_date.getTime())) { 168 + return new Date(); 169 + } else { 170 + return written_date; 171 + } 172 + } 163 173 164 174 165 175 // Render the day-of-week and calendar views. 166 176 var render_day = function() { 177 + var today = new Date(); 178 + var valid_date = getValidDate(); 179 + 167 180 var weeks = []; 168 181 169 182 // First, render the weekday names. ··· 179 192 // Render the calendar itself. NOTE: Javascript uses 0-based month indexes 180 193 // while we use 1-based month indexes, so we have to adjust for that. 181 194 var days = []; 182 - var start = new Date(value_y, value_m - 1, 1).getDay(); 195 + var start = new Date( 196 + valid_date.getYear() + 1900, 197 + valid_date.getMonth(), 198 + 1).getDay(); 199 + 183 200 while (start--) { 184 201 days.push(cell('', null, false, 'day-placeholder')); 185 202 } 186 203 187 - var today = new Date(); 188 - 189 204 for (ii = 1; ii <= 31; ii++) { 190 - var date = new Date(value_y, value_m - 1, ii); 191 - if (date.getMonth() != (value_m - 1)) { 205 + var date = new Date( 206 + valid_date.getYear() + 1900, 207 + valid_date.getMonth(), 208 + ii); 209 + if (date.getMonth() != (valid_date.getMonth())) { 192 210 // We've spilled over into the next month, so stop rendering. 193 211 break; 194 212 } ··· 206 224 classes.push('weekend'); 207 225 } 208 226 209 - days.push(cell(ii, 'd:'+ii, value_d == ii, classes.join(' '))); 227 + days.push(cell( 228 + ii, 229 + 'd:'+ii, 230 + valid_date.getDate() == ii, 231 + classes.join(' '))); 210 232 } 211 233 212 234 // Slice the days into weeks. ··· 262 284 263 285 render(); 264 286 }); 287 + 288 + JX.Stratcom.listen('click', null, function(e){ 289 + if (e.getNode('phabricator-datepicker')) { 290 + return; 291 + } 292 + onclose(); 293 + }); 265 294 266 295 });