Edit and new renderers for DateTime columns

This commit is contained in:
Urban Rotnik 2019-12-16 15:21:50 +01:00
parent 7c71159303
commit 2a63854123
10 changed files with 265 additions and 15 deletions

View file

@ -0,0 +1,186 @@
/* global Inputmask formatJS */
/* eslint-disable no-unused-vars */
var DateTimeHelper = (function() {
function isValidTimeStr(timeStr) {
return /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(timeStr);
}
function isValidDate(date) {
return (Object.prototype.toString.call(date) === '[object Date]') && !isNaN(date.getTime());
}
function addLeadingZero(value) {
return ('0' + value).slice(-2);
}
function recalcTimestamp(date, timeStr) {
if (!isValidTimeStr(timeStr)) {
date.setHours(0);
date.setMinutes(0);
return date;
}
let hours = timeStr.split(':')[0];
let mins = timeStr.split(':')[1];
date.setHours(hours);
date.setMinutes(mins);
return date;
}
function stringDateTimeFormat(date, format) {
let y = date.getFullYear();
let m = addLeadingZero(date.getMonth() + 1);
let d = addLeadingZero(date.getDate());
let hours = addLeadingZero(date.getHours());
let mins = addLeadingZero(date.getMinutes());
if (format === 'dateonly') {
return `${y}/${m}/${d}`;
}
return `${y}/${m}/${d} ${hours}:${mins}`;
}
function insertHiddenField($input, date, timeStr, format) {
let formId = $input.data('form-id');
let columnId = $input.data('column-id');
let hiddenFieldContainer = $input.parent().find('.cell-timestamp-container');
let hasTime = isValidTimeStr(timeStr);
let hasDate = isValidDate(date);
let value;
let hiddenField;
if (!hasDate) { // Date needs to be presence
value = '';
} else if (format === 'time' && !hasTime) { // Delete time value
value = '';
} else if (format === 'datetime' && !hasTime) { // Delete date time value
value = '';
} else {
// create date time format
value = stringDateTimeFormat(recalcTimestamp(date, timeStr), 'full');
}
hiddenField = `
<input type="hidden"
form="${formId}"
name="repository_cells[${columnId}]"
value="${value}" />`;
hiddenFieldContainer.html(hiddenField);
}
function initChangeEvents($cell) {
$cell.find('input[data-mask-type=time]').on('change', function() {
let timeStr = $(this).val();
let $container = $(this).parent().find('.cell-timestamp-container');
let dateStr = $container.data('current-date');
let columnType = $container.data('datetime-type');
if (columnType === 'time' && !isValidDate(dateStr)) {
// new time without value for date
dateStr = stringDateTimeFormat(new Date(), 'dateonly');
}
insertHiddenField($(this), new Date(dateStr), timeStr, columnType);
});
$cell.find('.calendar-input').on('dp.change', function(e) {
let date = e.date._d;
let timeStr = $(this).parent().find('input[data-mask-type=time]').val();
let $container = $(this).parent().find('.cell-timestamp-container');
if (date !== undefined) {
$container.data('current-date', stringDateTimeFormat(date, 'dateonly'));
} else {
$container.data('current-date', '');
}
insertHiddenField($(this), date, timeStr, $container.data('datetime-type'));
});
}
function dateInputField(formId, columnId, value) {
return `
<input class="form-control editing calendar-input"
type="datetime"
data-form-id="${formId}"
data-column-id="${columnId}"
value='${value}'/>
`;
}
function timeInputField(formId, columnId, value) {
return `
<input class="form-control editing"
type="text"
data-mask-type="time"
data-form-id="${formId}"
data-column-id="${columnId}"
value='${value}'
placeholder="HH:mm"/>
`;
}
function initDateEditMode(formId, columnId, $cell, date, datetime) {
let inputFields = `
<div class="form-group">
<div class="cell-timestamp-container" data-current-date="${datetime}" data-datetime-type="date"></div>
${dateInputField(formId, columnId, date)}
</div>
`;
$cell.html(inputFields);
$cell.find('.calendar-input').datetimepicker({ ignoreReadonly: true, locale: 'en', format: formatJS });
initChangeEvents($cell);
}
function initTimeEditMode(formId, columnId, $cell, time, datetime) {
let inputFields = `
<div class="form-group">
<div class="cell-timestamp-container" data-current-date="${datetime}" data-datetime-type="time"></div>
${timeInputField(formId, columnId, time)}
</div>
`;
$cell.html(inputFields);
Inputmask('datetime', {
inputFormat: 'HH:MM',
placeholder: 'HH:mm',
clearIncomplete: true,
showMaskOnHover: true,
hourFormat: 24
}).mask($cell.find('input[data-mask-type="time"]'));
initChangeEvents($cell);
}
function initDateTimeEditMode(formId, columnId, $cell, date, time, datetime) {
let inputFields = `
<div class="form-group">
<div class="cell-timestamp-container" data-current-date="${datetime}" data-datetime-type="datetime"></div>
${dateInputField(formId, columnId, date)}
${timeInputField(formId, columnId, time)}
</div>
`;
$cell.html(inputFields);
Inputmask('datetime', {
inputFormat: 'HH:MM',
placeholder: 'HH:mm',
clearIncomplete: true,
showMaskOnHover: true,
hourFormat: 24
}).mask($cell.find('input[data-mask-type="time"]'));
$cell.find('.calendar-input').datetimepicker({ ignoreReadonly: true, locale: 'en', format: formatJS });
initChangeEvents($cell);
}
return {
initDateEditMode: initDateEditMode,
initTimeEditMode: initTimeEditMode,
initDateTimeEditMode: initDateTimeEditMode,
};
}());

