Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
e014b02478
23 changed files with 121 additions and 82 deletions
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Wenn die Datenmenge groß ist, wird die erste Synchronisation langsam sein. Bitte haben Sie Geduld<br>Wechseln Sie nicht zwischen Apps und halten Sie den Bildschirm während der Synchronisation des iOS/iPad hell.",
|
||||
"copyPlainText": "Reinen Text kopieren",
|
||||
"findInDoc": "Übereinstimmungen ${y} Blöcke in ${x} Dokumenten",
|
||||
"matchDoc": "${x} Dokumente gefunden",
|
||||
"jumpToParentNext": "Springen Sie zum nächsten Block des übergeordneten Blocks",
|
||||
"jumpToParentPrev": "Springen Sie zum vorherigen Block des übergeordneten Blocks",
|
||||
"jumpToParent": "Springe zu übergeordnetem Block",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "If the amount of data is large, the first sync will be slow, please wait patiently<br>Do not switch apps and keep the screen bright while the iOS/iPad is syncing",
|
||||
"copyPlainText": "Copy plain text",
|
||||
"findInDoc": "Matches ${y} blocks in ${x} documents",
|
||||
"matchDoc": "Matched ${x} documents",
|
||||
"jumpToParentNext": "Jump to the next block of the parent block",
|
||||
"jumpToParentPrev": "Jump to the previous block of the parent block",
|
||||
"jumpToParent": "Jump to parent block",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Si la cantidad de datos es grande, la primera sincronización será lenta, espere pacientemente<br>No cambie de aplicación y mantenga la pantalla brillante mientras iOS/iPad se sincroniza",
|
||||
"copyPlainText": "Copiar texto sin formato",
|
||||
"findInDoc": "Coincide con bloques ${y} en documentos ${x}",
|
||||
"matchDoc": "Se encontraron ${x} documentos",
|
||||
"jumpToParentNext": "Saltar al siguiente bloque del bloque principal",
|
||||
"jumpToParentPrev": "Saltar al bloque anterior del bloque principal",
|
||||
"jumpToParent": "Saltar al bloque principal",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Si la quantité de données est importante, la première synchronisation sera lente, veuillez patienter<br> Ne changez pas d'application et gardez l'écran lumineux pendant la synchronisation de l'iOS/iPad",
|
||||
"copyPlainText": "Copier du texte brut",
|
||||
"findInDoc": "Correspond à ${y} blocs dans ${x} documents",
|
||||
"matchDoc": "${x} documents trouvés",
|
||||
"jumpToParentNext": "Sauter au bloc suivant du bloc parent",
|
||||
"jumpToParentPrev": "Sauter au bloc précédent du bloc parent",
|
||||
"jumpToParent": "Sauter au bloc parent",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "אם הכמות של הנתונים גבוהה, הסנכרון הראשון יתקשח, אנא חכה בסבלנות<br>אל תחליף אפליקציות ושמור על המסך מואר בזמן שמכשירי iOS/iPad בתהליך סנכרון",
|
||||
"copyPlainText": "העתק טקסט פשוט",
|
||||
"findInDoc": "התאמות ${y} בלוקים ב${x} מסמכים",
|
||||
"matchDoc": "נמצאו ${x} מסמכים",
|
||||
"jumpToParentNext": "קפוץ לבלוק הבא של הבלוק ההורה",
|
||||
"jumpToParentPrev": "קפוץ לבלוק הקודם של הבלוק ההורה",
|
||||
"jumpToParent": "קפוץ לבלוק ההורה",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Se la quantità di dati è grande, la prima sincronizzazione sarà lenta, si prega di aspettare con pazienza<br>Non passare ad altre app e mantieni lo schermo acceso mentre si sincronizza su iOS/iPad",
|
||||
"copyPlainText": "Copia testo semplice",
|
||||
"findInDoc": "Corrispondenze ${y} blocchi in ${x} documenti",
|
||||
"matchDoc": "Trovati ${x} documenti",
|
||||
"jumpToParentNext": "Salta al blocco successivo del blocco genitore",
|
||||
"jumpToParentPrev": "Salta al blocco precedente del blocco genitore",
|
||||
"jumpToParent": "Salta al blocco genitore",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "データ量が多い場合は最初の同期が遅くなる場合がありますのでしばらくお待ちください。<br>iOS/iPad で同期している間はアプリを切り替えず画面を明るく保ってください",
|
||||
"copyPlainText": "プレーンテキストとしてコピー",
|
||||
"findInDoc": "${x} 個のドキュメントの ${y} ブロックと一致します",
|
||||
"matchDoc": "${x} 件のドキュメントが見つかりました",
|
||||
"jumpToParentNext": "次の親ブロックへ移動",
|
||||
"jumpToParentPrev": "前の親ブロックへ移動",
|
||||
"jumpToParent": "親ブロックへ移動",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Jeśli ilość danych jest duża, pierwsza synchronizacja będzie wolna, proszę czekać cierpliwie<br>Nie przełączaj aplikacji i utrzymuj ekran włączony, podczas synchronizacji iOS/iPad",
|
||||
"copyPlainText": "Kopiuj tekst zwykły",
|
||||
"findInDoc": "Zgadza się ${y} bloków w ${x} dokumentach",
|
||||
"matchDoc": "Znaleziono ${x} dokumentów",
|
||||
"jumpToParentNext": "Przejdź do następnego bloku rodzica",
|
||||
"jumpToParentPrev": "Przejdź do poprzedniego bloku rodzica",
|
||||
"jumpToParent": "Przejdź do bloku rodzica",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "Если объем данных большой, первая синхронизация будет медленной, пожалуйста, ожидайте терпеливо<br>Не переключайте приложения и поддерживайте экран ярким, пока iOS/iPad синхронизирует",
|
||||
"copyPlainText": "Скопировать обычный текст",
|
||||
"findInDoc": "Соответствует ${y} блокам в ${x} документах",
|
||||
"matchDoc": "Найдено ${x} документов",
|
||||
"jumpToParentNext": "Перейти к следующему блоку родительского блока",
|
||||
"jumpToParentPrev": "Перейти к предыдущему блоку родительского блока",
|
||||
"jumpToParent": "Перейти к родительскому блоку",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "如果資料量較大,第一次同步會比較慢,請耐心等待<br>iOS/iPad 端在同步時請勿切換應用並保持螢幕恆亮",
|
||||
"copyPlainText": "複製純文字",
|
||||
"findInDoc": "${x} 個文件中符合 ${y} 個塊",
|
||||
"matchDoc": "匹配到 ${x} 個文檔",
|
||||
"jumpToParentNext": "跳到父塊的下一個塊",
|
||||
"jumpToParentPrev": "跳到父塊的上一個塊",
|
||||
"jumpToParent": "跳到父塊",
|
||||
|
|
|
@ -531,6 +531,7 @@
|
|||
"syncConfGuide5": "如果数据量较大,第一次同步会比较慢,请耐心等待<br>iOS/iPad 端在同步时请勿切换应用并保持亮屏",
|
||||
"copyPlainText": "复制纯文本",
|
||||
"findInDoc": "${x} 个文档中匹配 ${y} 个块",
|
||||
"matchDoc": "匹配到 ${x} 个文档",
|
||||
"jumpToParentNext": "跳转到父块的下一个块",
|
||||
"jumpToParentPrev": "跳转到父块的上一个块",
|
||||
"jumpToParent": "跳转到父块",
|
||||
|
|
|
@ -17,7 +17,9 @@ import {
|
|||
progressBackgroundTask,
|
||||
progressLoading,
|
||||
progressStatus,
|
||||
reloadSync, setDefRefCount, setRefDynamicText,
|
||||
reloadSync,
|
||||
setDefRefCount,
|
||||
setRefDynamicText,
|
||||
setTitle,
|
||||
transactionError
|
||||
} from "./dialog/processSystem";
|
||||
|
@ -166,6 +168,7 @@ export class App {
|
|||
addScriptSync(`${Constants.PROTYLE_CDN}/js/lute/lute.min.js?v=${Constants.SIYUAN_VERSION}`, "protyleLuteScript");
|
||||
addScript(`${Constants.PROTYLE_CDN}/js/protyle-html.js?v=${Constants.SIYUAN_VERSION}`, "protyleWcHtmlScript");
|
||||
window.siyuan.config = response.data.conf;
|
||||
window.siyuan.isPublish = response.data.isPublish;
|
||||
await loadPlugins(this);
|
||||
getLocalStorage(() => {
|
||||
fetchGet(`/appearance/langs/${window.siyuan.config.appearance.lang}.json?v=${Constants.SIYUAN_VERSION}`, (lauguages: IObject) => {
|
||||
|
|
|
@ -446,6 +446,9 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme
|
|||
};
|
||||
|
||||
export const exportMd = (id: string) => {
|
||||
if (window.siyuan.isPublish) {
|
||||
return;
|
||||
}
|
||||
return new MenuItem({
|
||||
id: "export",
|
||||
label: window.siyuan.languages.export,
|
||||
|
|
|
@ -97,6 +97,7 @@ class App {
|
|||
addScriptSync(`${Constants.PROTYLE_CDN}/js/lute/lute.min.js?v=${Constants.SIYUAN_VERSION}`, "protyleLuteScript");
|
||||
addScript(`${Constants.PROTYLE_CDN}/js/protyle-html.js?v=${Constants.SIYUAN_VERSION}`, "protyleWcHtmlScript");
|
||||
window.siyuan.config = confResponse.data.conf;
|
||||
window.siyuan.isPublish = confResponse.data.isPublish;
|
||||
correctHotkey(siyuanApp);
|
||||
await loadPlugins(this);
|
||||
getLocalStorage(() => {
|
||||
|
|
|
@ -204,7 +204,11 @@ ${unicode2Emoji(childItem.ial.icon, "b3-list-item__graphic", true)}
|
|||
listElement.scrollTop = 0;
|
||||
let countHTML = "";
|
||||
if (response) {
|
||||
countHTML = `<span class="fn__flex-center">${window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount)}</span>
|
||||
let text = window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount);
|
||||
if (response.data.docMode) {
|
||||
text = window.siyuan.languages.matchDoc.replace("${x}", response.data.matchedRootCount);
|
||||
}
|
||||
countHTML = `<span class="fn__flex-center">${text}</span>
|
||||
<span class="fn__flex-1"></span>
|
||||
<span class="fn__flex-center">${config.page}/${response.data.pageCount || 1}</span>`;
|
||||
}
|
||||
|
|
|
@ -1367,8 +1367,12 @@ export const inputEvent = (element: Element, config: Config.IUILayoutTabSearchCo
|
|||
nextElement.setAttribute("disabled", "disabled");
|
||||
}
|
||||
onSearch(response.data.blocks, edit, element, config);
|
||||
let text = window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount);
|
||||
if (response.data.docMode) {
|
||||
text = window.siyuan.languages.matchDoc.replace("${x}", response.data.matchedRootCount);
|
||||
}
|
||||
searchResultElement.innerHTML = `${config.page}/${response.data.pageCount || 1}<span class="fn__space"></span>
|
||||
<span class="ft__on-surface">${window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount)}</span>`;
|
||||
<span class="ft__on-surface">${text}</span>`;
|
||||
loadingElement.classList.add("fn__none");
|
||||
searchResultElement.setAttribute("data-pagecount", response.data.pageCount || 1);
|
||||
});
|
||||
|
|
6
app/src/types/index.d.ts
vendored
6
app/src/types/index.d.ts
vendored
|
@ -432,7 +432,11 @@ interface ISiyuan {
|
|||
bookmarkLabel?: string[]
|
||||
blockPanels: import("../block/Panel").BlockPanel[],
|
||||
dialogs: import("../dialog").Dialog[],
|
||||
viewer?: Viewer
|
||||
viewer?: Viewer,
|
||||
/**
|
||||
* 是否在发布服务下访问
|
||||
*/
|
||||
isPublish?: boolean;
|
||||
}
|
||||
|
||||
interface IOperation {
|
||||
|
|
|
@ -9,9 +9,13 @@ import {fetchGet, fetchPost} from "../util/fetch";
|
|||
import {addBaseURL, setNoteBook} from "../util/pathName";
|
||||
import {openFileById} from "../editor/util";
|
||||
import {
|
||||
processSync, progressBackgroundTask,
|
||||
processSync,
|
||||
progressBackgroundTask,
|
||||
progressLoading,
|
||||
progressStatus, reloadSync, setDefRefCount, setRefDynamicText,
|
||||
progressStatus,
|
||||
reloadSync,
|
||||
setDefRefCount,
|
||||
setRefDynamicText,
|
||||
setTitle,
|
||||
transactionError
|
||||
} from "../dialog/processSystem";
|
||||
|
@ -151,6 +155,7 @@ class App {
|
|||
addScriptSync(`${Constants.PROTYLE_CDN}/js/lute/lute.min.js?v=${Constants.SIYUAN_VERSION}`, "protyleLuteScript");
|
||||
addScript(`${Constants.PROTYLE_CDN}/js/protyle-html.js?v=${Constants.SIYUAN_VERSION}`, "protyleWcHtmlScript");
|
||||
window.siyuan.config = response.data.conf;
|
||||
window.siyuan.isPublish = response.data.isPublish;
|
||||
await loadPlugins(this);
|
||||
getLocalStorage(() => {
|
||||
fetchGet(`/appearance/langs/${window.siyuan.config.appearance.lang}.json?v=${Constants.SIYUAN_VERSION}`, (lauguages: IObject) => {
|
||||
|
|
|
@ -90,7 +90,7 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
ginServer.Handle("POST", "/api/notebook/renameNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameNotebook)
|
||||
ginServer.Handle("POST", "/api/notebook/changeSortNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, changeSortNotebook)
|
||||
ginServer.Handle("POST", "/api/notebook/setNotebookIcon", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNotebookIcon)
|
||||
ginServer.Handle("POST", "/api/notebook/getNotebookInfo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getNotebookInfo)
|
||||
ginServer.Handle("POST", "/api/notebook/getNotebookInfo", model.CheckAuth, model.CheckReadonly, getNotebookInfo)
|
||||
|
||||
ginServer.Handle("POST", "/api/filetree/searchDocs", model.CheckAuth, searchDocs)
|
||||
ginServer.Handle("POST", "/api/filetree/listDocsByPath", model.CheckAuth, listDocsByPath)
|
||||
|
@ -276,33 +276,33 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
ginServer.Handle("POST", "/api/asset/fullReindexAssetContent", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, fullReindexAssetContent)
|
||||
ginServer.Handle("POST", "/api/asset/statAsset", model.CheckAuth, model.CheckAdminRole, statAsset)
|
||||
|
||||
ginServer.Handle("POST", "/api/export/batchExportMd", model.CheckAuth, batchExportMd)
|
||||
ginServer.Handle("POST", "/api/export/exportMd", model.CheckAuth, exportMd)
|
||||
ginServer.Handle("POST", "/api/export/exportSY", model.CheckAuth, exportSY)
|
||||
ginServer.Handle("POST", "/api/export/exportNotebookSY", model.CheckAuth, exportNotebookSY)
|
||||
ginServer.Handle("POST", "/api/export/exportMdContent", model.CheckAuth, exportMdContent)
|
||||
ginServer.Handle("POST", "/api/export/exportHTML", model.CheckAuth, exportHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportPreviewHTML", model.CheckAuth, exportPreviewHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportMdHTML", model.CheckAuth, exportMdHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportDocx", model.CheckAuth, exportDocx)
|
||||
ginServer.Handle("POST", "/api/export/processPDF", model.CheckAuth, processPDF)
|
||||
ginServer.Handle("POST", "/api/export/batchExportMd", model.CheckAuth, model.CheckAdminRole, batchExportMd)
|
||||
ginServer.Handle("POST", "/api/export/exportMd", model.CheckAuth, model.CheckAdminRole, exportMd)
|
||||
ginServer.Handle("POST", "/api/export/exportSY", model.CheckAuth, model.CheckAdminRole, exportSY)
|
||||
ginServer.Handle("POST", "/api/export/exportNotebookSY", model.CheckAuth, model.CheckAdminRole, exportNotebookSY)
|
||||
ginServer.Handle("POST", "/api/export/exportMdContent", model.CheckAuth, model.CheckAdminRole, exportMdContent)
|
||||
ginServer.Handle("POST", "/api/export/exportHTML", model.CheckAuth, model.CheckAdminRole, exportHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportPreviewHTML", model.CheckAuth, model.CheckAdminRole, exportPreviewHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportMdHTML", model.CheckAuth, model.CheckAdminRole, exportMdHTML)
|
||||
ginServer.Handle("POST", "/api/export/exportDocx", model.CheckAuth, model.CheckAdminRole, exportDocx)
|
||||
ginServer.Handle("POST", "/api/export/processPDF", model.CheckAuth, model.CheckAdminRole, processPDF)
|
||||
ginServer.Handle("POST", "/api/export/preview", model.CheckAuth, exportPreview)
|
||||
ginServer.Handle("POST", "/api/export/exportResources", model.CheckAuth, exportResources)
|
||||
ginServer.Handle("POST", "/api/export/exportAsFile", model.CheckAuth, exportAsFile)
|
||||
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, exportData)
|
||||
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, exportDataInFolder)
|
||||
ginServer.Handle("POST", "/api/export/exportTempContent", model.CheckAuth, exportTempContent)
|
||||
ginServer.Handle("POST", "/api/export/exportResources", model.CheckAuth, model.CheckAdminRole, exportResources)
|
||||
ginServer.Handle("POST", "/api/export/exportAsFile", model.CheckAuth, model.CheckAdminRole, exportAsFile)
|
||||
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, model.CheckAdminRole, exportData)
|
||||
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, model.CheckAdminRole, exportDataInFolder)
|
||||
ginServer.Handle("POST", "/api/export/exportTempContent", model.CheckAuth, model.CheckAdminRole, exportTempContent)
|
||||
ginServer.Handle("POST", "/api/export/export2Liandi", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, export2Liandi)
|
||||
ginServer.Handle("POST", "/api/export/exportReStructuredText", model.CheckAuth, exportReStructuredText)
|
||||
ginServer.Handle("POST", "/api/export/exportAsciiDoc", model.CheckAuth, exportAsciiDoc)
|
||||
ginServer.Handle("POST", "/api/export/exportTextile", model.CheckAuth, exportTextile)
|
||||
ginServer.Handle("POST", "/api/export/exportOPML", model.CheckAuth, exportOPML)
|
||||
ginServer.Handle("POST", "/api/export/exportOrgMode", model.CheckAuth, exportOrgMode)
|
||||
ginServer.Handle("POST", "/api/export/exportMediaWiki", model.CheckAuth, exportMediaWiki)
|
||||
ginServer.Handle("POST", "/api/export/exportODT", model.CheckAuth, exportODT)
|
||||
ginServer.Handle("POST", "/api/export/exportRTF", model.CheckAuth, exportRTF)
|
||||
ginServer.Handle("POST", "/api/export/exportEPUB", model.CheckAuth, exportEPUB)
|
||||
ginServer.Handle("POST", "/api/export/exportAttributeView", model.CheckAuth, exportAttributeView)
|
||||
ginServer.Handle("POST", "/api/export/exportReStructuredText", model.CheckAuth, model.CheckAdminRole, exportReStructuredText)
|
||||
ginServer.Handle("POST", "/api/export/exportAsciiDoc", model.CheckAuth, model.CheckAdminRole, exportAsciiDoc)
|
||||
ginServer.Handle("POST", "/api/export/exportTextile", model.CheckAuth, model.CheckAdminRole, exportTextile)
|
||||
ginServer.Handle("POST", "/api/export/exportOPML", model.CheckAuth, model.CheckAdminRole, exportOPML)
|
||||
ginServer.Handle("POST", "/api/export/exportOrgMode", model.CheckAuth, model.CheckAdminRole, exportOrgMode)
|
||||
ginServer.Handle("POST", "/api/export/exportMediaWiki", model.CheckAuth, model.CheckAdminRole, exportMediaWiki)
|
||||
ginServer.Handle("POST", "/api/export/exportODT", model.CheckAuth, model.CheckAdminRole, exportODT)
|
||||
ginServer.Handle("POST", "/api/export/exportRTF", model.CheckAuth, model.CheckAdminRole, exportRTF)
|
||||
ginServer.Handle("POST", "/api/export/exportEPUB", model.CheckAuth, model.CheckAdminRole, exportEPUB)
|
||||
ginServer.Handle("POST", "/api/export/exportAttributeView", model.CheckAuth, model.CheckAdminRole, exportAttributeView)
|
||||
|
||||
ginServer.Handle("POST", "/api/import/importStdMd", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importStdMd)
|
||||
ginServer.Handle("POST", "/api/import/importData", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importData)
|
||||
|
|
|
@ -369,12 +369,13 @@ func fullTextSearchBlock(c *gin.Context) {
|
|||
}
|
||||
|
||||
page, pageSize, query, paths, boxes, types, method, orderBy, groupBy := parseSearchBlockArgs(arg)
|
||||
blocks, matchedBlockCount, matchedRootCount, pageCount := model.FullTextSearchBlock(query, boxes, paths, types, method, orderBy, groupBy, page, pageSize)
|
||||
blocks, matchedBlockCount, matchedRootCount, pageCount, docMode := model.FullTextSearchBlock(query, boxes, paths, types, method, orderBy, groupBy, page, pageSize)
|
||||
ret.Data = map[string]interface{}{
|
||||
"blocks": blocks,
|
||||
"matchedBlockCount": matchedBlockCount,
|
||||
"matchedRootCount": matchedRootCount,
|
||||
"pageCount": pageCount,
|
||||
"docMode": docMode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -429,7 +429,8 @@ func getConf(c *gin.Context) {
|
|||
|
||||
// REF: https://github.com/siyuan-note/siyuan/issues/11364
|
||||
role := model.GetGinContextRole(c)
|
||||
if model.IsReadOnlyRole(role) {
|
||||
isPublish := model.IsReadOnlyRole(role)
|
||||
if isPublish {
|
||||
maskedConf.ReadOnly = true
|
||||
}
|
||||
if !model.IsValidRole(role, []model.Role{
|
||||
|
@ -439,8 +440,9 @@ func getConf(c *gin.Context) {
|
|||
}
|
||||
|
||||
ret.Data = map[string]interface{}{
|
||||
"conf": maskedConf,
|
||||
"start": !util.IsUILoaded,
|
||||
"conf": maskedConf,
|
||||
"start": !util.IsUILoaded,
|
||||
"isPublish": isPublish,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -476,7 +476,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids
|
|||
|
||||
if 1 > len(ids) {
|
||||
// `Replace All` is no longer affected by pagination https://github.com/siyuan-note/siyuan/issues/8265
|
||||
blocks, _, _, _ := FullTextSearchBlock(keyword, boxes, paths, types, method, orderBy, groupBy, 1, math.MaxInt)
|
||||
blocks, _, _, _, _ := FullTextSearchBlock(keyword, boxes, paths, types, method, orderBy, groupBy, 1, math.MaxInt)
|
||||
for _, block := range blocks {
|
||||
ids = append(ids, block.ID)
|
||||
}
|
||||
|
@ -903,7 +903,7 @@ func replaceNodeTokens(n *ast.Node, method int, keyword string, replacement stri
|
|||
// method:0:关键字,1:查询语法,2:SQL,3:正则表达式
|
||||
// orderBy: 0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序
|
||||
// groupBy:0:不分组,1:按文档分组
|
||||
func FullTextSearchBlock(query string, boxes, paths []string, types map[string]bool, method, orderBy, groupBy, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount, pageCount int) {
|
||||
func FullTextSearchBlock(query string, boxes, paths []string, types map[string]bool, method, orderBy, groupBy, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount, pageCount int, docMode bool) {
|
||||
ret = []*Block{}
|
||||
if "" == query {
|
||||
return
|
||||
|
@ -945,7 +945,12 @@ func FullTextSearchBlock(query string, boxes, paths []string, types map[string]b
|
|||
typeFilter := buildTypeFilter(types)
|
||||
boxFilter := buildBoxesFilter(boxes)
|
||||
pathFilter := buildPathsFilter(paths)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByKeyword(query, boxFilter, pathFilter, typeFilter, ignoreFilter, orderByClause, beforeLen, page, pageSize)
|
||||
if 2 > len(strings.Split(query, " ")) {
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, ignoreFilter, orderByClause, beforeLen, page, pageSize)
|
||||
} else {
|
||||
docMode = true // 文档全文搜索模式 https://github.com/siyuan-note/siyuan/issues/10584
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByKeyword(query, boxFilter, pathFilter, typeFilter, ignoreFilter, orderByClause, beforeLen, page, pageSize)
|
||||
}
|
||||
}
|
||||
pageCount = (matchedBlockCount + pageSize - 1) / pageSize
|
||||
|
||||
|
@ -1324,6 +1329,7 @@ func fullTextSearchCountByRegexp(exp, boxFilter, pathFilter, typeFilter, ignoreF
|
|||
}
|
||||
|
||||
func fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, ignoreFilter, orderBy string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
start := time.Now()
|
||||
query = stringQuery(query)
|
||||
table := "blocks_fts" // 大小写敏感
|
||||
if !Conf.Search.CaseSensitive {
|
||||
|
@ -1349,20 +1355,11 @@ func fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, ignoreFilter,
|
|||
}
|
||||
|
||||
matchedBlockCount, matchedRootCount = fullTextSearchCountByFTS(query, boxFilter, pathFilter, typeFilter, ignoreFilter)
|
||||
logging.LogInfof("time cost [fts]: %v", time.Since(start))
|
||||
return
|
||||
}
|
||||
|
||||
func fullTextSearchCountByFTS(query, boxFilter, pathFilter, typeFilter, ignoreFilter string) (matchedBlockCount, matchedRootCount int) {
|
||||
if ast.IsNodeIDPattern(query) {
|
||||
ret, _ := sql.QueryNoLimit("SELECT COUNT(id) AS `matches`, COUNT(DISTINCT(root_id)) AS `docs` FROM `blocks` WHERE `id` = '" + query + "'")
|
||||
if 1 > len(ret) {
|
||||
return
|
||||
}
|
||||
matchedBlockCount = int(ret[0]["matches"].(int64))
|
||||
matchedRootCount = int(ret[0]["docs"].(int64))
|
||||
return
|
||||
}
|
||||
|
||||
table := "blocks_fts" // 大小写敏感
|
||||
if !Conf.Search.CaseSensitive {
|
||||
table = "blocks_fts_case_insensitive"
|
||||
|
@ -1403,43 +1400,17 @@ func fullTextSearchByFTSWithRoot(query, boxFilter, pathFilter, typeFilter, ignor
|
|||
" GROUP BY root_id HAVING " + likeFilter + "ORDER BY " + orderByLike + " DESC, MAX(updated) DESC"
|
||||
cteStmt := "WITH docBlocks AS (" + dMatchStmt + ")"
|
||||
likeFilter = strings.ReplaceAll(likeFilter, "GROUP_CONCAT("+contentField+")", "concatContent")
|
||||
limit := " LIMIT " + strconv.Itoa(pageSize) + " OFFSET " + strconv.Itoa((page-1)*pageSize)
|
||||
selectStmt := cteStmt + "\nSELECT *, " +
|
||||
"(" + contentField + ") AS concatContent, " +
|
||||
"(SELECT COUNT(root_id) FROM docBlocks) AS docs, " +
|
||||
"(CASE WHEN (root_id IN (SELECT root_id FROM docBlocks) AND (" + strings.ReplaceAll(likeFilter, "concatContent", contentField) + ")) THEN 1 ELSE 0 END) AS blockSort" +
|
||||
" FROM blocks WHERE type IN " + typeFilter + boxFilter + pathFilter + ignoreFilter +
|
||||
" AND (id IN (SELECT root_id FROM docBlocks) OR" +
|
||||
" (root_id IN (SELECT root_id FROM docBlocks) AND (" + likeFilter + ")))"
|
||||
selectStmt += " " + strings.Replace(orderBy, "END ASC, ", "END ASC, blockSort DESC, ", 1) +
|
||||
" LIMIT " + strconv.Itoa(pageSize) + " OFFSET " + strconv.Itoa((page-1)*pageSize)
|
||||
result, _ := sql.Query(selectStmt, -1)
|
||||
var resultBlocks []*sql.Block
|
||||
for _, row := range result {
|
||||
b := &sql.Block{
|
||||
ID: row["id"].(string),
|
||||
ParentID: row["parent_id"].(string),
|
||||
RootID: row["root_id"].(string),
|
||||
Hash: row["hash"].(string),
|
||||
Box: row["box"].(string),
|
||||
Path: row["path"].(string),
|
||||
HPath: row["hpath"].(string),
|
||||
Name: row["name"].(string),
|
||||
Alias: row["alias"].(string),
|
||||
Memo: row["memo"].(string),
|
||||
Tag: row["tag"].(string),
|
||||
Content: row["content"].(string),
|
||||
FContent: row["fcontent"].(string),
|
||||
Markdown: row["markdown"].(string),
|
||||
Length: int(row["length"].(int64)),
|
||||
Type: row["type"].(string),
|
||||
SubType: row["subtype"].(string),
|
||||
IAL: row["ial"].(string),
|
||||
Sort: int(row["sort"].(int64)),
|
||||
Created: row["created"].(string),
|
||||
Updated: row["updated"].(string),
|
||||
}
|
||||
resultBlocks = append(resultBlocks, b)
|
||||
}
|
||||
" AND (id IN (SELECT root_id FROM docBlocks " + limit + ") OR" +
|
||||
" (root_id IN (SELECT root_id FROM docBlocks" + limit + ") AND (" + likeFilter + ")))"
|
||||
selectStmt += " " + strings.Replace(orderBy, "END ASC, ", "END ASC, blockSort DESC, ", 1)
|
||||
result, _ := sql.QueryNoLimit(selectStmt)
|
||||
resultBlocks := sql.ToBlocks(result)
|
||||
if 0 < len(resultBlocks) {
|
||||
matchedRootCount = int(result[0]["docs"].(int64))
|
||||
matchedBlockCount = matchedRootCount
|
||||
|
@ -1452,7 +1423,7 @@ func fullTextSearchByFTSWithRoot(query, boxFilter, pathFilter, typeFilter, ignor
|
|||
ret = []*Block{}
|
||||
}
|
||||
|
||||
logging.LogInfof("time cost [search]: %v", time.Since(start))
|
||||
logging.LogInfof("time cost [like]: %v", time.Since(start))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -457,6 +457,36 @@ func Query(stmt string, limit int) (ret []map[string]interface{}, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func ToBlocks(result []map[string]interface{}) (ret []*Block) {
|
||||
for _, row := range result {
|
||||
b := &Block{
|
||||
ID: row["id"].(string),
|
||||
ParentID: row["parent_id"].(string),
|
||||
RootID: row["root_id"].(string),
|
||||
Hash: row["hash"].(string),
|
||||
Box: row["box"].(string),
|
||||
Path: row["path"].(string),
|
||||
HPath: row["hpath"].(string),
|
||||
Name: row["name"].(string),
|
||||
Alias: row["alias"].(string),
|
||||
Memo: row["memo"].(string),
|
||||
Tag: row["tag"].(string),
|
||||
Content: row["content"].(string),
|
||||
FContent: row["fcontent"].(string),
|
||||
Markdown: row["markdown"].(string),
|
||||
Length: int(row["length"].(int64)),
|
||||
Type: row["type"].(string),
|
||||
SubType: row["subtype"].(string),
|
||||
IAL: row["ial"].(string),
|
||||
Sort: int(row["sort"].(int64)),
|
||||
Created: row["created"].(string),
|
||||
Updated: row["updated"].(string),
|
||||
}
|
||||
ret = append(ret, b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getLimitClause(parsedStmt sqlparser.Statement, limit int) (ret *sqlparser.Limit) {
|
||||
switch parsedStmt.(type) {
|
||||
case *sqlparser.Select:
|
||||
|
|
Loading…
Add table
Reference in a new issue