diff --git a/app/assets/javascripts/repositories/renderers/columns/date_time_helper.js b/app/assets/javascripts/repositories/renderers/columns/date_time_helper.js index 4be902d54..c36be5356 100644 --- a/app/assets/javascripts/repositories/renderers/columns/date_time_helper.js +++ b/app/assets/javascripts/repositories/renderers/columns/date_time_helper.js @@ -2,316 +2,84 @@ /* 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 (date instanceof Date) && !isNaN(date.getTime()); - } - - function addLeadingZero(value) { - return ('0' + value).slice(-2); - } - - function setDateTimePickerOpeningDirection(event) { - const element = $(event.target); - const dateTimePickerWidget = $('.bootstrap-datetimepicker-widget'); - - const windowHeight = element.closest('table').offset().top; - const inputTop = element.offset().top; - const pickerHeight = $('.bootstrap-datetimepicker-widget').outerHeight(); - - if (inputTop - windowHeight > pickerHeight) { - dateTimePickerWidget.addClass('top') - .removeClass('bottom') - .css({ - top: 'auto', - bottom: '36px', - }); - } else { - dateTimePickerWidget.addClass('bottom') - .removeClass('top') - .css({ - top: '36px', - bottom: 'auto', - }); - } - } - - function recalcTimestamp(date, timeStr) { - if (!isValidTimeStr(timeStr)) { - date.setHours(0); - date.setMinutes(0); - return date; - } - - date.setHours(timeStr.split(':')[0]); - date.setMinutes(timeStr.split(':')[1]); - 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($container) { - let formId = $container.data('form-id'); - let columnId = $container.data('column-id'); - let dateStr = $container.find('input.date-part').data('selected-date'); - let timeStr = $container.find('input.time-part').val(); - let columnType = $container.data('type'); - let date = new Date(dateStr); - let value = ''; - let hiddenField; - - if (isValidDate(date) && isValidTimeStr(timeStr)) { - value = stringDateTimeFormat(recalcTimestamp(date, timeStr), 'full'); - } - - hiddenField = ` - `; - - $container.find('input.repository-cell-value').remove(); - $container.prepend(hiddenField); - } - - - function insertRangeHiddenField($container) { - let formId = $container.data('form-id'); - let columnId = $container.data('column-id'); - let columnType = $container.data('type'); - let $startContainer = $container.find('.start-time'); - let $endContainer = $container.find('.end-time'); - let startDate = new Date($startContainer.find('input.date-part').data('selected-date')); - let startTimeStr = $startContainer.find('input.time-part').val(); - let endDate = new Date($endContainer.find('input.date-part').data('selected-date')); - let endTimeStr = $endContainer.find('input.time-part').val(); - let hiddenField; - let value = ''; - - if (isValidDate(startDate) - && isValidTimeStr(startTimeStr) - && isValidDate(endDate) - && isValidTimeStr(endTimeStr)) { - let start = stringDateTimeFormat(recalcTimestamp(startDate, startTimeStr), 'full'); - let end = stringDateTimeFormat(recalcTimestamp(endDate, endTimeStr), 'full'); - value = JSON.stringify({ start_time: start, end_time: end }); - } - - hiddenField = ` - `; - - $container.find('input.repository-cell-value').remove(); - $container.prepend(hiddenField); - } - - function initChangeEvents($cell) { - $cell.find('input.time-part').on('change', function() { - let $input = $(this); - let $container = $input.closest('.datetime-container'); - - if ($container.hasClass('range-type')) { - insertRangeHiddenField($container); - } else { - insertHiddenField($container); - } - }); - - $cell.find('input.date-part').on('dp.change', function(e) { - let $input = $(this); - let date = e.date._d; - let $container = $input.closest('.datetime-container'); - - if (date !== undefined) { - $input.data('selected-date', stringDateTimeFormat(date, 'dateonly')); - } else { - $input.data('selected-date', ''); - } - - if ($container.hasClass('range-type')) { - insertRangeHiddenField($container); - } else { - insertHiddenField($container); - } - }); - } - - - function dateInputField(value, dateDataValue) { - return ` -
- - -
- `; - } - - function timeInputField(value) { - return ` -
- - -
- `; - } - - function getDateOrDefault($span, mode) { - let dateStr = $span.data('date'); - let date; - if (mode === 'timeonly') { - // Set default date if no data in span - date = new Date(dateStr); - if (isValidDate(date)) { - dateStr = stringDateTimeFormat(new Date(date), 'dateonly'); - } else { - dateStr = stringDateTimeFormat(new Date(), 'dateonly'); - } - } - return dateStr; - } - - function getTimeOrDefault($span, mode) { - let timeStr = $span.data('time'); - - if ((mode === 'dateonly') && (!isValidTimeStr(timeStr))) { - timeStr = '00:00'; - } - return timeStr; - } - - function initCurrentTimeSelector($cell) { - $cell.find('.time-container .fa-clock').click(function() { - var inputField = $(this).prev(); - var d = new Date(); - var h = addLeadingZero(d.getHours()); - var m = addLeadingZero(d.getMinutes()); - inputField.val(h + ':' + m).change(); - }); + function placeholder(mode) { + if (mode === 'date') return formatJS; + if (mode === 'time') return 'HH:mm'; + return `${formatJS} HH:mm`; } function initDateTimeEditMode(formId, columnId, $cell, mode, columnType) { - let $span = $cell.find('span').first(); - let date = $span.data('date'); - let dateDataValue = getDateOrDefault($span, mode); - let time = getTimeOrDefault($span, mode); - let datetime = $span.data('datetime'); - let inputFields = ` -
+
+ - ${dateInputField(date, dateDataValue)} - ${timeInputField(time)} -
- `; + data-simple-format="true" + form="${formId}" + name="repository_cells[${columnId}]" + class="datetime" type="hidden" + data-default="${dateTime}" + v-model="date" + id="datetimePicker${formId}${columnId}" /> + +
+ + `; $cell.html(inputFields); - initCurrentTimeSelector($cell); - 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 }) - .on('dp.show', (e) => { - setDateTimePickerOpeningDirection(e); - }); - initChangeEvents($cell); + window.initDateTimePickerComponent(`#datetimePickerContainer${formId}${columnId}`); } function initDateTimeRangeEditMode(formId, columnId, $cell, mode, columnType) { - let $startSpan = $cell.find('span').first(); - let startDate = $startSpan.data('date'); - let startTime = getTimeOrDefault($startSpan, mode); - let startDatetime = getDateOrDefault($startSpan, mode); - let startDateDataValue = getDateOrDefault($startSpan, mode); - let $endSpan = $cell.find('span').last(); - let endDate = $endSpan.data('date'); - let endTime = getTimeOrDefault($endSpan, mode); - let endDatetime = getDateOrDefault($endSpan, mode); - let endDateDataValue = getDateOrDefault($endSpan, mode); + const $startSpan = $cell.find('span').first(); + const startDateTime = $startSpan.data('datetime') || ''; + const $endSpan = $cell.find('span').last(); + const endDateTime = $endSpan.data('datetime') || ''; - let inputFields = ` -
-
- ${dateInputField(startDate, startDatetime)} - ${timeInputField(startTime)} -
-
-
- ${dateInputField(endDate, endDatetime)} - ${timeInputField(endTime)} -
-
- `; + const inputFields = ` +
+
+ + +
+
+
+ + +
+
`; $cell.html(inputFields); - initCurrentTimeSelector($cell); - - Inputmask('datetime', { - inputFormat: 'HH:MM', - placeholder: 'HH:mm', - clearIncomplete: true, - showMaskOnHover: true, - hourFormat: 24 - }).mask($cell.find('input[data-mask-type="time"]')); - - let $cal1 = $cell.find('.calendar-input').first().datetimepicker({ ignoreReadonly: true, locale: 'en', format: formatJS }); - let $cal2 = $cell.find('.calendar-input').last().datetimepicker({ ignoreReadonly: true, locale: 'en', format: formatJS }); - - $cal1.on('dp.change', function(e) { - $cal2.data('DateTimePicker').minDate(e.date); - }).on('dp.show', (e) => { - setDateTimePickerOpeningDirection(e); - }); - $cal2.on('dp.change', function(e) { - $cal1.data('DateTimePicker').maxDate(e.date); - }).on('dp.show', (e) => { - setDateTimePickerOpeningDirection(e); - }); - - initChangeEvents($cell); + window.initDateTimePickerComponent(`#datetimeStartPickerComtainer${formId}${columnId}`); + window.initDateTimePickerComponent(`#datetimeEndPickerComtainer${formId}${columnId}`); } return { diff --git a/app/assets/javascripts/repositories/renderers/edit_renderers.js b/app/assets/javascripts/repositories/renderers/edit_renderers.js index ab9884915..0f1e320ff 100644 --- a/app/assets/javascripts/repositories/renderers/edit_renderers.js +++ b/app/assets/javascripts/repositories/renderers/edit_renderers.js @@ -75,37 +75,37 @@ $.fn.dataTable.render.editRepositoryStatusValue = function(formId, columnId, cel $.fn.dataTable.render.editRepositoryDateTimeValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, '', 'RepositoryDateTimeValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'datetime', 'RepositoryDateTimeValue'); }; $.fn.dataTable.render.editRepositoryDateValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'dateonly', 'RepositoryDateValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'date', 'RepositoryDateValue'); }; $.fn.dataTable.render.editRepositoryTimeValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'timeonly', 'RepositoryTimeValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'time', 'RepositoryTimeValue'); }; $.fn.dataTable.render.editRepositoryDateTimeRangeValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, '', 'RepositoryDateTimeRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'datetime', 'RepositoryDateTimeRangeValue'); }; $.fn.dataTable.render.editRepositoryDateRangeValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'dateonly', 'RepositoryDateRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'date', 'RepositoryDateRangeValue'); }; $.fn.dataTable.render.editRepositoryTimeRangeValue = function(formId, columnId, cell) { let $cell = $(cell.node()); - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'timeonly', 'RepositoryTimeRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'time', 'RepositoryTimeRangeValue'); }; $.fn.dataTable.render.editRepositoryChecklistValue = function(formId, columnId, cell) { diff --git a/app/assets/javascripts/repositories/renderers/new_renderers.js b/app/assets/javascripts/repositories/renderers/new_renderers.js index c4f834c04..3002856d8 100644 --- a/app/assets/javascripts/repositories/renderers/new_renderers.js +++ b/app/assets/javascripts/repositories/renderers/new_renderers.js @@ -78,27 +78,27 @@ $.fn.dataTable.render.newRepositoryNumberValue = function(formId, columnId, $cel }; $.fn.dataTable.render.newRepositoryDateTimeValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, '', 'RepositoryDateTimeValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'datetime', 'RepositoryDateTimeValue'); }; $.fn.dataTable.render.newRepositoryTimeValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'timeonly', 'RepositoryTimeValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'time', 'RepositoryTimeValue'); }; $.fn.dataTable.render.newRepositoryDateValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'dateonly', 'RepositoryDateValue'); + DateTimeHelper.initDateTimeEditMode(formId, columnId, $cell, 'date', 'RepositoryDateValue'); }; $.fn.dataTable.render.newRepositoryDateTimeRangeValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, '', 'RepositoryDateTimeRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'datetime', 'RepositoryDateTimeRangeValue'); }; $.fn.dataTable.render.newRepositoryDateRangeValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'dateonly', 'RepositoryDateRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'date', 'RepositoryDateRangeValue'); }; $.fn.dataTable.render.newRepositoryTimeRangeValue = function(formId, columnId, $cell) { - DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'timeonly', 'RepositoryTimeRangeValue'); + DateTimeHelper.initDateTimeRangeEditMode(formId, columnId, $cell, 'time', 'RepositoryTimeRangeValue'); }; $.fn.dataTable.render.newRepositoryStockValue = function() { diff --git a/app/assets/javascripts/repositories/validators/base_validator.js b/app/assets/javascripts/repositories/validators/base_validator.js index 951cdfe32..bd263c0b0 100644 --- a/app/assets/javascripts/repositories/validators/base_validator.js +++ b/app/assets/javascripts/repositories/validators/base_validator.js @@ -76,18 +76,7 @@ $.fn.dataTable.render.RepositoryNumberValueValidator = function($input) { }; $.fn.dataTable.render.RepositoryDateTimeValueValidator = function($input) { - let $container = $input.parents('.datetime-container'); - let $date = $container.find('input.date-part'); - let $time = $container.find('input.time-part'); - - if (($date.val() === '') === ($time.val() === '')) { - return true; - } - $container.find('.date-container') - .addClass('error') - .attr('data-error-text', I18n.t('repositories.table.date_time.errors.set_all_or_none')); - $container.find('.time-container').addClass('error'); - return false; + return true; }; $.fn.dataTable.render.RepositoryDateValueValidator = function() { @@ -99,11 +88,9 @@ $.fn.dataTable.render.RepositoryTimeValueValidator = function() { }; $.fn.dataTable.render.RepositoryDateTimeRangeValueValidator = function($input) { - let $container = $input.parents('.datetime-container'); - let $dateS = $container.find('.start-time input.date-part'); - let $timeS = $container.find('.start-time input.time-part'); - let $dateE = $container.find('.end-time input.date-part'); - let $timeE = $container.find('.end-time input.time-part'); + const $container = $input.parents('.datetime-container'); + const $dateS = $container.find('.datetime.start'); + const $dateE = $container.find('.datetime.end'); let isValid = true; let errorMessage; let startTime; @@ -111,14 +98,12 @@ $.fn.dataTable.render.RepositoryDateTimeRangeValueValidator = function($input) { let a = []; if ($input.val()) { - startTime = new Date(JSON.parse($input.val()).start_time); - endTime = new Date(JSON.parse($input.val()).end_time); + startTime = new Date($dateS.val()); + endTime = new Date($dateE.val()); } a.push($dateS.val() === ''); - a.push($timeS.val() === ''); a.push($dateE.val() === ''); - a.push($timeE.val() === ''); if (a.filter((v, i, arr) => arr.indexOf(v) === i).length > 1) { isValid = false; @@ -133,22 +118,22 @@ $.fn.dataTable.render.RepositoryDateTimeRangeValueValidator = function($input) { } $container.find('.date-container').addClass('error'); - $container.find('.time-container').addClass('error'); $container.find('.date-container').first().attr('data-error-text', errorMessage); return false; }; $.fn.dataTable.render.RepositoryDateRangeValueValidator = function($input) { - let $container = $input.parents('.datetime-container'); - let $dateS = $container.find('.start-time input.date-part'); - let $dateE = $container.find('.end-time input.date-part'); + const $container = $input.parents('.datetime-container'); + const $dateS = $container.find('.datetime.start'); + const $dateE = $container.find('.datetime.end'); let isValid = true; let errorMessage; - let endTime; let startTime; + let endTime; + if ($input.val()) { - startTime = new Date(JSON.parse($input.val()).start_time); - endTime = new Date(JSON.parse($input.val()).end_time); + startTime = new Date($dateS.val()); + endTime = new Date($dateE.val()); } if (($dateS.val() === '') !== ($dateE.val() === '')) { @@ -169,16 +154,23 @@ $.fn.dataTable.render.RepositoryDateRangeValueValidator = function($input) { }; $.fn.dataTable.render.RepositoryTimeRangeValueValidator = function($input) { - let $container = $input.parents('.datetime-container'); - let $timeS = $container.find('.start-time input.time-part'); - let $timeE = $container.find('.end-time input.time-part'); + const $container = $input.parents('.datetime-container'); + const $dateS = $container.find('.datetime.start'); + const $dateE = $container.find('.datetime.end'); let isValid = true; let errorMessage; + let startTime; + let endTime; - if (($timeS.val() === '') !== ($timeE.val() === '')) { + if ($input.val()) { + startTime = new Date($dateS.val()); + endTime = new Date($dateE.val()); + } + + if (($dateS.val() === '') !== ($dateE.val() === '')) { isValid = false; errorMessage = I18n.t('repositories.table.date_time.errors.set_all_or_none'); - } else if ($timeS.val() > $timeE.val()) { + } else if (endTime < startTime) { isValid = false; errorMessage = I18n.t('repositories.table.date_time.errors.not_valid_range'); } @@ -186,7 +178,7 @@ $.fn.dataTable.render.RepositoryTimeRangeValueValidator = function($input) { return true; } - $container.find('.time-container').addClass('error'); - $container.find('.time-container').first().attr('data-error-text', errorMessage); + $container.find('.date-container').addClass('error'); + $container.find('.date-container').first().attr('data-error-text', errorMessage); return false; }; diff --git a/app/assets/stylesheets/repository/repository_table.scss b/app/assets/stylesheets/repository/repository_table.scss index 5d96287ae..0258a6008 100644 --- a/app/assets/stylesheets/repository/repository_table.scss +++ b/app/assets/stylesheets/repository/repository_table.scss @@ -349,7 +349,28 @@ } .date-container { - width: 160px; + &.datetime { + width: 240px; + } + + &.time { + width: 120px; + } + + &.date { + width: 200px; + } + + &.error { + &::after { + color: $brand-danger; + content: attr(data-error-text); + font-size: 12px; + margin-top: -4px; + position: absolute; + top: 100%; + } + } } .time-container { diff --git a/app/javascript/packs/vue/legacy/datetime_picker.js b/app/javascript/packs/vue/legacy/datetime_picker.js index afcbf34b4..3da60fcbd 100644 --- a/app/javascript/packs/vue/legacy/datetime_picker.js +++ b/app/javascript/packs/vue/legacy/datetime_picker.js @@ -20,7 +20,7 @@ window.initDateTimePickerComponent = (id) => { mounted() { if (this.$refs.input.dataset.default) { let defaultDate = new Date(this.$refs.input.dataset.default); - this.date = defaultDate.toISOString(); + this.date = this.formatDate(defaultDate); this.$refs.vueDateTime.datetime = defaultDate; } else if (this.date) { this.$refs.vueDateTime.datetime = new Date(this.date); @@ -31,15 +31,26 @@ window.initDateTimePickerComponent = (id) => { $(this.$el.parentElement).parent().trigger('dp:ready'); }, methods: { + formatDate(date) { + if (this.$refs.input.dataset.simpleFormat) { + const y = date.getFullYear(); + const m = date.getMonth() + 1; + const d = date.getDate(); + const hours = date.getHours(); + const mins = date.getMinutes(); + return `${y}/${m}/${d} ${hours}:${mins}`; + } + return date.toISOString(); + }, updateDate(date) { - this.date = date.toISOString(); + this.date = this.formatDate(date); this.$nextTick(() => { if (this.onChange) this.onChange(date); }); }, setDate(date) { - this.date = date.toISOString(); + this.date = this.formatDate(date); this.$refs.vueDateTime.datetime = date; this.$nextTick(() => { if (this.onChange) this.onChange(date); diff --git a/app/javascript/vue/shared/date_time_picker.vue b/app/javascript/vue/shared/date_time_picker.vue index fa289ef3f..06c8e0c83 100644 --- a/app/javascript/vue/shared/date_time_picker.vue +++ b/app/javascript/vue/shared/date_time_picker.vue @@ -4,6 +4,8 @@ v-if="mode == 'datetime'" v-model="datetime" :teleport="true" + text-input + time-picker-inline :format="dateTimeFormat" :placeholder="placeholder" > @@ -11,14 +13,16 @@ v-if="mode == 'date'" v-model="datetime" :teleport="true" + text-input :format="dateFormat" :enable-time-picker="false" :placeholder="placeholder" > @@ -37,30 +41,61 @@ }, data() { return { - datetime: this.defaultValue + datetime: this.defaultValue, + time: null } }, - watch: { - defaultValue: function () { - this.datetime = this.defaultValue; + created() { + if (this.defaultValue) { + this.time = { + hours: this.defaultValue.getHours(), + minutes:this.defaultValue.getMinutes(), + } } }, components: { VueDatePicker }, watch: { + defaultValue: function () { + this.datetime = this.defaultValue; + this.time = { + hours: this.defaultValue ? this.defaultValue.getHours() : 0, + minutes: this.defaultValue ? this.defaultValue.getMinutes() : 0 + } + }, datetime: function () { + if (this.mode == 'time') { + this.time = { + hours: this.datetime ? this.datetime.getHours() : 0, + minutes: this.datetime ? this.datetime.getMinutes() : 0 + } + return + } + if ( this.datetime == null) { this.$emit('cleared'); } if (this.defaultValue != this.datetime) { - let newDate = this.datetime; - if (this.mode == 'time') { - newDate = new Date(); - newDate.setHours(this.datetime.hours); - newDate.setMinutes(this.datetime.minutes); - } + this.$emit('change', this.datetime); + } + }, + time: function () { + if (this.mode != 'time') return; + + let newDate; + + if (this.time) { + newDate = new Date(); + newDate.setHours(this.time.hours); + newDate.setMinutes(this.time.minutes); + } else { + newDate = null; + this.$emit('cleared'); + } + + if (this.defaultValue != newDate) { this.$emit('change', newDate); } } @@ -74,7 +109,7 @@ }, timeFormat() { return 'HH:mm' - } + }, } }