diff --git a/conversejs/custom/plugins/tasks/index.js b/conversejs/custom/plugins/tasks/index.js index 8a99b3b8..c47e4248 100644 --- a/conversejs/custom/plugins/tasks/index.js +++ b/conversejs/custom/plugins/tasks/index.js @@ -1,7 +1,7 @@ import { _converse, converse } from '../../../src/headless/core.js' import { ChatRoomTaskLists } from './task-lists.js' import { ChatRoomTaskList } from './task-list.js' -import { getHeadingButtons } from './utils.js' +import { getHeadingButtons, initOrDestroyChatRoomTaskLists } from './utils.js' import './muc-task-lists-view.js' // FIXME: here or in another file? import './modals/muc-task-lists.js' // FIXME: here or in another file? @@ -12,6 +12,22 @@ converse.plugins.add('livechat-converse-tasks', { _converse.ChatRoomTaskLists = ChatRoomTaskLists _converse.ChatRoomTaskList = ChatRoomTaskList + _converse.api.listen.on('chatRoomInitialized', muc => { + muc.session.on('change:connection_status', _session => { + // When joining a room, initializing the TaskLists object (if user has access), + // When disconnected from a room, destroying the Tasklists object: + initOrDestroyChatRoomTaskLists(muc) + }) + + // When the current user role changes, we must also delete or initilize the TaskLists object: + muc.occupants.on('change:role', occupant => { + if (occupant.get('jid') !== _converse.bare_jid) { // only for myself + return + } + initOrDestroyChatRoomTaskLists(muc) + }) + }) + // adding the "Tasks" button in the MUC heading buttons: _converse.api.listen.on('getHeadingButtons', getHeadingButtons) } diff --git a/conversejs/custom/plugins/tasks/modals/muc-task-lists.js b/conversejs/custom/plugins/tasks/modals/muc-task-lists.js index b11d266e..4113be65 100644 --- a/conversejs/custom/plugins/tasks/modals/muc-task-lists.js +++ b/conversejs/custom/plugins/tasks/modals/muc-task-lists.js @@ -10,7 +10,8 @@ export default class mucTaskListsModal extends BaseModal { } getModalTitle () { - return __('Tasks') + // eslint-disable-next-line no-undef + return __(LOC_tasks) } } diff --git a/conversejs/custom/plugins/tasks/muc-task-lists-view.js b/conversejs/custom/plugins/tasks/muc-task-lists-view.js index 271d3ae5..736c7d7d 100644 --- a/conversejs/custom/plugins/tasks/muc-task-lists-view.js +++ b/conversejs/custom/plugins/tasks/muc-task-lists-view.js @@ -1,5 +1,6 @@ import { CustomElement } from 'shared/components/element.js' import { _converse, api } from '@converse/headless/core' +import tplMucTaskLists from './templates/muc-task-lists' export default class MUCTaskListsView extends CustomElement { static get properties () { @@ -9,11 +10,18 @@ export default class MUCTaskListsView extends CustomElement { } async initialize () { - this.model = _converse.chatboxes.get(this.getAttribute('jid')) + this.model = _converse.chatboxes.get(this.getAttribute('jid')).tasklists + + if (!this.model) { + return + } + + this.listenTo(this.model, 'add', () => this.requestUpdate()) + this.listenTo(this.model, 'change', () => this.requestUpdate()) } render () { - return '' + return tplMucTaskLists(this.model) } } diff --git a/conversejs/custom/plugins/tasks/task-list.js b/conversejs/custom/plugins/tasks/task-list.js index 99184828..3f0e1426 100644 --- a/conversejs/custom/plugins/tasks/task-list.js +++ b/conversejs/custom/plugins/tasks/task-list.js @@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js' * @memberof _converse */ class ChatRoomTaskList extends Model { - + idAttribute = 'id' } export { diff --git a/conversejs/custom/plugins/tasks/task-lists.js b/conversejs/custom/plugins/tasks/task-lists.js index 44fa1b4a..76a9bbfc 100644 --- a/conversejs/custom/plugins/tasks/task-lists.js +++ b/conversejs/custom/plugins/tasks/task-lists.js @@ -1,5 +1,7 @@ import { Collection } from '@converse/skeletor/src/collection.js' import { ChatRoomTaskList } from './task-list' +import { initStorage } from '@converse/headless/utils/storage.js' +import { getUniqueId } from '@converse/headless/utils/core.js' /** * A list of {@link _converse.ChatRoomTaskList} instances, representing task lists associated to a MUC. @@ -9,6 +11,66 @@ import { ChatRoomTaskList } from './task-list' */ class ChatRoomTaskLists extends Collection { model = ChatRoomTaskList + + initialize (models, options) { + super.initialize(arguments) + this.chatroom = options.chatroom + + const id = `converse-livechat-tasks-lists-${this.chatroom.get('jid')}` + initStorage(this, id, 'session') + + this.on('change:name', () => this.sort()) + + this.fetchTasksLists().catch(console.error) + } + + comparator (tasklist1, tasklist2) { + // Case insensitive on task list name. + const name1 = tasklist1.get('name').toLowerCase() + const name2 = tasklist2.get('name').toLowerCase() + return name1 < name2 ? -1 : name1 > name2 ? 1 : 0 + } + + create (attrs, options) { + attrs.id ??= getUniqueId() + return super.create(attrs, options) + } + + /** + * Requires Task lists from the server. + */ + async fetchTasksLists () { + // TODO: remove these test lines, and subscribe to pubsub. + const taskListsData = [ + { + id: 'task-list-1', + name: 'Task List 1' + }, + { + // id: 'task-list-2', + name: 'Task List 2' + } + ] + + for (const item of taskListsData) { + let id = item.id + + const tasklist = id ? this.get(id) : undefined + if (tasklist) { + tasklist.save({ + name: item.name + }) + return + } + + id ??= getUniqueId() + + this.create({ + id, + name: item.name + }) + } + } } export { diff --git a/conversejs/custom/plugins/tasks/templates/muc-task-list.js b/conversejs/custom/plugins/tasks/templates/muc-task-list.js new file mode 100644 index 00000000..0e39b483 --- /dev/null +++ b/conversejs/custom/plugins/tasks/templates/muc-task-list.js @@ -0,0 +1,7 @@ +import { html } from 'lit' + +export default function tplMucTaskList (tasklist) { + return html`
+ Tasklist: ${tasklist.get('name')} +
` +} diff --git a/conversejs/custom/plugins/tasks/templates/muc-task-lists.js b/conversejs/custom/plugins/tasks/templates/muc-task-lists.js new file mode 100644 index 00000000..27a0590f --- /dev/null +++ b/conversejs/custom/plugins/tasks/templates/muc-task-lists.js @@ -0,0 +1,43 @@ +import tplMucTaskList from './muc-task-list' +import { html } from 'lit' +import { repeat } from 'lit/directives/repeat.js' +import { __ } from 'i18n' + +export default function tplMucTaskLists (tasklists) { + if (!tasklists) { // if user losed rights + return html`` // FIXME: add a message like "you dont have access"? + } + + const i18nAdd = __('Add') + // eslint-disable-next-line no-undef + const i18nCreateTaskList = __(LOC_task_list_create) + // eslint-disable-next-line no-undef + const i18nTaskListName = __(LOC_task_list_name) + + return html` +
{ + ev.preventDefault() + const name = ev.target.name.value.trim() + if ((name ?? '') === '') { return } + + ev.target.name.value = '' + + tasklists.create({ + name + }) + }} + > +
+ + +
+
+
+ ${ + repeat(tasklists, (tasklist) => tasklist.get('id'), (tasklist) => tplMucTaskList(tasklist)) + } +
` +} diff --git a/conversejs/custom/plugins/tasks/utils.js b/conversejs/custom/plugins/tasks/utils.js index 2ea7c465..5546235d 100644 --- a/conversejs/custom/plugins/tasks/utils.js +++ b/conversejs/custom/plugins/tasks/utils.js @@ -1,4 +1,4 @@ -import { _converse, api } from '../../../src/headless/core.js' +import { converse, _converse, api } from '../../../src/headless/core.js' import { __ } from 'i18n' export function getHeadingButtons (view, buttons) { @@ -8,15 +8,14 @@ export function getHeadingButtons (view, buttons) { return buttons } - const myself = muc.getOwnOccupant() - if (!myself || !myself.isModerator()) { - // User must be moderator + if (!muc.tasklists) { // this is defined only if user has access (see initOrDestroyChatRoomTaskLists) return buttons } // Adding a "Open task list" button. buttons.unshift({ - i18n_text: __('Tasks'), + // eslint-disable-next-line no-undef + i18n_text: __(LOC_tasks), handler: async (ev) => { ev.preventDefault() ev.stopPropagation() @@ -30,3 +29,38 @@ export function getHeadingButtons (view, buttons) { return buttons } + +function _initChatRoomTaskLists (mucModel) { + if (mucModel.tasklists) { + // already initiliazed + return + } + + mucModel.tasklists = new _converse.ChatRoomTaskLists(undefined, { chatroom: mucModel }) +} + +function _destroyChatRoomTaskLists (mucModel) { + if (!mucModel.tasklists) { return } + + // mucModel.tasklists.unload() FIXME: add a method to unregister from the pubsub, and empty the tasklist. + mucModel.tasklists = undefined +} + +export function initOrDestroyChatRoomTaskLists (mucModel) { + if (mucModel.get('type') !== _converse.CHATROOMS_TYPE) { + // only on MUC. + return _destroyChatRoomTaskLists(mucModel) + } + + if (mucModel.session.get('connection_status') !== converse.ROOMSTATUS.ENTERED) { + _destroyChatRoomTaskLists(mucModel) + } + + const myself = mucModel.getOwnOccupant() + if (!myself || !myself.isModerator()) { + // User must be moderator + return _destroyChatRoomTaskLists(mucModel) + } + + return _initChatRoomTaskLists(mucModel) +} diff --git a/conversejs/loc.keys.js b/conversejs/loc.keys.js index f09f3cea..f51e7472 100644 --- a/conversejs/loc.keys.js +++ b/conversejs/loc.keys.js @@ -16,7 +16,9 @@ const locKeys = [ 'login_remote_peertube_video_not_found_try_anyway_button', 'login_remote_peertube_video_open_failed', 'login_external_auth_alert_message', - 'tasks' + 'tasks', + 'task_list_create', + 'task_list_name' ] module.exports = locKeys diff --git a/languages/en.yml b/languages/en.yml index 8e031fe0..3baf26dc 100644 --- a/languages/en.yml +++ b/languages/en.yml @@ -435,4 +435,6 @@ login_remote_peertube_video_not_found_try_anyway_button: "Try anyway to open the login_remote_peertube_video_open_failed: "Your browser has blocked the opening on the remote instance, please try to open manually this link:" login_external_auth_alert_message: "Authentication failed" -tasks: Tasks +tasks: 'Tasks' +task_list_create: 'Create new task list:' +task_list_name: 'Task list name' \ No newline at end of file