Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php
index 45f9f3fa01..7c70089836 100644
--- a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php
+++ b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php
@@ -1,106 +1,123 @@
<?php
final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
public function getPanelKey() {
return 'datetime';
}
public function getPanelName() {
return pht('Date and Time');
}
public function getPanelGroup() {
return pht('Account Information');
}
public function processRequest(AphrontRequest $request) {
$user = $request->getUser();
$username = $user->getUsername();
$pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
+ $pref_date = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
$pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
$preferences = $user->loadPreferences();
$errors = array();
if ($request->isFormPost()) {
$new_timezone = $request->getStr('timezone');
if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
$user->setTimezoneIdentifier($new_timezone);
} else {
$errors[] = pht('The selected timezone is not a valid timezone.');
}
- $preferences->setPreference(
- $pref_time,
- $request->getStr($pref_time));
- $preferences->setPreference(
- $pref_week_start,
- $request->getStr($pref_week_start));
+ $preferences
+ ->setPreference(
+ $pref_time,
+ $request->getStr($pref_time))
+ ->setPreference(
+ $pref_date,
+ $request->getStr($pref_date))
+ ->setPreference(
+ $pref_week_start,
+ $request->getStr($pref_week_start));
if (!$errors) {
$preferences->save();
$user->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI('?saved=true'));
}
}
$timezone_ids = DateTimeZone::listIdentifiers();
$timezone_id_map = array_fuse($timezone_ids);
$form = new AphrontFormView();
$form
->setUser($user)
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Timezone'))
->setName('timezone')
->setOptions($timezone_id_map)
->setValue($user->getTimezoneIdentifier()))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Time-of-Day Format'))
->setName($pref_time)
->setOptions(array(
'g:i A' => pht('12-hour (2:34 PM)'),
'H:i' => pht('24-hour (14:34)'),
))
->setCaption(
pht('Format used when rendering a time of day.'))
->setValue($preferences->getPreference($pref_time)))
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setLabel(pht('Date Format'))
+ ->setName($pref_date)
+ ->setOptions(array(
+ 'Y-m-d' => pht('ISO 8601 (2000-02-28)'),
+ 'n/j/Y' => pht('US (2/28/2000)'),
+ 'd-m-Y' => pht('European (28-02-2000)'),
+ ))
+ ->setCaption(
+ pht('Format used when rendering a date.'))
+ ->setValue($preferences->getPreference($pref_date)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Week Starts On'))
->setOptions($this->getWeekDays())
->setName($pref_week_start)
->setCaption(
pht('Calendar weeks will start with this day.'))
->setValue($preferences->getPreference($pref_week_start, 0)))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Account Settings')));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Date and Time Settings'))
->setFormSaved($request->getStr('saved'))
->setFormErrors($errors)
->setForm($form);
return array(
$form_box,
);
}
private function getWeekDays() {
return array(
pht('Sunday'),
pht('Monday'),
pht('Tuesday'),
pht('Wednesday'),
pht('Thursday'),
pht('Friday'),
pht('Saturday'),
);
}
}
diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php
index d54cf6cb46..cb04f59392 100644
--- a/src/applications/settings/storage/PhabricatorUserPreferences.php
+++ b/src/applications/settings/storage/PhabricatorUserPreferences.php
@@ -1,112 +1,113 @@
<?php
final class PhabricatorUserPreferences extends PhabricatorUserDAO {
const PREFERENCE_MONOSPACED = 'monospaced';
const PREFERENCE_DARK_CONSOLE = 'dark_console';
const PREFERENCE_EDITOR = 'editor';
const PREFERENCE_MULTIEDIT = 'multiedit';
const PREFERENCE_TITLES = 'titles';
const PREFERENCE_MONOSPACED_TEXTAREAS = 'monospaced-textareas';
+ const PREFERENCE_DATE_FORMAT = 'date-format';
const PREFERENCE_TIME_FORMAT = 'time-format';
const PREFERENCE_WEEK_START_DAY = 'week-start-day';
const PREFERENCE_RE_PREFIX = 're-prefix';
const PREFERENCE_NO_SELF_MAIL = 'self-mail';
const PREFERENCE_NO_MAIL = 'no-mail';
const PREFERENCE_MAILTAGS = 'mailtags';
const PREFERENCE_VARY_SUBJECT = 'vary-subject';
const PREFERENCE_HTML_EMAILS = 'html-emails';
const PREFERENCE_SEARCHBAR_JUMP = 'searchbar-jump';
const PREFERENCE_SEARCH_SHORTCUT = 'search-shortcut';
const PREFERENCE_SEARCH_SCOPE = 'search-scope';
const PREFERENCE_DIFFUSION_BLAME = 'diffusion-blame';
const PREFERENCE_DIFFUSION_COLOR = 'diffusion-color';
const PREFERENCE_NAV_COLLAPSED = 'nav-collapsed';
const PREFERENCE_NAV_WIDTH = 'nav-width';
const PREFERENCE_APP_TILES = 'app-tiles';
const PREFERENCE_APP_PINNED = 'app-pinned';
const PREFERENCE_DIFF_UNIFIED = 'diff-unified';
const PREFERENCE_DIFF_FILETREE = 'diff-filetree';
const PREFERENCE_DIFF_GHOSTS = 'diff-ghosts';
const PREFERENCE_CONPH_NOTIFICATIONS = 'conph-notifications';
const PREFERENCE_CONPHERENCE_COLUMN = 'conpherence-column';
// These are in an unusual order for historic reasons.
const MAILTAG_PREFERENCE_NOTIFY = 0;
const MAILTAG_PREFERENCE_EMAIL = 1;
const MAILTAG_PREFERENCE_IGNORE = 2;
protected $userPHID;
protected $preferences = array();
protected function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'preferences' => self::SERIALIZATION_JSON,
),
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_KEY_SCHEMA => array(
'userPHID' => array(
'columns' => array('userPHID'),
'unique' => true,
),
),
) + parent::getConfiguration();
}
public function getPreference($key, $default = null) {
return idx($this->preferences, $key, $default);
}
public function setPreference($key, $value) {
$this->preferences[$key] = $value;
return $this;
}
public function unsetPreference($key) {
unset($this->preferences[$key]);
return $this;
}
public function getPinnedApplications(array $apps, PhabricatorUser $viewer) {
$pref_pinned = self::PREFERENCE_APP_PINNED;
$pinned = $this->getPreference($pref_pinned);
if ($pinned) {
return $pinned;
}
$pref_tiles = self::PREFERENCE_APP_TILES;
$tiles = $this->getPreference($pref_tiles, array());
$full_tile = 'full';
$large = array();
foreach ($apps as $app) {
$show = $app->isPinnedByDefault($viewer);
// TODO: This is legacy stuff, clean it up eventually. This approximately
// retains the old "tiles" preference.
if (isset($tiles[get_class($app)])) {
$show = ($tiles[get_class($app)] == $full_tile);
}
if ($show) {
$large[] = get_class($app);
}
}
return $large;
}
public static function filterMonospacedCSSRule($monospaced) {
// Prevent the user from doing dangerous things.
return preg_replace('/[^a-z0-9 ,".]+/i', '', $monospaced);
}
}
diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php
index 6f826cf830..4bf7619875 100644
--- a/src/view/form/control/AphrontFormDateControl.php
+++ b/src/view/form/control/AphrontFormDateControl.php
@@ -1,339 +1,355 @@
<?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() {
- return $this->valueDate;
+ $date_format = $this->getDateFormat();
+ $timezone = $this->getTimezone();
+
+ $datetime = new DateTime($this->valueDate, $timezone);
+ $date = $datetime->format($date_format);
+
+ return $date;
+ }
+
+ 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,
));
$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());
+ 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() {
$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;
}
}
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 43fb42664e..c084eecf2a 100644
--- a/src/view/form/control/AphrontFormDateControlValue.php
+++ b/src/view/form/control/AphrontFormDateControlValue.php
@@ -1,212 +1,266 @@
<?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 = $month.'/'.$day.'/'.$year;
+ $value->valueDate = $value->getFormattedDateFromParts(
+ $year,
+ $month,
+ $day,
+ $value);
$value->valueTime = coalesce($time, '12:00 AM');
$value->valueEnabled = $enabled;
return $value;
}
public static function newFromRequest(AphrontRequest $request, $key) {
$value = new AphrontFormDateControlValue();
$value->viewer = $request->getViewer();
- $value->valueDate = $request->getStr($key.'_d');
+
+ $value->valueDate = $value->getFormattedDateFromDate(
+ $request->getStr($key.'_d'),
+ $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];
- $value->valueDate = $month.'/'.$day.'/'.$year;
+ $value->valueDate = $value->getFormattedDateFromParts(
+ $year,
+ $month,
+ $day,
+ $value);
$value->valueTime = $readable[3];
return $value;
}
public static function newFromDictionary(
PhabricatorUser $viewer,
array $dictionary) {
$value = new AphrontFormDateControlValue();
$value->viewer = $viewer;
- $value->valueDate = idx($dictionary, 'd');
+ $value->valueDate = $value->getFormattedDateFromDate(
+ idx($dictionary, 'd'),
+ $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 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) {
+ $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());
+ } else {
+ return $original_input;
+ }
+ }
+
+ private function getFormattedDateFromParts($year, $month, $day, $value) {
+ $zone = $value->getTimezone();
+
+ return id(new DateTime("{$year}-{$month}-{$day}", $zone))
+ ->format($value->getDateFormat());
+ }
+
+ 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-fancy-datepicker.js b/webroot/rsrc/js/core/behavior-fancy-datepicker.js
index d00f6cc77f..99feaa31f2 100644
--- a/webroot/rsrc/js/core/behavior-fancy-datepicker.js
+++ b/webroot/rsrc/js/core/behavior-fancy-datepicker.js
@@ -1,307 +1,395 @@
/**
* @provides javelin-behavior-fancy-datepicker
* @requires javelin-behavior
* javelin-util
* javelin-dom
* javelin-stratcom
* javelin-vector
*/
-JX.behavior('fancy-datepicker', function() {
+JX.behavior('fancy-datepicker', function(config, statics) {
+ if (statics.initialized) {
+ return;
+ }
+ statics.initialized = true;
var picker;
var root;
var value_y;
var value_m;
var value_d;
+ var get_format_separator = function() {
+ var format = get_format();
+ switch (format.toLowerCase()) {
+ case 'n/j/y':
+ return '/';
+ default:
+ return '-';
+ }
+ };
+
+ var get_key_maps = function() {
+ var format = get_format();
+ var regex = new RegExp('[./ -]');
+ return format.split(regex);
+ };
+
+ var get_format = function() {
+ var format = config.format;
+
+ if (format === null) {
+ format = 'Y-m-d';
+ }
+
+ return format;
+ };
+
var onopen = function(e) {
e.kill();
// If you click the calendar icon while the date picker is open, close it
// without writing the change.
if (picker) {
if (root == e.getNode('phabricator-date-control')) {
// If the user clicked the same control, just close it.
onclose(e);
return;
} else {
// If the user clicked a different control, close the old one but then
// open the new one.
onclose(e);
}
}
root = e.getNode('phabricator-date-control');
picker = JX.$N(
'div',
{className: 'fancy-datepicker', sigil: 'phabricator-datepicker'},
JX.$N('div', {className: 'fancy-datepicker-core'}));
document.body.appendChild(picker);
var button = e.getNode('calendar-button');
var p = JX.$V(button);
var d = JX.Vector.getDim(picker);
picker.style.left = (p.x - d.x - 2) + 'px';
picker.style.top = (p.y) + 'px';
JX.DOM.alterClass(root, 'picker-open', true);
read_date();
render();
};
var onclose = function(e) {
if (!picker) {
return;
}
JX.DOM.remove(picker);
picker = null;
JX.DOM.alterClass(root, 'picker-open', false);
if (e) {
e.kill();
}
root = null;
};
var ontoggle = function(e) {
var box = e.getTarget();
root = e.getNode('phabricator-date-control');
JX.Stratcom.getData(root).disabled = !box.checked;
redraw_inputs();
};
var get_inputs = function() {
return {
d: JX.DOM.find(root, 'input', 'date-input'),
t: JX.DOM.find(root, 'input', 'time-input')
};
};
- var read_date = function() {
- var i = get_inputs();
- var date = i.d.value;
- var parts = date.split('/');
- value_y = +parts[2];
- value_m = +parts[0];
- value_d = +parts[1];
+ var read_date = function(){
+ var inputs = get_inputs();
+ var date = inputs.d.value;
+ var regex = new RegExp('[./ -]');
+ var date_parts = date.split(regex);
+ var map = get_key_maps();
+
+ for (var i=0; i < date_parts.length; i++) {
+ var key = map[i].toLowerCase();
+
+ switch (key) {
+ case 'y':
+ value_y = date_parts[i];
+ break;
+ case 'm':
+ value_m = date_parts[i];
+ break;
+ case 'd':
+ value_d = date_parts[i];
+ break;
+ }
+ }
};
var write_date = function() {
- var i = get_inputs();
- i.d.value = value_m + '/' + value_d + '/' + value_y;
+ var inputs = get_inputs();
+ var map = get_key_maps();
+ var arr_values = [];
+
+ for(var i=0; i < map.length; i++) {
+ switch (map[i].toLowerCase()) {
+ case 'y':
+ arr_values[i] = value_y;
+ break;
+ case 'm':
+ arr_values[i] = value_m;
+ break;
+ case 'n':
+ arr_values[i] = value_m;
+ break;
+ case 'd':
+ arr_values[i] = value_d;
+ break;
+ case 'j':
+ arr_values[i] = value_d;
+ break;
+ }
+ }
+
+ var text_value = '';
+ var separator = get_format_separator();
+
+ for(var j=0; j < arr_values.length; j++) {
+ var element = arr_values[j];
+ var format = get_format();
+
+ if ((format.toLowerCase() === 'd-m-y' ||
+ format.toLowerCase() === 'y-m-d') &&
+ element < 10) {
+ element = '0' + element;
+ }
+
+ if (text_value.length === 0) {
+ text_value += element;
+ } else {
+ text_value = text_value + separator + element;
+ }
+ }
+
+ inputs.d.value = text_value;
};
var render = function() {
JX.DOM.setContent(
picker.firstChild,
[
render_month(),
render_day()
]);
};
var redraw_inputs = function() {
var disabled = JX.Stratcom.getData(root).disabled;
JX.DOM.alterClass(root, 'datepicker-disabled', disabled);
var box = JX.DOM.scry(root, 'input', 'calendar-enable');
if (box.length) {
box[0].checked = !disabled;
}
};
// Render a cell for the date picker.
var cell = function(label, value, selected, class_name) {
class_name = class_name || '';
if (selected) {
class_name += ' datepicker-selected';
}
if (!value) {
class_name += ' novalue';
}
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',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'];
var buttons = [
cell('\u25C0', 'm:-1', false, 'lrbutton'),
cell(months[month] + ' ' + year, null),
cell('\u25B6', 'm:1', false, 'lrbutton')];
return JX.$N(
'table',
{className: 'month-table'},
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 {
//year 01 should be 2001, not 1901
if (written_date.getYear() < 70) {
value_y += 2000;
written_date = new Date(value_y, value_m-1, value_d);
}
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.
var weekdays = 'SMTWTFS';
var weekday_names = [];
var ii;
for (ii = 0; ii < weekdays.length; ii++) {
weekday_names.push(cell(weekdays.charAt(ii), null, false, 'day-name'));
}
weeks.push(JX.$N('tr', {}, weekday_names));
// 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(
valid_date.getYear() + 1900,
valid_date.getMonth(),
1).getDay();
while (start--) {
days.push(cell('', null, false, 'day-placeholder'));
}
for (ii = 1; ii <= 31; ii++) {
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;
}
var is_today = (today.getYear() == date.getYear() &&
today.getMonth() == date.getMonth() &&
today.getDate() == date.getDate());
var classes = [];
classes.push('day');
if (is_today) {
classes.push('today');
}
if (date.getDay() === 0 || date.getDay() == 6) {
classes.push('weekend');
}
days.push(cell(
ii,
'd:'+ii,
valid_date.getDate() == ii,
classes.join(' ')));
}
// Slice the days into weeks.
for (ii = 0; ii < days.length; ii += 7) {
weeks.push(JX.$N('tr', {}, days.slice(ii, ii + 7)));
}
return JX.$N('table', {className: 'day-table'}, weeks);
};
JX.Stratcom.listen('click', 'calendar-button', onopen);
JX.Stratcom.listen('change', 'calendar-enable', ontoggle);
JX.Stratcom.listen(
'click',
['phabricator-datepicker', 'tag:td'],
function(e) {
e.kill();
var data = e.getNodeData('tag:td');
if (!data.value) {
return;
}
var valid_date = getValidDate();
value_y = valid_date.getYear() + 1900;
value_m = valid_date.getMonth() + 1;
value_d = valid_date.getDate();
var p = data.value.split(':');
switch (p[0]) {
case 'm':
// User clicked left or right month selection buttons.
value_m = value_m + parseInt(p[1], 10);
if (value_m > 12) {
value_m -= 12;
value_y++;
} else if (value_m <= 0) {
value_m += 12;
value_y--;
}
break;
case 'd':
// User clicked a day.
value_d = parseInt(p[1], 10);
write_date();
// Wait a moment to close the selector so they can see the effect
// of their action.
setTimeout(JX.bind(null, onclose, e), 150);
break;
}
// Enable the control.
JX.Stratcom.getData(root).disabled = false;
redraw_inputs();
render();
});
JX.Stratcom.listen('click', null, function(e){
if (e.getNode('phabricator-datepicker')) {
return;
}
onclose();
});
});

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 2:53 PM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140421
Default Alt Text
(34 KB)

Event Timeline