mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-30 19:43:47 +00:00 
			
		
		
		
	ES and TypeScript modules are strict by default and don’t need this directive. ESLint will remind us to add it to new CommonJS files and remove it from ES and TypeScript modules. Signed-off-by: Anders Kaseorg <anders@zulip.com>
		
			
				
	
	
		
			187 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| 
 | |
| const render_widgets_todo_widget = require("../templates/widgets/todo_widget.hbs");
 | |
| const render_widgets_todo_widget_tasks = require("../templates/widgets/todo_widget_tasks.hbs");
 | |
| 
 | |
| class TaskData {
 | |
|     task_map = new Map();
 | |
| 
 | |
|     get_new_index() {
 | |
|         let idx = 0;
 | |
| 
 | |
|         for (const item of this.task_map.values()) {
 | |
|             idx = Math.max(idx, item.idx);
 | |
|         }
 | |
| 
 | |
|         return idx + 1;
 | |
|     }
 | |
| 
 | |
|     get_widget_data() {
 | |
|         const all_tasks = Array.from(this.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,
 | |
|             completed_tasks,
 | |
|         };
 | |
| 
 | |
|         return widget_data;
 | |
|     }
 | |
| 
 | |
|     name_in_use(name) {
 | |
|         for (const item of this.task_map.values()) {
 | |
|             if (item.task === name) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     handle = {
 | |
|         new_task: {
 | |
|             outbound: (task, desc) => {
 | |
|                 const event = {
 | |
|                     type: "new_task",
 | |
|                     key: this.get_new_index(),
 | |
|                     task,
 | |
|                     desc,
 | |
|                     completed: false,
 | |
|                 };
 | |
| 
 | |
|                 if (!this.name_in_use(task)) {
 | |
|                     return event;
 | |
|                 }
 | |
|                 return;
 | |
|             },
 | |
| 
 | |
|             inbound: (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,
 | |
|                     desc,
 | |
|                     idx,
 | |
|                     key,
 | |
|                     completed,
 | |
|                 };
 | |
| 
 | |
|                 if (!this.name_in_use(task)) {
 | |
|                     this.task_map.set(key, task_data);
 | |
|                 }
 | |
|             },
 | |
|         },
 | |
| 
 | |
|         strike: {
 | |
|             outbound: (key) => {
 | |
|                 const event = {
 | |
|                     type: "strike",
 | |
|                     key,
 | |
|                 };
 | |
| 
 | |
|                 return event;
 | |
|             },
 | |
| 
 | |
|             inbound: (sender_id, data) => {
 | |
|                 const key = data.key;
 | |
|                 const item = this.task_map.get(key);
 | |
| 
 | |
|                 if (item === undefined) {
 | |
|                     blueslip.warn("Do we have legacy data? unknown key for tasks: " + key);
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 item.completed = !item.completed;
 | |
|             },
 | |
|         },
 | |
|     };
 | |
| 
 | |
|     handle_event(sender_id, data) {
 | |
|         const type = data.type;
 | |
|         if (this.handle[type]) {
 | |
|             this.handle[type].inbound(sender_id, data);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| exports.TaskData = TaskData;
 | |
| 
 | |
| exports.activate = function (opts) {
 | |
|     const elem = opts.elem;
 | |
|     const callback = opts.callback;
 | |
| 
 | |
|     const task_data = new TaskData();
 | |
| 
 | |
|     function render() {
 | |
|         const html = render_widgets_todo_widget();
 | |
|         elem.html(html);
 | |
| 
 | |
|         elem.find("button.add-task").on("click", (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("").trigger("focus");
 | |
|             elem.find(".add-desc").val("").trigger("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", (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;
 |