$(function () { 'use strict'; var $modal = $('#working-plan-exceptions-modal'); var $date = $('#working-plan-exceptions-date'); var $start = $('#working-plan-exceptions-start'); var $end = $('#working-plan-exceptions-end'); var $breaks = $('#working-plan-exceptions-breaks'); var $save = $('#working-plan-exceptions-save'); var deferred = null; var enableSubmit = false; var enableCancel = false; function resetModal() { $date.val(''); $start.val(''); $end.val(''); $breaks.find('tbody').empty(); } function validate() { $modal.find('.is-invalid').removeClass('is-invalid'); var date = $date.datepicker('getDate'); if (!date) { $date.addClass('is-invalid'); } var start = $start.timepicker('getDate'); if (!start) { $start.addClass('is-invalid'); } var end = $end.timepicker('getDate'); if (!end) { $end.addClass('is-invalid'); } return !$modal.find('.is-invalid').length; } function onModalHidden() { resetModal(); } function getBreaks() { var breaks = []; $breaks.find('tbody tr').each(function (index, tr) { var $tr = $(tr); if ($tr.find('input:text').length) { return true; } var start = $tr.find('.working-plan-exceptions-break-start').text(); var end = $tr.find('.working-plan-exceptions-break-end').text(); breaks.push({ start: moment(start, GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm').format('HH:mm'), end: moment(end, GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm').format('HH:mm') }); }); // Sort breaks increasingly by hour within day breaks.sort(function (break1, break2) { // We can do a direct string comparison since we have time based on 24 hours clock. return break1.start.localeCompare(break2.start); }); return breaks; } function onSaveClick() { if (!deferred) { return; } if (!validate()) { return; } var date = moment($date.datepicker('getDate')).format('YYYY-MM-DD'); var workingPlanException = { start: moment($start.datetimepicker('getDate')).format('HH:mm'), end: moment($end.datetimepicker('getDate')).format('HH:mm'), breaks: getBreaks() }; deferred.resolve(date, workingPlanException); $modal.modal('hide'); resetModal(); } function editableTimeCell($target) { $target.editable( function (value) { // Do not return the value because the user needs to press the "Save" button. return value; }, { event: 'edit', height: '30px', submit: $('<button/>', { 'type': 'button', 'class': 'd-none submit-editable', 'text': EALang.save }).get(0).outerHTML, cancel: $('<button/>', { 'type': 'button', 'class': 'd-none cancel-editable', 'text': EALang.cancel }).get(0).outerHTML, onblur: 'ignore', onreset: function () { if (!enableCancel) { return false; // disable ESC button } }, onsubmit: function () { if (!enableSubmit) { return false; // disable Enter button } } } ); } function add() { deferred = jQuery.Deferred(); $date.datepicker('setDate', new Date()); $start.timepicker('setDate', moment('08:00', 'HH:mm').toDate()); $end.timepicker('setDate', moment('20:00', 'HH:mm').toDate()); $modal.modal('show'); return deferred.promise(); } function edit(date, workingPlanException) { deferred = jQuery.Deferred(); $date.datepicker('setDate', moment(date, 'YYYY-MM-DD').toDate()); $start.timepicker('setDate', moment(workingPlanException.start, 'HH:mm').toDate()); $end.timepicker('setDate', moment(workingPlanException.end, 'HH:mm').toDate()); workingPlanException.breaks.forEach(function (workingPlanExceptionBreak) { renderBreakRow(workingPlanExceptionBreak).appendTo($breaks.find('tbody')); }); editableTimeCell( $breaks.find('tbody .working-plan-exceptions-break-start, tbody .working-plan-exceptions-break-end') ); $modal.modal('show'); return deferred.promise(); } function renderBreakRow(breakPeriod) { var timeFormat = GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm'; return $('<tr/>', { 'html': [ $('<td/>', { 'class': 'working-plan-exceptions-break-start editable', 'text': moment(breakPeriod.start, 'HH:mm').format(timeFormat) }), $('<td/>', { 'class': 'working-plan-exceptions-break-end editable', 'text': moment(breakPeriod.end, 'HH:mm').format(timeFormat) }), $('<td/>', { 'html': [ $('<button/>', { 'type': 'button', 'class': 'btn btn-outline-secondary btn-sm me-2 working-plan-exceptions-edit-break', 'title': EALang.edit, 'html': [ $('<span/>', { 'class': 'fas fa-edit' }) ] }), $('<button/>', { 'type': 'button', 'class': 'btn btn-outline-secondary btn-sm working-plan-exceptions-delete-break', 'title': EALang.delete, 'html': [ $('<span/>', { 'class': 'fas fa-trash-alt' }) ] }), $('<button/>', { 'type': 'button', 'class': 'btn btn-outline-secondary btn-sm me-2 working-plan-exceptions-save-break d-none', 'title': EALang.save, 'html': [ $('<span/>', { 'class': 'fas fa-check-circle' }) ] }), $('<button/>', { 'type': 'button', 'class': 'btn btn-outline-secondary btn-sm working-plan-exceptions-cancel-break d-none', 'title': EALang.cancel, 'html': [ $('<span/>', { 'class': 'fas fa-ban' }) ] }) ] }) ] }); } function onAddBreakClick() { var $newBreak = renderBreakRow({ start: '12:00', end: '14:00' }).appendTo('#working-plan-exceptions-breaks tbody'); // Bind editable and event handlers. editableTimeCell($newBreak.find('.working-plan-exceptions-break-start, .working-plan-exceptions-break-end')); $newBreak.find('.working-plan-exceptions-edit-break').trigger('click'); $('.working-plan-exceptions-add-break').prop('disabled', true); } function onEditBreakClick() { // Reset previous editable table cells. var $previousEdits = $(this).closest('table').find('.editable'); $previousEdits.each(function (index, editable) { if (editable.reset) { editable.reset(); } }); // Make all cells in current row editable. var $tr = $(this).closest('tr'); $tr.children().trigger('edit'); initializeTimepicker( $tr.find('.working-plan-exceptions-break-start input, .working-plan-exceptions-break-end input') ); $(this).closest('tr').find('.working-plan-exceptions-break-start').focus(); // Show save - cancel buttons. $tr = $(this).closest('tr'); $tr.find('.working-plan-exceptions-edit-break, .working-plan-exceptions-delete-break').addClass('d-none'); $tr.find('.working-plan-exceptions-save-break, .working-plan-exceptions-cancel-break').removeClass('d-none'); $tr.find('select,input:text').addClass('form-control input-sm'); $('.working-plan-exceptions-add-break').prop('disabled', true); } function onDeleteBreakClick() { $(this).closest('tr').remove(); } function onSaveBreakClick() { // Break's start time must always be prior to break's end. var $tr = $(this).closest('tr'); var start = moment( $tr.find('.working-plan-exceptions-break-start input').val(), GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm' ); var end = moment( $tr.find('.working-plan-exceptions-break-end input').val(), GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm' ); if (start > end) { $tr.find('.working-plan-exceptions-break-end input').val( start.add(1, 'hour').format(GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm') ); } enableSubmit = true; $tr.find('.editable .submit-editable').trigger('click'); enableSubmit = false; $tr.find('.working-plan-exceptions-save-break, .working-plan-exceptions-cancel-break').addClass('d-none'); $tr.closest('table') .find('.working-plan-exceptions-edit-break, .working-plan-exceptions-delete-break') .removeClass('d-none'); $('.working-plan-exceptions-add-break').prop('disabled', false); } function onCancelBreakClick() { var $tr = $(this).closest('tr'); enableCancel = true; $tr.find('.cancel-editable').trigger('click'); enableCancel = false; $breaks .find('.working-plan-exceptions-edit-break, .working-plan-exceptions-delete-break') .removeClass('d-none'); $tr.find('.working-plan-exceptions-save-break, .working-plan-exceptions-cancel-break').addClass('d-none'); $('.working-plan-exceptions-add-break').prop('disabled', false); } function initializeDatepicker($target) { var dateFormat; switch (GlobalVariables.dateFormat) { case 'DMY': dateFormat = 'dd/mm/yy'; break; case 'MDY': dateFormat = 'mm/dd/yy'; break; case 'YMD': dateFormat = 'yy/mm/dd'; break; default: throw new Error('Invalid date format setting provided: ' + GlobalVariables.dateFormat); } $target.datepicker({ dateFormat: dateFormat, firstDay: GeneralFunctions.getWeekDayId(GlobalVariables.firstWeekday), minDate: 0, defaultDate: moment().toDate(), dayNames: [ EALang.sunday, EALang.monday, EALang.tuesday, EALang.wednesday, EALang.thursday, EALang.friday, EALang.saturday ], dayNamesShort: [ EALang.sunday.substr(0, 3), EALang.monday.substr(0, 3), EALang.tuesday.substr(0, 3), EALang.wednesday.substr(0, 3), EALang.thursday.substr(0, 3), EALang.friday.substr(0, 3), EALang.saturday.substr(0, 3) ], dayNamesMin: [ EALang.sunday.substr(0, 2), EALang.monday.substr(0, 2), EALang.tuesday.substr(0, 2), EALang.wednesday.substr(0, 2), EALang.thursday.substr(0, 2), EALang.friday.substr(0, 2), EALang.saturday.substr(0, 2) ], monthNames: [ EALang.january, EALang.february, EALang.march, EALang.april, EALang.may, EALang.june, EALang.july, EALang.august, EALang.september, EALang.october, EALang.november, EALang.december ], prevText: EALang.previous, nextText: EALang.next, currentText: EALang.now, closeText: EALang.close }); } function initializeTimepicker($target) { $target.timepicker({ timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm', currentText: EALang.now, closeText: EALang.close, timeOnlyTitle: EALang.select_time, timeText: EALang.time, hourText: EALang.hour, minuteText: EALang.minutes }); } initializeDatepicker($date); initializeTimepicker($start); initializeTimepicker($end); $modal .on('hidden.bs.modal', onModalHidden) .on('click', '.working-plan-exceptions-add-break', onAddBreakClick) .on('click', '.working-plan-exceptions-edit-break', onEditBreakClick) .on('click', '.working-plan-exceptions-delete-break', onDeleteBreakClick) .on('click', '.working-plan-exceptions-save-break', onSaveBreakClick) .on('click', '.working-plan-exceptions-cancel-break', onCancelBreakClick); $save.on('click', onSaveClick); window.WorkingPlanExceptionsModal = { add: add, edit: edit }; });