View file

@ -1,4 +1,4 @@
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS */
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS DateTimeHelper*/
$.fn.dataTable.render.editRowName = function(formId, cell) {
let $cell = $(cell.node());
@ -89,15 +89,31 @@ $.fn.dataTable.render.editRepositoryStatusValue = function(formId, columnId, cel
};
$.fn.dataTable.render.editRepositoryDateTimeValue = function(formId, columnId, cell) {
return '';
let $cell = $(cell.node());
let $span = $cell.find('span').first();
let date = $span.data('date');
let time = $span.data('time');
let datetime = $span.data('datetime');
DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, date, time, datetime);
};
$.fn.dataTable.render.editRepositoryDateValue = function(formId, columnId, cell) {
return '';
let $cell = $(cell.node());
let $span = $cell.find('span').first();
let date = $span.data('date');
let datetime = $span.data('datetime');
DateTimeHelper.initDateEditMode(formId, columnId, $cell, date, datetime);
};
$.fn.dataTable.render.editRepositoryTimeValue = function(formId, columnId, cell) {
return '';
let $cell = $(cell.node());
let $span = $cell.find('span').first();
let time = $span.data('time');
let datetime = $span.data('datetime');
DateTimeHelper.initTimeEditMode(formId, columnId, $cell, time, datetime);
};
$.fn.dataTable.render.editRepositoryDateTimeRangeValue = function(formId, columnId, cell) {

View file

@ -1,4 +1,4 @@
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS */
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS DateTimeHelper formatJS */
$.fn.dataTable.render.newRowName = function(formId, $cell) {
$cell.html(`
@ -85,3 +85,19 @@ $.fn.dataTable.render.newRepositoryNumberValue = function(formId, columnId, $cel
SmartAnnotation.init($cell.find('input'));
};
$.fn.dataTable.render.newRepositoryDateTimeValue = function(formId, columnId, $cell) {
DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, '', '', '');
};
$.fn.dataTable.render.newRepositoryTimeValue = function(formId, columnId, $cell) {
DateTimeHelper.initTimeEditMode(formId, columnId, $cell, '', '');
};
$.fn.dataTable.render.newRepositoryDateValue = function(formId, columnId, $cell) {
DateTimeHelper.initDateEditMode(formId, columnId, $cell, '', '');
};
$.fn.dataTable.render.newRepositoryCheckboxValue = function(formId, columnId) {
return '';
};

View file

@ -55,7 +55,7 @@ $.fn.dataTable.render.defaultRepositoryDateValue = function() {
};
$.fn.dataTable.render.RepositoryDateValue = function(data) {
return data.value;
return `<span data-datetime="${data.value.datetime}" data-date="${data.value.formatted}">${data.value.formatted}</span>`;
};
$.fn.dataTable.render.defaultRepositoryDateTimeValue = function() {
@ -63,7 +63,9 @@ $.fn.dataTable.render.defaultRepositoryDateTimeValue = function() {
};
$.fn.dataTable.render.RepositoryDateTimeValue = function(data) {
return data.value;
return `<span data-time="${data.value.time_formatted}"
data-datetime="${data.value.datetime}"
data-date="${data.value.date_formatted}">${data.value.formatted}</span>`;
};
$.fn.dataTable.render.defaultRepositoryTimeValue = function() {
@ -71,7 +73,8 @@ $.fn.dataTable.render.defaultRepositoryTimeValue = function() {
};
$.fn.dataTable.render.RepositoryTimeValue = function(data) {
return data.value;
return `<span data-time="${data.value.formatted}"
data-datetime="${data.value.datetime}">${data.value.formatted}</span>`;
};
$.fn.dataTable.render.defaultRepositoryTimeRangeValue = function() {
@ -79,7 +82,7 @@ $.fn.dataTable.render.defaultRepositoryTimeRangeValue = function() {
};
$.fn.dataTable.render.RepositoryTimeRangeValue = function(data) {
return data.value;
return `<span data-datetime="${data.value.datetime}">${data.value.formatted}</span>`;
};
$.fn.dataTable.render.defaultRepositoryDateTimeRangeValue = function() {

View file

@ -37,3 +37,7 @@ $.fn.dataTable.render.RepositoryChecklistValueValidator = function() {
$.fn.dataTable.render.RepositoryNumberValueValidator = function() {
return true;
};
$.fn.dataTable.render.RepositoryDateTimeValueValidator = function() {
return true;
}

View file

@ -23,7 +23,7 @@ class RepositoryCell < ApplicationRecord
belongs_to :repository_date_value,
(lambda do
includes(:repository_cell)
.where(repository_cells: { value_type: 'RepositoryDateValue' })
.where(repository_cells: { value_type: 'RepositoryDateTimeValueBase' })
end),
optional: true, foreign_key: :value_id, inverse_of: :repository_cell
belongs_to :repository_list_value,
@ -56,14 +56,14 @@ class RepositoryCell < ApplicationRecord
belongs_to :repository_date_time_value,
(lambda do
includes(:repository_cell)
.where(repository_cells: { value_type: 'RepositoryDateTimeValue' })
.where(repository_cells: { value_type: 'RepositoryDateTimeValueBase' })
end),
optional: true, foreign_key: :value_id, inverse_of: :repository_cell
belongs_to :repository_time_value,
(lambda do
includes(:repository_cell)
.where(repository_cells: { value_type: 'RepositoryTimeValue' })
.where(repository_cells: { value_type: 'RepositoryDateTimeValueBase' })
end),
optional: true, foreign_key: :value_id, inverse_of: :repository_cell

View file

@ -3,7 +3,12 @@
module RepositoryDatatable
class RepositoryDateTimeValueSerializer < RepositoryBaseValueSerializer
def value
I18n.l(object.data, format: :full_with_comma)
{
formatted: I18n.l(object.data, format: :full_with_comma),
date_formatted: I18n.l(object.data, format: :full_date),
time_formatted: I18n.l(object.data, format: :time),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
}
end
end
end

View file

@ -3,7 +3,10 @@
module RepositoryDatatable
class RepositoryDateValueSerializer < RepositoryBaseValueSerializer
def value
I18n.l(object.data, format: :full_date)
{
formatted: I18n.l(object.data, format: :full_date),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
}
end
end
end

View file

@ -3,7 +3,10 @@
module RepositoryDatatable
class RepositoryTimeValueSerializer < RepositoryBaseValueSerializer
def value
I18n.l(object.data, format: :time)
{
formatted: I18n.l(object.data, format: :time),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
}
end
end
end

View file

@ -170,3 +170,17 @@
<%= javascript_include_tag "repositories/show" %>
<%= javascript_include_tag "repositories/index" %>
<%= javascript_pack_tag 'custom/inputmask' %>
<script type="text/javascript" charset="utf-8">
<%
js_format = I18n.backend.date_format.dup
js_format.gsub!(/%-d/, 'D')
js_format.gsub!(/%d/, 'DD')
js_format.gsub!(/%-m/, 'M')
js_format.gsub!(/%m/, 'MM')
js_format.gsub!(/%b/, 'MMM')
js_format.gsub!(/%B/, 'MMMM')
js_format.gsub!('%Y', 'YYYY')
%>
const formatJS = "<%= js_format %>"
</script>