import {Wnd} from "./Wnd";
import {genUUID} from "../util/genID";
import {Model} from "./Model";
import {Editor} from "../editor";
import {hasClosestByTag} from "../protyle/util/hasClosest";
import {Constants} from "../constants";
import {escapeGreat, escapeHtml} from "../util/escape";
import {unicode2Emoji} from "../emoji";
import {fetchPost} from "../util/fetch";
import {showTooltip} from "../dialog/tooltip";
import {isTouchDevice} from "../util/functions";
/// #if !BROWSER
import {openNewWindow} from "../window/openNewWindow";
/// #endif
import {layoutToJSON} from "./util";
export class Tab {
public parent: Wnd;
public id: string;
public headElement: HTMLElement;
public panelElement: HTMLElement;
public callback: (tab: Tab) => void;
public model: Model;
public title: string;
public icon: string;
public docIcon: string;
constructor(options: ITab) {
this.id = genUUID();
this.callback = options.callback;
if (options.title || options.icon) {
this.title = options.title;
this.icon = options.icon;
this.docIcon = options.docIcon;
this.headElement = document.createElement("li");
this.headElement.setAttribute("data-type", "tab-header");
this.headElement.setAttribute("draggable", "true");
this.headElement.setAttribute("data-id", this.id);
this.headElement.setAttribute("data-position", "center"); // showTooltip 位置标识
this.headElement.classList.add("item", "item--focus");
let iconHTML = "";
if (options.icon) {
iconHTML = ``;
} else if (options.docIcon) {
iconHTML = `${unicode2Emoji(options.docIcon)}`;
}
this.headElement.innerHTML = `${iconHTML}${escapeHtml(options.title)}
`;
this.headElement.addEventListener("mouseenter", (event) => {
event.stopPropagation();
event.preventDefault();
let id = "";
if (this.model instanceof Editor && this.model.editor?.protyle?.block?.rootID) {
id = (this.model as Editor).editor.protyle.block.rootID;
} else if (!this.model) {
const initData = JSON.parse(this.headElement.getAttribute("data-initdata") || "{}");
if (initData && initData.instance === "Editor") {
id = initData.blockId;
}
}
if (id) {
fetchPost("/api/filetree/getFullHPathByID", {
id
}, (response) => {
if (!this.headElement.getAttribute("aria-label")) {
showTooltip(escapeGreat(response.data), this.headElement);
}
this.headElement.setAttribute("aria-label", escapeGreat(response.data));
});
}
});
this.headElement.addEventListener("dragstart", (event: DragEvent & { target: HTMLElement }) => {
if (isTouchDevice()) {
event.stopPropagation();
event.preventDefault();
return;
}
window.getSelection().removeAllRanges();
const tabElement = hasClosestByTag(event.target, "LI");
if (tabElement) {
event.dataTransfer.setData("text/html", tabElement.outerHTML);
const modeJSON = {id: this.id};
layoutToJSON(this, modeJSON);
event.dataTransfer.setData(Constants.SIYUAN_DROP_TAB, JSON.stringify(modeJSON));
event.dataTransfer.dropEffect = "move";
tabElement.style.opacity = "0.1";
window.siyuan.dragElement = this.headElement;
}
});
this.headElement.addEventListener("dragend", (event: DragEvent & { target: HTMLElement }) => {
const tabElement = hasClosestByTag(event.target, "LI");
if (tabElement) {
tabElement.style.opacity = "1";
document.querySelectorAll(".layout-tab-bar li[data-clone='true']").forEach((item) => {
item.remove();
});
}
/// #if !BROWSER
// 拖拽到屏幕外
setTimeout(() => {
if (document.body.contains(this.panelElement) &&
(event.clientX < 0 || event.clientY < 0 || event.clientX > window.innerWidth || event.clientY > window.innerHeight)) {
openNewWindow(this);
}
}, Constants.TIMEOUT_LOAD); // 等待主进程发送关闭消息
/// #endif
window.siyuan.dragElement = undefined;
if (event.dataTransfer.dropEffect === "none") {
// 按 esc 取消的时候应该还原在 dragover 时交换的 tab
this.parent.children.forEach((item, index) => {
const currentElement = this.headElement.parentElement.children[index];
if (!item.headElement.isSameNode(currentElement)) {
if (index === 0) {
this.headElement.parentElement.firstElementChild.before(item.headElement);
} else {
this.headElement.parentElement.children[index - 1].after(item.headElement);
}
}
});
}
});
}
this.panelElement = document.createElement("div");
this.panelElement.classList.add("fn__flex-1");
this.panelElement.innerHTML = options.panel || "";
this.panelElement.setAttribute("data-id", this.id);
}
public updateTitle(title: string) {
this.title = title;
this.headElement.querySelector(".item__text").innerHTML = escapeHtml(title);
}
public addModel(model: Model) {
this.model = model;
model.parent = this;
}
public pin() {
if (!this.headElement.previousElementSibling || (this.headElement.previousElementSibling && this.headElement.previousElementSibling.classList.contains("item--pin"))) {
// 如果是第一个,或者前一个是 pinned,则不处理
} else {
let tempTab: Tab;
let pinIndex = 0;
let lastHeadElement: Element;
this.parent.children.find((item, index) => {
if (item.headElement.classList.contains("item--pin")) {
pinIndex = index + 1;
lastHeadElement = item.headElement;
}
if (item.id === this.id) {
tempTab = this.parent.children.splice(index, 1)[0];
return true;
}
});
if (lastHeadElement) {
lastHeadElement.after(tempTab.headElement);
} else {
this.parent.children[0].headElement.before(tempTab.headElement);
}
this.parent.children.splice(pinIndex, 0, tempTab);
}
this.headElement.classList.add("item--pin");
if (this.docIcon || this.icon) {
this.headElement.querySelector(".item__text").classList.add("fn__none");
}
}
public setDocIcon(icon: string) {
this.docIcon = icon;
if (this.docIcon) {
const iconElement = this.headElement.querySelector(".item__icon");
if (iconElement) {
iconElement.innerHTML = unicode2Emoji(icon);
} else {
this.headElement.querySelector(".item__text").insertAdjacentHTML("beforebegin", `${unicode2Emoji(icon)}`);
}
if (this.headElement.classList.contains("item--pin")) {
this.headElement.querySelector(".item__text").classList.add("fn__none");
}
} else {
this.headElement.querySelector(".item__icon").remove();
this.headElement.querySelector(".item__text").classList.remove("fn__none");
}
}
public unpin() {
if (!this.headElement.nextElementSibling || (this.headElement.nextElementSibling && !this.headElement.nextElementSibling.classList.contains("item--pin"))) {
// 如果是最后一个,或者后一个是 unpinned,则不处理
} else {
let tempTab: Tab;
let pinIndex = 0;
let lastHeadElement: Element;
for (let index = 0; index < this.parent.children.length; index++) {
if (this.parent.children[index].id === this.id) {
tempTab = this.parent.children.splice(index, 1)[0];
index--;
}
if (index > -1 && this.parent.children[index].headElement.classList.contains("item--pin")) {
pinIndex = index + 1;
lastHeadElement = this.parent.children[index].headElement;
}
}
lastHeadElement.after(tempTab.headElement);
this.parent.children.splice(pinIndex, 0, tempTab);
}
this.headElement.classList.remove("item--pin");
if (this.docIcon || this.icon) {
this.headElement.querySelector(".item__text").classList.remove("fn__none");
}
}
public close() {
this.parent.removeTab(this.id);
}
}