Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/view/form/control/AphrontFormDateControl.php
12262 views
1
<?php
2
3
final class AphrontFormDateControl extends AphrontFormControl {
4
5
private $initialTime;
6
private $zone;
7
8
private $valueDate;
9
private $valueTime;
10
private $allowNull;
11
private $continueOnInvalidDate = false;
12
private $isTimeDisabled;
13
private $isDisabled;
14
private $endDateID;
15
16
public function setAllowNull($allow_null) {
17
$this->allowNull = $allow_null;
18
return $this;
19
}
20
21
public function setIsTimeDisabled($is_disabled) {
22
$this->isTimeDisabled = $is_disabled;
23
return $this;
24
}
25
26
public function setIsDisabled($is_datepicker_disabled) {
27
$this->isDisabled = $is_datepicker_disabled;
28
return $this;
29
}
30
31
public function setEndDateID($value) {
32
$this->endDateID = $value;
33
return $this;
34
}
35
36
const TIME_START_OF_DAY = 'start-of-day';
37
const TIME_END_OF_DAY = 'end-of-day';
38
const TIME_START_OF_BUSINESS = 'start-of-business';
39
const TIME_END_OF_BUSINESS = 'end-of-business';
40
41
public function setInitialTime($time) {
42
$this->initialTime = $time;
43
return $this;
44
}
45
46
public function readValueFromRequest(AphrontRequest $request) {
47
$date = $request->getStr($this->getDateInputName());
48
$time = $request->getStr($this->getTimeInputName());
49
$enabled = $request->getBool($this->getCheckboxInputName());
50
51
if ($this->allowNull && !$enabled) {
52
$this->setError(null);
53
$this->setValue(null);
54
return;
55
}
56
57
$err = $this->getError();
58
59
if ($date || $time) {
60
$this->valueDate = $date;
61
$this->valueTime = $time;
62
63
// Assume invalid.
64
$err = pht('Invalid');
65
66
$zone = $this->getTimezone();
67
68
try {
69
$datetime = new DateTime("{$date} {$time}", $zone);
70
$value = $datetime->format('U');
71
} catch (Exception $ex) {
72
$value = null;
73
}
74
75
if ($value) {
76
$this->setValue($value);
77
$err = null;
78
} else {
79
$this->setValue(null);
80
}
81
} else {
82
$value = $this->getInitialValue();
83
if ($value) {
84
$this->setValue($value);
85
} else {
86
$this->setValue(null);
87
}
88
}
89
90
$this->setError($err);
91
92
return $this->getValue();
93
}
94
95
protected function getCustomControlClass() {
96
return 'aphront-form-control-date';
97
}
98
99
public function setValue($epoch) {
100
if ($epoch instanceof AphrontFormDateControlValue) {
101
$this->continueOnInvalidDate = true;
102
$this->valueDate = $epoch->getValueDate();
103
$this->valueTime = $epoch->getValueTime();
104
$this->allowNull = $epoch->getOptional();
105
$this->isDisabled = $epoch->isDisabled();
106
107
return parent::setValue($epoch->getEpoch());
108
}
109
110
$result = parent::setValue($epoch);
111
112
if ($epoch === null) {
113
return $result;
114
}
115
116
$readable = $this->formatTime($epoch, 'Y!m!d!'.$this->getTimeFormat());
117
$readable = explode('!', $readable, 4);
118
119
$year = $readable[0];
120
$month = $readable[1];
121
$day = $readable[2];
122
123
$this->valueDate = $month.'/'.$day.'/'.$year;
124
$this->valueTime = $readable[3];
125
126
return $result;
127
}
128
129
private function getDateInputValue() {
130
$date_format = $this->getDateFormat();
131
$timezone = $this->getTimezone();
132
133
try {
134
$datetime = new DateTime($this->valueDate, $timezone);
135
} catch (Exception $ex) {
136
return $this->valueDate;
137
}
138
139
return $datetime->format($date_format);
140
}
141
142
private function getTimeFormat() {
143
$viewer = $this->getViewer();
144
$time_key = PhabricatorTimeFormatSetting::SETTINGKEY;
145
return $viewer->getUserSetting($time_key);
146
}
147
148
private function getDateFormat() {
149
$viewer = $this->getViewer();
150
$date_key = PhabricatorDateFormatSetting::SETTINGKEY;
151
return $viewer->getUserSetting($date_key);
152
}
153
154
private function getTimeInputValue() {
155
return $this->valueTime;
156
}
157
158
private function formatTime($epoch, $fmt) {
159
return phabricator_format_local_time(
160
$epoch,
161
$this->getViewer(),
162
$fmt);
163
}
164
165
private function getDateInputName() {
166
return $this->getName().'_d';
167
}
168
169
private function getTimeInputName() {
170
return $this->getName().'_t';
171
}
172
173
private function getCheckboxInputName() {
174
return $this->getName().'_e';
175
}
176
177
protected function renderInput() {
178
179
$disabled = null;
180
if ($this->getValue() === null && !$this->continueOnInvalidDate) {
181
$this->setValue($this->getInitialValue());
182
if ($this->allowNull) {
183
$disabled = 'disabled';
184
}
185
}
186
187
if ($this->isDisabled) {
188
$disabled = 'disabled';
189
}
190
191
$checkbox = null;
192
if ($this->allowNull) {
193
$checkbox = javelin_tag(
194
'input',
195
array(
196
'type' => 'checkbox',
197
'name' => $this->getCheckboxInputName(),
198
'sigil' => 'calendar-enable',
199
'class' => 'aphront-form-date-enabled-input',
200
'value' => 1,
201
'checked' => ($disabled === null ? 'checked' : null),
202
));
203
}
204
205
$date_sel = javelin_tag(
206
'input',
207
array(
208
'autocomplete' => 'off',
209
'name' => $this->getDateInputName(),
210
'sigil' => 'date-input',
211
'value' => $this->getDateInputValue(),
212
'type' => 'text',
213
'class' => 'aphront-form-date-input',
214
),
215
'');
216
217
$date_div = javelin_tag(
218
'div',
219
array(
220
'class' => 'aphront-form-date-input-container',
221
),
222
$date_sel);
223
224
$cicon = id(new PHUIIconView())
225
->setIcon('fa-calendar');
226
227
$cal_icon = javelin_tag(
228
'a',
229
array(
230
'href' => '#',
231
'class' => 'calendar-button',
232
'sigil' => 'calendar-button',
233
),
234
$cicon);
235
236
$values = $this->getTimeTypeaheadValues();
237
238
$time_id = celerity_generate_unique_node_id();
239
Javelin::initBehavior('time-typeahead', array(
240
'startTimeID' => $time_id,
241
'endTimeID' => $this->endDateID,
242
'timeValues' => $values,
243
'format' => $this->getTimeFormat(),
244
));
245
246
$time_sel = javelin_tag(
247
'input',
248
array(
249
'autocomplete' => 'off',
250
'name' => $this->getTimeInputName(),
251
'sigil' => 'time-input',
252
'value' => $this->getTimeInputValue(),
253
'type' => 'text',
254
'class' => 'aphront-form-time-input',
255
),
256
'');
257
258
$time_div = javelin_tag(
259
'div',
260
array(
261
'id' => $time_id,
262
'class' => 'aphront-form-time-input-container',
263
),
264
$time_sel);
265
266
$viewer = $this->getViewer();
267
$week_key = PhabricatorWeekStartDaySetting::SETTINGKEY;
268
$week_start = $viewer->getUserSetting($week_key);
269
270
Javelin::initBehavior('fancy-datepicker', array(
271
'format' => $this->getDateFormat(),
272
'weekStart' => $week_start,
273
));
274
275
$classes = array();
276
$classes[] = 'aphront-form-date-container';
277
if ($disabled) {
278
$classes[] = 'datepicker-disabled';
279
}
280
if ($this->isTimeDisabled) {
281
$classes[] = 'no-time';
282
}
283
284
return javelin_tag(
285
'div',
286
array(
287
'class' => implode(' ', $classes),
288
'sigil' => 'phabricator-date-control',
289
'meta' => array(
290
'disabled' => (bool)$disabled,
291
),
292
'id' => $this->getID(),
293
),
294
array(
295
$checkbox,
296
$date_div,
297
$cal_icon,
298
$time_div,
299
));
300
}
301
302
private function getTimezone() {
303
if ($this->zone) {
304
return $this->zone;
305
}
306
307
$viewer = $this->getViewer();
308
309
$user_zone = $viewer->getTimezoneIdentifier();
310
$this->zone = new DateTimeZone($user_zone);
311
return $this->zone;
312
}
313
314
private function getInitialValue() {
315
$zone = $this->getTimezone();
316
317
// TODO: We could eventually allow these to be customized per install or
318
// per user or both, but let's wait and see.
319
switch ($this->initialTime) {
320
case self::TIME_START_OF_DAY:
321
default:
322
$time = '12:00 AM';
323
break;
324
case self::TIME_START_OF_BUSINESS:
325
$time = '9:00 AM';
326
break;
327
case self::TIME_END_OF_BUSINESS:
328
$time = '5:00 PM';
329
break;
330
case self::TIME_END_OF_DAY:
331
$time = '11:59 PM';
332
break;
333
}
334
335
$today = $this->formatTime(time(), 'Y-m-d');
336
try {
337
$date = new DateTime("{$today} {$time}", $zone);
338
$value = $date->format('U');
339
} catch (Exception $ex) {
340
$value = null;
341
}
342
343
return $value;
344
}
345
346
private function getTimeTypeaheadValues() {
347
$time_format = $this->getTimeFormat();
348
$times = array();
349
350
if ($time_format == 'g:i A') {
351
$am_pm_list = array('AM', 'PM');
352
353
foreach ($am_pm_list as $am_pm) {
354
for ($hour = 0; $hour < 12; $hour++) {
355
$actual_hour = ($hour == 0) ? 12 : $hour;
356
$times[] = $actual_hour.':00 '.$am_pm;
357
$times[] = $actual_hour.':30 '.$am_pm;
358
}
359
}
360
} else if ($time_format == 'H:i') {
361
for ($hour = 0; $hour < 24; $hour++) {
362
$written_hour = ($hour > 9) ? $hour : '0'.$hour;
363
$times[] = $written_hour.':00';
364
$times[] = $written_hour.':30';
365
}
366
}
367
368
foreach ($times as $key => $time) {
369
$times[$key] = array($key, $time);
370
}
371
372
return $times;
373
}
374
375
}
376
377