Optimize attributeView image browsing (#14843)

This commit is contained in:
Jiangshuon 2025-05-18 11:31:22 +08:00 committed by GitHub
parent b06cee76f8
commit 2b03a364af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 169 additions and 8 deletions

View file

@ -92,3 +92,60 @@ export const previewDocImage = (src: string, id: string) => {
});
});
};
export const previewAttrViewImages = (src: string, avID: string,viewID: string,query?:string,pageSize?: number) => {
addScript(`${Constants.PROTYLE_CDN}/js/viewerjs/viewer.js?v=1.11.7`, "protyleViewerScript").then(() => {
fetchPost("/api/av/getCurrentAttrViewImages", {
id: avID,
query: query,
pageSize: pageSize,
viewID: viewID
}, (response) => {
const imagesElement = document.createElement("ul");
let html = "";
let initialViewIndex = -1;
response.data.forEach((item: string, index: number) => {
if (item) {
html += `<li><img src="${item}"></li>`;
if (initialViewIndex === -1 && (src.endsWith(encodeURI(item)) || src.endsWith(item))) {
initialViewIndex = index;
}
}
});
imagesElement.innerHTML = html;
window.siyuan.viewer = new Viewer(imagesElement, {
title: [1, (image: HTMLImageElement, imageData: IObject) => {
let name = image.alt;
if (!name) {
name = image.src.substring(image.src.lastIndexOf("/") + 1);
}
name = name.substring(0, name.lastIndexOf(".")).replace(/-\d{14}-\w{7}$/, "");
return `${name} [${imageData.naturalWidth} × ${imageData.naturalHeight}]`;
}],
button: false,
initialViewIndex,
transition: false,
hidden: function () {
window.siyuan.viewer.destroy();
},
toolbar: {
zoomIn: true,
zoomOut: true,
oneToOne: true,
reset: true,
prev: true,
play: true,
next: true,
rotateLeft: true,
rotateRight: true,
flipHorizontal: true,
flipVertical: true,
close: function () {
window.siyuan.viewer.destroy();
},
},
});
window.siyuan.viewer.show();
});
});
};

View file

@ -21,7 +21,7 @@ import {openMenuPanel} from "./openMenuPanel";
import {hintRef} from "../../hint/extend";
import {focusBlock, focusByRange} from "../../util/selection";
import {showMessage} from "../../../dialog/message";
import {previewImage} from "../../preview/image";
import {previewAttrViewImages} from "../../preview/image";
import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
import * as dayjs from "dayjs";
import {openCalcMenu} from "./calc";
@ -64,7 +64,13 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
}
const imgElement = hasClosestByClassName(event.target, "av__cellassetimg");
if (imgElement) {
previewImage((imgElement as HTMLImageElement).src);
previewAttrViewImages(
(imgElement as HTMLImageElement).src,
blockElement.getAttribute("data-av-id"),
blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
(blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "",
parseInt(blockElement.dataset.pageSize) || undefined
);
event.preventDefault();
event.stopPropagation();
return true;

View file

@ -9,7 +9,7 @@ import {openMenu} from "../../../menus/commonMenuItem";
import {MenuItem} from "../../../menus/Menu";
import {copyPNGByLink, exportAsset} from "../../../menus/util";
import {setPosition} from "../../../util/setPosition";
import {previewImage} from "../../preview/image";
import {previewAttrViewImages} from "../../preview/image";
import {genAVValueHTML} from "./blockAttr";
import {hideMessage, showMessage} from "../../../dialog/message";
import {fetchPost} from "../../../util/fetch";
@ -338,8 +338,13 @@ export const editAssetItem = (options: {
icon: "iconPreview",
label: window.siyuan.languages.cardPreview,
click() {
previewImage(linkAddress);
}
previewAttrViewImages(
linkAddress,
options.blockElement.getAttribute("data-av-id"),
options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
(options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "",
parseInt(options.blockElement.getAttribute("data-page-size")) || undefined
)}
});
}
if (openSubMenu.length > 0) {

View file

@ -18,7 +18,7 @@ import {getSearch} from "../../../util/functions";
/// #if !MOBILE
import {openAsset} from "../../../editor/util";
/// #endif
import {previewImage} from "../../preview/image";
import {previewAttrViewImages} from "../../preview/image";
import {assetMenu} from "../../../menus/protyle";
import {addView, bindSwitcherEvent, bindViewEvent, getSwitcherHTML, getViewHTML, openViewMenu} from "./view";
import {focusBlock} from "../../util/selection";
@ -1259,13 +1259,22 @@ export const openMenuPanel = (options: {
)) {
openAsset(options.protyle.app, assetLink.trim(), parseInt(getSearch("page", assetLink)), "right");
} else if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
previewImage(assetLink);
previewAttrViewImages(assetLink,avID,
options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
(options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "",
parseInt(options.blockElement.getAttribute("data-page-size")) || undefined
)
} else {
window.open(assetLink);
}
/// #else
if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
previewImage(assetLink);
previewAttrViewImages(assetLink,avID,
options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW),
(options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement)?.value.trim() || "",
parseInt(options.blockElement.getAttribute("data-page-size")) || undefined
)
} else {
window.open(assetLink);
}

