Page MenuHomestyx hydra

No OneTemporary

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
@@ -1,355 +1,375 @@
<?php
final class AphrontFormDateControl extends AphrontFormControl {
private $initialTime;
private $zone;
private $valueDate;
private $valueTime;
private $allowNull;
private $continueOnInvalidDate = false;
private $isTimeDisabled;
private $isDisabled;
private $endDateID;
public function setAllowNull($allow_null) {
$this->allowNull = $allow_null;
return $this;
}
public function setIsTimeDisabled($is_disabled) {
$this->isTimeDisabled = $is_disabled;
return $this;
}
public function setIsDisabled($is_datepicker_disabled) {
$this->isDisabled = $is_datepicker_disabled;
return $this;
}
public function setEndDateID($value) {
$this->endDateID = $value;
return $this;
}
const TIME_START_OF_DAY = 'start-of-day';
const TIME_END_OF_DAY = 'end-of-day';
const TIME_START_OF_BUSINESS = 'start-of-business';
const TIME_END_OF_BUSINESS = 'end-of-business';
public function setInitialTime($time) {
$this->initialTime = $time;
return $this;
}
public function readValueFromRequest(AphrontRequest $request) {
$date = $request->getStr($this->getDateInputName());
$time = $request->getStr($this->getTimeInputName());
$enabled = $request->getBool($this->getCheckboxInputName());
if ($this->allowNull && !$enabled) {
$this->setError(null);
$this->setValue(null);
return;
}
$err = $this->getError();
if ($date || $time) {
$this->valueDate = $date;
$this->valueTime = $time;
// Assume invalid.
$err = pht('Invalid');
$zone = $this->getTimezone();
try {
$datetime = new DateTime("{$date} {$time}", $zone);
$value = $datetime->format('U');
} catch (Exception $ex) {
$value = null;
}
if ($value) {
$this->setValue($value);
$err = null;
} else {
$this->setValue(null);
}
} else {
$value = $this->getInitialValue();
if ($value) {
$this->setValue($value);
} else {
$this->setValue(null);
}
}
$this->setError($err);
return $this->getValue();
}
protected function getCustomControlClass() {
return 'aphront-form-control-date';
}
public function setValue($epoch) {
if ($epoch instanceof AphrontFormDateControlValue) {
$this->continueOnInvalidDate = true;
$this->valueDate = $epoch->getValueDate();
$this->valueTime = $epoch->getValueTime();
$this->allowNull = $epoch->getOptional();
$this->isDisabled = $epoch->isDisabled();
return parent::setValue($epoch->getEpoch());
}
$result = parent::setValue($epoch);
if ($epoch === null) {
return $result;
}
$readable = $this->formatTime($epoch, 'Y!m!d!g:i A');
$readable = explode('!', $readable, 4);
$year = $readable[0];
$month = $readable[1];
$day = $readable[2];
$this->valueDate = $month.'/'.$day.'/'.$year;
$this->valueTime = $readable[3];
return $result;
}
private function getDateInputValue() {
$date_format = $this->getDateFormat();
$timezone = $this->getTimezone();
$datetime = new DateTime($this->valueDate, $timezone);
$date = $datetime->format($date_format);
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();
$pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
return $preferences->getPreference($pref_date_format, 'Y-m-d');
}
private function getTimeInputValue() {
return $this->valueTime;
}
private function formatTime($epoch, $fmt) {
return phabricator_format_local_time(
$epoch,
$this->user,
$fmt);
}
private function getDateInputName() {
return $this->getName().'_d';
}
private function getTimeInputName() {
return $this->getName().'_t';
}
private function getCheckboxInputName() {
return $this->getName().'_e';
}
protected function renderInput() {
$disabled = null;
if ($this->getValue() === null && !$this->continueOnInvalidDate) {
$this->setValue($this->getInitialValue());
if ($this->allowNull) {
$disabled = 'disabled';
}
}
if ($this->isDisabled) {
$disabled = 'disabled';
}
$checkbox = null;
if ($this->allowNull) {
$checkbox = javelin_tag(
'input',
array(
'type' => 'checkbox',
'name' => $this->getCheckboxInputName(),
'sigil' => 'calendar-enable',
'class' => 'aphront-form-date-enabled-input',
'value' => 1,
'checked' => ($disabled === null ? 'checked' : null),
));
}
$date_sel = javelin_tag(
'input',
array(
'autocomplete' => 'off',
'name' => $this->getDateInputName(),
'sigil' => 'date-input',
'value' => $this->getDateInputValue(),
'type' => 'text',
'class' => 'aphront-form-date-input',
),
'');
$date_div = javelin_tag(
'div',
array(
'class' => 'aphront-form-date-input-container',
),
$date_sel);
$cicon = id(new PHUIIconView())
->setIconFont('fa-calendar');
$cal_icon = javelin_tag(
'a',
array(
'href' => '#',
'class' => 'calendar-button',
'sigil' => 'calendar-button',
),
$cicon);
$values = $this->getTimeTypeaheadValues();
$time_id = celerity_generate_unique_node_id();
Javelin::initBehavior('time-typeahead', array(
'startTimeID' => $time_id,
'endTimeID' => $this->endDateID,
'timeValues' => $values,
+ 'format' => $this->getTimeFormat(),
));
$time_sel = javelin_tag(
'input',
array(
'autocomplete' => 'off',
'name' => $this->getTimeInputName(),
'sigil' => 'time-input',
'value' => $this->getTimeInputValue(),
'type' => 'text',
'class' => 'aphront-form-time-input',
),
'');
$time_div = javelin_tag(
'div',
array(
'id' => $time_id,
'class' => 'aphront-form-time-input-container',
),
$time_sel);
Javelin::initBehavior('fancy-datepicker', array(
'format' => $this->getDateFormat(),
));
$classes = array();
$classes[] = 'aphront-form-date-container';
if ($disabled) {
$classes[] = 'datepicker-disabled';
}
if ($this->isTimeDisabled) {
$classes[] = 'no-time';
}
return javelin_tag(
'div',
array(
'class' => implode(' ', $classes),
'sigil' => 'phabricator-date-control',
'meta' => array(
'disabled' => (bool)$disabled,
),
'id' => $this->getID(),
),
array(
$checkbox,
$date_div,
$cal_icon,
$time_div,
));
}
private function getTimezone() {
if ($this->zone) {
return $this->zone;
}
$user = $this->getUser();
if (!$this->getUser()) {
throw new PhutilInvalidStateException('setUser');
}
$user_zone = $user->getTimezoneIdentifier();
$this->zone = new DateTimeZone($user_zone);
return $this->zone;
}
private function getInitialValue() {
$zone = $this->getTimezone();
// TODO: We could eventually allow these to be customized per install or
// per user or both, but let's wait and see.
switch ($this->initialTime) {
case self::TIME_START_OF_DAY:
default:
$time = '12:00 AM';
break;
case self::TIME_START_OF_BUSINESS:
$time = '9:00 AM';
break;
case self::TIME_END_OF_BUSINESS:
$time = '5:00 PM';
break;
case self::TIME_END_OF_DAY:
$time = '11:59 PM';
break;
}
$today = $this->formatTime(time(), 'Y-m-d');
try {
$date = new DateTime("{$today} {$time}", $zone);
$value = $date->format('U');
} catch (Exception $ex) {
$value = null;
}
return $value;
}
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
@@ -1,266 +1,292 @@
<?php
final class AphrontFormDateControlValue extends Phobject {
private $valueDate;
private $valueTime;
private $valueEnabled;
private $viewer;
private $zone;
private $optional;
public function getValueDate() {
return $this->valueDate;
}
public function getValueTime() {
return $this->valueTime;
}
public function isValid() {
if ($this->isDisabled()) {
return true;
}
return ($this->getEpoch() !== null);
}
public function isEmpty() {
if ($this->valueDate) {
return false;
}
if ($this->valueTime) {
return false;
}
return true;
}
public function isDisabled() {
return ($this->optional && !$this->valueEnabled);
}
public function setEnabled($enabled) {
$this->valueEnabled = $enabled;
return $this;
}
public function setOptional($optional) {
$this->optional = $optional;
return $this;
}
public function getOptional() {
return $this->optional;
}
public static function newFromParts(
PhabricatorUser $viewer,
$year,
$month,
$day,
$time = null,
$enabled = true) {
$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;
}
public static function newFromRequest(AphrontRequest $request, $key) {
$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;
}
public static function newFromEpoch(PhabricatorUser $viewer, $epoch) {
$value = new AphrontFormDateControlValue();
$value->viewer = $viewer;
$readable = $value->formatTime($epoch, 'Y!m!d!g:i A');
$readable = explode('!', $readable, 4);
$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;
}
public static function newFromDictionary(
PhabricatorUser $viewer,
array $dictionary) {
$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;
}
public static function newFromWild(PhabricatorUser $viewer, $wild) {
if (is_array($wild)) {
return self::newFromDictionary($viewer, $wild);
} else if (is_numeric($wild)) {
return self::newFromEpoch($viewer, $wild);
} else {
throw new Exception(
pht(
'Unable to construct a date value from value of type "%s".',
gettype($wild)));
}
}
public function getDictionary() {
return array(
'd' => $this->valueDate,
't' => $this->valueTime,
'e' => $this->valueEnabled,
);
}
public function getValueAsFormat($format) {
return phabricator_format_local_time(
$this->getEpoch(),
$this->viewer,
$format);
}
private function formatTime($epoch, $format) {
return phabricator_format_local_time(
$epoch,
$this->viewer,
$format);
}
public function getEpoch() {
if ($this->isDisabled()) {
return null;
}
$date = $this->valueDate;
$time = $this->valueTime;
$zone = $this->getTimezone();
if (!strlen($time)) {
return null;
}
$colloquial = array(
'elevenses' => '11:00 AM',
'morning tea' => '11:00 AM',
'noon' => '12:00 PM',
'high noon' => '12:00 PM',
'lunch' => '12:00 PM',
'tea time' => '3:00 PM',
'witching hour' => '12:00 AM',
'midnight' => '12:00 AM',
);
$normalized = phutil_utf8_strtolower($time);
if (isset($colloquial[$normalized])) {
$time = $colloquial[$normalized];
}
try {
$datetime = new DateTime("{$date} {$time}", $zone);
$value = $datetime->format('U');
} catch (Exception $ex) {
$value = null;
}
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;
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();
$parts = preg_split('@[,./:-]@', $date);
$date = implode($separator, $parts);
$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() {
$format = $this->getDateFormat();
switch ($format) {
case 'n/j/Y':
return '/';
default:
return '-';
}
}
public function getDateTime() {
$epoch = $this->getEpoch();
$date = null;
if ($epoch) {
$zone = $this->getTimezone();
$date = new DateTime('@'.$epoch);
$date->setTimeZone($zone);
}
return $date;
}
private function getTimezone() {
if ($this->zone) {
return $this->zone;
}
$viewer_zone = $this->viewer->getTimezoneIdentifier();
$this->zone = new DateTimeZone($viewer_zone);
return $this->zone;
}
}
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
@@ -1,123 +1,148 @@
/**
* @provides javelin-behavior-time-typeahead
* @requires javelin-behavior
* javelin-util
* javelin-dom
* javelin-stratcom
* javelin-vector
* javelin-typeahead-static-source
*/
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;
var datasource = new JX.TypeaheadStaticSource(config.timeValues);
datasource.setTransformer(function(v) {
var attributes = {'className' : 'phui-time-typeahead-value'};
var display = JX.$N('div', attributes, v[1]);
var object = {
'id' : v[0],
'name' : v[1],
'display' : display,
'uri' : null
};
return object;
});
datasource.setSortHandler(function(value, list) {
list.sort(function(u,v){
return (u.id > v.id) ? 1 : -1;
});
});
datasource.setMaximumResultCount(24);
var typeahead = new JX.Typeahead(
start_date_control,
JX.DOM.find(start_date_control, 'input', null));
typeahead.setDatasource(datasource);
if (!end_date_control) {
typeahead.start();
return;
}
var start_time_control = JX.DOM.find(
start_date_control,
'input',
'time-input');
var end_time_control = JX.DOM.find(
end_date_control,
'input',
'time-input');
JX.DOM.listen(start_time_control, 'input', null, function() {
if (end_date_tampered) {
return;
}
var time = start_time_control.value;
var end_value = getNewValue(time);
if (end_value) {
end_time_control.value = end_value;
}
});
typeahead.listen('choose', function(e) {
if (end_date_tampered) {
return;
}
var time = e.name;
var end_value = getNewValue(time);
if (end_value) {
end_time_control.value = end_value;
}
});
JX.DOM.listen(end_date_control, 'input', null, function() {
end_date_tampered = true;
});
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;
}
var results = regex.exec(time);
var hours = parseInt(results[1], 10);
var minutes = parseInt(results[2], 10) ? parseInt(results[2], 10) : 0;
var real_time = 0;
-
- if (/pm/i.test(results[3])) {
- real_time = 12*60;
- } else if (/am/i.test(results[3]) && hours == 12) {
- hours = 0;
+ var end_value = '';
+
+ 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;
}
typeahead.start();
});

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 3:20 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140447
Default Alt Text
(22 KB)

Event Timeline