UNPKG

pit-scheduler

Version:

A complet scheduler build with jQuery and Boostrap

1,137 lines (1,027 loc) 149 kB
/* * jQuery pit-Scheduler Plugin v2.0 * https://github.com/chuck-durst/pit-scheduler * * Copyright 2016 Charles Durst * Released under the MIT license */ var i18n = { allowed: [ 'en' ], en: { day: 'Day', days: 'Days', months: 'Months', list: 'List', tasks: 'Tasks', task: 'Task', hour: 'Hour', hours: 'Hours', users: 'Users', unlisted: 'Unlisted', settings: 'Settings', hideEmptyLine: 'Hide lines with no task', description: 'Description', assignedUsers: 'assigned users', assignedUser: 'assigned user', from: 'From', to: 'to', notSpecified: 'Not specified', disableLabelsMovement: 'Disable labels mouvement', today: 'Today', thisWeek: 'This week', thisMonth: 'This month', thisYear: 'This year', personalized: 'Personalized', selectAll: 'Select all', always: 'always', total: 'Total', usersWhose: 'user(s) with', cycleWhose: 'cycle(s) with', inSelectedPeriod: 'in the selected period', all: 'All', search: 'Search', addNewTask: 'Create a new task', addNewUser: 'Create a new user', editUser: 'Edit the user', name: 'Name', required: 'Required', color: 'Color', cancel: 'Cancel', create: 'Create', createAndAssign: 'Create and assign', idAlreadyTaken: 'This ID is already taken', remove: 'Remove', assign: 'Assign', edit: 'Edit', confirm: 'Confirm', assignTaskTitle: 'Assign users', assignUserTitle: 'Assign to a task', allInputRequired: 'All fields are required', requiredField: 'That field is required', userIsAlreadyAssigned: 'is already assigned to this task for this period', selectUsersToAssign: 'Select the users to assign', selectTasksToAssign: 'Select the tasks to assign', editTask: 'Edit a task', group: 'Group', groups: 'Groups', selectGroup: 'Select an existing group', createNewGroup: 'Create a new group', or: 'or', seeAll: 'See all', allocations: 'allocations', allocation: 'allocation', tag: 'Tag', tags: 'Tags', tagColor: 'Tag color', filters: 'Filters', deleteAll: 'Delete all', addFilter: 'Create filter', contains: 'Contains', notContains: 'Does not contains', added: 'Added', active: 'Active', inactive: 'Inactive', notif: { taskCreated: 'The task has been successfully created', userCreated: 'The user has been successfully created', taskRemoved: 'The task has been successfully removed', userRemoved: 'The user has been successfully removed', usersAssigned: 'users has been assigned to the task', userAssigned: 'user has been assigned to the task', userUnassigned: 'has correctly been unassigned', noUser: '<b>Warning : </b>No user has been set', noTask: '<b>Warning : </b>No task has been set', taskNotExist: 'is assigned to an inexistent task', taskInformationsUpdated: 'The task has been edited', userHasNoTask: 'is not assigned to any task', userEdited: 'The user has been successfully edited', userAssignedTo: 'has been assigned to', userTaskModified: 'The task will now end the', filterAdded: 'The filter has been added', filterEdited: 'The filter has been edited', filterRemoved: 'The filter has been removed', allFiltersRemoved: 'All fiters has been removed' } } }; (function ($) { 'use strict'; $.fn.pitScheduler = function (options) { var $scheduler = $(this); /********* Settings initialization *********/ options = options || {}; var settings = $.extend({ date: { current: moment(), selected: (options.defaultDate && moment(options.defaultDate).isValid() ? moment(options.defaultDate) : moment()) }, locale: (options.locale && i18n.allowed.indexOf(options.locale) != -1 ? options.locale : i18n.allowed[0]), //if no locale is defined, it takes the first allowed one currentDisplay: (options.defaultDisplay && 'days;months;list'.indexOf(options.defaultDisplay) != -1 ? options.defaultDisplay : 'months'), projectState : 'production', //debug will log all function calls, development will only log the important ones tasks: options.tasks || [], users: options.users || [], defaultColor: options.defaultColor ||'#00BCD4', notificationDuration: options.notificationDuration || 4000, hideEmptyLines: options.hideEmptyLines || true, undo: [], resize: {}, filters: [] }, options); moment.locale(settings.locale); settings.i18n = (i18n.allowed.indexOf(settings.locale) == -1 ? i18n.en : i18n[settings.locale]); /* Debug tool */ var log = { log : function (data) { if (settings.projectState == 'debug') { console.log(data); } }, warn: function (data) { if (settings.projectState == 'development') { console.warn(data); } }, info: function (data) { if (settings.projectState == 'development') { console.info(data); } } }; /********* Main functions *********/ /** * Update display view * @param {String} viewMode: can be 'days', 'months' or 'list' */ var updateDisplay = function (viewMode) { log.info('CALL FUNCTION: updateDisplay: viewMode:' + viewMode); var scrollTop = $('.pts-scheduler-container').scrollTop(); updateDisplayReset(); switch (viewMode) { case 'days': setButtonViewFocus('day'); settings.currentDisplay = 'days'; initMainContent(); updateHeaderDates(); $('.pts-line-title-container div').scrollTop(scrollTop); break; case 'months': setButtonViewFocus('month'); settings.currentDisplay = 'months'; initMainContent(); updateHeaderDates(); $('.pts-line-title-container div').scrollTop(scrollTop); break; case 'list': setButtonViewFocus('list'); settings.currentDisplay = 'list'; $('.pts-btn-next').attr('disabled', 'disabled'); $('.pts-btn-previous').attr('disabled', 'disabled'); $('.pts-header-date-display').css('display', 'none'); $('.pts-column-title-container').css('overflow', 'visible'); $('#header-datetimepicker').data("DateTimePicker").disable(); generateListBaseView(); switchListRange('today'); break; } }; /** * Reset elements content that have been modified */ var updateDisplayReset = function () { log.info('CALL FUNCTION: updateDisplayReset'); closeToolbox(); $('.pts-main-content').empty(); $('.pts-column-title-container > div').empty(); $('.pts-line-title-container').empty(); $('.pts-line-title-container').append($('<div></div>')); $('.pts-corner-mask').empty(); $('.pts-btn-next').removeAttr('disabled'); $('.pts-btn-previous').removeAttr('disabled'); $('.pts-header-date-display').css('display', 'block'); $('.pts-column-title-container').css('overflow', 'hidden'); }; /** * Function used to update the header datetimepicker */ var updateHeaderDates = function () { log.log('CALL FUNCTION: updateHeaderDates'); $('#header-datetimepicker').data("DateTimePicker").enable(); $('.pts-header-date-display').empty(); switch (settings.currentDisplay) { case 'days': $('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('LL')); break; case 'months': $('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('MMMM YYYY')); break; case 'list': $('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('LL')); break; } }; /** * Launch all the main generations */ var initMainContent = function () { log.info('CALL FUNCTION: initMainContent'); generateBaseView(); generateTableLines(); initGroup(); generateGroupMainContent(); generateUsersList(); updateDatePicker(); }; /** * Set the focus on the right view mode button * @param {String} viewMode: can be 'days', 'months' or 'list' */ var setButtonViewFocus = function (viewMode) { $('.pts-header-right-container button').removeClass('pts-active'); $('.pts-header-right-container .pts-btn-' + viewMode + '-view').addClass('pts-active'); }; /** * Init function that saves users index into associated tasks */ var getUsersTasksInTasks = function () { log.info('CALL FUNCTION: getUsersTasksInTasks'); if (!settings.tasks || settings.tasks.length == 0) return generateNotification('danger', settings.i18n.notif.noTask); settings.tasks.forEach(function (task) { task = generateTaskInTask(task); }); }; /** * Add an index list of the assigned users of the task * @param {Object} task * @returns {Object} task */ var generateTaskInTask = function (task) { log.log('CALL FUNCTION: generateTaskInTask: task: ' + task.name); task.users = {}; if (! settings.users) return generateNotification('danger', settings.i18n.notif.noUser ); if (!task.color) task.color = (settings.defaultColor ? settings.defaultColor : '#00bdd6'); settings.users.forEach(function (user, userIndex) { user.index = userIndex; if (user.tasks) { user.tasks.forEach(function (userTask, taskIndex) { if (userTask.id === task.id) { if (!task.users[userIndex]) { task.users[userIndex] = []; } task.users[userIndex].push(taskIndex); } }); } }); return task; }; /** * Generates the groups panels */ var initGroup = function () { log.info('CALL FUNCTION: initGroup'); if ($('.pts-line-group-container').length || !settings.users) return; settings.defaultGroupName = (settings.defaultGroupName ? settings.defaultGroupName : settings.i18n.unlisted); settings.groups = [settings.defaultGroupName]; settings.users.forEach(function (user, i) { if (user.group === undefined || user.group === '') { user.group = settings.defaultGroupName; } else if (settings.groups.indexOf(user.group) == -1) { settings.groups.push(user.group); } }); settings.groups.unlisted = 0; //stores the id of the unlisted group settings.groups.added = []; settings.groups.forEach(function (e, i) { var usersInGroup = getUsersInGroup(e); if (usersInGroup.length > 0) { var mustBeShowed = false; usersInGroup.forEach(function (userIndex) { if (settings.users[userIndex] && settings.users[userIndex].isShowed == true) { mustBeShowed = true; } }); if (mustBeShowed) { generateGroupTab(e, i); } } }); }; /** * Returns the real length of an array * @param {Object | Array} arr * @returns {Number} The real object length */ var getLength = function (arr) { return Object.keys(arr).length; }; /** * Init all the users */ var initUsers = function () { log.info('CALL FUNCTION: initUsers'); if (!settings.users) return; settings.users.forEach(function (user, i) { initUser(user, i); }); }; /** * Used to clone an array and all the data it contains * @param {Array | Object} origin * @returns {Array | Object} cloned */ var clone = function (origin) { var cloned = (origin instanceof Array) ? [] : {}; for (var i in origin) { if (i == 'clone') continue; if (origin[i] && typeof origin[i] == "object") { cloned[i] = clone(origin[i]); } else { cloned[i] = origin[i] } } return cloned; }; /** * Returns a temporary object that contains the data required to make an undo * @returns {Object} contains the saved data */ var getUndo = function () { if (settings.disableUndo == true) return null; return { tasks: clone(settings.tasks), users: clone(settings.users), groups: clone(settings.groups) }; }; /** * Add some useful data to an user * @param {Object} user * @param {Number} index of the user */ var initUser = function (user, index) { user.isShowed = userLineIsShowed(user); user.lineHeight = getUserLineHeight(user); user.index = index; }; /** * Update the content of the datepicker */ var updateDatePicker = function () { log.log('CALL FUNCTION: updateDatePicker'); $('#header-datetimepicker').datetimepicker() .data('DateTimePicker').locale(settings.locale) .defaultDate(settings.date.selected) .date(settings.date.selected) .viewDate(settings.date.selected) .enabledHours(false) .format((settings.currentDisplay === 'months' ? 'MM/YYYY' : 'L')) .viewMode((settings.currentDisplay === 'months' ? 'months' : 'days')); }; /** * Go to the next month/day */ var goForward = function () { log.info('CALL FUNCTION: goForward'); closeToolbox(); if (settings.currentDisplay == 'months') { settings.date.selected = moment(settings.date.selected).add(1, 'months'); } else { settings.date.selected = moment(settings.date.selected).add(1, 'day'); } generateTableLines(); generateGroupMainContent(); generateUsersList(); updateHeaderDates(); updateDatePicker(); }; /** * Go to the previous month/day */ var goBackward = function () { log.info('CALL FUNCTION: goBackward'); closeToolbox(); if (settings.currentDisplay == 'months') { settings.date.selected = moment(settings.date.selected).add(-1, 'months'); } else { settings.date.selected = moment(settings.date.selected).add(-1, 'day'); } generateTableLines(); generateGroupMainContent(); generateUsersList(); updateHeaderDates(); updateDatePicker(); }; /** * Shows or hides the pre-loader spinner * @returns {{show: show, hide: hide}} */ var spinner = function () { var $spinner = $('#pts-spinner-container'); return { show: function () { if (settings.hideSpinner) return; $spinner.css('display', 'block'); }, hide: function () { if (settings.hideSpinner) return; $spinner.css('display', 'none'); } } }; /** * Returns true if the first date contains the second one * @param {Object} origin * @param {Object} date * @returns {Boolean} */ var isDateInDate = function (origin, date) { log.log('CALL FUNCTION: isDateInDate'); if ((moment(date.start_date) <= moment(origin.start_date) && moment(date.end_date) >= moment(origin.end_date)) || (moment(date.start_date) >= moment(origin.start_date) && moment(date.start_date) <= moment(origin.end_date)) || (moment(date.end_date) <= moment(origin.end_date) && moment(date.end_date) >= moment(origin.start_date))) { return true; } return false; }; /** * Returns a task from its Id * @param {String] taskId * @returns {Object} the task */ var getTaskById = function (taskId) { log.log('CALL FUNCTION: getTaskById: taskId: ' + taskId); if (!settings.tasks) return; var task; settings.tasks.forEach(function (_task) { if (_task.id === taskId) { task = _task; } }); return task; }; /** * Return true if the user has tasks in the selected month/day * @param {Object} user * @returns {Boolean} */ var userHasTask = function (user) { log.log('CALL FUNCTION: userHasTask: user: ' + user.name); var response = false; var originDates = { start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')), end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month')) }; user.tasks.forEach(function (task) { if (isDateInDate(originDates, task) == true) { response = true; } }); return response; }; /** * Get the height of an user line * @param {Object} user * @returns {Number} */ var getUserLineHeight = function (user) { log.log('CALL FUNCTION: getUserLineHeight: user: ' + user.name); var tasks = []; var lineIsHidden = user.isShowed; var originDates = { start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')), end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month')) }; user.tasks.forEach(function (task) { var original = getTaskById(task.id); if (getFiltersResponse('task', original.name) == false && getFiltersResponse('tag', original.tag) == false) { if (settings.hideEmptyLines && tasks.indexOf(task.id) < 0 && isDateInDate(originDates, task) == true) { tasks.push(task.id); } else if (!settings.hideEmptyLines && tasks.indexOf(task.id) < 0 && lineIsHidden == true) { tasks.push(task.id); } } }); return tasks.length * 40; }; /** * Return true if the user line must be showed * @param {Object} user * @returns {Boolean} */ var userLineIsShowed = function (user) { log.log('CALL FUNCTION: userLineIsShowed: user: ' + user.name); if (getFiltersResponse('group', user.group)) return false; if (getFiltersResponse('user', user.name)) return false; var response = 0, originDates = { start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')), end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month')) }; if (!user.tasks) return generateNotification('warning', '<b>' + user.name + '</b> ' + settings.i18n.notif.userHasNoTask); user.tasks.forEach(function (task) { var original = getTaskById(task.id) if (isDateInDate(originDates, task) && getFiltersResponse('task', original.name) == false && getFiltersResponse('tag', original.tag) == false) response++; }); return ((response > 0) || settings.hideEmptyLines === false); }; /** * Moves the tasks labels on horizontal scroll */ var setTaskLabelPosition = function () { log.log('CALL FUNCTION: setTaskLabelPosition'); if (settings.disableLabelsMovement) return; var $elements = $('.pts-line-marker:has(> .pts-line-marker-label)'), limit = parseInt($('.pts-line-title-container').offset().left + $('.pts-line-title-container').width()); $.each($elements, function() { var $label = $(this).children('p'), right = parseInt($(this).offset().left) + parseInt($(this).width()) - parseInt($label.width()), left = parseInt($(this).offset().left); if (left < limit && right > limit + 20) { $label.css('left', $('.pts-scheduler-container').scrollLeft() - parseInt($(this).css('left')) + 10); } else { $label.css('left', '10px'); } }); }; /** * Returns an array of the users index that are in the specified group * @param {String} groupName * @returns {Array} */ var getUsersInGroup = function (groupName) { log.log('CALL FUNCTION: getUsersInGroup: groupName' + groupName); var inGroup =[]; settings.users.forEach(function (user) { if (user.group == groupName) { inGroup.push(user.index); } }); return inGroup; }; /** * Opens the toolbox panel * @param {String} taskId * @param {Number} userIndex * @param {String} viewType */ var openToolbox = function (taskId, userIndex, viewType) { log.info('CALL FUNCTION: openToolbox: taskId: ' + taskId + ': userIndex: ' + userIndex + ': viewType: ' + viewType); var $toolbox = $('#pts-toolbox-container'); $toolbox.empty(); $toolbox.scrollTop(); switch (viewType) { case 'task': var task = getTaskById(taskId), $markers = $('.pts-line-marker'); generateToolboxContentTask(task, settings.users[userIndex]); $.each($markers, function () { $(this).css('background-color', getTaskById($(this).attr('data-task')).color); if ($(this).attr('data-task') !== taskId) { $(this).css('background-color', '#8e8e8e'); } }); $('.pts-main-group-column').css('background-color', '#eee'); $toolbox.attr('data-toggle', 'opened'); break; case 'user': var user = settings.users[userIndex]; generateToolboxContentUser(user); $toolbox.attr('data-toggle', 'opened'); break; case 'createTask': generateToolboxContentCreateTask(); $toolbox.attr('data-toggle', 'opened'); break; case 'assignTask': generateToolboxContentAssignTask(taskId); $toolbox.attr('data-toggle', 'opened'); break; case 'editTask': generateToolboxContentEditTask(taskId); $toolbox.attr('data-toggle', 'opened'); break; case 'createUser': generateToolboxContentCreateUser(); $toolbox.attr('data-toggle', 'opened'); break; case 'editUser': var user = settings.users[userIndex]; generateToolboxContentEditUser(user); $toolbox.attr('data-toggle', 'opened'); break; case 'assignUser': var user = settings.users[userIndex]; generateToolboxContentAssignUser(user); $toolbox.attr('data-toggle', 'opened'); break; case 'seeAll': generateToolboxContentSeeAll(); $toolbox.attr('data-toggle', 'opened'); break; case 'filters': generateToolboxContentFilters(); $toolbox.attr('data-toggle', 'opened'); break; default: return; } $toolbox.animate({ width: '460px' }, 300); getContrastedColor(); }; /** * Closes the toolbox panel */ var closeToolbox = function () { log.info('CALL FUNCTION: closeToolbox'); var $toolbox = $('#pts-toolbox-container'), $markers = $('.pts-line-marker'); if ($toolbox.attr('data-toggle') === 'closed') return; $.each($markers, function () { var task = getTaskById($(this).attr('data-task')); $(this).css('background-color', (task ? task.color : settings.defaultColor)); }); $('.pts-main-group-column').css('background-color', '#fff'); $toolbox.animate({ width: '0%' }, 300); $toolbox.attr('data-toggle', 'closed'); $toolbox.empty(); getContrastedColor(); }; /** * Mixes the overlaid tasks * @param {String} originIndex: The index of the task * @param {Object} task: the task to check from * @param {Object} user: the owner of the task * @returns {Object} the mixed (or not) task */ var hideTaskSuperposition = function (originIndex, task, user) { log.log('CALL FUNCTION: hideTaskSuperposition: originIndex: ' + originIndex + ':task: ' + task.name + ': user: ' + user.name); user.tasks.forEach(function (userTask, index) { if (userTask.id === task.id && index !== originIndex) { if (moment(task.start_date).format('YYMMDD') == moment(userTask.end_date).format('YYMMDD')&& ((moment(task.start_date).format('H') <= 12 && moment(userTask.end_date).format('H') <= 12 && moment(userTask.end_date).format('H') > 0) || (moment(task.start_date).format('H') > 12 && moment(userTask.end_date).format('H') > 12))) { task.superposed = 'border-left: 2px dotted #000'; } } }); return task; }; /** * Replaces all elements with the class pts-check-color color * depending on their background color and their contrast */ var getContrastedColor = function () { log.log('CALL FUNCTION: getContrastedColor'); $('.pts-check-color').each(function () { var rgb = $(this).css('background-color').match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); if (rgb && rgb.length == 4) { var L = (rgb[1] * 0.299 + rgb[2] * 0.587 + rgb[3] * 0.114) / 255; if (L > 0.60) { $(this).children().css('color', '#000'); $(this).css('color', '#000'); $(this).css('border-color', '#000'); } else { $(this).children().css('color', '#fff'); $(this).css('color', '#fff'); $(this).css('border-color', '#fff'); } } }); }; /** * Changes the selected list view date range * @param {String} range: the range to display */ var switchListRange = function (range) { log.log('CALL FUNCTION: switchListRange: range: ' + range); $('.pts-list-tasks-container').empty(); switch (range) { case 'all': settings.list.start_date = moment(); settings.list.end_date = moment(); var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.all + ' :</b></h4>'; $('.pts-list-tasks-container').append($content); break; case 'today': settings.list.start_date = moment().startOf('day'); settings.list.end_date = moment().endOf('day'); var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>'; $('.pts-list-tasks-container').append($content); break; case 'week': settings.list.start_date = moment().startOf('week'); settings.list.end_date = moment().endOf('week'); var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>'; $('.pts-list-tasks-container').append($content); break; case 'month': settings.list.start_date = moment().startOf('month'); settings.list.end_date = moment().endOf('month'); var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>'; $('.pts-list-tasks-container').append($content); break; case 'year': settings.list.start_date = moment().startOf('year'); settings.list.end_date = moment().endOf('year'); var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>'; $('.pts-list-tasks-container').append($content); break; case 'personalized': var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>'; $('.pts-list-tasks-container').append($content); break; } settings.tasks.forEach(function (task) { if ($('.pts-list-task-enabler-input[data-task=' + task.id + ']').is(':checked')) { generateListTaskContent(task); } }); }; /** * Creates a new task * @param {String} name * @param {String} id * @param {String} description * @param {String} color * @param {Object} tag: contains the tag informations (name and color) * @param {Boolean} assign: true if the task must be assigned after being created */ var createNewTask = function (name, id, description, color, tag, assign) { log.info('CALL FUNCTION: createNewTask'); var undo = getUndo(); var newTask = { id: (id.length > 0 ? id : generateRandomId()), name: name, description: (description.length > 0 ? description : ''), color: (color.length > 0 ? color : settings.defaultColor), tag: tag.name, tagColor: tag.color }; newTask = generateTaskInTask(newTask); settings.tasks.push(newTask); updateDisplay(settings.currentDisplay); generateNotification('success', settings.i18n.notif.taskCreated + ' : <b>' + newTask.name + '</b>', undo, settings.onTaskCreation); if (assign == true) return openToolbox(newTask.id, null, 'assignTask'); }; /** * Generates a random Id * @returns {String} */ var generateRandomId = function () { log.log('CALL FUNCTION: generateRandomId'); var S4 = function() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); }; return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); }; /** * Removes a task * @param {String} taskId */ var removeTask = function (taskId) { log.info('CALL FUNCTION: removeTask'); var undo = getUndo(); $.each(settings.tasks, function (i, task) { if (task && task.id === taskId) { delete settings.tasks[i]; } }); $.each(settings.users, function (userIndex, user) { if (user) { $.each(user.tasks, function (taskIndex, task) { if (task && task.id === taskId) { delete settings.users[userIndex].tasks[taskIndex]; } }); } }); updateDisplay(settings.currentDisplay); generateNotification('success', settings.i18n.notif.taskRemoved, undo, settings.onTaskRemoval); }; /** * Assigns users to a specific task * @param {Array} users: the users index * @param {Object} task: the task to assign too * @param {Date} start_date * @param {Date} end_date */ var assignUsersToTask = function (users, task, start_date, end_date) { log.info('CALL FUNCTION: assignUsersToTask'); var undo = getUndo(); var taskDates = { start_date: start_date, end_date: end_date }; $('#pts-assign-task-err').empty(); if (!users || !task || !start_date || ! end_date) return; users.forEach(function (userIndex) { var user = settings.users[userIndex], taskExist = false; user.tasks.forEach(function (_task) { if (_task.id === task.id && (isDateInDate(_task, taskDates) || isDateInDate(taskDates, _task))) { taskExist = true; } }); if (taskExist) { return $('#pts-assign-task-err').append('<b>' + user.name + '</b> ' + settings.i18n.userIsAlreadyAssigned + '<br>'); } user.tasks.push({ id: task.id, start_date: moment(start_date).format('YYYY-MM-DD HH:mm'), end_date: moment(end_date).format('YYYY-MM-DD HH:mm') }); generateTaskInTask(task); if ($('.pts-toolbox-user[data-user=' + user.index + ']').length == 0) { var $head = '<hr><div class="pts-toolbox-user animated fadeIn" data-user="' + user.index + '"><h4 class=" text-semibold heading-divided">' + user.name + '</h4>' + '<table><tbody class="pts-toolbox-user-list" data-head="' + user.index + '"></tbody></table></div>'; $('#pts-toolbox-container > .panel-body').append($head); } var $userTasks = ['<tr class="animated fadeIn"><td>', '<i class="glyphicon glyphicon-trash pts-task-assign-delete-user" data-user="' + user.index + '" data-task="' + task.id + '" data-task-index="' + (user.tasks.length - 1) + '"></i>', '<b>' + settings.i18n.from + '</b> ' + moment(start_date).locale(settings.locale).format('llll'), ' <b>' + settings.i18n.to + '</b> ' + moment(end_date).locale(settings.locale).format('llll') + '</td></tr>'].join('\n'); $('.pts-toolbox-user-list[data-head=' + user.index + ']').append($userTasks); $('#pts-toolbox-container').scrollTop($('#pts-toolbox-container')[0].scrollHeight); }); generateNotification('success', '<b>' + users.length + '</b> ' + ( users.length > 1 ? settings.i18n.notif.usersAssigned: settings.i18n.notif.userAssigned) + ' <b>' + task.name + '</b>', undo, settings.onTaskAssignation); }; /** * Assigns tasks to a specific user * @param {Object} user * @param {Array} tasks * @param {Date} start_date * @param {Date} end_date */ var assignTasksToUser = function (user, tasks, start_date, end_date) { log.info('CALL FUNCTION: assignTasksToUser'); var undo = getUndo(); if (!user || !tasks || !start_date || ! end_date) return; $('#pts-assign-user-err').empty(); var taskDates = { start_date: start_date, end_date: end_date }; tasks.forEach(function (taskId) { var task = getTaskById(taskId), taskExist = false; user.tasks.forEach(function (_task) { if (_task.id === task.id && (isDateInDate(_task, taskDates) || isDateInDate(taskDates, _task))) { taskExist = true; } }); if (taskExist) { return $('#pts-assign-user-err').append('<b>' + user.name + '</b> ' + settings.i18n.userIsAlreadyAssigned + '<br>'); } user.tasks.push({ id: task.id, start_date: moment(start_date).format('YYYY-MM-DD HH:mm'), end_date: moment(end_date).format('YYYY-MM-DD HH:mm') }); generateTaskInTask(task); if ($('.pts-toolbox-task-header[data-task=' + task.id + ']').length == 0) { var $head = ['<p class="animated fadeIn pts-check-color progress-bar-striped pts-toolbox-task-header" style="background-color:' + task.color + ';margin-top:10px" data-task="' + task.id + '" data-user="' + user.index + '"><b>', task.name + '</b></p><table style="position: relative;left:30px;"><tbody class="pts-user-sorted-task" data-task="' + task.id + '" class="pts-toolbox-user-list" data-head="' + user.index + '">', '</tbody></table>'].join('\n'); $('.pts-toolbox-user-list').append($head); } var $line = '<tr><td><i class="animated fadeIn glyphicon glyphicon-trash pts-task-assign-delete-user" data-user="' + user.index + '" data-task="' + task.id + '" data-task-index="' + task.index + '"></i>' + '<b>' + settings.i18n.from + '</b> ' + moment(start_date).locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + moment(end_date).locale(settings.locale).format('lll') + '</td></tr>'; $('.pts-user-sorted-task[data-task=' + task.id + ']').append($line); $('#pts-toolbox-container').scrollTop($('#pts-toolbox-container')[0].scrollHeight); }); generateNotification('success', '<b>' + user.name + '</b> ' + settings.i18n.notif.userAssignedTo + ' <b>' + tasks.length + '</b> ' + (tasks.length > 1 ? settings.i18n.tasks : settings.i18n.task), undo, settings.onTaskAssignation); }; /** * Removes a task line from a user * @param {Object} user * @param {Object} task * @param {Number} taskIndex * @param {Object} undo */ var deleteTaskFromUser = function (user, task, taskIndex, undo) { log.info('CALL FUNCTION: deleteTaskFromUser'); var undo = undo || getUndo(); if (!user.tasks[taskIndex]) return; delete user.tasks[taskIndex]; generateTaskInTask(task); initUsers(); initGroup(); generateNotification('success', '<b>' + user.name + '</b> ' + settings.i18n.notif.userUnassigned, undo, settings.onUserTaskDeletion); }; /** * Edited the information of an existing task * @param {Object} task * @param {Array} newData */ var editTask = function (task, newData) { log.info('CALL FUNCTION: editTask'); var undo = getUndo(); task.name = (newData.name || task.name); task.color = (newData.color || task.color); task.description = (newData.description || ''); task.tag = (newData.tag || ''); task.tagColor = (newData.tagColor || ''); updateDisplay(settings.currentDisplay); generateNotification('success', settings.i18n.notif.taskInformationsUpdated, undo, settings.onTaskEdition); }; /** * Creates a new user * @param {String} name * @param {String} group * @param {Boolean} assign: true if the user must be assigned after being created */ var createNewUser = function (name, group, assign) { log.info('CALL FUNCTION: createNewUser'); var undo = getUndo(); settings.users.push({ name: name, group: (group ? group : ''), tasks: [] }); var userIndex = settings.users.length - 1; initUser(settings.users[userIndex], settings.users.length - 1); generateNotification('success', settings.i18n.notif.userCreated + ' : <b>' + name + '</b>', undo, settings.onUserCreation); if (assign == true) return openToolbox(null, userIndex, 'assignUser'); updateDisplay(settings.currentDisplay); }; /** * Removes a user * @param {Object} user */ var removeUser = function (user) { var undo = getUndo(); delete settings.users[user.index]; updateDisplay(settings.currentDisplay); getUsersTasksInTasks(); generateNotification('success', settings.i18n.notif.userRemoved, undo, settings.onUserRemoval); }; /** * Edited a user * @param {Number} userIndex * @param {Array} newData */ var editUser = function (userIndex, newData) { if (!settings.users[userIndex]) return; var undo = getUndo(); settings.users[userIndex].name = newData.name; settings.users[userIndex].group = (newData.group ? newData.group : ''); initUsers(); updateDisplay(settings.currentDisplay); generateNotification('success', settings.i18n.notif.userEdited, undo, settings.onUserEdition); }; /** * update a task when it has been resized */ var resizeTask = function () { clearInterval(settings.resize.timeout); settings.users[settings.resize.user].tasks.forEach(function (task, taskIndex) { if (task.id == settings.resize.task && moment(task.end_date).format('YYYYMMDD') == moment(settings.resize.end_date).format('YYYYMMDD')) { var undo = getUndo(); var count = settings.resize.count; var splitted = (settings.currentDisplay == 'months' ? (moment(task.end_date).format('H') <= 12 && parseInt(moment(task.end_date).format('Hmm')) > 0? true : false) : (moment(task.end_date).format('mm') <= 30 && parseInt(moment(task.end_date).format('mm')) > 0 ? true : false)); task.end_date = moment(task.end_date).add((count * (settings.currentDisplay == 'months' ? 1440 : 60)) , 'minute'); if ((splitted && count % 1 !== 0) || (!splitted && count % 1 == 0)) { //On main border if (moment(task.end_date).format('HHmm') != '0000') { task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).endOf('day') : moment(task.end_date)); } else { task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).add(-1, 'minute') : moment(task.end_date)); } } else { task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).hours(12).minutes(0) : moment(task.end_date).minutes(30)); } task.end_date = moment(task.end_date).format('YYYY-MM-DD HH:mm'); if (parseInt(moment(task.start_date).format('YYYYMMDDHHmm')) >= parseInt(moment(task.end_date).format('YYYYMMDDHHmm'))) { deleteTaskFromUser(settings.users[settings.resize.user], task, taskIndex, undo); } else { generateNotification('success', settings.i18n.notif.userTaskModified + ': <b>' + moment(task.end_date).locale(settings.locale).format('LLLL') + '</b>', undo, settings.onUserEdition); } updateDisplay(settings.currentDisplay); } }); settings.resize = {}; }; /** * apply the task resizing * @param e: the action event */ var moveTaskResize = function (e) { var $taskMarker = settings.resize.element; $('.pts-task-tooltip').remove(); var overlapse = false;