/* ---------------------------------------------------------------------------- * Easy!Appointments - Open Source Web Scheduler * * @package EasyAppointments * @author A.Tselegidis * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis * @license http://opensource.org/licenses/GPL-3.0 - GPLv3 * @link http://easyappointments.org * @since v1.0.0 * ---------------------------------------------------------------------------- */ (function() { 'use strict'; /** * Class WorkingPlan * * Contains the working plan functionality. The working plan DOM elements must be same * in every page this class is used. * * @class WorkingPlan */ var WorkingPlan = function() { /** * This flag is used when trying to cancel row editing. It is * true only whenever the user presses the cancel button. * * @type {Boolean} */ this.enableCancel = false; /** * This flag determines whether the jeditables are allowed to submit. It is * true only whenever the user presses the save button. * * @type {Boolean} */ this.enableSubmit = false; }; /** * Setup the dom elements of a given working plan. * * @param {Object} workingPlan Contains the working hours and breaks for each day of the week. */ WorkingPlan.prototype.setup = function(workingPlan) { $.each(workingPlan, function(index, workingDay) { if (workingDay != null) { $('#' + index).prop('checked', true); $('#' + index + '-start').val(workingDay.start); $('#' + index + '-end').val(workingDay.end); // Add the day's breaks on the breaks table. $.each(workingDay.breaks, function(i, brk) { var day = this.convertValueToDay(index); var tr = '' + '' + GeneralFunctions.ucaseFirstLetter(day) + '' + '' + brk.start + '' + '' + brk.end + '' + '' + '' + '' + '' + '' + '' + ''; $('.breaks tbody').append(tr); }.bind(this)); } else { $('#' + index).prop('checked', false); $('#' + index + '-start').prop('disabled', true); $('#' + index + '-end').prop('disabled', true); } }.bind(this)); // Make break cells editable. this.editableBreakDay($('.breaks .break-day')); this.editableBreakTime($('.breaks').find('.break-start, .break-end')); }; /** * Enable editable break day. * * This method makes editable the break day cells. * * @param {Object} $selector The jquery selector ready for use. */ WorkingPlan.prototype.editableBreakDay = function($selector) { var weekDays = {}; weekDays[EALang['monday']] = EALang['monday']; //'Monday'; weekDays[EALang['tuesday']] = EALang['tuesday']; //'Tuesday'; weekDays[EALang['wednesday']] = EALang['wednesday']; //'Wednesday'; weekDays[EALang['thursday']] = EALang['thursday']; //'Thursday'; weekDays[EALang['friday']] = EALang['friday']; //'Friday'; weekDays[EALang['saturday']] = EALang['saturday']; //'Saturday'; weekDays[EALang['sunday']] = EALang['sunday']; //'Sunday'; $selector.editable(function(value, settings) { return value; }, { type: 'select', data: weekDays, event: 'edit', height: '30px', submit: '', cancel: '', onblur: 'ignore', onreset: function(settings, td) { if (!this.enableCancel) { return false; // disable ESC button } }.bind(this), onsubmit: function(settings, td) { if (!this.enableSubmit) { return false; // disable Enter button } }.bind(this) }); }; /** * Enable editable break time. * * This method makes editable the break time cells. * * @param {Object} $selector The jquery selector ready for use. */ WorkingPlan.prototype.editableBreakTime = function($selector) { $selector.editable(function(value, settings) { // Do not return the value because the user needs to press the "Save" button. return value; }, { event: 'edit', height: '25px', submit: '', cancel: '', onblur: 'ignore', onreset: function(settings, td) { if (!this.enableCancel) { return false; // disable ESC button } }.bind(this), onsubmit: function(settings, td) { if (!this.enableSubmit) { return false; // disable Enter button } }.bind(this) }); }; /** * Binds the event handlers for the working plan dom elements. */ WorkingPlan.prototype.bindEventHandlers = function() { /** * Event: Day Checkbox "Click" * * Enable or disable the time selection for each day. */ $('.working-plan input[type="checkbox"]').click(function() { var id = $(this).attr('id'); if ($(this).prop('checked') == true) { $('#' + id + '-start').prop('disabled', false).val('09:00'); $('#' + id + '-end').prop('disabled', false).val('18:00'); } else { $('#' + id + '-start').prop('disabled', true).val(''); $('#' + id + '-end').prop('disabled', true).val(''); } }); /** * Event: Add Break Button "Click" * * A new row is added on the table and the user can enter the new break * data. After that he can either press the save or cancel button. */ $('.add-break').click(function() { var tr = '' + '' + EALang['monday'] + '' + '09:00' + '10:00' + '' + '' + '' + '' + '' + '' + ''; $('.breaks').prepend(tr); // Bind editable and event handlers. tr = $('.breaks tr')[1]; this.editableBreakDay($(tr).find('.break-day')); this.editableBreakTime($(tr).find('.break-start, .break-end')); $(tr).find('.edit-break').trigger('click'); $('.add-break').prop('disabled', true); }.bind(this)); /** * Event: Edit Break Button "Click" * * Enables the row editing for the "Breaks" table rows. */ $(document).on('click', '.edit-break', function() { // Reset previous editable tds var $previousEdt = $(this).closest('table').find('.editable').get(); $.each($previousEdt, function(index, editable) { if (editable.reset !== undefined) { editable.reset(); } }); // Make all cells in current row editable. $(this).parent().parent().children().trigger('edit'); $(this).parent().parent().find('.break-start input, .break-end input').timepicker({ currentText: EALang['now'], closeText: EALang['close'], timeOnlyTitle: EALang['select_time'], timeText: EALang['time'], hourText: EALang['hour'], minuteText: EALang['minutes'] }); $(this).parent().parent().find('.break-day select').focus(); // Show save - cancel buttons. $(this).closest('table').find('.edit-break, .delete-break').addClass('hidden'); $(this).parent().find('.save-break, .cancel-break').removeClass('hidden'); $('.add-break').prop('disabled', true); }); /** * Event: Delete Break Button "Click" * * Removes the current line from the "Breaks" table. */ $(document).on('click', '.delete-break', function() { $(this).parent().parent().remove(); }); /** * Event: Cancel Break Button "Click" * * Bring the ".breaks" table back to its initial state. * * @param {jQuery.Event} e */ $(document).on('click', '.cancel-break', function(e) { var element = e.target; this.enableCancel = true; $(element).parent().parent().find('.cancel-editable').trigger('click'); this.enableCancel = false; $(element).closest('table').find('.edit-break, .delete-break').removeClass('hidden'); $(element).parent().find('.save-break, .cancel-break').addClass('hidden'); $('.add-break').prop('disabled', false); }.bind(this)); /** * Event: Save Break Button "Click" * * Save the editable values and restore the table to its initial state. * * @param {jQuery.Event} e * * @todo: Prevent from adding interrelated breaks */ $(document).on('click', '.save-break', function(e) { // Break's start time must always be prior to break's end. var element = e.target, $editedTr = $(element).closest('tr'), start = Date.parse($editedTr.find('.break-start input').val()), end = Date.parse($editedTr.find('.break-end input').val()); if (start > end) { $editedTr.find('.break-end input').val(start.addHours(1).toString('HH:mm')); } this.enableSubmit = true; $editedTr.find('.editable .submit-editable').trigger('click'); this.enableSubmit = false; $editedTr.find('.save-break, .cancel-break').addClass('hidden'); $(element).closest('table').find('.edit-break, .delete-break').removeClass('hidden'); $('.add-break').prop('disabled', false); }.bind(this)); }; /** * Get the working plan settings. * * @return {Object} Returns the working plan settings object. * * @todo: Add sorting by range within day breaks */ WorkingPlan.prototype.get = function() { var workingPlan = {}; $('.working-plan input[type="checkbox"]').each(function(index, checkbox) { var id = $(checkbox).attr('id'); if ($(checkbox).prop('checked') == true) { workingPlan[id] = {}; workingPlan[id].start = $('#' + id + '-start').val(); workingPlan[id].end = $('#' + id + '-end').val(); workingPlan[id].breaks = []; $('.breaks tr').each(function(index, tr) { var day = this.convertDayToValue($(tr).find('.break-day').text()); if (day == id) { var start = $(tr).find('.break-start').text(), end = $(tr).find('.break-end').text(); workingPlan[id].breaks.push({ 'start': start, 'end': end }); } workingPlan[id].breaks.sort(function(break1, break2) { // We can do a direct string comparison since we have time based on 24 hours clock return break1.start - break2.start; }); }.bind(this)); } else { workingPlan[id] = null; } }.bind(this)); return workingPlan; }; /** * Enables or disables the timepicker functionality from the working plan input text fields. * * @param {Boolean} disabled (OPTIONAL = false) If true then the timepickers will be disabled. */ WorkingPlan.prototype.timepickers = function(disabled) { disabled = disabled || false; if (disabled == false) { // Set timepickers where needed. $('.working-plan input[type="text"]').timepicker({ timeFormat: 'HH:mm', currentText: EALang['now'], closeText: EALang['close'], timeOnlyTitle: EALang['select_time'], timeText: EALang['time'], hourText: EALang['hour'], minuteText: EALang['minutes'], onSelect: function(datetime, inst) { // Start time must be earlier than end time. var start = Date.parse($(this).parent().parent().find('.work-start').val()), end = Date.parse($(this).parent().parent().find('.work-end').val()); if (start > end) { $(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm')); } } }); } else { $('.working-plan input').timepicker('destroy'); } }; /** * Reset the current plan back to the company's default working plan. */ WorkingPlan.prototype.reset = function() { }; /** * This is necessary for translated days. * * @param {String} value Day value could be like "monday", "tuesday" etc. */ WorkingPlan.prototype.convertValueToDay = function(value) { switch (value) { case 'monday': return EALang['monday']; break; case 'tuesday': return EALang['tuesday']; break; case 'wednesday': return EALang['wednesday']; break; case 'thursday': return EALang['thursday']; break; case 'friday': return EALang['friday']; break; case 'saturday': return EALang['saturday']; break; case 'sunday': return EALang['sunday']; break; } }; /** * This is necessary for translated days. * * @param {String} value Day value could be like "Monday", "Tuesday" etc. */ WorkingPlan.prototype.convertDayToValue = function(day) { switch (day) { case EALang['monday']: return 'monday'; break; case EALang['tuesday']: return 'tuesday'; break; case EALang['wednesday']: return 'wednesday'; break; case EALang['thursday']: return 'thursday'; break; case EALang['friday']: return 'friday'; break; case EALang['saturday']: return 'saturday'; break; case EALang['sunday']: return 'sunday'; break; } }; window.WorkingPlan = WorkingPlan; })();