View file

@ -600,6 +600,49 @@ func renderAttributeView(c *gin.Context) {
}
}
func getCurrentAttrViewImages(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}
id := arg["id"].(string)
viewIDArg := arg["viewID"]
var viewID string
if nil != viewIDArg {
viewID = viewIDArg.(string)
}
page := 1
pageArg := arg["page"]
if nil != pageArg {
page = int(pageArg.(float64))
}
pageSize := -1
pageSizeArg := arg["pageSize"]
if nil != pageSizeArg {
pageSize = int(pageSizeArg.(float64))
}
query := ""
queryArg := arg["query"]
if nil != queryArg {
query = queryArg.(string)
}
images, err := model.GetCurrentAttributeViewImages(id, viewID, query, page, pageSize)
if err != nil {
ret.Code = -1
ret.Msg = err.Error()
return
}
ret.Data = images
}
func getAttributeViewKeys(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -452,6 +452,8 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/av/getAttributeViewKeysByAvID", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getAttributeViewKeysByAvID)
ginServer.Handle("POST", "/api/av/duplicateAttributeViewBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, duplicateAttributeViewBlock)
ginServer.Handle("POST", "/api/av/appendAttributeViewDetachedBlocksWithValues", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, appendAttributeViewDetachedBlocksWithValues)
ginServer.Handle("POST", "/api/av/getCurrentAttrViewImages", model.CheckAuth, getCurrentAttrViewImages)
ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT)
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction)

View file

@ -933,6 +933,45 @@ func renderAttributeView(attrView *av.AttributeView, viewID, query string, page,
return
}
func GetCurrentAttributeViewImages(avID, viewID, query string, page, pageSize int) (ret []string, err error) {
var attrView *av.AttributeView
attrView, err = av.ParseAttributeView(avID)
if err != nil {
logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
return
}
var view *av.View
if "" != viewID {
view, _ = attrView.GetCurrentView(viewID)
} else {
view = attrView.GetView(attrView.ViewID)
}
table := sql.RenderAttributeViewTable(attrView, view, query)
table.FilterRows(attrView)
table.SortRows(attrView)
for _, row := range table.Rows {
for _, cell := range row.Cells {
if nil != cell.Value {
if av.KeyTypeMAsset == cell.Value.Type {
if nil != cell.Value.MAsset {
for _, a := range cell.Value.MAsset {
if av.AssetTypeImage == a.Type {
ret = append(ret, a.Content)
}
}
}
}
}
}
}
return
}
func (tx *Transaction) doUnbindAttrViewBlock(operation *Operation) (ret *TxErr) {
err := unbindAttributeViewBlock(operation, tx)
if err != nil {