Task lists WIP:
* front-end
This commit is contained in:
parent
964b8854f6
commit
1e876e60ee
@ -22,6 +22,11 @@ export default class MUCTaskListView extends CustomElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.listenTo(this.model, 'change', () => this.requestUpdate())
|
this.listenTo(this.model, 'change', () => this.requestUpdate())
|
||||||
|
|
||||||
|
// We must also listen for new tasks
|
||||||
|
// FIXME: is there a way to only refresh if the task is part of this list?
|
||||||
|
this.listenTo(this.model.collection.chatroom.tasks, 'add', () => this.requestUpdate())
|
||||||
|
this.listenTo(this.model.collection.chatroom.tasks, 'remove', () => this.requestUpdate())
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import { CustomElement } from 'shared/components/element.js'
|
import { CustomElement } from 'shared/components/element.js'
|
||||||
import { api } from '@converse/headless/core'
|
import { api } from '@converse/headless/core'
|
||||||
import { tplMucTask } from './templates/muc-task'
|
import { tplMucTask } from './templates/muc-task'
|
||||||
|
import { __ } from 'i18n'
|
||||||
|
|
||||||
|
import './styles/muc-tasks.scss'
|
||||||
|
|
||||||
export default class MUCTaskView extends CustomElement {
|
export default class MUCTaskView extends CustomElement {
|
||||||
static get properties () {
|
static get properties () {
|
||||||
return {
|
return {
|
||||||
model: { type: Object, attribute: true }
|
model: { type: Object, attribute: true },
|
||||||
|
edit: { type: Boolean, attribute: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize () {
|
async initialize () {
|
||||||
|
this.edit = false
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -18,7 +23,70 @@ export default class MUCTaskView extends CustomElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return tplMucTask(this.model)
|
return tplMucTask(this, this.model)
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveTask (ev) {
|
||||||
|
ev?.preventDefault?.()
|
||||||
|
|
||||||
|
const name = ev.target.name.value.trim()
|
||||||
|
|
||||||
|
if ((name ?? '') === '') { return }
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.querySelectorAll('input[type=submit]').forEach(el => {
|
||||||
|
el.setAttribute('disabled', true)
|
||||||
|
el.classList.add('disabled')
|
||||||
|
})
|
||||||
|
|
||||||
|
const task = this.model
|
||||||
|
task.set('name', name)
|
||||||
|
task.set('description', ev.target.description.value.trim())
|
||||||
|
await task.saveItem()
|
||||||
|
|
||||||
|
this.edit = false
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
this.querySelectorAll('input[type=submit]').forEach(el => {
|
||||||
|
el.removeAttribute('disabled')
|
||||||
|
el.classList.remove('disabled')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteTask (ev) {
|
||||||
|
ev?.preventDefault?.()
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nConfirmDelete = __(LOC_task_delete_confirm)
|
||||||
|
|
||||||
|
// FIXME: when tasks are in a modal, api.confirm replaces the modal. This is not ok.
|
||||||
|
// const result = await api.confirm(i18nConfirmDelete)
|
||||||
|
const result = confirm(i18nConfirmDelete)
|
||||||
|
if (!result) { return }
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.model.deleteItem()
|
||||||
|
} catch (err) {
|
||||||
|
api.alert(
|
||||||
|
'error', __('Error'), [__('Error')]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleEdit () {
|
||||||
|
this.edit = !this.edit
|
||||||
|
if (this.edit) {
|
||||||
|
await this.updateComplete
|
||||||
|
const input = this.querySelector('.task-name input[name="name"]')
|
||||||
|
if (input) {
|
||||||
|
input.focus()
|
||||||
|
// Placing cursor at the end:
|
||||||
|
input.selectionStart = input.value.length
|
||||||
|
input.selectionEnd = input.selectionStart
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
livechat-converse-muc-task-list {
|
livechat-converse-muc-task-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.task-list-description {
|
.task-list-line {
|
||||||
border: 1px solid var(--chatroom-head-bg-color);
|
border: 1px solid var(--chatroom-head-bg-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
|
31
conversejs/custom/plugins/tasks/styles/muc-tasks.scss
Normal file
31
conversejs/custom/plugins/tasks/styles/muc-tasks.scss
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.conversejs {
|
||||||
|
livechat-converse-muc-task {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.task-line {
|
||||||
|
border: 1px solid var(--chatroom-head-bg-color);
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 0.25em;
|
||||||
|
column-gap: 0.25em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.task-description {
|
||||||
|
flex-grow: 2;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-action {
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0.25em;
|
||||||
|
padding-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,8 +18,8 @@ class ChatRoomTaskList extends Model {
|
|||||||
|
|
||||||
async saveItem () {
|
async saveItem () {
|
||||||
console.log('Saving task list ' + this.get('id') + '...')
|
console.log('Saving task list ' + this.get('id') + '...')
|
||||||
await this.collection.chatroom.taskManager.saveItem(this, { name })
|
await this.collection.chatroom.taskManager.saveItem(this)
|
||||||
console.log('Task list ' + this.get('id') + ' created.')
|
console.log('Task list ' + this.get('id') + ' saved.')
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteItem () {
|
async deleteItem () {
|
||||||
@ -36,7 +36,10 @@ class ChatRoomTaskList extends Model {
|
|||||||
|
|
||||||
data.list = this.get('id')
|
data.list = this.get('id')
|
||||||
if (!data.order) {
|
if (!data.order) {
|
||||||
data.order = 1 + Math.max(...this.getTasks().map(t => t.get('order') ?? 0))
|
data.order = 1 + Math.max(
|
||||||
|
0,
|
||||||
|
...(this.getTasks().map(t => t.get('order') ?? 0).filter(o => !isNaN(o)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Creating task ' + name + '...')
|
console.log('Creating task ' + name + '...')
|
||||||
|
@ -8,6 +8,16 @@ import { Model } from '@converse/skeletor/src/model.js'
|
|||||||
*/
|
*/
|
||||||
class ChatRoomTask extends Model {
|
class ChatRoomTask extends Model {
|
||||||
idAttribute = 'id'
|
idAttribute = 'id'
|
||||||
|
|
||||||
|
async saveItem () {
|
||||||
|
console.log('Saving task ' + this.get('id') + '...')
|
||||||
|
await this.collection.chatroom.taskManager.saveItem(this)
|
||||||
|
console.log('Task ' + this.get('id') + ' saved.')
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteItem () {
|
||||||
|
return this.collection.chatroom.taskManager.deleteItem(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -12,7 +12,7 @@ export default function tplMucTaskList (el, tasklist) {
|
|||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const i18nTaskListName = __(LOC_task_list_name)
|
const i18nTaskListName = __(LOC_task_list_name)
|
||||||
return html`
|
return html`
|
||||||
<div class="task-list-description">
|
<div class="task-list-line">
|
||||||
${el.collapsed
|
${el.collapsed
|
||||||
? html`
|
? html`
|
||||||
<button @click=${el.toggleTasks} class="task-list-toggle-tasks">
|
<button @click=${el.toggleTasks} class="task-list-toggle-tasks">
|
||||||
|
@ -1,39 +1,81 @@
|
|||||||
import { html } from 'lit'
|
import { html } from 'lit'
|
||||||
import { __ } from 'i18n'
|
import { __ } from 'i18n'
|
||||||
|
|
||||||
export function tplMucTask (task) {
|
export function tplMucTask (el, task) {
|
||||||
const done = task.get('done')
|
const done = task.get('done')
|
||||||
return html`
|
// eslint-disable-next-line no-undef
|
||||||
<div class="">
|
const i18nDelete = __(LOC_task_delete)
|
||||||
|
|
||||||
|
const doneId = 'livechat-task-done-id-' + task.get('id')
|
||||||
|
return !el.edit
|
||||||
|
? html`
|
||||||
|
<div class="task-line">
|
||||||
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
|
id="${doneId}"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
.checked=${done === true}
|
.checked=${done === true}
|
||||||
@click=${(_ev) => {
|
@click=${(_ev) => {
|
||||||
task.save('done', !done)
|
task.set('done', !done)
|
||||||
|
task.saveItem()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<label class="form-check-label task-name" for="${doneId}">
|
||||||
${task.get('name')}
|
${task.get('name')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="task-description">${task.get('description') ?? ''}</div>
|
||||||
|
<button class="task-action" title="${__('Edit')}"
|
||||||
|
@click=${el.toggleEdit}
|
||||||
|
>
|
||||||
|
<converse-icon class="fa fa-edit" size="1em"></converse-icon>
|
||||||
|
</button>
|
||||||
|
<button class="task-action" title="${i18nDelete}"
|
||||||
|
@click=${el.deleteTask}
|
||||||
|
>
|
||||||
|
<converse-icon class="fa fa-trash-alt" size="1em"></converse-icon>
|
||||||
|
</button>
|
||||||
|
</div>`
|
||||||
|
: html`
|
||||||
|
<div class="task-line">
|
||||||
|
<form class="converse-form" @submit=${el.saveTask}>
|
||||||
|
${_tplTaskForm(task)}
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<input type="submit" class="btn btn-primary" value="${__('Ok')}" />
|
||||||
|
<input type="button" class="btn btn-secondary button-cancel"
|
||||||
|
value="${__('Cancel')}" @click=${el.toggleEdit}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tplMucAddTaskForm (tasklistEl, _tasklist) {
|
function _tplTaskForm (task) {
|
||||||
const i18nOk = __('Ok')
|
|
||||||
const i18nCancel = __('Cancel')
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const i18nTaskName = __(LOC_task_name)
|
const i18nTaskName = __(LOC_task_name)
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const i18nTaskDesc = __(LOC_task_description)
|
const i18nTaskDesc = __(LOC_task_description)
|
||||||
|
|
||||||
return html`
|
return html`<fieldset class="form-group">
|
||||||
<form class="task-list-add-task converse-form" @submit=${tasklistEl.submitAddTask}>
|
|
||||||
<fieldset class="form-group">
|
|
||||||
<input type="text" name="name"
|
<input type="text" name="name"
|
||||||
class="form-control" value=""
|
class="form-control" value="${task ? task.get('name') : ''}"
|
||||||
placeholder="${i18nTaskName}"
|
placeholder="${i18nTaskName}"
|
||||||
/>
|
/>
|
||||||
<textarea class="form-control" name="description" placeholder="${i18nTaskDesc}"></textarea>
|
<textarea
|
||||||
</fieldset>
|
class="form-control" name="description"
|
||||||
|
placeholder="${i18nTaskDesc}"
|
||||||
|
>${task ? task.get('description') : ''}</textarea>
|
||||||
|
</fieldset>`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tplMucAddTaskForm (tasklistEl, _tasklist) {
|
||||||
|
const i18nOk = __('Ok')
|
||||||
|
const i18nCancel = __('Cancel')
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<form class="task-list-add-task converse-form" @submit=${tasklistEl.submitAddTask}>
|
||||||
|
${_tplTaskForm(undefined)}
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<input type="submit" class="btn btn-primary" value="${i18nOk}" />
|
<input type="submit" class="btn btn-primary" value="${i18nOk}" />
|
||||||
<input type="button" class="btn btn-secondary button-cancel"
|
<input type="button" class="btn btn-secondary button-cancel"
|
||||||
|
@ -24,7 +24,9 @@ const locKeys = [
|
|||||||
'task_list_delete_confirm',
|
'task_list_delete_confirm',
|
||||||
'task_create',
|
'task_create',
|
||||||
'task_name',
|
'task_name',
|
||||||
'task_description'
|
'task_description',
|
||||||
|
'task_delete',
|
||||||
|
'task_delete_confirm'
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = locKeys
|
module.exports = locKeys
|
||||||
|
@ -444,3 +444,5 @@ task_list_delete_confirm: 'Are you sure you want to delete this task list?'
|
|||||||
task_create: 'Create a new task'
|
task_create: 'Create a new task'
|
||||||
task_name: 'Task name'
|
task_name: 'Task name'
|
||||||
task_description: 'Description'
|
task_description: 'Description'
|
||||||
|
task_delete: 'Delete task'
|
||||||
|
task_delete_confirm: 'Are you sure you want to delete this task?'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user