diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 227693847..ea074d250 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -579,8 +579,11 @@ export const avContextmenu = (protyle: IProtyle, rowElement: HTMLElement, positi sourceIds.push(rowId); }); const avID = listItemElement.dataset.avId; + const viewID = listItemElement.dataset.viewId; transaction(protyle, [{ action: "insertAttrViewBlock", + ignoreDefaultFill: viewID ? false : true, + viewID, avID, srcs, context: {ignoreTip: "true"}, diff --git a/app/src/protyle/render/av/addToDatabase.ts b/app/src/protyle/render/av/addToDatabase.ts index b89249034..ba258c2ad 100644 --- a/app/src/protyle/render/av/addToDatabase.ts +++ b/app/src/protyle/render/av/addToDatabase.ts @@ -19,8 +19,11 @@ export const addFilesToDatabase = (fileLiElements: Element[]) => { if (srcs.length > 0) { openSearchAV("", fileLiElements[0] as HTMLElement, (listItemElement) => { const avID = listItemElement.dataset.avId; + const viewID = listItemElement.dataset.viewId; transaction(undefined, [{ action: "insertAttrViewBlock", + ignoreDefaultFill: viewID ? false : true, + viewID, avID, srcs, blockID: listItemElement.dataset.blockId @@ -37,8 +40,11 @@ export const addEditorToDatabase = (protyle: IProtyle, range: Range, type?: stri if ((range && protyle.title?.editElement?.contains(range.startContainer)) || type === "title") { openSearchAV("", protyle.breadcrumb.element, (listItemElement) => { const avID = listItemElement.dataset.avId; + const viewID = listItemElement.dataset.viewId; transaction(protyle, [{ action: "insertAttrViewBlock", + ignoreDefaultFill: viewID ? false : true, + viewID, avID, srcs: [{ itemID: Lute.NewNodeID(), @@ -89,8 +95,11 @@ export const addEditorToDatabase = (protyle: IProtyle, range: Range, type?: stri }); }); const avID = listItemElement.dataset.avId; + const viewID = listItemElement.dataset.viewId; transaction(protyle, [{ action: "insertAttrViewBlock", + ignoreDefaultFill: viewID ? false : true, + viewID, avID, srcs, blockID: listItemElement.dataset.blockId diff --git a/app/src/protyle/render/av/relation.ts b/app/src/protyle/render/av/relation.ts index 401df9380..8292c7226 100644 --- a/app/src/protyle/render/av/relation.ts +++ b/app/src/protyle/render/av/relation.ts @@ -1,6 +1,6 @@ import {Menu} from "../../../plugin/Menu"; import {hasClosestByClassName, hasTopClosestByClassName} from "../../util/hasClosest"; -import {upDownHint} from "../../../util/upDownHint"; +import {UDLRHint, upDownHint} from "../../../util/upDownHint"; import {fetchPost} from "../../../util/fetch"; import {escapeGreat, escapeHtml} from "../../../util/escape"; import {transaction} from "../../wysiwyg/transaction"; @@ -12,6 +12,16 @@ import * as dayjs from "dayjs"; import {getFieldsByData} from "./view"; import {getColId} from "./col"; import {getFieldIdByCellElement} from "./row"; +import {isMobile} from "../../../util/functions"; + +interface IAVItem { + avID: string; + avName: string; + blockID: string; + hPath: string; + viewName: string; + viewID: string; +} const genSearchList = (element: Element, keyword: string, avId?: string, excludes = true, cb?: () => void) => { fetchPost("/api/av/searchAttributeView", { @@ -19,13 +29,13 @@ const genSearchList = (element: Element, keyword: string, avId?: string, exclude excludes: (excludes && avId) ? [avId] : undefined }, (response) => { let html = ""; - response.data.results.forEach((item: { - avID: string - avName: string - blockID: string - hPath: string - }, index: number) => { + response.data.results.forEach((item: IAVItem & { children: IAVItem[] }, index: number) => { + const hasChildren = item.children && item.children.length > 0 && excludes; html += `
+ + ${hasChildren ? '' : ""} + +
${escapeHtml(item.avName || window.siyuan.languages._kernel[267])} @@ -34,6 +44,16 @@ const genSearchList = (element: Element, keyword: string, avId?: string, exclude
`; + if (hasChildren) { + html += '
'; + item.children.forEach((subItem) => { + html += `
+${escapeHtml(subItem.avName || window.siyuan.languages._kernel[267])} +${escapeHtml(subItem.viewName)} +
`; + }); + html += "
"; + } }); element.innerHTML = html; if (cb) { @@ -58,7 +78,7 @@ export const openSearchAV = (avId: string, target: HTMLElement, cb?: (element: H menu.addItem({ iconHTML: "", type: "empty", - label: `
+ label: `
@@ -72,10 +92,7 @@ export const openSearchAV = (avId: string, target: HTMLElement, cb?: (element: H if (event.isComposing) { return; } - const currentElement = upDownHint(listElement, event); - if (currentElement) { - event.stopPropagation(); - } + UDLRHint(listElement, event); if (event.key === "Enter") { event.preventDefault(); event.stopPropagation(); @@ -99,15 +116,31 @@ export const openSearchAV = (avId: string, target: HTMLElement, cb?: (element: H genSearchList(listElement, inputElement.value, avId, excludes); }); element.lastElementChild.addEventListener("click", (event) => { - const listItemElement = hasClosestByClassName(event.target as HTMLElement, "b3-list-item"); - if (listItemElement) { - event.stopPropagation(); - if (cb) { - cb(listItemElement); - } else { - setDatabase(avId, target, listItemElement); + let clickTarget = event.target as HTMLElement; + while (clickTarget && !clickTarget.classList.contains("b3-list")) { + if (clickTarget.classList.contains("b3-list-item__toggle")) { + if (clickTarget.firstElementChild.classList.contains("b3-list-item__arrow--open")) { + clickTarget.firstElementChild.classList.remove("b3-list-item__arrow--open"); + clickTarget.parentElement.nextElementSibling.classList.add("fn__none"); + } else { + clickTarget.firstElementChild.classList.add("b3-list-item__arrow--open"); + clickTarget.parentElement.nextElementSibling.classList.remove("fn__none"); + } + event.preventDefault(); + event.stopPropagation(); + break; + } else if (clickTarget.classList.contains("b3-list-item")) { + event.preventDefault(); + event.stopPropagation(); + if (cb) { + cb(clickTarget); + } else { + setDatabase(avId, target, clickTarget); + } + window.siyuan.menus.menu.remove(); + break; } - window.siyuan.menus.menu.remove(); + clickTarget = clickTarget.parentElement; } }); genSearchList(listElement, "", avId, excludes, () => { diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index f62cf75bb..97708626f 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -547,6 +547,8 @@ interface IOperation { isDetached?: boolean // insertAttrViewBlock 专享 srcIDs?: string[] // removeAttrViewBlock 专享 srcs?: IOperationSrcs[] // insertAttrViewBlock 专享 + ignoreDefaultFill?: boolean // insertAttrViewBlock 专享 + viewID?: string // insertAttrViewBlock 专享 name?: string // addAttrViewCol 专享 type?: TAVCol // addAttrViewCol 专享 deckID?: string // add/removeFlashcards 专享 diff --git a/app/src/util/upDownHint.ts b/app/src/util/upDownHint.ts index 16522d288..0e6614b6e 100644 --- a/app/src/util/upDownHint.ts +++ b/app/src/util/upDownHint.ts @@ -95,3 +95,138 @@ export const upDownHint = (listElement: Element, event: KeyboardEvent, classActi return currentHintElement; } }; + +export const UDLRHint = (listElement: Element, event: KeyboardEvent, classActiveName = "b3-list-item--focus", defaultElement?: Element) => { + let currentHintElement: HTMLElement = listElement.querySelector("." + classActiveName); + if (!currentHintElement && defaultElement) { + defaultElement.classList.add(classActiveName); + defaultElement.scrollIntoView(true); + return; + } + if (!currentHintElement) { + return; + } + const className = classActiveName.split("--")[0]; + if (event.key === "ArrowLeft") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + if (currentHintElement.parentElement.classList.contains("b3-list")) { + if (currentHintElement.querySelector(".b3-list-item__arrow--open")) { + currentHintElement.querySelector(".b3-list-item__arrow--open").classList.remove("b3-list-item__arrow--open"); + currentHintElement.nextElementSibling.classList.add("fn__none"); + } else { + currentHintElement = listElement.firstElementChild as HTMLElement; + } + } else { + currentHintElement = currentHintElement.parentElement.previousElementSibling as HTMLElement; + } + currentHintElement.classList.add(classActiveName); + const overTop = listElement.scrollTop > currentHintElement.offsetTop - 46 - (currentHintElement.previousElementSibling?.clientHeight || 0); + if (listElement.scrollTop < currentHintElement.offsetTop - 46 - listElement.clientHeight + currentHintElement.clientHeight || overTop) { + currentHintElement.scrollIntoView(overTop); + } + return currentHintElement; + } else if (event.key === "ArrowRight") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + if (currentHintElement.parentElement.classList.contains("b3-list")) { + if (currentHintElement.querySelector(".b3-list-item__arrow--open")) { + currentHintElement = currentHintElement.nextElementSibling.firstElementChild as HTMLElement; + } else { + currentHintElement.querySelector(".b3-list-item__arrow").classList.add("b3-list-item__arrow--open"); + currentHintElement.nextElementSibling.classList.remove("fn__none"); + } + } else { + if (!currentHintElement.nextElementSibling) { + if (currentHintElement.parentElement.nextElementSibling) { + currentHintElement = currentHintElement.parentElement.nextElementSibling as HTMLElement; + } + } else { + currentHintElement = currentHintElement.nextElementSibling as HTMLElement; + } + } + currentHintElement.classList.add(classActiveName); + if (listElement.scrollTop < currentHintElement.offsetTop - 46 - listElement.clientHeight + currentHintElement.clientHeight || + listElement.scrollTop > currentHintElement.offsetTop - 46) { + currentHintElement.scrollIntoView(listElement.scrollTop > currentHintElement.offsetTop - 46); + } + return currentHintElement; + } else if (event.key === "ArrowDown") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + if (!currentHintElement.nextElementSibling) { + currentHintElement = currentHintElement.parentElement.nextElementSibling as HTMLElement || listElement.firstElementChild as HTMLElement; + } else { + currentHintElement = currentHintElement.nextElementSibling as HTMLElement; + if (!currentHintElement.classList.contains(className)) { + if (currentHintElement.classList.contains("fn__none")) { + currentHintElement = currentHintElement.nextElementSibling as HTMLElement; + if (!currentHintElement) { + currentHintElement = listElement.firstElementChild as HTMLElement; + } + } else { + currentHintElement = currentHintElement.firstElementChild as HTMLElement; + } + } + } + currentHintElement.classList.add(classActiveName); + if (listElement.scrollTop < currentHintElement.offsetTop - 46 - listElement.clientHeight + currentHintElement.clientHeight || + listElement.scrollTop > currentHintElement.offsetTop - 46) { + currentHintElement.scrollIntoView(listElement.scrollTop > currentHintElement.offsetTop - 46); + } + return currentHintElement; + } else if (event.key === "ArrowUp") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + if (!currentHintElement.previousElementSibling) { + if (currentHintElement.parentElement.classList.contains("b3-list")) { + if (listElement.lastElementChild.classList.contains("fn__none")) { + currentHintElement = listElement.lastElementChild.previousElementSibling as HTMLElement; + } else { + currentHintElement = listElement.lastElementChild.lastElementChild as HTMLElement; + } + } else { + currentHintElement = currentHintElement.parentElement.previousElementSibling as HTMLElement; + } + } else { + currentHintElement = currentHintElement.previousElementSibling as HTMLElement; + if (!currentHintElement.classList.contains(className)) { + if (currentHintElement.classList.contains("fn__none")) { + currentHintElement = currentHintElement.previousElementSibling as HTMLElement; + } else { + currentHintElement = currentHintElement.lastElementChild as HTMLElement; + } + } + } + currentHintElement.classList.add(classActiveName); + const overTop = listElement.scrollTop > currentHintElement.offsetTop - 46 - (currentHintElement.previousElementSibling?.clientHeight || 0); + if (listElement.scrollTop < currentHintElement.offsetTop - 46 - listElement.clientHeight + currentHintElement.clientHeight || overTop) { + currentHintElement.scrollIntoView(overTop); + } + return currentHintElement; + } else if (event.key === "Home") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + currentHintElement = listElement.children[0] as HTMLElement; + currentHintElement.classList.add(classActiveName); + currentHintElement.scrollIntoView(); + return currentHintElement; + } else if (event.key === "End") { + event.preventDefault(); + event.stopPropagation(); + currentHintElement.classList.remove(classActiveName); + if (listElement.lastElementChild.classList.contains("fn__none")) { + currentHintElement = listElement.lastElementChild.previousElementSibling as HTMLElement; + } else { + currentHintElement = listElement.lastElementChild.lastElementChild as HTMLElement; + } + currentHintElement.classList.add(classActiveName); + currentHintElement.scrollIntoView(false); + return currentHintElement; + } +};