const render_widgets_todo_widget = require('../templates/widgets/todo_widget.hbs'); const render_widgets_todo_widget_tasks = require('../templates/widgets/todo_widget_tasks.hbs'); exports.task_data_holder = function () { const self = {}; const task_map = new Map(); function get_new_index() { let idx = 0; for (const item of task_map.values()) { idx = Math.max(idx, item.idx); } return idx + 1; } self.get_widget_data = function () { const all_tasks = Array.from(task_map.values()); all_tasks.sort((a, b) => a.task.localeCompare(b.task)); const pending_tasks = []; const completed_tasks = []; for (const item of all_tasks) { if (item.completed) { completed_tasks.push(item); } else { pending_tasks.push(item); } } const widget_data = { pending_tasks: pending_tasks, completed_tasks: completed_tasks, }; return widget_data; }; self.name_in_use = function (name) { for (const item of task_map.values()) { if (item.task === name) { return true; } } return false; }; self.handle = { new_task: { outbound: function (task, desc) { const event = { type: 'new_task', key: get_new_index(), task: task, desc: desc, completed: false, }; if (!self.name_in_use(task)) { return event; } return; }, inbound: function (sender_id, data) { // for legacy reasons, the inbound idx is // called key in the event const idx = data.key; const key = idx + "," + sender_id; const task = data.task; const desc = data.desc; const completed = data.completed; const task_data = { task: task, desc: desc, idx: idx, key: key, completed: completed, }; if (!self.name_in_use(task)) { task_map.set(key, task_data); } }, }, strike: { outbound: function (key) { const event = { type: 'strike', key: key, }; return event; }, inbound: function (sender_id, data) { const key = data.key; const item = task_map.get(key); if (item === undefined) { blueslip.error('unknown key for tasks: ' + key); return; } item.completed = !item.completed; }, }, }; self.handle_event = function (sender_id, data) { const type = data.type; if (self.handle[type]) { self.handle[type].inbound(sender_id, data); } }; return self; }; exports.activate = function (opts) { const elem = opts.elem; const callback = opts.callback; const task_data = exports.task_data_holder(); function render() { const html = render_widgets_todo_widget(); elem.html(html); elem.find("button.add-task").on('click', function (e) { e.stopPropagation(); elem.find(".widget-error").text(''); const task = elem.find("input.add-task").val().trim(); const desc = elem.find("input.add-desc").val().trim(); if (task === '') { return; } elem.find(".add-task").val('').focus(); elem.find(".add-desc").val('').focus(); const task_exists = task_data.name_in_use(task); if (task_exists) { elem.find(".widget-error").text(i18n.t('Task already exists')); return; } const data = task_data.handle.new_task.outbound(task, desc); callback(data); }); } function render_results() { const widget_data = task_data.get_widget_data(); const html = render_widgets_todo_widget_tasks(widget_data); elem.find('ul.todo-widget').html(html); elem.find(".widget-error").text(''); elem.find("button.task").on('click', function (e) { e.stopPropagation(); const key = $(e.target).attr('data-key'); const data = task_data.handle.strike.outbound(key); callback(data); }); } elem.handle_events = function (events) { for (const event of events) { task_data.handle_event(event.sender_id, event.data); } render_results(); }; render(); render_results(); }; window.todo_widget = exports;