mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-17 15:10:12 +01:00
Optimize attributeView image browsing (#14843)
This commit is contained in:
parent
b06cee76f8
commit
2b03a364af
7 changed files with 169 additions and 8 deletions
|
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import {openMenuPanel} from "./openMenuPanel";
|
||||||
import {hintRef} from "../../hint/extend";
|
import {hintRef} from "../../hint/extend";
|
||||||
import {focusBlock, focusByRange} from "../../util/selection";
|
import {focusBlock, focusByRange} from "../../util/selection";
|
||||||
import {showMessage} from "../../../dialog/message";
|
import {showMessage} from "../../../dialog/message";
|
||||||
import {previewImage} from "../../preview/image";
|
import {previewAttrViewImages} from "../../preview/image";
|
||||||
import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
|
import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
|
||||||
import * as dayjs from "dayjs";
|
import * as dayjs from "dayjs";
|
||||||
import {openCalcMenu} from "./calc";
|
import {openCalcMenu} from "./calc";
|
||||||
|
|
@ -64,7 +64,13 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
|
||||||
}
|
}
|
||||||
const imgElement = hasClosestByClassName(event.target, "av__cellassetimg");
|
const imgElement = hasClosestByClassName(event.target, "av__cellassetimg");
|
||||||
if (imgElement) {
|
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.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {openMenu} from "../../../menus/commonMenuItem";
|
||||||
import {MenuItem} from "../../../menus/Menu";
|
import {MenuItem} from "../../../menus/Menu";
|
||||||
import {copyPNGByLink, exportAsset} from "../../../menus/util";
|
import {copyPNGByLink, exportAsset} from "../../../menus/util";
|
||||||
import {setPosition} from "../../../util/setPosition";
|
import {setPosition} from "../../../util/setPosition";
|
||||||
import {previewImage} from "../../preview/image";
|
import {previewAttrViewImages} from "../../preview/image";
|
||||||
import {genAVValueHTML} from "./blockAttr";
|
import {genAVValueHTML} from "./blockAttr";
|
||||||
import {hideMessage, showMessage} from "../../../dialog/message";
|
import {hideMessage, showMessage} from "../../../dialog/message";
|
||||||
import {fetchPost} from "../../../util/fetch";
|
import {fetchPost} from "../../../util/fetch";
|
||||||
|
|
@ -338,8 +338,13 @@ export const editAssetItem = (options: {
|
||||||
icon: "iconPreview",
|
icon: "iconPreview",
|
||||||
label: window.siyuan.languages.cardPreview,
|
label: window.siyuan.languages.cardPreview,
|
||||||
click() {
|
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) {
|
if (openSubMenu.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {getSearch} from "../../../util/functions";
|
||||||
/// #if !MOBILE
|
/// #if !MOBILE
|
||||||
import {openAsset} from "../../../editor/util";
|
import {openAsset} from "../../../editor/util";
|
||||||
/// #endif
|
/// #endif
|
||||||
import {previewImage} from "../../preview/image";
|
import {previewAttrViewImages} from "../../preview/image";
|
||||||
import {assetMenu} from "../../../menus/protyle";
|
import {assetMenu} from "../../../menus/protyle";
|
||||||
import {addView, bindSwitcherEvent, bindViewEvent, getSwitcherHTML, getViewHTML, openViewMenu} from "./view";
|
import {addView, bindSwitcherEvent, bindViewEvent, getSwitcherHTML, getViewHTML, openViewMenu} from "./view";
|
||||||
import {focusBlock} from "../../util/selection";
|
import {focusBlock} from "../../util/selection";
|
||||||
|
|
@ -1259,13 +1259,22 @@ export const openMenuPanel = (options: {
|
||||||
)) {
|
)) {
|
||||||
openAsset(options.protyle.app, assetLink.trim(), parseInt(getSearch("page", assetLink)), "right");
|
openAsset(options.protyle.app, assetLink.trim(), parseInt(getSearch("page", assetLink)), "right");
|
||||||
} else if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
|
} 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 {
|
} else {
|
||||||
window.open(assetLink);
|
window.open(assetLink);
|
||||||
}
|
}
|
||||||
/// #else
|
/// #else
|
||||||
if (Constants.SIYUAN_ASSETS_IMAGE.includes(suffix)) {
|
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 {
|
} else {
|
||||||
window.open(assetLink);
|
window.open(assetLink);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
func getAttributeViewKeys(c *gin.Context) {
|
||||||
ret := gulu.Ret.NewResult()
|
ret := gulu.Ret.NewResult()
|
||||||
defer c.JSON(http.StatusOK, ret)
|
defer c.JSON(http.StatusOK, ret)
|
||||||
|
|
|
||||||
|
|
@ -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/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/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/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/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT)
|
||||||
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction)
|
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction)
|
||||||
|
|
|
||||||
|
|
@ -933,6 +933,45 @@ func renderAttributeView(attrView *av.AttributeView, viewID, query string, page,
|
||||||
return
|
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) {
|
func (tx *Transaction) doUnbindAttrViewBlock(operation *Operation) (ret *TxErr) {
|
||||||
err := unbindAttributeViewBlock(operation, tx)
|
err := unbindAttributeViewBlock(operation, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue