anareaty_html-checkboxes/main.ts

278 lines
6.4 KiB
TypeScript
Raw Normal View History

2025-02-02 09:18:54 +00:00
import { Editor, Plugin, TFile, Menu, WorkspaceLeaf } from 'obsidian';
2024-09-15 07:25:33 +00:00
2025-02-02 09:18:54 +00:00
export default class HTMLCheckboxPlugin extends Plugin {
2025-02-01 21:41:18 +00:00
2024-09-15 07:25:33 +00:00
async onload() {
2025-02-01 21:41:18 +00:00
/* Add menu item to create checkbox */
this.registerEvent(this.app.workspace.on('editor-menu', (menu, editor, view) => {
menu.addItem((item) => {
item
.setTitle("Add HTML checkbox")
.setIcon("check-square-2")
.onClick(async () => {
this.addCheckbox(editor)
});
});
}));
2024-09-15 07:25:33 +00:00
this.addCommand({
2025-02-01 21:41:18 +00:00
id: "add-html-checkbox",
name: "Add HTML checkbox",
editorCallback: async (editor, view) => {
this.addCheckbox(editor)
2024-09-15 07:25:33 +00:00
}
});
2025-02-01 21:41:18 +00:00
/* Add listener to make checkbox clickable */
this.registerDomEvent(window, 'click', async (e: MouseEvent) => {
let target = e.target as HTMLElement
if (target.localName == "input" &&
(target as HTMLInputElement).type == "checkbox" &&
target.id
) {
e.preventDefault()
2025-02-02 09:18:54 +00:00
let file = this.app.workspace.getActiveFile()
2025-02-01 21:41:18 +00:00
/* Check if checkbox is inside embedded file */
let embedWrapper = target.closest(".internal-embed")
if (embedWrapper) {
let embedSrc = embedWrapper.getAttribute("src") || ""
2025-02-02 09:18:54 +00:00
file = this.app.metadataCache.getFirstLinkpathDest(embedSrc, "")
2025-02-01 21:41:18 +00:00
}
2025-02-02 09:18:54 +00:00
if (file instanceof TFile) {
let content = await this.app.vault.cachedRead(file)
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let id = target.id
let checkboxRE = new RegExp("<input[^>]*?id=\"" + id + "\"[^>]*?>")
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (file.extension == "canvas") {
checkboxRE = new RegExp("<input[^>]*?id=\\\\\"" + id + "\\\\\"[^>]*?>")
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let checkboxMatch = content.match(checkboxRE)
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (checkboxMatch) {
let checkboxString = checkboxMatch[0]
let dataTaskMatch = checkboxString.match(/data-task="."/)
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let newCheckboxString = checkboxString
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if ((target as HTMLInputElement).checked) {
newCheckboxString = newCheckboxString.replace(">", " checked>")
} else {
newCheckboxString = newCheckboxString.replace(" checked>", ">").replace(" >", ">")
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (dataTaskMatch) {
newCheckboxString = newCheckboxString.replace(dataTaskMatch[0], "")
}
}
let newContent = content.replace(checkboxString, newCheckboxString)
await this.app.vault.modify(file, newContent)
let inCanvas = target.closest(".canvas-node-content")
if (file.extension != "canvas" && inCanvas) {
let leaf = this.app.workspace.getMostRecentLeaf()
if (leaf instanceof WorkspaceLeaf) {
//@ts-ignore
await leaf.rebuildView()
}
2025-02-01 21:41:18 +00:00
}
}
2025-02-02 09:18:54 +00:00
}
2024-09-15 07:25:33 +00:00
}
});
2025-02-01 21:41:18 +00:00
/* Add menu for alternative checkboxes */
2024-09-15 07:25:33 +00:00
2025-02-01 21:41:18 +00:00
this.registerDomEvent(window, "mouseup", (e: MouseEvent) => {
if (e.button == 2) {
let target = e.target as HTMLElement
if (target.localName == "input" &&
(target as HTMLInputElement).type == "checkbox" &&
target.id
) {
2024-09-15 07:25:33 +00:00
2025-02-01 21:41:18 +00:00
const menu = new Menu();
2024-09-15 07:25:33 +00:00
2025-02-01 21:41:18 +00:00
menu.addItem((item) =>
item
.setIcon("square")
.onClick(() => {
this.setStatus(" ", target)
})
);
2024-09-15 07:25:33 +00:00
2025-02-01 21:41:18 +00:00
menu.addItem((item) =>
item
.setIcon("square-check")
.setTitle("x")
.onClick(() => {
this.setStatus("x", target)
})
);
menu.addItem((item) =>
item
.setIcon("square-minus")
.setTitle("-")
.onClick(() => {
this.setStatus("-", target)
})
);
menu.addItem((item) =>
item
.setIcon("x-square")
.setTitle("~")
.onClick(() => {
this.setStatus("~", target)
})
);
menu.addItem((item) =>
item
.setIcon("square-slash")
.setTitle("/")
.onClick(() => {
this.setStatus("/", target)
})
);
menu.showAtMouseEvent(e as MouseEvent);
2025-02-02 09:18:54 +00:00
console.log(menu)
2025-02-01 21:41:18 +00:00
//@ts-ignore
menu.dom.classList.add("checkbox-menu");
}
}
})
2024-09-15 07:25:33 +00:00
}
2025-02-01 21:41:18 +00:00
onunload() {}
2024-09-15 07:25:33 +00:00
2025-02-01 21:41:18 +00:00
async addCheckbox(editor: Editor) {
const generateId: any = (content: string) => {
let id = "hc-" + (Math.floor(Math.random() * 999) + 1);
let match = content.match("id=\"" + id + "\"")
if (match) {
return generateId(content)
} else {
return id
}
}
let lastLine = editor.lastLine()
let lastLineLength = editor.getLine(lastLine).length
let editorContent = editor.getRange({line:0, ch: 0}, {line:lastLine, ch: lastLineLength})
let id = generateId(editorContent)
let checkbox = '<input id="' + id + '" type="checkbox">'
editor.replaceSelection(checkbox)
2024-09-15 07:25:33 +00:00
}
2025-02-01 21:41:18 +00:00
async setStatus(status: string, target: HTMLElement) {
2025-02-02 09:18:54 +00:00
let file = this.app.workspace.getActiveFile()
2025-02-01 21:41:18 +00:00
/* Check if checkbox is inside embedded file */
let embedWrapper = target.closest(".internal-embed")
if (embedWrapper) {
let embedSrc = embedWrapper.getAttribute("src") || ""
2025-02-02 09:18:54 +00:00
file = this.app.metadataCache.getFirstLinkpathDest(embedSrc, "")
2025-02-01 21:41:18 +00:00
}
2025-02-02 09:18:54 +00:00
if (file instanceof TFile) {
let content = await this.app.vault.cachedRead(file)
let id = target.id
let checkboxRE = new RegExp("<input[^>]*?id=\"" + id + "\"[^>]*?>")
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (file.extension == "canvas") {
checkboxRE = new RegExp("<input[^>]*?id=\\\\\"" + id + "\\\\\"[^>]*?>")
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let checkboxString = content.match(checkboxRE)![0]
let newCheckboxString = checkboxString
let statusRe = new RegExp("data-task=\"" + status + "\"")
let dataTaskMatch = checkboxString.match(/data-task="."/)
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (file.extension == "canvas") {
dataTaskMatch = checkboxString.match(/data-task=\\".\\"/)
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let dataTaskMatchFirst = ""
if (dataTaskMatch) {
dataTaskMatchFirst = dataTaskMatch[0]
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
let statusMatch = checkboxString.match(statusRe)
let dataTaskString = "data-task=\"" + status + "\""
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (file.extension == "canvas") {
dataTaskString = 'data-task=\\\"' + status + '\\\"'
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (status == " ") {
newCheckboxString = newCheckboxString
.replace(dataTaskMatchFirst, "")
.replace(" checked>", ">").replace(" >", ">")
} else {
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (dataTaskMatch && !statusMatch) {
newCheckboxString = newCheckboxString.replace(dataTaskMatchFirst, dataTaskString)
}
2025-02-01 21:41:18 +00:00
2025-02-02 09:18:54 +00:00
if (!dataTaskMatch && (target as HTMLInputElement).checked) {
newCheckboxString = newCheckboxString.replace("checked", dataTaskString + " checked")
}
if (!dataTaskMatch && !(target as HTMLInputElement).checked) {
newCheckboxString = newCheckboxString.replace(">", " " + dataTaskString + " checked>")
}
2025-02-01 21:41:18 +00:00
}
2025-02-02 09:18:54 +00:00
let newContent = content.replace(checkboxString, newCheckboxString)
await this.app.vault.modify(file, newContent)
2025-02-01 21:41:18 +00:00
}
2024-09-15 07:25:33 +00:00
}
}
2025-02-01 21:41:18 +00:00