Add datetime picker for start date
This commit is contained in:
@@ -64,7 +64,7 @@ class Task extends Base
|
|||||||
'time_spent' => $task['time_spent'] ?: '',
|
'time_spent' => $task['time_spent'] ?: '',
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->dateParser->format($values, array('date_started'));
|
$this->dateParser->format($values, array('date_started'), 'Y-m-d H:i');
|
||||||
|
|
||||||
$this->response->html($this->taskLayout('task/show', array(
|
$this->response->html($this->taskLayout('task/show', array(
|
||||||
'project' => $this->project->getById($task['project_id']),
|
'project' => $this->project->getById($task['project_id']),
|
||||||
|
|||||||
@@ -85,8 +85,7 @@ class DateParser extends Base
|
|||||||
*/
|
*/
|
||||||
public function getTimestamp($value)
|
public function getTimestamp($value)
|
||||||
{
|
{
|
||||||
foreach ($this->getDateFormats() as $format) {
|
foreach ($this->getAllFormats() as $format) {
|
||||||
|
|
||||||
$timestamp = $this->getValidDate($value, $format);
|
$timestamp = $this->getValidDate($value, $format);
|
||||||
|
|
||||||
if ($timestamp !== 0) {
|
if ($timestamp !== 0) {
|
||||||
@@ -97,6 +96,25 @@ class DateParser extends Base
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all combinations of date/time formats
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return []string
|
||||||
|
*/
|
||||||
|
public function getAllFormats()
|
||||||
|
{
|
||||||
|
$formats = array();
|
||||||
|
|
||||||
|
foreach ($this->getDateFormats() as $date) {
|
||||||
|
foreach ($this->getTimeFormats() as $time) {
|
||||||
|
$formats[] = $date.' '.$time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($formats, $this->getDateFormats());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the list of supported date formats (for the parser)
|
* Return the list of supported date formats (for the parser)
|
||||||
*
|
*
|
||||||
@@ -112,6 +130,21 @@ class DateParser extends Base
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of supported time formats (for the parser)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getTimeFormats()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'H:i',
|
||||||
|
'g:i A',
|
||||||
|
'g:iA',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the list of available date formats (for the config page)
|
* Return the list of available date formats (for the config page)
|
||||||
*
|
*
|
||||||
@@ -143,7 +176,7 @@ class DateParser extends Base
|
|||||||
* Get a timetstamp from an ISO date format
|
* Get a timetstamp from an ISO date format
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $date Date format
|
* @param string $date
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function getTimestampFromIsoFormat($date)
|
public function getTimestampFromIsoFormat($date)
|
||||||
@@ -166,7 +199,6 @@ class DateParser extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
|
||||||
if (! empty($values[$field])) {
|
if (! empty($values[$field])) {
|
||||||
$values[$field] = date($format, $values[$field]);
|
$values[$field] = date($format, $values[$field]);
|
||||||
}
|
}
|
||||||
@@ -182,13 +214,14 @@ class DateParser extends Base
|
|||||||
* @access public
|
* @access public
|
||||||
* @param array $values Database values
|
* @param array $values Database values
|
||||||
* @param string[] $fields Date fields
|
* @param string[] $fields Date fields
|
||||||
|
* @param boolean $keep_time Keep time or not
|
||||||
*/
|
*/
|
||||||
public function convert(array &$values, array $fields)
|
public function convert(array &$values, array $fields, $keep_time = false)
|
||||||
{
|
{
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
|
||||||
if (! empty($values[$field]) && ! is_numeric($values[$field])) {
|
if (! empty($values[$field]) && ! is_numeric($values[$field])) {
|
||||||
$values[$field] = $this->removeTimeFromTimestamp($this->getTimestamp($values[$field]));
|
$timestamp = $this->getTimestamp($values[$field]);
|
||||||
|
$values[$field] = $keep_time ? $timestamp : $this->removeTimeFromTimestamp($timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ class TaskCreation extends Base
|
|||||||
*/
|
*/
|
||||||
public function prepare(array &$values)
|
public function prepare(array &$values)
|
||||||
{
|
{
|
||||||
$this->dateParser->convert($values, array('date_due', 'date_started'));
|
$this->dateParser->convert($values, array('date_due'));
|
||||||
|
$this->dateParser->convert($values, array('date_started'), true);
|
||||||
$this->removeFields($values, array('another_task'));
|
$this->removeFields($values, array('another_task'));
|
||||||
$this->resetFields($values, array('owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated'));
|
$this->resetFields($values, array('owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated'));
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ class TaskModification extends Base
|
|||||||
*/
|
*/
|
||||||
public function prepare(array &$values)
|
public function prepare(array &$values)
|
||||||
{
|
{
|
||||||
$this->dateParser->convert($values, array('date_due', 'date_started'));
|
$this->dateParser->convert($values, array('date_due'));
|
||||||
|
$this->dateParser->convert($values, array('date_started'), true);
|
||||||
$this->removeFields($values, array('another_task', 'id'));
|
$this->removeFields($values, array('another_task', 'id'));
|
||||||
$this->resetFields($values, array('date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
|
$this->resetFields($values, array('date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
|
||||||
$this->convertIntegerFields($values, array('is_active', 'recurrence_status', 'recurrence_trigger', 'recurrence_factor', 'recurrence_timeframe', 'recurrence_basedate'));
|
$this->convertIntegerFields($values, array('is_active', 'recurrence_status', 'recurrence_trigger', 'recurrence_factor', 'recurrence_timeframe', 'recurrence_basedate'));
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class TaskValidator extends Base
|
|||||||
new Validators\Integer('recurrence_status', t('This value must be an integer')),
|
new Validators\Integer('recurrence_status', t('This value must be an integer')),
|
||||||
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
||||||
new Validators\Date('date_due', t('Invalid date'), $this->dateParser->getDateFormats()),
|
new Validators\Date('date_due', t('Invalid date'), $this->dateParser->getDateFormats()),
|
||||||
new Validators\Date('date_started', t('Invalid date'), $this->dateParser->getDateFormats()),
|
new Validators\Date('date_started', t('Invalid date'), $this->dateParser->getAllFormats()),
|
||||||
new Validators\Numeric('time_spent', t('This value must be numeric')),
|
new Validators\Numeric('time_spent', t('This value must be numeric')),
|
||||||
new Validators\Numeric('time_estimated', t('This value must be numeric')),
|
new Validators\Numeric('time_estimated', t('This value must be numeric')),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<?= $this->form->hidden('id', $values) ?>
|
<?= $this->form->hidden('id', $values) ?>
|
||||||
|
|
||||||
<?= $this->form->label(t('Start date'), 'date_started') ?>
|
<?= $this->form->label(t('Start date'), 'date_started') ?>
|
||||||
<?= $this->form->text('date_started', $values, array(), array('placeholder="'.$this->text->in($date_format, $date_formats).'"'), 'form-date') ?>
|
<?= $this->form->text('date_started', $values, array(), array('placeholder="'.$this->text->in($date_format, $date_formats).'"'), 'form-datetime') ?>
|
||||||
|
|
||||||
<?= $this->form->label(t('Time estimated'), 'time_estimated') ?>
|
<?= $this->form->label(t('Time estimated'), 'time_estimated') ?>
|
||||||
<?= $this->form->numeric('time_estimated', $values, array(), array('placeholder="'.t('hours').'"')) ?>
|
<?= $this->form->numeric('time_estimated', $values, array(), array('placeholder="'.t('hours').'"')) ?>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -52,3 +52,8 @@ hr {
|
|||||||
float: left;
|
float: left;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* datepicker */
|
||||||
|
#ui-datepicker-div {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ ul.form-errors li {
|
|||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.form-datetime,
|
||||||
input.form-date {
|
input.form-date {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
/* datepicker */
|
|
||||||
#ui-datepicker-div {
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pagination */
|
/* pagination */
|
||||||
.pagination {
|
.pagination {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
5
assets/css/vendor/jquery-ui-timepicker-addon.min.css
vendored
Normal file
5
assets/css/vendor/jquery-ui-timepicker-addon.min.css
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*! jQuery Timepicker Addon - v1.5.5 - 2015-05-24
|
||||||
|
* http://trentrichardson.com/examples/timepicker
|
||||||
|
* Copyright (c) 2015 Trent Richardson; Licensed MIT */
|
||||||
|
|
||||||
|
.ui-timepicker-div .ui-widget-header{margin-bottom:8px}.ui-timepicker-div dl{text-align:left}.ui-timepicker-div dl dt{float:left;clear:left;padding:0 0 0 5px}.ui-timepicker-div dl dd{margin:0 10px 10px 40%}.ui-timepicker-div td{font-size:90%}.ui-tpicker-grid-label{background:0 0;border:0;margin:0;padding:0}.ui-timepicker-div .ui_tpicker_unit_hide{display:none}.ui-timepicker-rtl{direction:rtl}.ui-timepicker-rtl dl{text-align:right;padding:0 5px 0 0}.ui-timepicker-rtl dl dt{float:right;clear:right}.ui-timepicker-rtl dl dd{margin:0 40% 10px 10px}.ui-timepicker-div.ui-timepicker-oneLine{padding-right:2px}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,.ui-timepicker-div.ui-timepicker-oneLine dt{display:none}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label{display:block;padding-top:2px}.ui-timepicker-div.ui-timepicker-oneLine dl{text-align:right}.ui-timepicker-div.ui-timepicker-oneLine dl dd,.ui-timepicker-div.ui-timepicker-oneLine dl dd>div{display:inline-block;margin:0}.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before,.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before{content:':';display:inline-block}.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before,.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before{content:'.';display:inline-block}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide,.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{display:none}
|
||||||
File diff suppressed because one or more lines are too long
@@ -277,6 +277,15 @@ var Kanboard = (function() {
|
|||||||
constrainInput: false
|
constrainInput: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Datetime picker
|
||||||
|
$(".form-datetime").datetimepicker({
|
||||||
|
controlType: 'select',
|
||||||
|
oneLine: true,
|
||||||
|
dateFormat: 'yy-mm-dd',
|
||||||
|
// timeFormat: 'h:mm tt',
|
||||||
|
constrainInput: false
|
||||||
|
});
|
||||||
|
|
||||||
// Markdown Preview for textareas
|
// Markdown Preview for textareas
|
||||||
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
||||||
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
||||||
|
|||||||
5
assets/js/vendor/jquery-ui-timepicker-addon.min.js
vendored
Normal file
5
assets/js/vendor/jquery-ui-timepicker-addon.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
print_css="print links table board task comment subtask markdown"
|
print_css="print links table board task comment subtask markdown"
|
||||||
app_css="base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown screenshot filters"
|
app_css="base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown screenshot filters"
|
||||||
vendor_css="jquery-ui.min chosen.min fullcalendar.min font-awesome.min c3.min"
|
vendor_css="jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min"
|
||||||
|
|
||||||
app_js="base board calendar analytic swimlane screenshot"
|
app_js="base board calendar analytic swimlane screenshot"
|
||||||
vendor_js="jquery-1.11.1.min jquery-ui.min jquery.ui.touch-punch.min chosen.jquery.min dropit.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min app.min"
|
vendor_js="jquery-1.11.1.min jquery-ui.min jquery-ui-timepicker-addon.min jquery.ui.touch-punch.min chosen.jquery.min dropit.min moment.min fullcalendar.min mousetrap.min mousetrap-global-bind.min app.min"
|
||||||
lang_js="da de es fi fr hu it ja nl pl pt-br ru sv sr th tr zh-cn"
|
lang_js="da de es fi fr hu it ja nl pl pt-br ru sv sr th tr zh-cn"
|
||||||
|
|
||||||
function merge_css {
|
function merge_css {
|
||||||
|
|||||||
@@ -56,6 +56,12 @@ class DateParserTest extends Base
|
|||||||
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('2014-03-05')));
|
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('2014-03-05')));
|
||||||
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('2014_03_05')));
|
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('2014_03_05')));
|
||||||
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('03/05/2014')));
|
$this->assertEquals('2014-03-05', date('Y-m-d', $d->getTimestamp('03/05/2014')));
|
||||||
|
$this->assertEquals('2014-03-25 17:18', date('Y-m-d H:i', $d->getTimestamp('03/25/2014 5:18 pm')));
|
||||||
|
$this->assertEquals('2014-03-25 05:18', date('Y-m-d H:i', $d->getTimestamp('03/25/2014 5:18 am')));
|
||||||
|
$this->assertEquals('2014-03-25 05:18', date('Y-m-d H:i', $d->getTimestamp('03/25/2014 5:18am')));
|
||||||
|
$this->assertEquals('2014-03-25 23:14', date('Y-m-d H:i', $d->getTimestamp('03/25/2014 23:14')));
|
||||||
|
$this->assertEquals('2014-03-29 23:14', date('Y-m-d H:i', $d->getTimestamp('2014_03_29 23:14')));
|
||||||
|
$this->assertEquals('2014-03-29 23:14', date('Y-m-d H:i', $d->getTimestamp('2014-03-29 23:14')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConvert()
|
public function testConvert()
|
||||||
|
|||||||
@@ -284,29 +284,35 @@ class TaskCreationTest extends Base
|
|||||||
|
|
||||||
public function testDateStarted()
|
public function testDateStarted()
|
||||||
{
|
{
|
||||||
$date = '2014-11-23';
|
|
||||||
$timestamp = strtotime('+2days');
|
|
||||||
$p = new Project($this->container);
|
$p = new Project($this->container);
|
||||||
$tc = new TaskCreation($this->container);
|
$tc = new TaskCreation($this->container);
|
||||||
$tf = new TaskFinder($this->container);
|
$tf = new TaskFinder($this->container);
|
||||||
|
|
||||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => $date)));
|
|
||||||
$this->assertEquals(2, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => $timestamp)));
|
// Set only a date
|
||||||
|
$this->assertEquals(1, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => '2014-11-24')));
|
||||||
|
|
||||||
$task = $tf->getById(1);
|
$task = $tf->getById(1);
|
||||||
$this->assertNotEmpty($task);
|
$this->assertEquals('2014-11-24 '.date('H:i'), date('Y-m-d H:i', $task['date_started']));
|
||||||
$this->assertNotFalse($task);
|
|
||||||
|
|
||||||
$this->assertEquals(1, $task['id']);
|
// Set a datetime
|
||||||
$this->assertEquals($date, date('Y-m-d', $task['date_started']));
|
$this->assertEquals(2, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => '2014-11-24 16:25')));
|
||||||
|
|
||||||
$task = $tf->getById(2);
|
$task = $tf->getById(2);
|
||||||
$this->assertNotEmpty($task);
|
$this->assertEquals('2014-11-24 16:25', date('Y-m-d H:i', $task['date_started']));
|
||||||
$this->assertNotFalse($task);
|
|
||||||
|
|
||||||
$this->assertEquals(2, $task['id']);
|
// Set a datetime
|
||||||
$this->assertEquals($timestamp, $task['date_started']);
|
$this->assertEquals(3, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => '2014-11-24 6:25pm')));
|
||||||
|
|
||||||
|
$task = $tf->getById(3);
|
||||||
|
$this->assertEquals('2014-11-24 18:25', date('Y-m-d H:i', $task['date_started']));
|
||||||
|
|
||||||
|
// Set a timestamp
|
||||||
|
$this->assertEquals(4, $tc->create(array('project_id' => 1, 'title' => 'test', 'date_started' => time())));
|
||||||
|
|
||||||
|
$task = $tf->getById(4);
|
||||||
|
$this->assertEquals(time(), $task['date_started'], '', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTime()
|
public function testTime()
|
||||||
|
|||||||
@@ -202,15 +202,29 @@ class TaskModificationTest extends Base
|
|||||||
$task = $tf->getById(1);
|
$task = $tf->getById(1);
|
||||||
$this->assertEquals(0, $task['date_started']);
|
$this->assertEquals(0, $task['date_started']);
|
||||||
|
|
||||||
|
// Set only a date
|
||||||
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => '2014-11-24')));
|
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => '2014-11-24')));
|
||||||
|
|
||||||
$task = $tf->getById(1);
|
$task = $tf->getById(1);
|
||||||
$this->assertEquals('2014-11-24', date('Y-m-d', $task['date_started']));
|
$this->assertEquals('2014-11-24 '.date('H:i'), date('Y-m-d H:i', $task['date_started']));
|
||||||
|
|
||||||
|
// Set a datetime
|
||||||
|
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => '2014-11-24 16:25')));
|
||||||
|
|
||||||
|
$task = $tf->getById(1);
|
||||||
|
$this->assertEquals('2014-11-24 16:25', date('Y-m-d H:i', $task['date_started']));
|
||||||
|
|
||||||
|
// Set a datetime
|
||||||
|
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => '2014-11-24 6:25pm')));
|
||||||
|
|
||||||
|
$task = $tf->getById(1);
|
||||||
|
$this->assertEquals('2014-11-24 18:25', date('Y-m-d H:i', $task['date_started']));
|
||||||
|
|
||||||
|
// Set a timestamp
|
||||||
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => time())));
|
$this->assertTrue($tm->update(array('id' => 1, 'date_started' => time())));
|
||||||
|
|
||||||
$task = $tf->getById(1);
|
$task = $tf->getById(1);
|
||||||
$this->assertEquals(date('Y-m-d'), date('Y-m-d', $task['date_started']));
|
$this->assertEquals(time(), $task['date_started'], '', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testChangeTimeEstimated()
|
public function testChangeTimeEstimated()
|
||||||
|
|||||||
Reference in New Issue
Block a user