Vanessa 2025-10-21 20:21:33 +08:00
parent 3f9e6d0eaa
commit 9dba5dbb4a

View file

@ -875,169 +875,128 @@ export class Outline extends Model {
const currentLevel = this.getHeadingLevel(element);
window.siyuan.menus.menu.remove();
window.siyuan.menus.menu.element.setAttribute("data-name", Constants.MENU_OUTLINE_CONTEXT);
// 升级
if (currentLevel > 1) {
window.siyuan.menus.menu.append(new MenuItem({
id: "upgrade",
icon: "iconUp",
label: window.siyuan.languages.upgrade,
click: () => {
const data = this.getProtyleAndBlockElement(element);
if (data) {
turnsIntoTransaction({
protyle: data.protyle,
selectsElement: [data.blockElement],
type: "Blocks2Hs",
level: currentLevel - 1
});
}
}
}).element);
}
// 降级
if (currentLevel < 6) {
window.siyuan.menus.menu.append(new MenuItem({
id: "downgrade",
icon: "iconDown",
label: window.siyuan.languages.downgrade,
click: () => {
const data = this.getProtyleAndBlockElement(element);
if (data) {
turnsIntoTransaction({
protyle: data.protyle,
selectsElement: [data.blockElement],
type: "Blocks2Hs",
level: currentLevel + 1
});
}
}
}).element);
}
// 带子标题转换
const id = element.getAttribute("data-node-id");
checkFold(id, (zoomIn) => {
openFileById({
app: this.app,
id,
action: zoomIn ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML, Constants.CB_GET_OUTLINE] : [Constants.CB_GET_FOCUS, Constants.CB_GET_OUTLINE, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML],
});
});
this.setCurrentById(id);
const headingSubMenu = [];
if (currentLevel !== 1) {
headingSubMenu.push(this.genHeadingTransform(id, 1));
}
if (currentLevel !== 2) {
headingSubMenu.push(this.genHeadingTransform(id, 2));
}
if (currentLevel !== 3) {
headingSubMenu.push(this.genHeadingTransform(id, 3));
}
if (currentLevel !== 4) {
headingSubMenu.push(this.genHeadingTransform(id, 4));
}
if (currentLevel !== 5) {
headingSubMenu.push(this.genHeadingTransform(id, 5));
}
if (currentLevel !== 6) {
headingSubMenu.push(this.genHeadingTransform(id, 6));
}
if (headingSubMenu.length > 0) {
window.siyuan.menus.menu.append(new MenuItem({
id: "tWithSubtitle",
type: "submenu",
icon: "iconRefresh",
label: window.siyuan.languages.tWithSubtitle,
submenu: headingSubMenu
}).element);
}
window.siyuan.menus.menu.append(new MenuItem({id: "separator_1", type: "separator"}).element);
// 在前面插入同级标题
window.siyuan.menus.menu.append(new MenuItem({
id: "insertSameLevelHeadingBefore",
icon: "iconBefore",
label: window.siyuan.languages.insertSameLevelHeadingBefore,
click: () => {
const data = this.getProtyleAndBlockElement(element);
const newId = Lute.NewNodeID();
const html = `<div data-subtype="h${currentLevel}" data-node-id="${newId}" data-type="NodeHeading" class="h${currentLevel}"><div contenteditable="true" spellcheck="false"><wbr></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div></div>`;
transaction(data.protyle, [{
action: "insert",
data: html,
id: newId,
previousID: data.blockElement.previousElementSibling?.getAttribute("data-node-id"),
parentID: data.blockElement.parentElement.getAttribute("data-node-id") || data.protyle.block.parentID,
}], [{
action: "delete",
id: newId
}]);
data.blockElement.insertAdjacentHTML("beforebegin", html);
data.blockElement.previousElementSibling.scrollIntoView();
focusByWbr(data.blockElement.previousElementSibling, document.createRange());
if (!window.siyuan.config.readonly) {
// 升级
if (currentLevel > 1) {
window.siyuan.menus.menu.append(new MenuItem({
id: "upgrade",
icon: "iconUp",
label: window.siyuan.languages.upgrade,
click: () => {
const data = this.getProtyleAndBlockElement(element);
if (data) {
turnsIntoTransaction({
protyle: data.protyle,
selectsElement: [data.blockElement],
type: "Blocks2Hs",
level: currentLevel - 1
});
}
}
}).element);
}
}).element);
// 在后面插入同级标题
window.siyuan.menus.menu.append(new MenuItem({
id: "insertSameLevelHeadingAfter",
icon: "iconAfter",
label: window.siyuan.languages.insertSameLevelHeadingAfter,
click: () => {
fetchPost("/api/block/getHeadingDeleteTransaction", {
// 降级
if (currentLevel < 6) {
window.siyuan.menus.menu.append(new MenuItem({
id: "downgrade",
icon: "iconDown",
label: window.siyuan.languages.downgrade,
click: () => {
const data = this.getProtyleAndBlockElement(element);
if (data) {
turnsIntoTransaction({
protyle: data.protyle,
selectsElement: [data.blockElement],
type: "Blocks2Hs",
level: currentLevel + 1
});
}
}
}).element);
}
// 带子标题转换
checkFold(id, (zoomIn) => {
openFileById({
app: this.app,
id,
}, (deleteResponse) => {
const data = this.getProtyleAndBlockElement(element);
const previousID = deleteResponse.data.doOperations[deleteResponse.data.doOperations.length - 1].id;
action: zoomIn ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL, Constants.CB_GET_HTML, Constants.CB_GET_OUTLINE] : [Constants.CB_GET_FOCUS, Constants.CB_GET_OUTLINE, Constants.CB_GET_SETID, Constants.CB_GET_CONTEXT, Constants.CB_GET_HTML],
});
});
this.setCurrentById(id);
const headingSubMenu = [];
if (currentLevel !== 1) {
headingSubMenu.push(this.genHeadingTransform(id, 1));
}
if (currentLevel !== 2) {
headingSubMenu.push(this.genHeadingTransform(id, 2));
}
if (currentLevel !== 3) {
headingSubMenu.push(this.genHeadingTransform(id, 3));
}
if (currentLevel !== 4) {
headingSubMenu.push(this.genHeadingTransform(id, 4));
}
if (currentLevel !== 5) {
headingSubMenu.push(this.genHeadingTransform(id, 5));
}
if (currentLevel !== 6) {
headingSubMenu.push(this.genHeadingTransform(id, 6));
}
if (headingSubMenu.length > 0) {
window.siyuan.menus.menu.append(new MenuItem({
id: "tWithSubtitle",
type: "submenu",
icon: "iconRefresh",
label: window.siyuan.languages.tWithSubtitle,
submenu: headingSubMenu
}).element);
}
window.siyuan.menus.menu.append(new MenuItem({id: "separator_1", type: "separator"}).element);
// 在前面插入同级标题
window.siyuan.menus.menu.append(new MenuItem({
id: "insertSameLevelHeadingBefore",
icon: "iconBefore",
label: window.siyuan.languages.insertSameLevelHeadingBefore,
click: () => {
const data = this.getProtyleAndBlockElement(element);
const newId = Lute.NewNodeID();
const html = `<div data-subtype="h${currentLevel}" data-node-id="${newId}" data-type="NodeHeading" class="h${currentLevel}"><div contenteditable="true" spellcheck="false"><wbr></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div></div>`;
transaction(data.protyle, [{
action: "insert",
data: html,
id: newId,
previousID,
previousID: data.blockElement.previousElementSibling?.getAttribute("data-node-id"),
parentID: data.blockElement.parentElement.getAttribute("data-node-id") || data.protyle.block.parentID,
}], [{
action: "delete",
id: newId
}]);
const previousElement = data.protyle.wysiwyg.element.querySelector(`[data-node-id="${previousID}"]`);
if (previousElement) {
previousElement.insertAdjacentHTML("afterend", html);
previousElement.nextElementSibling.scrollIntoView();
focusByWbr(previousElement.nextElementSibling, document.createRange());
}
});
}
}).element);
data.blockElement.insertAdjacentHTML("beforebegin", html);
data.blockElement.previousElementSibling.scrollIntoView();
focusByWbr(data.blockElement.previousElementSibling, document.createRange());
}
}).element);
// 添加子标题
if (currentLevel < 6) { // 只有当前级别小于6时才能添加子标题
// 在后面插入同级标题
window.siyuan.menus.menu.append(new MenuItem({
id: "addChildHeading",
icon: "iconAdd",
label: window.siyuan.languages.addChildHeading,
id: "insertSameLevelHeadingAfter",
icon: "iconAfter",
label: window.siyuan.languages.insertSameLevelHeadingAfter,
click: () => {
fetchPost("/api/block/getHeadingDeleteTransaction", {
id,
}, (deleteResponse) => {
let previousID = deleteResponse.data.doOperations[deleteResponse.data.doOperations.length - 1].id;
deleteResponse.data.undoOperations.find((operationsItem: IOperation, index: number) => {
const startIndex = operationsItem.data.indexOf(' data-subtype="h');
if (startIndex > -1 && startIndex < 260 && parseInt(operationsItem.data.substring(startIndex + 16, startIndex + 17)) === currentLevel + 1) {
previousID = deleteResponse.data.undoOperations[index - 1].id;
return true;
}
});
const data = this.getProtyleAndBlockElement(element);
const previousID = deleteResponse.data.doOperations[deleteResponse.data.doOperations.length - 1].id;
const newId = Lute.NewNodeID();
const html = `<div data-subtype="h${currentLevel + 1}" data-node-id="${newId}" data-type="NodeHeading" class="h${currentLevel + 1}"><div contenteditable="true" spellcheck="false"><wbr></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div></div>`;
const html = `<div data-subtype="h${currentLevel}" data-node-id="${newId}" data-type="NodeHeading" class="h${currentLevel}"><div contenteditable="true" spellcheck="false"><wbr></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div></div>`;
transaction(data.protyle, [{
action: "insert",
data: html,
@ -1056,9 +1015,52 @@ export class Outline extends Model {
});
}
}).element);
}
window.siyuan.menus.menu.append(new MenuItem({id: "separator_2", type: "separator"}).element);
// 添加子标题
if (currentLevel < 6) { // 只有当前级别小于6时才能添加子标题
window.siyuan.menus.menu.append(new MenuItem({
id: "addChildHeading",
icon: "iconAdd",
label: window.siyuan.languages.addChildHeading,
click: () => {
fetchPost("/api/block/getHeadingDeleteTransaction", {
id,
}, (deleteResponse) => {
let previousID = deleteResponse.data.doOperations[deleteResponse.data.doOperations.length - 1].id;
deleteResponse.data.undoOperations.find((operationsItem: IOperation, index: number) => {
const startIndex = operationsItem.data.indexOf(' data-subtype="h');
if (startIndex > -1 && startIndex < 260 && parseInt(operationsItem.data.substring(startIndex + 16, startIndex + 17)) === currentLevel + 1) {
previousID = deleteResponse.data.undoOperations[index - 1].id;
return true;
}
});
const data = this.getProtyleAndBlockElement(element);
const newId = Lute.NewNodeID();
const html = `<div data-subtype="h${currentLevel + 1}" data-node-id="${newId}" data-type="NodeHeading" class="h${currentLevel + 1}"><div contenteditable="true" spellcheck="false"><wbr></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div></div>`;
transaction(data.protyle, [{
action: "insert",
data: html,
id: newId,
previousID,
}], [{
action: "delete",
id: newId
}]);
const previousElement = data.protyle.wysiwyg.element.querySelector(`[data-node-id="${previousID}"]`);
if (previousElement) {
previousElement.insertAdjacentHTML("afterend", html);
previousElement.nextElementSibling.scrollIntoView();
focusByWbr(previousElement.nextElementSibling, document.createRange());
}
});
}
}).element);
}
window.siyuan.menus.menu.append(new MenuItem({id: "separator_2", type: "separator"}).element);
}
// 复制带子标题
window.siyuan.menus.menu.append(new MenuItem({
@ -1082,28 +1084,66 @@ export class Outline extends Model {
}
}).element);
// 剪切带子标题
window.siyuan.menus.menu.append(new MenuItem({
id: "cutHeadings1",
icon: "iconCut",
label: `${window.siyuan.languages.cut} ${window.siyuan.languages.headings1}`,
click: () => {
const data = this.getProtyleAndBlockElement(element);
fetchPost("/api/block/getHeadingChildrenDOM", {
id,
removeFoldAttr: data.blockElement.getAttribute("fold") !== "1"
}, (response) => {
if (isInAndroid()) {
window.JSAndroid.writeHTMLClipboard(data.protyle.lute.BlockDOM2StdMd(response.data).trimEnd(), response.data + Constants.ZWSP);
} else if (isInHarmony()) {
window.JSHarmony.writeHTMLClipboard(data.protyle.lute.BlockDOM2StdMd(response.data).trimEnd(), response.data + Constants.ZWSP);
} else {
writeText(response.data + Constants.ZWSP);
}
if (!window.siyuan.config.readonly) {
// 剪切带子标题
window.siyuan.menus.menu.append(new MenuItem({
id: "cutHeadings1",
icon: "iconCut",
label: `${window.siyuan.languages.cut} ${window.siyuan.languages.headings1}`,
click: () => {
const data = this.getProtyleAndBlockElement(element);
fetchPost("/api/block/getHeadingChildrenDOM", {
id,
removeFoldAttr: data.blockElement.getAttribute("fold") !== "1"
}, (response) => {
if (isInAndroid()) {
window.JSAndroid.writeHTMLClipboard(data.protyle.lute.BlockDOM2StdMd(response.data).trimEnd(), response.data + Constants.ZWSP);
} else if (isInHarmony()) {
window.JSHarmony.writeHTMLClipboard(data.protyle.lute.BlockDOM2StdMd(response.data).trimEnd(), response.data + Constants.ZWSP);
} else {
writeText(response.data + Constants.ZWSP);
}
fetchPost("/api/block/getHeadingDeleteTransaction", {
id,
}, (deleteResponse) => {
deleteResponse.data.doOperations.forEach((operation: IOperation) => {
data.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${operation.id}"]`).forEach((itemElement: HTMLElement) => {
itemElement.remove();
});
});
if (data.protyle.wysiwyg.element.childElementCount === 0) {
const newID = Lute.NewNodeID();
const emptyElement = genEmptyElement(false, false, newID);
data.protyle.wysiwyg.element.insertAdjacentElement("afterbegin", emptyElement);
deleteResponse.data.doOperations.push({
action: "insert",
data: emptyElement.outerHTML,
id: newID,
parentID: data.protyle.block.parentID
});
deleteResponse.data.undoOperations.push({
action: "delete",
id: newID,
});
focusBlock(emptyElement);
}
transaction(data.protyle, deleteResponse.data.doOperations, deleteResponse.data.undoOperations);
});
});
}
}).element);
// 删除
window.siyuan.menus.menu.append(new MenuItem({
id: "deleteHeadings1",
icon: "iconTrashcan",
label: `${window.siyuan.languages.delete} ${window.siyuan.languages.headings1}`,
click: () => {
const data = this.getProtyleAndBlockElement(element);
fetchPost("/api/block/getHeadingDeleteTransaction", {
id,
}, (deleteResponse) => {
deleteResponse.data.doOperations.forEach((operation: IOperation) => {
}, (response) => {
response.data.doOperations.forEach((operation: IOperation) => {
data.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${operation.id}"]`).forEach((itemElement: HTMLElement) => {
itemElement.remove();
});
@ -1112,60 +1152,23 @@ export class Outline extends Model {
const newID = Lute.NewNodeID();
const emptyElement = genEmptyElement(false, false, newID);
data.protyle.wysiwyg.element.insertAdjacentElement("afterbegin", emptyElement);
deleteResponse.data.doOperations.push({
response.data.doOperations.push({
action: "insert",
data: emptyElement.outerHTML,
id: newID,
parentID: data.protyle.block.parentID
});
deleteResponse.data.undoOperations.push({
response.data.undoOperations.push({
action: "delete",
id: newID,
});
focusBlock(emptyElement);
}
transaction(data.protyle, deleteResponse.data.doOperations, deleteResponse.data.undoOperations);
transaction(data.protyle, response.data.doOperations, response.data.undoOperations);
});
});
}
}).element);
// 删除
window.siyuan.menus.menu.append(new MenuItem({
id: "deleteHeadings1",
icon: "iconTrashcan",
label: `${window.siyuan.languages.delete} ${window.siyuan.languages.headings1}`,
click: () => {
const data = this.getProtyleAndBlockElement(element);
fetchPost("/api/block/getHeadingDeleteTransaction", {
id,
}, (response) => {
response.data.doOperations.forEach((operation: IOperation) => {
data.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${operation.id}"]`).forEach((itemElement: HTMLElement) => {
itemElement.remove();
});
});
if (data.protyle.wysiwyg.element.childElementCount === 0) {
const newID = Lute.NewNodeID();
const emptyElement = genEmptyElement(false, false, newID);
data.protyle.wysiwyg.element.insertAdjacentElement("afterbegin", emptyElement);
response.data.doOperations.push({
action: "insert",
data: emptyElement.outerHTML,
id: newID,
parentID: data.protyle.block.parentID
});
response.data.undoOperations.push({
action: "delete",
id: newID,
});
focusBlock(emptyElement);
}
transaction(data.protyle, response.data.doOperations, response.data.undoOperations);
});
}
}).element);
}
}).element);
}
window.siyuan.menus.menu.append(new MenuItem({id: "separator_3", type: "separator"}).element);
// 展开子标题