You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.5 KiB
242 lines
6.5 KiB
import DropZone from "./DropZone.js";
|
|
import KanbanAPI from "../api/KanbanAPI.js";
|
|
import Dialog from "./Dialog.js";
|
|
import Priority from "./Priority.js";
|
|
import Complexity from "./Complexity.js";
|
|
|
|
export default class Item {
|
|
constructor(data) {
|
|
this.data = { ...data };
|
|
this.content = data.content || "";
|
|
|
|
const bottomDropZone = DropZone.createDropZone();
|
|
|
|
this.elements = {};
|
|
this.elements.root = Item.createRoot();
|
|
this.elements.input =
|
|
this.elements.root.querySelector(
|
|
".kanban__item-input"
|
|
);
|
|
|
|
this.elements.root.dataset.id = String(data.id);
|
|
this.elements.root.className =
|
|
`kanban__item color-${data.color || "yellow"}`;
|
|
|
|
this.elements.root.querySelector(
|
|
".kanban__number"
|
|
).textContent = String(data.id);
|
|
|
|
this.elements.root.querySelector(
|
|
".kanban__assign"
|
|
).textContent = data.assign || "";
|
|
|
|
this.elements.input.textContent = this.content;
|
|
|
|
this.renderDescription(data.description);
|
|
this.renderTags(data.tags);
|
|
this.renderDates(data);
|
|
this.renderTaskInformation(data);
|
|
this.renderComplexity(data.complexity);
|
|
this.renderPriority(data.priority);
|
|
|
|
this.elements.root.appendChild(bottomDropZone);
|
|
|
|
this.elements.input.addEventListener("blur", () => {
|
|
this.saveInlineContent();
|
|
});
|
|
|
|
this.elements.root.addEventListener("dblclick", event => {
|
|
if (event.target.closest(".kanban__dropzone")) {
|
|
return;
|
|
}
|
|
|
|
Dialog.modify_task(data.id);
|
|
});
|
|
|
|
this.elements.root.addEventListener("dragstart", event => {
|
|
event.dataTransfer.effectAllowed = "move";
|
|
event.dataTransfer.setData(
|
|
"text/plain",
|
|
String(data.id)
|
|
);
|
|
|
|
this.elements.root.classList.add(
|
|
"kanban__item--dragging"
|
|
);
|
|
});
|
|
|
|
this.elements.root.addEventListener("dragend", () => {
|
|
this.elements.root.classList.remove(
|
|
"kanban__item--dragging"
|
|
);
|
|
});
|
|
|
|
this.elements.input.addEventListener("drop", event => {
|
|
event.preventDefault();
|
|
});
|
|
}
|
|
|
|
async saveInlineContent() {
|
|
const newContent =
|
|
this.elements.input.textContent.trim();
|
|
|
|
if (newContent === this.content) {
|
|
return;
|
|
}
|
|
|
|
if (newContent === "") {
|
|
this.elements.input.textContent = this.content;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await KanbanAPI.updateItem(this.data.id, {
|
|
content: newContent
|
|
});
|
|
|
|
this.content = newContent;
|
|
this.data.content = newContent;
|
|
} catch (error) {
|
|
console.error(error);
|
|
this.elements.input.textContent = this.content;
|
|
}
|
|
}
|
|
|
|
renderDescription(description) {
|
|
if (!description) {
|
|
return;
|
|
}
|
|
|
|
const indicator = document.createElement("span");
|
|
const icon = document.createElement("i");
|
|
|
|
icon.textContent = "✍";
|
|
icon.title = description;
|
|
|
|
indicator.appendChild(icon);
|
|
this.elements.root.appendChild(indicator);
|
|
}
|
|
|
|
renderTags(tags) {
|
|
if (!tags) {
|
|
return;
|
|
}
|
|
|
|
const tagElement = document.createElement("span");
|
|
tagElement.className = "kanban__tags";
|
|
tagElement.textContent = tags;
|
|
|
|
this.elements.root.appendChild(tagElement);
|
|
}
|
|
|
|
renderDates(data) {
|
|
if (Item.isValidDate(data.start)) {
|
|
const startElement = document.createElement("span");
|
|
startElement.className = "date";
|
|
startElement.textContent =
|
|
`| Start: ${Item.formatDate(data.start)}`;
|
|
|
|
this.elements.root.appendChild(startElement);
|
|
}
|
|
|
|
if (Item.isValidDate(data.due)) {
|
|
const dueElement = document.createElement("span");
|
|
dueElement.className = "datetime";
|
|
dueElement.textContent =
|
|
`| Due: ${new Date(data.due).toLocaleString()}`;
|
|
|
|
this.elements.root.appendChild(dueElement);
|
|
}
|
|
}
|
|
|
|
renderTaskInformation(data) {
|
|
const information = [];
|
|
|
|
if (data.estimate !== null && data.estimate !== undefined) {
|
|
information.push(`| Estimate: ${data.estimate}h`);
|
|
}
|
|
|
|
if (
|
|
data.timeSpent !== null &&
|
|
data.timeSpent !== undefined
|
|
) {
|
|
information.push(`| Spent: ${data.timeSpent}h`);
|
|
}
|
|
|
|
if (information.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const informationElement =
|
|
document.createElement("span");
|
|
|
|
informationElement.className =
|
|
"kanban__task-information";
|
|
|
|
informationElement.textContent =
|
|
information.join(" | ");
|
|
|
|
this.elements.root.appendChild(informationElement);
|
|
}
|
|
|
|
renderPriority(priority) {
|
|
const priorityElement =
|
|
document.createElement("span");
|
|
|
|
priorityElement.className = "kanban__priority";
|
|
priorityElement.textContent =
|
|
Priority.get_priority(Number(priority));
|
|
|
|
this.elements.root.appendChild(priorityElement);
|
|
}
|
|
|
|
renderComplexity(level) {
|
|
const complexityElement =
|
|
document.createElement("div");
|
|
|
|
complexityElement.className = "kanban__complexity";
|
|
complexityElement.textContent =
|
|
Complexity.get_complexity(Number(level));
|
|
|
|
this.elements.root.appendChild(complexityElement);
|
|
}
|
|
|
|
static isValidDate(value) {
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
|
|
const date = new Date(value);
|
|
|
|
return !Number.isNaN(date.getTime());
|
|
}
|
|
|
|
static formatDate(value) {
|
|
const [year, month, day] = value.split("-");
|
|
|
|
if (!year || !month || !day) {
|
|
return value;
|
|
}
|
|
|
|
return new Date(
|
|
Number(year),
|
|
Number(month) - 1,
|
|
Number(day)
|
|
).toLocaleDateString();
|
|
}
|
|
|
|
static createRoot() {
|
|
const template = document.createElement("template");
|
|
|
|
template.innerHTML = `
|
|
<div class="kanban__item" draggable="true">
|
|
<div class="kanban__number"></div>
|
|
<div class="kanban__assign"></div>
|
|
<div class="kanban__item-input"
|
|
contenteditable="true"></div>
|
|
</div>
|
|
`;
|
|
|
|
return template.content.firstElementChild;
|
|
}
|
|
}
|
|
|