Merge branch 'dev' into dev-tooltip

This commit is contained in:
Jeffrey Chen 2024-12-18 12:41:18 +08:00 committed by GitHub
commit c55e39ac0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 2534 additions and 467 deletions

View file

@ -21,6 +21,8 @@
<a title="Twitter" target="_blank" href="https://twitter.com/b3logos"><img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/b3logos?label=Follow&style=social"></a>
<a title="Discord" target="_blank" href="https://discord.gg/dmMbCqVX7G"><img alt="Chat on Discord" src="https://img.shields.io/discord/808152298789666826?label=Discord&logo=Discord&style=social"></a>
<br><br>
<a href="https://trendshift.io/repositories/3949" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3949" alt="siyuan-note%2Fsiyuan | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<br><br>
<a href="https://www.producthunt.com/products/siyuan/reviews?utm_source=badge-product_rating&utm_medium=badge&utm_souce=badge-siyuan" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/product_rating.svg?product_id=534576&theme=light" alt="SiYuan - A&#0032;privacy&#0045;first&#0032;personal&#0032;knowledge&#0032;management&#0032;software | Product Hunt" style="width: 242px; height: 108px;" width="242" height="108" /></a>
</p>

View file

@ -21,6 +21,8 @@
<a title="Twitter" target="_blank" href="https://twitter.com/b3logos"><img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/b3logos?label=Follow&style=social"></a>
<a title="Discord" target="_blank" href="https://discord.gg/dmMbCqVX7G"><img alt="Chat on Discord" src="https://img.shields.io/discord/808152298789666826?label=Discord&logo=Discord&style=social"></a>
<br><br>
<a href="https://trendshift.io/repositories/3949" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3949" alt="siyuan-note%2Fsiyuan | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<br><br>
<a href="https://www.producthunt.com/products/siyuan/reviews?utm_source=badge-product_rating&utm_medium=badge&utm_souce=badge-siyuan" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/product_rating.svg?product_id=534576&theme=light" alt="SiYuan - A&#0032;privacy&#0045;first&#0032;personal&#0032;knowledge&#0032;management&#0032;software | Product Hunt" style="width: 242px; height: 108px;" width="242" height="108" /></a>
</p>

View file

@ -21,6 +21,8 @@
<a title="Twitter" target="_blank" href="https://twitter.com/b3logos"><img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/b3logos?label=Follow&style=social"></a>
<a title="Discord" target="_blank" href="https://discord.gg/dmMbCqVX7G"><img alt="Chat on Discord" src="https://img.shields.io/discord/808152298789666826?label=Discord&logo=Discord&style=social"></a>
<br><br>
<a href="https://trendshift.io/repositories/3949" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3949" alt="siyuan-note%2Fsiyuan | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<br><br>
<a href="https://www.producthunt.com/products/siyuan/reviews?utm_source=badge-product_rating&utm_medium=badge&utm_souce=badge-siyuan" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/product_rating.svg?product_id=534576&theme=light" alt="SiYuan - A&#0032;privacy&#0045;first&#0032;personal&#0032;knowledge&#0032;management&#0032;software | Product Hunt" style="width: 242px; height: 108px;" width="242" height="108" /></a>
</p>

View file

@ -3155,20 +3155,6 @@
"description_zh_cn": "西装革履的人",
"keywords": "business,person,suit,スレンダーマン,スーツ,ビジネスマン,男,男性,都市伝説,商务,业务,正装,西装革履"
},
{
"unicode": "1f574-fe0f-200d-2642-fe0f",
"description": "Man in Suit Levitating",
"description_ja_jp": "浮いてるスーツの男性",
"description_zh_cn": "西装革履的男人",
"keywords": "business,suit,man,male,men,スレンダーマン,スーツ,ビジネスマン,都市伝説,商务,正装,西装革履,业务,西装,男,男性,男子"
},
{
"unicode": "1f574-fe0f-200d-2640-fe0f",
"description": "Woman in Suit Levitating",
"description_ja_jp": "浮いてるスーツの女性",
"description_zh_cn": "西装革履的女人",
"keywords": "business,suit,woman,female,women,スレンダーマン,スーツ,ビジネスマン,都市伝説,商务,正装,西装革履,业务,西装,女,女性,妇女"
},
{
"unicode": "1f46f",
"description": "People with Bunny Ears",
@ -6953,13 +6939,6 @@
"description_zh_cn": "神社",
"keywords": "religion,shinto,shrine,宗教,建物,建築物,神社,神道,日本,神道教"
},
{
"unicode": "e50a",
"description": "Shibuya",
"description_ja_jp": "渋谷",
"description_zh_cn": "涩谷",
"keywords": "109,shibuya,建物,建築物,渋谷区,日本,涩谷区"
},
{
"unicode": "1f54b",
"description": "Kaaba",
@ -13664,4 +13643,4 @@
}
]
}
]
]

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{
"second": "Sekunde",
"syncInterval": "Synchronisierungsintervall",
"syncIntervalTip": "Automatische Datensynchronisierung, nachdem die Daten nicht mehr geändert werden",
"removeAV": "Aus der Datenbank entfernen",
"empty": "Leer",
"newRowInRelation": "Erstellen Sie einen neuen Eintrag in ${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "Fügen Sie einen leeren Block vor dem Block ein, an dem sich der Cursor befindet",
"insertAfter": "Fügen Sie einen leeren Block nach dem Block ein, an dem sich der Cursor befindet",
"list1": "Liste",
"insert": "Element einfügen",
"element": "Element",
"closeTab": "Aktuellen Tab schließen",
"keymap": "Tastenbelegung",
"clearFontStyle": "Stil löschen",

View file

@ -1,4 +1,7 @@
{
"second": "second",
"syncInterval": "sync interval",
"syncIntervalTip": "Automatically sync data after it stops changing",
"removeAV": "Remove from database",
"empty": "Empty",
"newRowInRelation": "Create a new entry in ${x} <b class='ft__on-surface'>${y}</b>",
@ -911,7 +914,7 @@
"insertBefore": "Insert an empty block before the block where the cursor is",
"insertAfter": "Insert an empty block after the block where the cursor is located",
"list1": "List",
"insert": "Insert Element",
"element": "Element",
"closeTab": "Close current Tab",
"keymap": "Keymap",
"clearFontStyle": "Clear Style",

View file

@ -1,8 +1,7 @@
{
"second": "second",
"syncInterval": "Sync interval",
"second": "segundo",
"syncInterval": "intervalo de sincronización",
"syncIntervalTip": "Sincronización automática de datos después de que los datos dejen de cambiar",
"removeAV": "Eliminar de la base de datos",
"empty": "Vacío",
"newRowInRelation": "Crear una nueva entrada en ${x} <b class='ft__on-surface'>${y}</b>",
@ -915,7 +914,7 @@
"insertBefore": "Inserta un bloque vacío antes del bloque donde está el cursor",
"insertAfter": "Inserta un bloque vacío después del bloque donde se encuentra el cursor",
"list1": "Lista",
"insert": "Insertar elemento",
"element": "elemento",
"closeTab": "Cerrar pestaña actual",
"keymap": "Mapa de teclas",
"clearFontStyle": "Limpiar estilo",

View file

@ -1,6 +1,7 @@
{
"second": "seconde",
"syncInterval": "intervalle de synchronisation",
"syncIntervalTip": "Synchronisation automatique des données après l'arrêt des modifications",
"removeAV": "Supprimer de la base de données",
"empty": "Vide",
"newRowInRelation": "Créer une nouvelle entrée dans ${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "Insérer un bloc vide devant le bloc où se trouve le curseur",
"insertAfter": "Insérer un bloc vide après le bloc où se trouve le curseur",
"list1": "Liste",
"insert": "Insérer l'élément",
"element": "élément",
"closeTab": "Fermer l'onglet actuel",
"keymap": "Raccourci",
"clearFontStyle": "Effacer Styles",

View file

@ -1,6 +1,7 @@
{
"second": "שנייה",
"syncInterval": "מרווח סנכרון",
"syncIntervalTip": "סנכרון נתונים אוטומטי לאחר שהנתונים מפסיקים להשתנות",
"removeAV": "הסר ממסד הנתונים",
"empty": "ריק",
"newRowInRelation": "צור ערך חדש ב-${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "הכנס בלוק ריק לפני הבלוק שבו נמצא הסמן",
"insertAfter": "הכנס בלוק ריק אחרי הבלוק שבו נמצא הסמן",
"list1": "רשימה",
"insert": "הכנס אלמנט",
"element": "אלמנט",
"closeTab": "סגור טאב נוכחי",
"keymap": "מפת מקשים",
"clearFontStyle": "נקה סגנון",

View file

@ -1,6 +1,7 @@
{
"second": "secondo",
"syncInterval": "intervallo di sincronizzazione",
"syncIntervalTip": "Sincronizzazione automatica dei dati dopo che non ci sono più variazioni",
"removeAV": "Rimuovi dal database",
"empty": "Vuoto",
"newRowInRelation": "Crea una nuova voce in ${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "Inserisci un blocco vuoto prima del blocco corrente",
"insertAfter": "Inserisci un blocco vuoto dopo il blocco corrente",
"list1": "Lista",
"insert": "Inserisci elemento",
"element": "elemento",
"closeTab": "Chiudi scheda corrente",
"keymap": "Mappa dei tasti",
"clearFontStyle": "Pulisci stile",

View file

@ -1,6 +1,7 @@
{
"second": "秒",
"syncInterval": "同期間隔",
"syncIntervalTip": "データが変動しなくなった後に自動的にデータを同期します",
"removeAV": "データベースから削除",
"empty": "空白",
"newRowInRelation": "${x} に新しい項目を作成 <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "前にブロックを挿入",
"insertAfter": "後にブロックを挿入",
"list1": "リスト",
"insert": "要素の挿入",
"element": "要素",
"closeTab": "現在のタブを閉じる",
"keymap": "ショートカット",
"clearFontStyle": "スタイルを消去",

View file

@ -1,6 +1,7 @@
{
"second": "sekunda",
"syncInterval": "interwał synchronizacji",
"syncIntervalTip": "Automatyczna synchronizacja danych po zaprzestaniu zmian",
"removeAV": "Usuń z bazy danych",
"empty": "Pusty",
"newRowInRelation": "Utwórz nowy wpis w ${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "Wstaw pusty blok przed blokiem, w którym znajduje się kursor",
"insertAfter": "Wstaw pusty blok po bloku, w którym znajduje się kursor",
"list1": "Lista",
"insert": "Wstaw element",
"element": "element",
"closeTab": "Zamknij bieżący zakładkę",
"keymap": "Zestaw klawiszy",
"clearFontStyle": "Wyczyść styl",

View file

@ -1,6 +1,7 @@
{
"second": "секунда",
"syncInterval": "интервал синхронизации",
"syncIntervalTip": "Автоматическая синхронизация данных после прекращения изменений",
"removeAV": "Удалить из базы данных",
"empty": "Пусто",
"newRowInRelation": "Создать новую запись в ${x} <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "Вставить пустой блок перед блоком, где находится курсор",
"insertAfter": "Вставить пустой блок после блока, где находится курсор",
"list1": "Список",
"insert": "Вставить элемент",
"element": "элемент",
"closeTab": "Закрыть текущую вкладку",
"keymap": "Карта клавиш",
"clearFontStyle": "Очистить стиль",

View file

@ -1,6 +1,7 @@
{
"second": "秒",
"syncInterval": "同步間隔",
"syncIntervalTip": "數據不再變動後自動進行數據同步",
"removeAV": "從資料庫中移除",
"empty": "空白",
"newRowInRelation": "在 ${x} 中新建條目 <b class='ft__on-surface'>${y}</b>",
@ -913,7 +914,7 @@
"insertBefore": "游標所在塊前插入空塊",
"insertAfter": "游標所在塊後插入空塊",
"list1": "列表",
"insert": "插入元素",
"element": "元素",
"closeTab": "關閉當前分頁",
"keymap": "快速鍵",
"clearFontStyle": "清除樣式",

View file

@ -22,12 +22,11 @@
--b3-theme-on-error: #fff;
/* 字体 */
/* Windows 斜体遮挡添加 "Segoe UI" 字体 https://github.com/siyuan-note/siyuan/issues/11841 */
--b3-font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Segoe UI", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family-protyle: "Number Glyphs", "SiYuan Emojis", var(--b3-font-family);
--b3-font-family-code: "Number Glyphs Of JetBrainsMono-Regular", "SiYuan Emojis", "JetBrainsMono-Regular", mononoki, Consolas, "Liberation Mono", Menlo, Courier, monospace, var(--b3-font-family);
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "Luxi Sans", "DejaVu Sans", "Hiragino Sans", arial, sans-serif, emojis;
--b3-font-family-protyle: var(--b3-font-family);
--b3-font-family-code: "Emojis Additional", "Emojis Reset", "JetBrainsMono-Regular", mononoki, Consolas, "Liberation Mono", var(--b3-font-family);
--b3-font-family-graph: arial;
--b3-font-family-emoji: "SiYuan Emojis", "Emojis";
--b3-font-family-emoji: "Emojis Additional", emojis;
--b3-font-family-math: KaTeX_Math;
--b3-font-size: 14px;
@ -201,16 +200,17 @@
--b3-parent-background: var(--b3-theme-background);
}
/* 微软字体斜体会被相邻背景遮挡,将 arial 放置其前 https://github.com/siyuan-note/siyuan/issues/11841"Segoe UI" 和 Noto-COLRv1-2.047 冲突,故移除。 */
:root:lang(zh_CN) {
--b3-font-family: "Helvetica Neue", "PingFang SC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans GB", "Segoe UI", "Source Han Sans SC", "Microsoft Yahei", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "PingFang SC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans GB", "Source Han Sans SC", arial, "Microsoft Yahei", sans-serif, emojis;
}
:root:lang(zh_CHT) {
--b3-font-family: "Helvetica Neue", "PingFang TC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans TC", "Segoe UI", "Source Han Sans TC", "Microsoft JhengHei", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "PingFang TC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans TC", "Source Han Sans TC", "Microsoft JhengHei", arial, sans-serif, emojis;
}
:root:lang(ja_JP) {
--b3-font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Yu Gothic UI", "Segoe UI", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Yu Gothic UI", arial, sans-serif, emojis;
}
/* https://github.com/siyuan-note/siyuan/issues/6440 */

View file

@ -22,11 +22,11 @@
--b3-theme-on-error: #fff;
/* 字体 */
--b3-font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Segoe UI", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family-protyle: "Number Glyphs", "SiYuan Emojis", var(--b3-font-family);
--b3-font-family-code: "Number Glyphs Of JetBrainsMono-Regular", "SiYuan Emojis", "JetBrainsMono-Regular", mononoki, Consolas, "Liberation Mono", Menlo, Courier, monospace, var(--b3-font-family);
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "Luxi Sans", "DejaVu Sans", "Hiragino Sans", arial, sans-serif, emojis;
--b3-font-family-protyle: var(--b3-font-family);
--b3-font-family-code: "Emojis Additional", "Emojis Reset", "JetBrainsMono-Regular", mononoki, Consolas, "Liberation Mono", var(--b3-font-family);
--b3-font-family-graph: arial;
--b3-font-family-emoji: "SiYuan Emojis", "Emojis";
--b3-font-family-emoji: "Emojis Additional", emojis;
--b3-font-family-math: KaTeX_Math;
--b3-font-size: 14px;
@ -200,16 +200,17 @@
--b3-parent-background: var(--b3-theme-background);
}
/* 微软字体斜体会被相邻背景遮挡,将 arial 放置其前 https://github.com/siyuan-note/siyuan/issues/11841"Segoe UI" 和 Noto-COLRv1-2.047 冲突,故移除。 */
:root:lang(zh_CN) {
--b3-font-family: "Helvetica Neue", "PingFang SC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans GB", "Segoe UI", "Source Han Sans SC", "Microsoft Yahei", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "PingFang SC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans GB", "Source Han Sans SC", arial, "Microsoft Yahei", sans-serif, emojis;
}
:root:lang(zh_CHT) {
--b3-font-family: "Helvetica Neue", "PingFang TC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans TC", "Segoe UI", "Source Han Sans TC", "Microsoft JhengHei", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "PingFang TC", "Luxi Sans", "DejaVu Sans", "Hiragino Sans TC", "Source Han Sans TC", "Microsoft JhengHei", arial, sans-serif, emojis;
}
:root:lang(ja_JP) {
--b3-font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Yu Gothic UI", "Segoe UI", sans-serif, "Arial", "Tahoma", "Emojis";
--b3-font-family: "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, Helvetica, "Luxi Sans", "DejaVu Sans", "Hiragino Sans", "Yu Gothic UI", arial, sans-serif, emojis;
}
/* https://github.com/siyuan-note/siyuan/issues/6440 */

View file

@ -0,0 +1,48 @@
## Overview
This version improves some details.
## Changelogs
Below are the detailed changes in this version.
### Enhancement
* [Improve database cell appearance](https://github.com/siyuan-note/siyuan/issues/10867)
* [The move doc window retains the keyword of the last search](https://github.com/siyuan-note/siyuan/issues/12335)
* [Improve font family and emoji ](https://github.com/siyuan-note/siyuan/pull/13241)
* [Improve database select field color and layout](https://github.com/siyuan-note/siyuan/issues/13263)
* [Improve cursor positioning after pasting images](https://github.com/siyuan-note/siyuan/issues/13336)
* [The database primary key field displays the icon of the bound doc](https://github.com/siyuan-note/siyuan/issues/13378)
* [Supports find-replace and asset file history on the mobile](https://github.com/siyuan-note/siyuan/issues/13415)
* [Improve inline elements parsing](https://github.com/siyuan-note/siyuan/issues/13420)
* [Allow stickTab icon in Panels to be used in a browser environment](https://github.com/siyuan-note/siyuan/pull/13421)
* [Add block content statistics template function `statBlock`](https://github.com/siyuan-note/siyuan/issues/13438)
* [Improve document tag interaction](https://github.com/siyuan-note/siyuan/issues/13440)
* [Improve forward and backward when `Open in current tab` is enabled](https://github.com/siyuan-note/siyuan/issues/13444)
* [Support setting automatic sync interval](https://github.com/siyuan-note/siyuan/issues/13448)
* [Improve importing markdown files](https://github.com/siyuan-note/siyuan/issues/13449)
* [Add SQL query template function `querySQL`](https://github.com/siyuan-note/siyuan/issues/13455)
* [Search preview area supports inline memo positioning](https://github.com/siyuan-note/siyuan/issues/13465)
* [Add Arabic support](https://github.com/siyuan-note/siyuan/pull/13475)
* [Improve exporting data](https://github.com/siyuan-note/siyuan/issues/13500)
* [Improve serving assets performance](https://github.com/siyuan-note/siyuan/issues/13501)
* [Improve data synchronization stability](https://github.com/siyuan-note/siyuan/issues/13503)
### Bugfix
* [Outline panel update overwrite content issue](https://github.com/siyuan-note/siyuan/issues/13409)
* [Paste code block missing line break](https://github.com/siyuan-note/siyuan/issues/13416)
* [Editor not automatically refreshed after rolling back document](https://github.com/siyuan-note/siyuan/issues/13419)
* [Unable to use `Query Syntax` to search](https://github.com/siyuan-note/siyuan/issues/13422)
* [Cannot enter Chinese characters in database search using Microsoft Pinyin](https://github.com/siyuan-note/siyuan/issues/13424)
* [Some security vulnerabilities](https://github.com/siyuan-note/siyuan/issues/13426)
### Development
* [Push update block ID event](https://github.com/siyuan-note/siyuan/issues/13434)
## Download
* [B3log](https://b3log.org/siyuan/en/download.html)
* [GitHub](https://github.com/siyuan-note/siyuan/releases)

View file

@ -0,0 +1,48 @@
## 概述
該版本改進了一些細節。
## 變更記錄
以下是此版本中的詳細變更。
### 改進功能
* [改進資料庫單元外觀](https://github.com/siyuan-note/siyuan/issues/10867)
* [行動文件視窗保留上次搜尋的關鍵字](https://github.com/siyuan-note/siyuan/issues/12335)
* [改進字體系列和表情符號](https://github.com/siyuan-note/siyuan/pull/13241)
* [改進資料庫選擇欄位的顏色和佈局](https://github.com/siyuan-note/siyuan/issues/13263)
* [改進貼上圖片後的遊標定位](https://github.com/siyuan-note/siyuan/issues/13336)
* [資料庫主鍵欄位顯示綁定文件區塊圖示](https://github.com/siyuan-note/siyuan/issues/13378)
* [支援在行動裝置上尋找替換和資源檔案歷史](https://github.com/siyuan-note/siyuan/issues/13415)
* [改進行級元素解析](https://github.com/siyuan-note/siyuan/issues/13420)
* [允許在瀏覽器環境中使用面板中的 stickTab 圖示](https://github.com/siyuan-note/siyuan/pull/13421)
* [新增區塊內容統計範本函數 `statBlock`](https://github.com/siyuan-note/siyuan/issues/13438)
* [改進文件標籤互動](https://github.com/siyuan-note/siyuan/issues/13440)
* [改進啟用「在目前標籤頁中開啟」時的前進與後退](https://github.com/siyuan-note/siyuan/issues/13444)
* [支援設定自動同步間隔](https://github.com/siyuan-note/siyuan/issues/13448)
* [改進導入 Markdown 檔案](https://github.com/siyuan-note/siyuan/issues/13449)
* [新增 SQL 查詢範本函數 `querySQL`](https://github.com/siyuan-note/siyuan/issues/13455)
* [搜尋預覽區域支援行級備註定位](https://github.com/siyuan-note/siyuan/issues/13465)
* [新增阿拉伯語支援](https://github.com/siyuan-note/siyuan/pull/13475)
* [改進匯出資料](https://github.com/siyuan-note/siyuan/issues/13500)
* [改進資源檔案載入效能](https://github.com/siyuan-note/siyuan/issues/13501)
* [改善資料同步穩定性](https://github.com/siyuan-note/siyuan/issues/13503)
### 修復缺陷
* [大綱面板更新覆蓋內容問題](https://github.com/siyuan-note/siyuan/issues/13409)
* [貼上程式碼區塊缺少換行](https://github.com/siyuan-note/siyuan/issues/13416)
* [回滾文件後編輯器未自動刷新](https://github.com/siyuan-note/siyuan/issues/13419)
* [無法使用 `查詢語法` 搜尋](https://github.com/siyuan-note/siyuan/issues/13422)
* [使用微軟拼音在資料庫搜尋中無法輸入中文字元](https://github.com/siyuan-note/siyuan/issues/13424)
* [一些安全漏洞](https://github.com/siyuan-note/siyuan/issues/13426)
### 開發者
* [推送更新區塊 ID 事件](https://github.com/siyuan-note/siyuan/issues/13434)
## 下載
* [B3log](https://b3log.org/siyuan/download.html)
* [GitHub](https://github.com/siyuan-note/siyuan/releases)

View file

@ -0,0 +1,48 @@
## 概述
该版本改进了一些细节。
## 变更记录
以下是此版本中的详细变更。
### 改进功能
* [改进数据库单元格外观](https://github.com/siyuan-note/siyuan/issues/10867)
* [移动文档窗口保留上次搜索的关键词](https://github.com/siyuan-note/siyuan/issues/12335)
* [改进字体系列和表情符号](https://github.com/siyuan-note/siyuan/pull/13241)
* [改进数据库选择字段的颜色和布局](https://github.com/siyuan-note/siyuan/issues/13263)
* [改进粘贴图片后的光标定位](https://github.com/siyuan-note/siyuan/issues/13336)
* [数据库主键字段显示绑定文档块图标](https://github.com/siyuan-note/siyuan/issues/13378)
* [支持在移动设备上查找替换和资源文件历史](https://github.com/siyuan-note/siyuan/issues/13415)
* [改进行级元素解析](https://github.com/siyuan-note/siyuan/issues/13420)
* [允许在浏览器环境中使用面板中的 stickTab 图标](https://github.com/siyuan-note/siyuan/pull/13421)
* [添加块内容统计模板函数 `statBlock`](https://github.com/siyuan-note/siyuan/issues/13438)
* [改进文档标签交互](https://github.com/siyuan-note/siyuan/issues/13440)
* [改进启用“在当前标签页中打开”时的前进和后退](https://github.com/siyuan-note/siyuan/issues/13444)
* [支持设置自动同步间隔](https://github.com/siyuan-note/siyuan/issues/13448)
* [改进导入 Markdown 文件](https://github.com/siyuan-note/siyuan/issues/13449)
* [添加 SQL 查询模板函数 `querySQL`](https://github.com/siyuan-note/siyuan/issues/13455)
* [搜索预览区域支持行级备注定位](https://github.com/siyuan-note/siyuan/issues/13465)
* [添加阿拉伯语支持](https://github.com/siyuan-note/siyuan/pull/13475)
* [改进导出数据](https://github.com/siyuan-note/siyuan/issues/13500)
* [改进资源文件加载性能](https://github.com/siyuan-note/siyuan/issues/13501)
* [改进数据同步稳定性](https://github.com/siyuan-note/siyuan/issues/13503)
### 修复缺陷
* [大纲面板更新覆盖内容问题](https://github.com/siyuan-note/siyuan/issues/13409)
* [粘贴代码块缺少换行](https://github.com/siyuan-note/siyuan/issues/13416)
* [回滚文档后编辑器未自动刷新](https://github.com/siyuan-note/siyuan/issues/13419)
* [无法使用 `查询语法` 进行搜索](https://github.com/siyuan-note/siyuan/issues/13422)
* [使用微软拼音在数据库搜索中无法输入中文字符](https://github.com/siyuan-note/siyuan/issues/13424)
* [一些安全漏洞](https://github.com/siyuan-note/siyuan/issues/13426)
### 开发者
* [推送更新块 ID 事件](https://github.com/siyuan-note/siyuan/issues/13434)
## 下载
* [B3log](https://b3log.org/siyuan/download.html)
* [GitHub](https://github.com/siyuan-note/siyuan/releases)

View file

@ -216,6 +216,7 @@
<option value="he_IL">עברית</option>
<option value="ru_RU">Русский</option>
<option value="pl_PL">Polski</option>
<option value="ar_SA">العربية</option>
</select>
</label>
<label class="b3-label">
@ -265,6 +266,7 @@
<option value="he_IL">עברית</option>
<option value="ru_RU">Русский</option>
<option value="pl_PL">Polski</option>
<option value="ar_SA">العربية</option>
</select>
</label>
<label class="b3-label">

View file

@ -5,7 +5,8 @@
"Properties": {
"id": "20230805232018-hgrq0ju",
"title": "Connect with third-party cloud storage",
"updated": "20240301091400"
"type": "doc",
"updated": "20241216171745"
},
"Children": [
{
@ -55,7 +56,7 @@
"ListData": {},
"Properties": {
"id": "20230805232156-kbi85az",
"updated": "20240301091400"
"updated": "20241216171745"
},
"Children": [
{
@ -121,7 +122,7 @@
},
"Properties": {
"id": "20230805232156-vqfp7fz",
"updated": "20240301091400"
"updated": "20241216171745"
},
"Children": [
{
@ -129,7 +130,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20230805232156-tliw65p",
"updated": "20240301091400"
"updated": "20241216171642"
},
"Children": [
{
@ -151,20 +152,79 @@
"TextMarkType": "a",
"TextMarkAHref": "https://koofr.eu/",
"TextMarkTextContent": "Koofr"
}
]
},
{
"ID": "20241216171644-p5dmsx8",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20241216171644-p5dmsx8",
"updated": "20241216171745"
},
"Children": [
{
"ID": "20241216171644-1x6gfx0",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171644-1x6gfx0",
"updated": "20241216171644"
},
"Children": [
{
"ID": "20241216171644-5v4890j",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171644-5v4890j",
"updated": "20241216171644"
},
"Children": [
{
"Type": "NodeText",
"Data": "Due to the problems of the WebDAV protocol itself, when the data volume is large, problems such as slow startup, slow synchronization, and high resource usage will occur, so it is recommended to use S3 object storage"
}
]
}
]
},
{
"Type": "NodeText",
"Data": " (Nutstore WebDAV is not supported because of its "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "interface limitations"
},
{
"Type": "NodeText",
"Data": ")"
"ID": "20241216171644-ie3pkyj",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171644-ie3pkyj",
"updated": "20241216171745"
},
"Children": [
{
"ID": "20241216171644-k4q14iw",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171644-k4q14iw",
"updated": "20241216171745"
},
"Children": [
{
"Type": "NodeText",
"Data": "Nutstore cloud WebDAV is not supported because its "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "interface has limitations"
}
]
}
]
}
]
}

View file

@ -5,7 +5,8 @@
"Properties": {
"id": "20230805230131-sn7obzb",
"title": "对接第三方云端存储",
"updated": "20240301090951"
"type": "doc",
"updated": "20241216171525"
},
"Children": [
{
@ -55,7 +56,7 @@
"ListData": {},
"Properties": {
"id": "20230805230746-4q9cmrb",
"updated": "20240301090951"
"updated": "20241216171525"
},
"Children": [
{
@ -121,7 +122,7 @@
},
"Properties": {
"id": "20230805230746-zb33erf",
"updated": "20240301090951"
"updated": "20241216171525"
},
"Children": [
{
@ -129,7 +130,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20230805230746-i9fzmzi",
"updated": "20240301090951"
"updated": "20241216171521"
},
"Children": [
{
@ -141,20 +142,79 @@
"TextMarkType": "a",
"TextMarkAHref": "https://infini-cloud.net/",
"TextMarkTextContent": "InfiniCLOUD"
}
]
},
{
"ID": "20241216171521-40xtiyf",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20241216171521-40xtiyf",
"updated": "20241216171525"
},
"Children": [
{
"ID": "20241216171530-dhfkay6",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171530-dhfkay6",
"updated": "20241216171530"
},
"Children": [
{
"ID": "20241216171530-kxdtu73",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171530-kxdtu73",
"updated": "20241216171531"
},
"Children": [
{
"Type": "NodeText",
"Data": "由于 WebDAV 协议本身的问题,数据量较大后会出现启动慢、同步慢、资源占用高等问题,所以建议选择使用 S3 对象存储"
}
]
}
]
},
{
"Type": "NodeText",
"Data": "(不支持坚果云 WebDAV因为其"
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "接口存在限制"
},
{
"Type": "NodeText",
"Data": ""
"ID": "20241216171521-ccruwd8",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171521-ccruwd8",
"updated": "20241216171525"
},
"Children": [
{
"ID": "20241216171521-z0p3t71",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171521-z0p3t71",
"updated": "20241216171525"
},
"Children": [
{
"Type": "NodeText",
"Data": "不支持坚果云 WebDAV因为其"
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "接口存在限制"
}
]
}
]
}
]
}
@ -167,7 +227,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20230805230746-pq0po1p",
"updated": "20230828111951"
"updated": "20241216171020"
},
"Children": [
{

View file

@ -5,7 +5,8 @@
"Properties": {
"id": "20230805232903-erdoerp",
"title": "對接第三方雲端存儲",
"updated": "20240301091104"
"type": "doc",
"updated": "20241216171627"
},
"Children": [
{
@ -55,7 +56,7 @@
"ListData": {},
"Properties": {
"id": "20230805232945-ugjx8sl",
"updated": "20240301091104"
"updated": "20241216171627"
},
"Children": [
{
@ -121,7 +122,7 @@
},
"Properties": {
"id": "20230805232945-2dksutx",
"updated": "20240301091104"
"updated": "20241216171627"
},
"Children": [
{
@ -129,7 +130,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20230805232945-ayx9zfr",
"updated": "20240301091104"
"updated": "20241216171606"
},
"Children": [
{
@ -151,20 +152,79 @@
"TextMarkType": "a",
"TextMarkAHref": "https://koofr.eu/",
"TextMarkTextContent": "Koofr"
}
]
},
{
"ID": "20241216171609-pu5jvmt",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20241216171609-pu5jvmt",
"updated": "20241216171627"
},
"Children": [
{
"ID": "20241216171609-abg7al0",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171609-abg7al0",
"updated": "20241216171627"
},
"Children": [
{
"ID": "20241216171609-aled0a0",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171609-aled0a0",
"updated": "20241216171627"
},
"Children": [
{
"Type": "NodeText",
"Data": "由於 WebDAV 協定本身的問題,資料量較大後會出現啟動慢、同步慢、資源佔用高等問題,所以建議選擇使用 S3 對象存儲服務"
}
]
}
]
},
{
"Type": "NodeText",
"Data": "(不支援堅果雲 WebDAV因為其"
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "介面存在限制"
},
{
"Type": "NodeText",
"Data": ""
"ID": "20241216171609-in2fc0o",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171609-in2fc0o",
"updated": "20241216171609"
},
"Children": [
{
"ID": "20241216171609-8zspojy",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171609-8zspojy",
"updated": "20241216171609"
},
"Children": [
{
"Type": "NodeText",
"Data": "不支援堅果雲 WebDAV因為其"
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "介面存在限制"
}
]
}
]
}
]
}

View file

@ -7,7 +7,7 @@
"id": "20240530101000-na9sys7",
"title": "サードパーティのクラウドストレージへの接続",
"type": "doc",
"updated": "20240530101000"
"updated": "20241216171841"
},
"Children": [
{
@ -57,9 +57,8 @@
"Type": "NodeList",
"ListData": {},
"Properties": {
"ID": "20240530101000-itl3kvt",
"id": "20240530101000-y5kmw6j",
"updated": "20240530101000"
"updated": "20241216171841"
},
"Children": [
{
@ -70,7 +69,6 @@
"Marker": "Kg=="
},
"Properties": {
"ID": "20240530101000-vlan2e3",
"id": "20240530101000-qqtgtoh",
"updated": "20240530101000"
},
@ -79,7 +77,6 @@
"ID": "20240530101000-aic7sey",
"Type": "NodeParagraph",
"Properties": {
"ID": "20240530101000-s1ytsva",
"id": "20240530101000-aic7sey",
"updated": "20240530101000"
},
@ -115,16 +112,14 @@
"Marker": "Kg=="
},
"Properties": {
"ID": "20240530101000-5i7ys4o",
"id": "20240530101000-wl4hjuf",
"updated": "20240530101000"
"updated": "20241216171841"
},
"Children": [
{
"ID": "20240530101000-6a5gjia",
"Type": "NodeParagraph",
"Properties": {
"ID": "20240530101000-y2dbhdv",
"id": "20240530101000-6a5gjia",
"updated": "20240530101000"
},
@ -159,6 +154,94 @@
"Data": " など"
}
]
},
{
"ID": "20241216171758-77i85wp",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20241216171758-77i85wp",
"updated": "20241216171812"
},
"Children": [
{
"ID": "20241216171801-fnqtfso",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171801-fnqtfso",
"updated": "20241216171812"
},
"Children": [
{
"ID": "20241216171801-0gz1sfs",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171801-0gz1sfs",
"updated": "20241216171812"
},
"Children": [
{
"Type": "NodeText",
"Data": "WebDAVプロトコル自体の問題により、データ量が多い場合には起動が遅い、同期が遅い、リソース使用量が多いなどの問題が発生する可能性があるため、S3オブジェクトストレージの使用を推奨します"
}
]
}
]
}
]
},
{
"ID": "20241216171758-7guo2ud",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20241216171758-7guo2ud",
"updated": "20241216171841"
},
"Children": [
{
"ID": "20241216171758-tl1nnuk",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20241216171758-tl1nnuk",
"updated": "20241216171841"
},
"Children": [
{
"ID": "20241216171758-y44s4r4",
"Type": "NodeParagraph",
"Properties": {
"id": "20241216171758-y44s4r4",
"updated": "20241216171841"
},
"Children": [
{
"Type": "NodeText",
"Data": "Nutstore cloud WebDAV は "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://help.jianguoyun.com/?p=2064",
"TextMarkTextContent": "インターフェース制限"
},
{
"Type": "NodeText",
"Data": " のためサポートされていません"
}
]
}
]
}
]
}
]
}

View file

@ -291,6 +291,10 @@
color: var(--b3-protyle-inline-blockref-color);
}
.b3-menu__avemoji {
display: inline-block;
}
&[data-wrap="true"] {
white-space: pre-wrap;
}

View file

@ -18,7 +18,7 @@
&__dockl,
&__dockr,
&__dockb {
transition: var(--b3-width-transition);
transition: var(--b3-width-transition), height .2s cubic-bezier(0, 0, .2, 1) 0ms;
flex-shrink: 0;
}

View file

@ -3,32 +3,6 @@
src: url(../fonts/JetBrainsMono-2.304/JetBrainsMono-Regular.woff2) format('woff2');
}
@font-face {
font-family: "Number Glyphs Of JetBrainsMono-Regular";
src: url(../fonts/JetBrainsMono-2.304/JetBrainsMono-Regular.woff2) format('woff2');
/* 数字 0-9 */
unicode-range: U+30-39;
}
@font-face {
font-family: "SiYuan Emojis";
src: url(../fonts/Noto-COLRv1-2.047/Noto-COLRv1.woff2) format("woff2");
// 表情中包含的 emoji 对应的 Unicode
unicode-range: U+23, U+2A, U+30-39, U+A9, U+AE, U+200D, U+203C, U+2049, U+2122, U+2139, U+2194-2199, U+21A9-21AA, U+231A-231B, U+2328, U+23CF, U+23E9-23F3, U+23F8-23FA, U+24C2, U+25AA-25AB, U+25B6, U+25C0, U+25FB-25FE, U+2600-2604, U+260E, U+2611, U+2614-2615, U+2618, U+261D, U+2620, U+2622-2623, U+2626, U+262A, U+262E-262F, U+2638-263A, U+2640, U+2642, U+2648-2653, U+265F-2660, U+2663, U+2665-2666, U+2668, U+267B, U+267E-267F, U+2692-2697, U+2699, U+269B-269C, U+26A0-26A1, U+26A7, U+26AA-26AB, U+26B0-26B1, U+26BD-26BE, U+26C4-26C5, U+26C8, U+26CE-26CF, U+26D1, U+26D3-26D4, U+26E9-26EA, U+26F0-26F5, U+26F7-26FA, U+26FD, U+2702, U+2705, U+2708-270D, U+270F, U+2712, U+2714, U+2716, U+271D, U+2721, U+2728, U+2733-2734, U+2744, U+2747, U+274C, U+274E, U+2753-2755, U+2757, U+2763-2764, U+2795-2797, U+27A1, U+27B0, U+27BF, U+2934-2935, U+2B05-2B07, U+2B1B-2B1C, U+2B50, U+2B55, U+3030, U+303D, U+3297, U+3299, U+E50A, U+1F004, U+1F0CF, U+1F170-1F171, U+1F17E-1F17F, U+1F18E, U+1F191-1F19A, U+1F1E6-1F1FF, U+1F201-1F202, U+1F21A, U+1F22F, U+1F232-1F23A, U+1F250-1F251, U+1F300-1F321, U+1F324-1F393, U+1F396-1F397, U+1F399-1F39B, U+1F39E-1F3F0, U+1F3F3-1F3F5, U+1F3F7-1F4FD, U+1F4FF-1F53D, U+1F549-1F54E, U+1F550-1F567, U+1F56F-1F570, U+1F573-1F57A, U+1F587, U+1F58A-1F58D, U+1F590, U+1F595-1F596, U+1F5A4-1F5A5, U+1F5A8, U+1F5B1-1F5B2, U+1F5BC, U+1F5C2-1F5C4, U+1F5D1-1F5D3, U+1F5DC-1F5DE, U+1F5E1, U+1F5E3, U+1F5E8, U+1F5EF, U+1F5F3, U+1F5FA-1F64F, U+1F680-1F6C5, U+1F6CB-1F6D2, U+1F6D5-1F6D7, U+1F6DC-1F6E5, U+1F6E9, U+1F6EB-1F6EC, U+1F6F0, U+1F6F3-1F6FC, U+1F7E0-1F7EB, U+1F7F0, U+1F90C-1F93A, U+1F93C-1F945, U+1F947-1F9FF, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8;
}
@font-face {
font-family: "Emojis";
src: local("Segoe UI Emoji"),
local("Segoe UI Symbol"),
local("Apple Color Emoji"),
local("Twemoji Mozilla"),
local("Noto Color Emoji"),
local("Android Emoji"),
local("EmojiSymbols"),
local("SiYuan Emojis");
}
.b3-typography,
.protyle-wysiwyg {
font-variant-ligatures: no-common-ligatures;

View file

@ -38,7 +38,7 @@
if (refreshElement) {
refreshElement.style.display = ""
}
}, 2000)
}, 7000)
</script>
</body>
</html>

View file

@ -213,7 +213,7 @@ const hidePopover = (event: MouseEvent & { path: HTMLElement[] }) => {
} else {
// 浮窗上点击菜单,浮窗不能消失 https://ld246.com/article/1632668091023
const menuElement = hasClosestByClassName(target, "b3-menu");
if (menuElement) {
if (menuElement && menuElement.getAttribute("data-name") !== "docTreeMore") {
const blockPanel = window.siyuan.blockPanels.find((item) => {
if (item.element.style.zIndex < menuElement.style.zIndex) {
return true;

View file

@ -392,7 +392,7 @@ export const repos = {
<option value="3" ${window.siyuan.config.sync.mode === 3 ? "selected" : ""}>${window.siyuan.languages.syncMode3}</option>
</select>
</div>
<label class="fn__flex b3-label${(window.siyuan.config.sync.mode !== 1 || window.siyuan.config.system.container === "docker" || window.siyuan.config.sync.provider !== 0) ? " fn__none" : ""}">
<label class="fn__flex b3-label${(window.siyuan.config.sync.mode !== 1) ? " fn__none" : ""}">
<div class="fn__flex-1">
${window.siyuan.languages.syncInterval}
<div class="b3-label__text">${window.siyuan.languages.syncIntervalTip}</div>
@ -477,9 +477,12 @@ export const repos = {
fetchPost("/api/sync/setSyncMode", {mode: parseInt(syncModeElement.value, 10)}, () => {
if (syncModeElement.value === "1" && window.siyuan.config.sync.provider === 0 && window.siyuan.config.system.container !== "docker") {
syncPerceptionElement.parentElement.classList.remove("fn__none");
syncIntervalElement.parentElement.classList.remove("fn__none");
} else {
syncPerceptionElement.parentElement.classList.add("fn__none");
}
if (syncModeElement.value === "1") {
syncIntervalElement.parentElement.classList.remove("fn__none");
} else {
syncIntervalElement.parentElement.classList.add("fn__none");
}
window.siyuan.config.sync.mode = parseInt(syncModeElement.value, 10);
@ -502,9 +505,12 @@ export const repos = {
syncConfigElement.classList.add("fn__none");
if (window.siyuan.config.sync.mode !== 1 || window.siyuan.config.system.container === "docker" || window.siyuan.config.sync.provider !== 0) {
syncPerceptionElement.parentElement.classList.add("fn__none");
syncIntervalElement.parentElement.classList.add("fn__none");
} else {
syncPerceptionElement.parentElement.classList.remove("fn__none");
}
if (window.siyuan.config.sync.mode !== 1) {
syncIntervalElement.parentElement.classList.add("fn__none");
} else {
syncIntervalElement.parentElement.classList.remove("fn__none");
}
});

View file

@ -204,6 +204,7 @@ export abstract class Constants {
he_IL: "20210808180117-6v0mkxr",
ru_RU: "20210808180117-6v0mkxr",
pl_PL: "20210808180117-6v0mkxr",
ar_SA: "20210808180117-6v0mkxr"
};
public static readonly QUICK_DECK_ID = "20230218211946-2kw8jgx";

View file

@ -276,7 +276,7 @@ export const openFile = async (options: IOpenFileOptions) => {
}
wnd.showHeading();
if (options.afterOpen) {
options.afterOpen(createdTab.model);
options.afterOpen(createdTab ? createdTab.model : undefined);
}
return createdTab;
}

View file

@ -705,6 +705,7 @@ export const initFileMenu = (app: App, notebookId: string, pathString: string, l
separatorPosition: "top",
});
}
window.siyuan.menus.menu.element.setAttribute("data-name", "docTreeMore");
return window.siyuan.menus.menu;
};

View file

@ -1027,7 +1027,7 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme
element.style.maxWidth = "none";
const textElements = element.querySelectorAll("textarea");
textElements[0].addEventListener("input", (event: InputEvent) => {
const value = (event.target as HTMLInputElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "");
const value = (event.target as HTMLInputElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "").trim();
imgElement.setAttribute("src", value);
imgElement.setAttribute("data-src", value);
if (value.startsWith("assets/")) {
@ -1854,7 +1854,7 @@ export const iframeMenu = (protyle: IProtyle, nodeElement: Element) => {
bind(element) {
element.style.maxWidth = "none";
element.querySelector("textarea").addEventListener("change", (event) => {
const value = (event.target as HTMLTextAreaElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "");
const value = (event.target as HTMLTextAreaElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "").trim();
const biliMatch = value.match(/(?:www\.|\/\/)bilibili\.com\/video\/(\w+)/);
if (value.indexOf("bilibili.com") > -1 && (value.indexOf("bvid=") > -1 || (biliMatch && biliMatch[1]))) {
const params: IObject = {
@ -1925,7 +1925,7 @@ export const videoMenu = (protyle: IProtyle, nodeElement: Element, type: string)
bind(element) {
element.style.maxWidth = "none";
element.querySelector("textarea").addEventListener("change", (event) => {
videoElement.setAttribute("src", (event.target as HTMLTextAreaElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, ""));
videoElement.setAttribute("src", (event.target as HTMLTextAreaElement).value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "").trim());
updateTransaction(protyle, id, nodeElement.outerHTML, html);
html = nodeElement.outerHTML;
event.stopPropagation();

View file

@ -443,7 +443,7 @@ export class Background {
if (tags) {
let html = "";
const colors = ["secondary", "primary", "info", "success", "warning", "error", "pink"];
new Set(tags.split(",")).forEach((item, index) => {
new Set(tags.split(",").map(item => item.trim())).forEach((item, index) => {
if (!item.replace(/ /g, "")) {
return;
}

View file

@ -22,7 +22,7 @@ import {hintRef} from "../../hint/extend";
import {focusBlock, focusByRange} from "../../util/selection";
import {showMessage} from "../../../dialog/message";
import {previewImage} from "../../preview/image";
import {unicode2Emoji} from "../../../emoji";
import {openEmojiPanel, unicode2Emoji} from "../../../emoji";
import * as dayjs from "dayjs";
import {openCalcMenu} from "./calc";
import {avRender} from "./render";
@ -233,6 +233,17 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
event.preventDefault();
event.stopPropagation();
return true;
} else if (target.classList.contains("b3-menu__avemoji")) {
const rect = target.getBoundingClientRect();
openEmojiPanel(target.parentElement.getAttribute("data-block-id"), "doc", {
x: rect.left,
y: rect.bottom,
h: rect.height,
w: rect.width,
}, undefined, target.querySelector("img"));
event.preventDefault();
event.stopPropagation();
return true;
}
target = target.parentElement;
}

View file

@ -789,7 +789,7 @@ export const renderCell = (cellValue: IAVCellValue, rowIndex = 0) => {
if (cellValue?.isDetached) {
text = `<span class="av__celltext">${cellValue.block.content || ""}</span><span class="b3-chip b3-chip--info b3-chip--small" data-type="block-more">${window.siyuan.languages.more}</span>`;
} else {
text = `<span data-type="block-ref" data-id="${cellValue.block.id}" data-subtype="s" class="av__celltext av__celltext--ref">${cellValue.block.content || window.siyuan.languages.untitled}</span><span class="b3-chip b3-chip--info b3-chip--small" data-type="block-more">${window.siyuan.languages.update}</span>`;
text = `${cellValue.block.icon ? `<span class="b3-menu__avemoji">${unicode2Emoji(cellValue.block.icon)}</span>` : ""}<span data-type="block-ref" data-id="${cellValue.block.id}" data-subtype="s" class="av__celltext av__celltext--ref">${cellValue.block.content || window.siyuan.languages.untitled}</span><span class="b3-chip b3-chip--info b3-chip--small" data-type="block-more">${window.siyuan.languages.update}</span>`;
}
} else if (cellValue.type === "number") {
text = `<span class="av__celltext" data-content="${cellValue?.number.isNotEmpty ? cellValue?.number.content : ""}">${cellValue?.number.formattedContent || cellValue?.number.content || ""}</span>`;
@ -877,7 +877,7 @@ const renderRollup = (cellValue: IAVCellValue) => {
if (cellValue?.isDetached) {
text = `<span class="av__celltext" data-id="${cellValue.block?.id}">${cellValue.block?.content || window.siyuan.languages.untitled}</span>`;
} else {
text = `<span data-type="block-ref" data-id="${cellValue.block?.id}" data-subtype="s" class="av__celltext av__celltext--ref">${cellValue.block?.content || window.siyuan.languages.untitled}</span>`;
text = `${cellValue.block.icon ? `<span class="b3-menu__avemoji">${unicode2Emoji(cellValue.block.icon)}</span>` : ""}<span data-type="block-ref" data-id="${cellValue.block?.id}" data-subtype="s" class="av__celltext av__celltext--ref">${cellValue.block?.content || window.siyuan.languages.untitled}</span>`;
}
} else if (cellValue.type === "number") {
text = cellValue?.number.formattedContent || cellValue?.number.content.toString() || "";

View file

@ -138,6 +138,19 @@ export const isMac = () => {
return navigator.platform.toUpperCase().indexOf("MAC") > -1;
};
export const isWin11 = async () => {
if (!navigator.userAgentData || !navigator.userAgentData.getHighEntropyValues) {
return false;
}
const ua = await navigator.userAgentData.getHighEntropyValues(["platformVersion"])
if (navigator.userAgentData.platform === "Windows") {
if (parseInt(ua.platformVersion.split('.')[0]) >= 13) {
return true
}
}
return false
}
export const isInAndroid = () => {
return window.siyuan.config.system.container === "android" && window.JSAndroid;
};

View file

@ -13,7 +13,7 @@ import {inputEvent} from "./util";
export const toggleReplaceHistory = (replaceInputElement: HTMLInputElement) => {
const list = window.siyuan.storage[Constants.LOCAL_SEARCHKEYS];
if (!list.replaceKeys || list.replaceKeys.length === 0) {
if (!list.replaceKeys || list.replaceKeys.length === 0 || (list.length === 1 && list[0] === replaceInputElement.value)) {
return;
}
const menu = new Menu("search-replace-history");
@ -79,8 +79,9 @@ export const toggleReplaceHistory = (replaceInputElement: HTMLInputElement) => {
};
export const toggleSearchHistory = (searchElement: Element, config: Config.IUILayoutTabSearchConfig, edit: Protyle) => {
const searchInputElement = searchElement.querySelector("#searchInput, #toolbarSearch") as HTMLInputElement;
const list = window.siyuan.storage[Constants.LOCAL_SEARCHKEYS];
if (!list.keys || list.keys.length === 0) {
if (!list.keys || list.keys.length === 0 || (list.length === 1 && list[0] === searchInputElement.value)) {
return;
}
const menu = new Menu("search-history");
@ -98,7 +99,6 @@ export const toggleSearchHistory = (searchElement: Element, config: Config.IUILa
});
const separatorElement = menu.addSeparator(1);
let current = true;
const searchInputElement = searchElement.querySelector("#searchInput, #toolbarSearch") as HTMLInputElement;
list.keys.forEach((s: string) => {
if (s !== searchInputElement.value && s) {
const menuItem = menu.addItem({
@ -153,8 +153,9 @@ export const toggleSearchHistory = (searchElement: Element, config: Config.IUILa
};
export const toggleAssetHistory = (assetElement: Element) => {
const assetInputElement = assetElement.querySelector("#searchAssetInput") as HTMLInputElement;
const keys = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].keys;
if (!keys || keys.length === 0) {
if (!keys || keys.length === 0 || (keys.length === 1 && keys[0] === assetInputElement.value)) {
return;
}
const menu = new Menu("search-asset-history");
@ -172,7 +173,6 @@ export const toggleAssetHistory = (assetElement: Element) => {
});
const separatorElement = menu.addSeparator(1);
let current = true;
const assetInputElement = assetElement.querySelector("#searchAssetInput") as HTMLInputElement;
keys.forEach((s: string) => {
if (s !== assetInputElement.value && s) {
const menuItem = menu.addItem({
@ -233,7 +233,7 @@ export const saveKeyList = (type: "keys" | "replaceKeys", value: string) => {
setStorageVal(Constants.LOCAL_SEARCHKEYS, window.siyuan.storage[Constants.LOCAL_SEARCHKEYS]);
};
export const saveAssetKeyList = (inputElement:HTMLInputElement) => {
export const saveAssetKeyList = (inputElement: HTMLInputElement) => {
if (!inputElement.value) {
return;
}

View file

@ -51,6 +51,7 @@ import {getUnRefList, openSearchUnRef, unRefMoreMenu} from "./unRef";
import {getDefaultType} from "./getDefault";
import {isSupportCSSHL, searchMarkRender} from "../protyle/render/searchMarkRender";
import {saveKeyList, toggleAssetHistory, toggleReplaceHistory, toggleSearchHistory} from "./toggleHistory";
import {highlightById} from "../util/highlightById";
export const openGlobalSearch = (app: App, text: string, replace: boolean, searchData?: Config.IUILayoutTabSearchConfig) => {
text = text.trim();
@ -1101,6 +1102,8 @@ export const getArticle = (options: {
searchMarkRender(options.edit.protyle, getResponse.data.keywords, options.id, () => {
if (options.edit.protyle.highlight.ranges.length > 0 && options.edit.protyle.highlight.ranges[options.edit.protyle.highlight.rangeIndex]) {
options.edit.protyle.contentElement.scrollTop = options.edit.protyle.contentElement.scrollTop + options.edit.protyle.highlight.ranges[options.edit.protyle.highlight.rangeIndex].getBoundingClientRect().top - contentRect.top - contentRect.height / 2;
} else {
highlightById(options.edit.protyle, options.id);
}
});
} else {

View file

@ -279,7 +279,8 @@ declare namespace Config {
| "de_DE"
| "he_IL"
| "ru_RU"
| "pl_PL";
| "pl_PL"
| "ar_SA";
/**
* SiYuan bazaar related configuration

View file

@ -874,7 +874,8 @@ interface IAVCellValue {
mAsset?: IAVCellAssetValue[]
block?: {
content: string,
id?: string
id?: string,
icon?: string
}
url?: {
content: string

44
app/src/types/user-agent.d.ts vendored Normal file
View file

@ -0,0 +1,44 @@
// WICG Spec: https://wicg.github.io/ua-client-hints
declare interface Navigator extends NavigatorUA {}
declare interface WorkerNavigator extends NavigatorUA {}
// https://wicg.github.io/ua-client-hints/#navigatorua
declare interface NavigatorUA {
readonly userAgentData?: NavigatorUAData;
}
// https://wicg.github.io/ua-client-hints/#dictdef-navigatoruabrandversion
interface NavigatorUABrandVersion {
readonly brand: string;
readonly version: string;
}
// https://wicg.github.io/ua-client-hints/#dictdef-uadatavalues
interface UADataValues {
readonly brands?: NavigatorUABrandVersion[];
readonly mobile?: boolean;
readonly platform?: string;
readonly architecture?: string;
readonly bitness?: string;
readonly formFactor?: string[];
readonly model?: string;
readonly platformVersion?: string;
/** @deprecated in favour of fullVersionList */
readonly uaFullVersion?: string;
readonly fullVersionList?: NavigatorUABrandVersion[];
readonly wow64?: boolean;
}
// https://wicg.github.io/ua-client-hints/#dictdef-ualowentropyjson
interface UALowEntropyJSON {
readonly brands: NavigatorUABrandVersion[];
readonly mobile: boolean;
readonly platform: string;
}
// https://wicg.github.io/ua-client-hints/#navigatoruadata
interface NavigatorUAData extends UALowEntropyJSON {
getHighEntropyValues(hints: string[]): Promise<UADataValues>;
toJSON(): UALowEntropyJSON;
}

View file

@ -7,7 +7,7 @@ import {exportLayout} from "../layout/util";
/// #endif
import {fetchPost} from "./fetch";
import {appearance} from "../config/appearance";
import {isInAndroid, isInHarmony, isInIOS} from "../protyle/util/compatibility";
import {isInAndroid, isInHarmony, isInIOS, isIPad, isIPhone, isMac, isWin11} from "../protyle/util/compatibility";
const loadThirdIcon = (iconURL: string, data: Config.IAppearance) => {
addScript(iconURL, "iconDefaultScript").then(() => {
@ -199,28 +199,77 @@ export const addGA = () => {
}
};
export const setInlineStyle = (set = true) => {
export const setInlineStyle = async (set = true) => {
const height = Math.floor(window.siyuan.config.editor.fontSize * 1.625);
let style;
if (window.siyuan.config.editor.fontFamily) {
// Emojis Reset: 字体中包含了 emoji需重置
// Emojis Additional 苹果/win11 字体中没有的 emoji
if (isMac() || isIPad() || isIPhone()) {
style = `@font-face {
font-family: "Number Glyphs";
src: local("${window.siyuan.config.editor.fontFamily}");
unicode-range: U+30-39;
font-family: "Emojis Additional";
src: url(stage/build/fonts/Noto-COLRv1.woff2) format("woff2");
unicode-range: U+1fae9, U+1fac6, U+1fabe, U+1fadc, U+e50a, U+1fa89, U+1fadf, U+1f1e6-1f1ff, U+1fa8f;
}
.b3-typography:not(.b3-typography--default), .protyle-wysiwyg, .protyle-title {font-family: "Number Glyphs", "SiYuan Emojis", "${window.siyuan.config.editor.fontFamily}", var(--b3-font-family-protyle)}`;
@font-face {
font-family: "Emojis Reset";
src: local("Apple Color Emoji"),
local("Segoe UI Emoji"),
local("Segoe UI Symbol");
unicode-range: U+26a1, U+21a9, U+21aa, U+2708, U+263a, U+1fae4, U+2194-2199, U+2934-2935, U+25b6, U+25c0, U+23cf, U+2640, U+2642, U+2611, U+303d,
U+3030, U+00a9, U+00ae, U+2122, U+1f170, U+1f171, U+24c2, U+1f17e, U+1f17f, U+1f250, U+1f21a, U+1f22f, U+1f232-1f23a,
U+1f251, U+3297, U+3299, U+2639, U+2660, U+2666, U+2665, U+2663, U+26A0;
}
@font-face {
font-family: "Emojis";
src: local("Apple Color Emoji"),
local("Segoe UI Emoji"),
local("Segoe UI Symbol");
}`
} else {
style = `@font-face {
font-family: "Number Glyphs";
src: local("Helvetica Neue"),
local("Luxi Sans"),
local("DejaVu Sans"),
local("Hiragino Sans GB"),
local("Segoe UI"),
local("Microsoft Yahei"),
local("sans-serif");
unicode-range: U+30-39;
const isWin11Browser = await isWin11();
if (isWin11Browser) {
style = `@font-face {
font-family: "Emojis Additional";
src: url(stage/build/fonts/Noto-COLRv1.woff2) format("woff2");
unicode-range: U+1fae9, U+1fac6, U+1fabe, U+1fadc, U+e50a, U+1fa89, U+1fadf, U+1f1e6-1f1ff, U+1f3f4, U+e0067, U+e0062,
U+e0065, U+e006e, U+e0067, U+e007f, U+e0073, U+e0063, U+e0074, U+e0077, U+e006c;
}
@font-face {
font-family: "Emojis Reset";
src: local("Segoe UI Emoji"),
local("Segoe UI Symbol");
unicode-range: U+263a,U+21a9,U+2642,U+303d,U+2197,U+2198,U+2199,U+2196,U+2195,U+2194,U+2660,U+2665,U+2666,U+2663,
U+3030,U+a9,U+ae,U+2122,U+21aa,U+25b6,U+25c0,U+2640,U+203c;
}
@font-face {
font-family: "Emojis";
src: local("Segoe UI Emoji"),
local("Segoe UI Symbol");
}`;
} else {
style = `
@font-face {
font-family: "Emojis Reset";
src: url(stage/build/fonts/Noto-COLRv1.woff2) format("woff2");
unicode-range: U+263a, U+2194-2199, U+2934-2935, U+2639, U+26a0, U+25b6, U+25c0, U+23cf, U+2640, U+2642, U+203c, U+2049,
U+2611, U+303d, U+00a9, U+00ae, U+2122, U+1f170-1f171, U+24c2, U+1f17e, U+1f17f, U+1f22f, U+1f250, U+1f21a,
U+1f232-1f23a, U+1f251, U+3297, U+3299, U+25aa, U+25ab, U+2660, U+2666, U+2665, U+2663, U+1f636, U+1f62e, U+1f642,
U+1f635, U+2620, U+2763, U+2764, U+1f441,U+fe0f, U+1f5e8, U+270c, U+261d, U+270d, U+200d, U+e50a, U+3030, U+21aa,
U+21a9, U+1f525, U+1fa79, U+1f4ab, U+1f4a8, U+1f32b;
}
@font-face {
font-family: "Emojis";
src: url(stage/build/fonts/Noto-COLRv1.woff2) format("woff2"),
local("Segoe UI Emoji"),
local("Segoe UI Symbol"),
local("Apple Color Emoji"),
local("Twemoji Mozilla"),
local("Noto Color Emoji"),
local("Android Emoji"),
local("EmojiSymbols");
}`;
}
}
style += `.b3-typography, .protyle-wysiwyg, .protyle-title {font-size:${window.siyuan.config.editor.fontSize}px !important}
.b3-typography code:not(.hljs), .protyle-wysiwyg span[data-type~=code] { font-variant-ligatures: ${window.siyuan.config.editor.codeLigatures ? "normal" : "none"} }
@ -239,6 +288,9 @@ export const setInlineStyle = (set = true) => {
.protyle-wysiwyg [data-node-id] {${window.siyuan.config.editor.justify ? " text-align: justify;" : ""}}
.protyle-wysiwyg .li {min-height:${height + 8}px}
.protyle-gutters button svg {height:${height}px}`;
if (window.siyuan.config.editor.fontFamily) {
style += `\n.b3-typography:not(.b3-typography--default), .protyle-wysiwyg, .protyle-title {font-family: "Emojis Additional", "Emojis Reset", "${window.siyuan.config.editor.fontFamily}", var(--b3-font-family)}`;
}
// pad 端菜单移除显示,如工作空间
if ("ontouchend" in document) {
style += "\n.b3-menu .b3-menu__action {opacity: 0.68;}";

View file

@ -154,8 +154,10 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
return;
}
const dialog = new Dialog({
title: `${title || window.siyuan.languages.move}
<div style="max-height: 16px;overflow: auto;line-height: 14px;-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 6px);padding-bottom: 4px;margin-bottom: -4px" class="ft__smaller ft__on-surface fn__hidescrollbar"></div>`,
title: `<div style="padding: 8px;">
${title || window.siyuan.languages.move}
<div style="max-height: 16px;overflow: auto;line-height: 14px;-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 6px);padding-bottom: 4px;margin-bottom: -4px" class="ft__smaller ft__on-surface fn__hidescrollbar"></div>
</div>`,
content: `<div class="b3-form__icon" style="margin: 8px">
<span data-menu="true" class="b3-form__icon-list fn__a b3-tooltips b3-tooltips__s" aria-label="${updateHotkeyTip("")}">
<svg class="svg--mid"><use xlink:href="#iconSearch"></use></svg>
@ -178,6 +180,7 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
}
}
});
dialog.element.querySelector(".b3-dialog__header").setAttribute("style", "padding:0");
dialog.element.setAttribute("data-key", Constants.DIALOG_MOVEPATHTO);
if (paths && paths.length > 0) {
fetchPost("/api/filetree/getHPathsByPaths", {paths}, (response) => {
@ -260,7 +263,7 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
const toggleMovePathHistory = () => {
const keys = window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys;
if (!keys || keys.length === 0) {
if (!keys || keys.length === 0 || (keys.length === 1 && keys[0] === inputElement.value)) {
return;
}
const menu = new Menu("move-path-history");

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@ func exportEPUB(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "epub", ".epub")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "epub", ".epub")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -84,7 +84,7 @@ func exportRTF(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "rtf", ".rtf")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "rtf", ".rtf")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -101,7 +101,7 @@ func exportODT(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "odt", ".odt")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "odt", ".odt")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -118,7 +118,7 @@ func exportMediaWiki(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "mediawiki", ".wiki")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "mediawiki", ".wiki")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -135,7 +135,7 @@ func exportOrgMode(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "org", ".org")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "org", ".org")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -152,7 +152,7 @@ func exportOPML(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "opml", ".opml")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "opml", ".opml")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -169,7 +169,7 @@ func exportTextile(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "textile", ".textile")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "textile", ".textile")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -186,7 +186,7 @@ func exportAsciiDoc(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "asciidoc", ".adoc")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "asciidoc", ".adoc")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -203,7 +203,7 @@ func exportReStructuredText(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "rst", ".rst")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "rst", ".rst")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -340,7 +340,7 @@ func exportMds(c *gin.Context) {
ids = append(ids, id.(string))
}
name, zipPath := model.BatchExportPandocConvertZip(ids, "", ".md")
name, zipPath := model.ExportPandocConvertZip(ids, "", ".md")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,
@ -357,7 +357,7 @@ func exportMd(c *gin.Context) {
}
id := arg["id"].(string)
name, zipPath := model.ExportPandocConvertZip(id, "", ".md")
name, zipPath := model.ExportPandocConvertZip([]string{id}, "", ".md")
ret.Data = map[string]interface{}{
"name": name,
"zip": zipPath,

View file

@ -10,7 +10,7 @@ require (
github.com/88250/epub v0.0.0-20230830085737-c19055cd1f48
github.com/88250/go-humanize v0.0.0-20240424102817-4f78fac47ea7
github.com/88250/gulu v1.2.3-0.20241212012748-c4dc08fe45ec
github.com/88250/lute v1.7.7-0.20241213121436-8647e479e280
github.com/88250/lute v1.7.7-0.20241217024500-996f9fa60606
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1
github.com/ClarkThan/ahocorasick v0.0.0-20231011042242-30d1ef1347f4
github.com/ConradIrwin/font v0.0.0-20240627033111-8567075b2bfe
@ -40,7 +40,7 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/gorilla/css v1.0.1
github.com/gorilla/websocket v1.5.3
github.com/imroc/req/v3 v3.48.0
github.com/imroc/req/v3 v3.49.0
github.com/jinzhu/copier v0.4.0
github.com/json-iterator/go v1.1.12
github.com/klippa-app/go-pdfium v1.12.2
@ -48,7 +48,7 @@ require (
github.com/mitchellh/go-ps v1.0.0
github.com/mssola/useragent v1.0.0
github.com/olahol/melody v1.2.1
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.0
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.1
github.com/panjf2000/ants/v2 v2.10.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pdfcpu/pdfcpu v0.9.1
@ -57,13 +57,13 @@ require (
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/sashabaranov/go-openai v1.29.1
github.com/shirou/gopsutil/v3 v3.24.5
github.com/siyuan-note/dejavu v0.0.0-20241212013736-f1a4428c07cc
github.com/siyuan-note/dejavu v0.0.0-20241217094848-8beeb0605db2
github.com/siyuan-note/encryption v0.0.0-20231219001248-1e028a4d13b4
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97
github.com/siyuan-note/filelock v0.0.0-20241212013445-c66518cdacfa
github.com/siyuan-note/httpclient v0.0.0-20241212013326-2b23123573c3
github.com/siyuan-note/httpclient v0.0.0-20241217094627-0dbb1d2d7698
github.com/siyuan-note/logging v0.0.0-20241212013108-623e0bb0bcd9
github.com/siyuan-note/riff v0.0.0-20241203002117-3b8d28360e46
github.com/siyuan-note/riff v0.0.0-20241217095231-017015753318
github.com/spf13/cast v1.7.0
github.com/steambap/captcha v1.4.1
github.com/studio-b12/gowebdav v0.9.0
@ -169,7 +169,7 @@ require (
go.uber.org/mock v0.5.0 // indirect
golang.org/x/arch v0.10.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/tools v0.28.0 // indirect

View file

@ -14,8 +14,8 @@ github.com/88250/go-sqlite3 v1.14.13-0.20231214121541-e7f54c482950 h1:Pa5hMiBceT
github.com/88250/go-sqlite3 v1.14.13-0.20231214121541-e7f54c482950/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/88250/gulu v1.2.3-0.20241212012748-c4dc08fe45ec h1:YsUSpByWJP+x8C+IT+C3QlFvU7ZQ6+E95SFd9+zy6QU=
github.com/88250/gulu v1.2.3-0.20241212012748-c4dc08fe45ec/go.mod h1:c8uVw25vW2W4dhJ/j4iYsX5H1hc19spim266jO5x2hU=
github.com/88250/lute v1.7.7-0.20241213121436-8647e479e280 h1:Ub4MpkyCTOvf3L1po5FUSJ1h52qlrThN8YQtbxbUu2s=
github.com/88250/lute v1.7.7-0.20241213121436-8647e479e280/go.mod h1:WYyUw//5yVw9BJnoVjx7rI/3szsISxNZCYGOqTIrV0o=
github.com/88250/lute v1.7.7-0.20241217024500-996f9fa60606 h1:x3VJugAZ6CuohGCFvk4eoujbE9iXO4HHvGKOT2FEeTg=
github.com/88250/lute v1.7.7-0.20241217024500-996f9fa60606/go.mod h1:WYyUw//5yVw9BJnoVjx7rI/3szsISxNZCYGOqTIrV0o=
github.com/88250/pdfcpu v0.3.14-0.20241201033812-5a93b7586a01 h1:AcFe63RXjIh1XtX/dc4Es3U8bYKjlEkvavHd1nFBOHM=
github.com/88250/pdfcpu v0.3.14-0.20241201033812-5a93b7586a01/go.mod h1:fVfOloBzs2+W2VJCCbq60XIxc3yJHAZ0Gahv1oO0gyI=
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1 h1:48T899JQDwyyRu9yXHePYlPdHtpJfrJEUGBMH3SMBWY=
@ -194,8 +194,8 @@ github.com/hhrutter/tiff v1.0.1/go.mod h1:zU/dNgDm0cMIa8y8YwcYBeuEEveI4B0owqHyiP
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/imroc/req/v3 v3.48.0 h1:IYuMGetuwLzOOTzDCquDqs912WNwpsPK0TBXWPIvoqg=
github.com/imroc/req/v3 v3.48.0/go.mod h1:weam9gmyb00QnOtu6HXSnk44dNFkIUQb5QdMx13FeUU=
github.com/imroc/req/v3 v3.49.0 h1:5Rac2qvz7Dq0E3PeBo/c2szV3hagPQIGLoHtfBmYhu4=
github.com/imroc/req/v3 v3.49.0/go.mod h1:XZf4t94DNJzcA0UOBlA68hmSrWsAyvN407ADdH4mzCA=
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
@ -272,8 +272,8 @@ github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.0 h1:4Y8oZN1oBAfS9UkUDuSk48VXjdb6BT1xD2MTFRTWTAc=
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.0/go.mod h1:zTtQIk3kOO9kweg5zJAgbdwBXR2HBPsDN0k6AxmTpzY=
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.1 h1:zKBIfL5ZmbJfSe4nXABkazrSw7BQufi5ghXTZWXsvq8=
github.com/open-spaced-repetition/go-fsrs/v3 v3.3.1/go.mod h1:zTtQIk3kOO9kweg5zJAgbdwBXR2HBPsDN0k6AxmTpzY=
github.com/otiai10/gosseract/v2 v2.4.1 h1:G8AyBpXEeSlcq8TI85LH/pM5SXk8Djy2GEXisgyblRw=
github.com/otiai10/gosseract/v2 v2.4.1/go.mod h1:1gNWP4Hgr2o7yqWfs6r5bZxAatjOIdqWxJLWsTsembk=
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
@ -341,20 +341,20 @@ github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+D
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d h1:lvCTyBbr36+tqMccdGMwuEU+hjux/zL6xSmf5S9ITaA=
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
github.com/siyuan-note/dejavu v0.0.0-20241212013736-f1a4428c07cc h1:QT2xfpSFChSdvw7uzY9S46pnKtsFkWKS0OOFfyjOtmA=
github.com/siyuan-note/dejavu v0.0.0-20241212013736-f1a4428c07cc/go.mod h1:ytDHT/FQKl1SuGEsnI2YQbhirlswQiiwc0rSW3nnnFo=
github.com/siyuan-note/dejavu v0.0.0-20241217094848-8beeb0605db2 h1:Mv1yhF4uGmIInRDiwqODyoQFsySIntv1HYSYvhnLUkc=
github.com/siyuan-note/dejavu v0.0.0-20241217094848-8beeb0605db2/go.mod h1:C4VZXf61Q5nvWo4sWaBO4AnqJSg4ly3kHQI+FrEuV+M=
github.com/siyuan-note/encryption v0.0.0-20231219001248-1e028a4d13b4 h1:kJaw5L/evyW6LcB9IQT8PR4ppx8JVqOFP9Ix3rfwSrc=
github.com/siyuan-note/encryption v0.0.0-20231219001248-1e028a4d13b4/go.mod h1:UYcCCY+0wh+GmUoDOaO63j1sV5lgy7laLAk1XhEiUis=
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97 h1:lM5v8BfNtbOL5jYwhCdMYBcYtr06IYBKjjSLAPMKTM8=
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97/go.mod h1:1/nGgthl89FPA7GzAcEWKl6zRRnfgyTjzLZj9bW7kuw=
github.com/siyuan-note/filelock v0.0.0-20241212013445-c66518cdacfa h1:NM/0m8/hmFZGo0v+xNnjEeoqTtZShcVadWS0WYah+yI=
github.com/siyuan-note/filelock v0.0.0-20241212013445-c66518cdacfa/go.mod h1:OmJuq0Dm+S8I713lmfmZNFwtQ/o4mdZHSfsEra39lfY=
github.com/siyuan-note/httpclient v0.0.0-20241212013326-2b23123573c3 h1:9iSRzXsEmDgofy11kjtiWFC83wqHsGSHZ0meW0qiCJw=
github.com/siyuan-note/httpclient v0.0.0-20241212013326-2b23123573c3/go.mod h1:PJNk4sdv+CQFjlAFJhv821asNZhJmBoa1Jbe4TAGQlg=
github.com/siyuan-note/httpclient v0.0.0-20241217094627-0dbb1d2d7698 h1:vds4JlCUMdLlpaobBJTgojpCaxJVbk7zVrZpP2RZrxM=
github.com/siyuan-note/httpclient v0.0.0-20241217094627-0dbb1d2d7698/go.mod h1:z9ala5zx8ivq8UaySAFkfk1ItSUoV8I0196Fu5NnpeE=
github.com/siyuan-note/logging v0.0.0-20241212013108-623e0bb0bcd9 h1:DYF4JZFiVTy1hmFvrpyRxc+8qaymm/THwdyow/xWark=
github.com/siyuan-note/logging v0.0.0-20241212013108-623e0bb0bcd9/go.mod h1:jZ4dO1KQBl3mqarQCwL8bnAyWz3SeZsySLT6HjSuZjY=
github.com/siyuan-note/riff v0.0.0-20241203002117-3b8d28360e46 h1:HHplIFTgsRdPJo3uQuVgzqwiw2+Uyurkpee8NAO+k+Q=
github.com/siyuan-note/riff v0.0.0-20241203002117-3b8d28360e46/go.mod h1:/mdhL34JKGnWtVuhenkIfeqqBeZTZg6ZOIklMXA7pvA=
github.com/siyuan-note/riff v0.0.0-20241217095231-017015753318 h1:f85tgE/sYxCOvJSwmKlsVJO5NSSMsScZDJ+dhK0V+1o=
github.com/siyuan-note/riff v0.0.0-20241217095231-017015753318/go.mod h1:y76kbfoAdNo04msO/YkoHZoxLIUF2J/CFP7abNN4LBc=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
@ -427,8 +427,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=

View file

@ -322,13 +322,24 @@ func GetAssetAbsPath(relativePath string) (ret string, err error) {
if strings.Contains(relativePath, "?") {
relativePath = relativePath[:strings.Index(relativePath, "?")]
}
// 在全局 assets 路径下搜索
p := filepath.Join(util.DataDir, relativePath)
if gulu.File.IsExist(p) {
ret = p
if !util.IsSubPath(util.WorkspaceDir, ret) {
err = fmt.Errorf("[%s] is not sub path of workspace", ret)
return
}
return
}
// 在笔记本下搜索
notebooks, err := ListNotebooks()
if err != nil {
err = errors.New(Conf.Language(0))
return
}
// 在笔记本下搜索
for _, notebook := range notebooks {
notebookAbsPath := filepath.Join(util.DataDir, notebook.ID)
filelock.Walk(notebookAbsPath, func(path string, d fs.DirEntry, err error) error {
@ -356,16 +367,6 @@ func GetAssetAbsPath(relativePath string) (ret string, err error) {
}
}
// 在全局 assets 路径下搜索
p := filepath.Join(util.DataDir, relativePath)
if gulu.File.IsExist(p) {
ret = p
if !util.IsSubPath(util.WorkspaceDir, ret) {
err = fmt.Errorf("[%s] is not sub path of workspace", ret)
return
}
return
}
return "", errors.New(fmt.Sprintf(Conf.Language(12), relativePath))
}

View file

@ -2011,7 +2011,7 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
IsDetached: isDetached,
CreatedAt: now,
UpdatedAt: now,
Block: &av.ValueBlock{ID: addingBlockID, Content: addingBlockContent, Created: now, Updated: now}}
Block: &av.ValueBlock{ID: addingBlockID, Icon: blockIcon, Content: addingBlockContent, Created: now, Updated: now}}
blockValues.Values = append(blockValues.Values, blockValue)
// 如果存在过滤条件,则将过滤条件应用到新添加的块上

View file

@ -18,6 +18,7 @@ package model
import (
"bytes"
"crypto/sha1"
"encoding/csv"
"errors"
"fmt"
@ -268,10 +269,10 @@ func Export2Liandi(id string) (err error) {
title := path.Base(tree.HPath)
tags := tree.Root.IALAttr("tags")
content := exportMarkdownContent0(tree, util.GetCloudForumAssetsServer()+time.Now().Format("2006/01")+"/siyuan/"+Conf.GetUser().UserId+"/", true,
4, 1, 0,
".md", 4, 1, 0,
"#", "#",
"", "",
false, nil)
false, nil, true)
result := gulu.Ret.NewResult()
request := httpclient.NewCloudRequest30s()
request = request.
@ -577,7 +578,7 @@ func Preview(id string) (retStdHTML string) {
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
Conf.Export.AddTitle, true)
Conf.Export.AddTitle, true, true)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
addBlockIALNodes(tree, false)
@ -680,7 +681,7 @@ func ExportMarkdownHTML(id, savePath string, docx, merge bool) (name, dom string
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
Conf.Export.AddTitle, true)
Conf.Export.AddTitle, true, true)
name = path.Base(tree.HPath)
name = util.FilterFileName(name) // 导出 PDF、HTML 和 Word 时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/5614
savePath = strings.TrimSpace(savePath)
@ -839,7 +840,7 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
blockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
Conf.Export.AddTitle, true)
Conf.Export.AddTitle, true, true)
name = path.Base(tree.HPath)
name = util.FilterFileName(name) // 导出 PDF、HTML 和 Word 时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/5614
@ -1420,7 +1421,6 @@ func ExportStdMarkdown(id string) string {
var defID string
if treenode.IsBlockLink(n) {
defID = strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
} else if treenode.IsBlockRef(n) {
defID, _, _ = treenode.GetBlockRef(n)
}
@ -1437,13 +1437,13 @@ func ExportStdMarkdown(id string) string {
defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
return exportMarkdownContent0(tree, cloudAssetsBase, false,
Conf.Export.BlockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
".md", Conf.Export.BlockRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
Conf.Export.AddTitle, defBlockIDs)
Conf.Export.AddTitle, defBlockIDs, true)
}
func BatchExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipPath string) {
func ExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipPath string) {
block := treenode.GetBlockTree(ids[0])
box := Conf.Box(block.BoxID)
baseFolderName := path.Base(block.HPath)
@ -1462,31 +1462,8 @@ func BatchExportPandocConvertZip(ids []string, pandocTo, ext string) (name, zipP
}
docPaths = util.FilterSelfChildDocs(docPaths)
zipPath = exportPandocConvertZip(baseFolderName, docPaths, "gfm+footnotes+hard_line_breaks", pandocTo, ext)
name = util.GetTreeID(block.Path)
return
}
func ExportPandocConvertZip(id, pandocTo, ext string) (name, zipPath string) {
block := treenode.GetBlockTree(id)
if nil == block {
logging.LogErrorf("not found block [%s]", id)
return
}
boxID := block.BoxID
box := Conf.Box(boxID)
baseFolderName := path.Base(block.HPath)
if "." == baseFolderName {
baseFolderName = path.Base(block.Path)
}
docPaths := []string{block.Path}
docFiles := box.ListFiles(strings.TrimSuffix(block.Path, ".sy"))
for _, docFile := range docFiles {
docPaths = append(docPaths, docFile.path)
}
zipPath = exportPandocConvertZip(baseFolderName, docPaths, "gfm+footnotes+hard_line_breaks", pandocTo, ext)
defBlockIDs, trees, docPaths := prepareExportTrees(docPaths)
zipPath = exportPandocConvertZip(baseFolderName, docPaths, defBlockIDs, "gfm+footnotes+hard_line_breaks", pandocTo, ext, trees)
name = util.GetTreeID(block.Path)
return
}
@ -1514,7 +1491,9 @@ func ExportNotebookMarkdown(boxID, folderPath string) (zipPath string) {
for _, docFile := range docFiles {
docPaths = append(docPaths, docFile.path)
}
zipPath = exportPandocConvertZip(baseFolderName, docPaths, "", "", ".md")
defBlockIDs, trees, docPaths := prepareExportTrees(docPaths)
zipPath = exportPandocConvertZip(baseFolderName, docPaths, defBlockIDs, "", "", ".md", trees)
return
}
@ -1641,7 +1620,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(70), fmt.Sprintf("%d/%d %s", count, len(docPaths), tree.Root.IALAttr("title"))))
refs := map[string]*parse.Tree{}
exportRefTrees(tree, &refs, &treeCache)
exportRefTrees(tree, &[]string{}, &refs, &treeCache)
for refTreeID, refTree := range refs {
if nil == trees[refTreeID] {
refTrees[refTreeID] = refTree
@ -1706,6 +1685,11 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
}
// 导出引用的资源文件
assetPathMap, err := allAssetAbsPaths()
if nil != err {
logging.LogWarnf("get assets abs path failed: %s", err)
return
}
copiedAssets := hashset.New()
for _, tree := range trees {
var assets []string
@ -1729,14 +1713,14 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
continue
}
srcPath, assetErr := GetAssetAbsPath(asset)
if nil != assetErr {
logging.LogWarnf("get asset [%s] abs path failed: %s", asset, assetErr)
srcPath := assetPathMap[asset]
if "" == srcPath {
logging.LogWarnf("get asset [%s] abs path failed", asset)
continue
}
destPath := filepath.Join(exportFolder, asset)
assetErr = filelock.Copy(srcPath, destPath)
assetErr := filelock.Copy(srcPath, destPath)
if nil != assetErr {
logging.LogErrorf("copy asset from [%s] to [%s] failed: %s", srcPath, destPath, assetErr)
continue
@ -1794,9 +1778,9 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
}
destPath := filepath.Join(exportFolder, asset.Content)
srcPath, assetErr := GetAssetAbsPath(asset.Content)
if nil != assetErr {
logging.LogWarnf("get asset [%s] abs path failed: %s", asset.Content, assetErr)
srcPath := assetPathMap[asset.Content]
if "" == srcPath {
logging.LogWarnf("get asset [%s] abs path failed", asset.Content)
continue
}
@ -1943,10 +1927,10 @@ func walkRelationAvs(avID string, exportAvIDs *hashset.Set) {
}
func ExportMarkdownContent(id string) (hPath, exportedMd string) {
return exportMarkdownContent(id, Conf.Export.BlockRefMode, nil)
return exportMarkdownContent(id, ".md", Conf.Export.BlockRefMode, nil, true)
}
func exportMarkdownContent(id string, exportRefMode int, defBlockIDs []string) (hPath, exportedMd string) {
func exportMarkdownContent(id, ext string, exportRefMode int, defBlockIDs []string, singleFile bool) (hPath, exportedMd string) {
tree, err := LoadTreeByBlockID(id)
if err != nil {
logging.LogErrorf("load tree by block id [%s] failed: %s", id, err)
@ -1954,26 +1938,24 @@ func exportMarkdownContent(id string, exportRefMode int, defBlockIDs []string) (
}
hPath = tree.HPath
exportedMd = exportMarkdownContent0(tree, "", false,
exportRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
ext, exportRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode,
Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker,
Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight,
Conf.Export.AddTitle, defBlockIDs)
Conf.Export.AddTitle, defBlockIDs, singleFile)
docIAL := parse.IAL2Map(tree.Root.KramdownIAL)
exportedMd = yfm(docIAL) + exportedMd
return
}
func exportMarkdownContent0(tree *parse.Tree, cloudAssetsBase string, assetsDestSpace2Underscore bool,
blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
tagOpenMarker, tagCloseMarker string,
blockRefTextLeft, blockRefTextRight string,
addTitle bool,
defBlockIDs []string) (ret string) {
ext string, blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
tagOpenMarker, tagCloseMarker string, blockRefTextLeft, blockRefTextRight string,
addTitle bool, defBlockIDs []string, singleFile bool) (ret string) {
tree = exportTree(tree, false, false, false,
blockRefMode, blockEmbedMode, fileAnnotationRefMode,
tagOpenMarker, tagCloseMarker,
blockRefTextLeft, blockRefTextRight,
addTitle, 0 < len(defBlockIDs))
addTitle, 0 < len(defBlockIDs), singleFile)
luteEngine := NewLute()
luteEngine.SetFootnotes(true)
luteEngine.SetKramdownIAL(false)
@ -2051,7 +2033,7 @@ func exportMarkdownContent0(tree *parse.Tree, cloudAssetsBase string, assetsDest
var href string
bt := treenode.GetBlockTree(defID)
if nil != bt {
href += bt.HPath + ".md"
href += bt.HPath + ext
if "d" != bt.Type {
href += "#" + defID
}
@ -2084,7 +2066,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
blockRefMode, blockEmbedMode, fileAnnotationRefMode int,
tagOpenMarker, tagCloseMarker string,
blockRefTextLeft, blockRefTextRight string,
addTitle, addDocAnchorSpan bool) (ret *parse.Tree) {
addTitle, addDocAnchorSpan, singleFile bool) (ret *parse.Tree) {
luteEngine := NewLute()
ret = tree
id := tree.Root.ID
@ -2101,7 +2083,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
// 收集引用转脚注+锚点哈希
var refFootnotes []*refAsFootnotes
if 4 == blockRefMode {
if 4 == blockRefMode && singleFile {
depth = 0
collectFootnotesDefs(ret, ret.ID, &refFootnotes, &treeCache, &depth)
}
@ -2260,8 +2242,10 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
}
} else {
if 4 == blockRefMode { // 脚注+锚点哈希
anchorSpan := treenode.NewSpanAnchor(id)
ret.Root.PrependChild(anchorSpan)
if addDocAnchorSpan {
anchorSpan := treenode.NewSpanAnchor(id)
ret.Root.PrependChild(anchorSpan)
}
}
}
@ -2683,13 +2667,9 @@ func resolveFootnotesDefs(refFootnotes *[]*refAsFootnotes, currentTree *parse.Tr
footnotesDefBlock = &ast.Node{Type: ast.NodeFootnotesDefBlock}
var rendered []string
for _, foot := range *refFootnotes {
t := (*treeCache)[foot.defID]
if nil == t {
var err error
if t, err = LoadTreeByBlockID(foot.defID); err != nil {
continue
}
(*treeCache)[t.ID] = t
t, err := loadTreeWithCache(foot.defID, treeCache)
if nil != err {
return
}
defNode := treenode.GetNodeInTree(t, foot.defID)
@ -2823,14 +2803,11 @@ func blockLink2Ref(currentTree *parse.Tree, id string, treeCache *map[string]*pa
if nil == b {
return
}
t := (*treeCache)[b.RootID]
if nil == t {
var err error
if t, err = LoadTreeByBlockID(b.ID); err != nil {
return
}
(*treeCache)[t.ID] = t
t, err := loadTreeWithCache(b.ID, treeCache)
if nil != err {
return
}
node := treenode.GetNodeInTree(t, b.ID)
if nil == node {
logging.LogErrorf("not found node [%s] in tree [%s]", b.ID, t.Root.ID)
@ -2876,14 +2853,11 @@ func collectFootnotesDefs(currentTree *parse.Tree, id string, refFootnotes *[]*r
if nil == b {
return
}
t := (*treeCache)[b.RootID]
if nil == t {
var err error
if t, err = LoadTreeByBlockID(b.ID); err != nil {
return
}
(*treeCache)[t.ID] = t
t, err := loadTreeWithCache(b.ID, treeCache)
if nil != err {
return
}
node := treenode.GetNodeInTree(t, b.ID)
if nil == node {
logging.LogErrorf("not found node [%s] in tree [%s]", b.ID, t.Root.ID)
@ -2959,84 +2933,6 @@ type refAsFootnotes struct {
refAnchorText string
}
func exportRefTrees(tree *parse.Tree, retTrees, treeCache *map[string]*parse.Tree) {
if nil != (*retTrees)[tree.ID] {
return
}
(*retTrees)[tree.ID] = tree
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering {
return ast.WalkContinue
}
if treenode.IsBlockRef(n) {
defID, _, _ := treenode.GetBlockRef(n)
if "" == defID {
return ast.WalkContinue
}
defBlock := treenode.GetBlockTree(defID)
if nil == defBlock {
return ast.WalkSkipChildren
}
var defTree *parse.Tree
var err error
if (*treeCache)[defBlock.RootID] != nil {
defTree = (*treeCache)[defBlock.RootID]
} else {
defTree, err = LoadTreeByBlockID(defBlock.RootID)
if err != nil {
return ast.WalkSkipChildren
}
(*treeCache)[defBlock.RootID] = defTree
}
exportRefTrees(defTree, retTrees, treeCache)
} else if ast.NodeAttributeView == n.Type {
// 导出数据库所在文档时一并导出绑定块所在文档
// Export the binding block docs when exporting the doc where the database is located https://github.com/siyuan-note/siyuan/issues/11486
avID := n.AttributeViewID
if "" == avID {
return ast.WalkContinue
}
attrView, _ := av.ParseAttributeView(avID)
if nil == attrView {
return ast.WalkContinue
}
blockKeyValues := attrView.GetBlockKeyValues()
if nil == blockKeyValues {
return ast.WalkContinue
}
for _, val := range blockKeyValues.Values {
defBlock := treenode.GetBlockTree(val.BlockID)
if nil == defBlock {
continue
}
var defTree *parse.Tree
var err error
if (*treeCache)[defBlock.RootID] != nil {
defTree = (*treeCache)[defBlock.RootID]
} else {
defTree, err = LoadTreeByBlockID(defBlock.RootID)
if err != nil {
continue
}
(*treeCache)[defBlock.RootID] = defTree
}
exportRefTrees(defTree, retTrees, treeCache)
}
}
return ast.WalkContinue
})
}
func processFileAnnotationRef(refID string, n *ast.Node, fileAnnotationRefMode int) ast.WalkStatus {
p := refID[:strings.LastIndex(refID, "/")]
absPath, err := GetAssetAbsPath(p)
@ -3084,8 +2980,10 @@ func processFileAnnotationRef(refID string, n *ast.Node, fileAnnotationRefMode i
return ast.WalkSkipChildren
}
func exportPandocConvertZip(baseFolderName string, docPaths []string,
pandocFrom, pandocTo, ext string) (zipPath string) {
func exportPandocConvertZip(baseFolderName string, docPaths, defBlockIDs []string,
pandocFrom, pandocTo, ext string, treeCache *map[string]*parse.Tree) (zipPath string) {
defer util.ClearPushProgress(100)
dir, name := path.Split(baseFolderName)
name = util.FilterFileName(name)
if strings.HasSuffix(name, "..") {
@ -3103,60 +3001,25 @@ func exportPandocConvertZip(baseFolderName string, docPaths []string,
}
exportRefMode := Conf.Export.BlockRefMode
var defBlockIDs []string
if 4 == exportRefMode { // 脚注+锚点哈希
// 导出锚点哈希,这里先记录下所有定义块的 ID
walked := map[string]bool{}
for _, p := range docPaths {
if walked[p] {
continue
}
id := util.GetTreeID(p)
tree, err := LoadTreeByBlockID(id)
if err != nil {
continue
}
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering {
return ast.WalkContinue
}
var defID string
if treenode.IsBlockLink(n) {
defID = strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
} else if treenode.IsBlockRef(n) {
defID, _, _ = treenode.GetBlockRef(n)
}
if "" != defID {
if defBt := treenode.GetBlockTree(defID); nil != defBt {
docPaths = append(docPaths, defBt.Path)
docPaths = gulu.Str.RemoveDuplicatedElem(docPaths)
defBlockIDs = append(defBlockIDs, defID)
defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
walked[defBt.Path] = true
}
}
return ast.WalkContinue
})
}
defBlockIDs = gulu.Str.RemoveDuplicatedElem(defBlockIDs)
docPaths = gulu.Str.RemoveDuplicatedElem(docPaths)
wrotePathHash := map[string]string{}
assetsPathMap, err := allAssetAbsPaths()
if nil != err {
logging.LogWarnf("get assets abs path failed: %s", err)
return
}
luteEngine := util.NewLute()
for _, p := range docPaths {
for i, p := range docPaths {
id := util.GetTreeID(p)
hPath, md := exportMarkdownContent(id, exportRefMode, defBlockIDs)
hPath, md := exportMarkdownContent(id, ext, exportRefMode, defBlockIDs, false)
dir, name = path.Split(hPath)
dir = util.FilterFilePath(dir) // 导出文档时未移除不支持的文件名符号 https://github.com/siyuan-note/siyuan/issues/4590
name = util.FilterFileName(name)
hPath = path.Join(dir, name)
p = hPath + ext
writePath := filepath.Join(exportFolder, p)
if gulu.File.IsExist(writePath) {
hash := fmt.Sprintf("%x", sha1.Sum([]byte(md)))
if gulu.File.IsExist(writePath) && hash != wrotePathHash[writePath] {
// 重名文档加 ID
p = hPath + "-" + id + ext
writePath = filepath.Join(exportFolder, p)
@ -3181,15 +3044,14 @@ func exportPandocConvertZip(baseFolderName string, docPaths []string,
continue
}
srcPath, err := GetAssetAbsPath(asset)
if err != nil {
logging.LogWarnf("get asset [%s] abs path failed: %s", asset, err)
srcPath := assetsPathMap[asset]
if "" == srcPath {
logging.LogWarnf("get asset [%s] abs path failed", asset)
continue
}
destPath := filepath.Join(writeFolder, asset)
err = filelock.Copy(srcPath, destPath)
if err != nil {
if copyErr := filelock.Copy(srcPath, destPath); copyErr != nil {
logging.LogErrorf("copy asset from [%s] to [%s] failed: %s", srcPath, destPath, err)
continue
}
@ -3201,6 +3063,9 @@ func exportPandocConvertZip(baseFolderName string, docPaths []string,
logging.LogErrorf("pandoc failed: %s", err)
continue
}
wrotePathHash[writePath] = hash
util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(70), fmt.Sprintf("%d/%d %s", i+1, len(docPaths), name)))
}
zipPath = exportFolder + ".zip"
@ -3251,41 +3116,139 @@ func getExportBlockRefLinkText(blockRef *ast.Node, blockRefTextLeft, blockRefTex
return
}
func getDestViewVal(attrView *av.AttributeView, keyID, blockID string) *av.TableColumn {
rollupKey, _ := attrView.GetKey(keyID)
if nil == rollupKey || nil == rollupKey.Rollup {
return nil
func prepareExportTrees(docPaths []string) (defBlockIDs []string, trees *map[string]*parse.Tree, relatedDocPaths []string) {
trees = &map[string]*parse.Tree{}
treeCache := &map[string]*parse.Tree{}
defBlockIDs = []string{}
for _, p := range docPaths {
id := util.GetTreeID(p)
tree, err := loadTreeWithCache(id, treeCache)
if err != nil {
continue
}
exportRefTrees(tree, &defBlockIDs, trees, treeCache)
}
relKey, _ := attrView.GetKey(rollupKey.Rollup.RelationKeyID)
if nil == relKey || nil == relKey.Relation {
return nil
for _, tree := range *trees {
relatedDocPaths = append(relatedDocPaths, tree.Path)
}
relVal := attrView.GetValue(relKey.ID, blockID)
if nil == relVal || nil == relVal.Relation {
return nil
}
destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
if nil == destAv {
return nil
}
destKey, _ := destAv.GetKey(rollupKey.Rollup.KeyID)
if nil == destKey {
return nil
}
destView, _ := destAv.GetCurrentView(destAv.ViewID)
if nil == destView {
return nil
}
destTable := sql.RenderAttributeViewTable(destAv, destView, "")
if nil == destTable {
return nil
}
return destTable.GetColumn(rollupKey.Rollup.KeyID)
relatedDocPaths = gulu.Str.RemoveDuplicatedElem(relatedDocPaths)
return
}
func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache *map[string]*parse.Tree) {
if nil != (*retTrees)[tree.ID] {
return
}
(*retTrees)[tree.ID] = tree
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering {
return ast.WalkContinue
}
if treenode.IsBlockRef(n) {
defID, _, _ := treenode.GetBlockRef(n)
if "" == defID {
return ast.WalkContinue
}
defBlock := treenode.GetBlockTree(defID)
if nil == defBlock {
return ast.WalkSkipChildren
}
var defTree *parse.Tree
var err error
if (*treeCache)[defBlock.RootID] != nil {
defTree = (*treeCache)[defBlock.RootID]
} else {
defTree, err = loadTreeWithCache(defBlock.RootID, treeCache)
if err != nil {
return ast.WalkSkipChildren
}
(*treeCache)[defBlock.RootID] = defTree
}
*defBlockIDs = append(*defBlockIDs, defID)
exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
} else if treenode.IsBlockLink(n) {
defID := strings.TrimPrefix(n.TextMarkAHref, "siyuan://blocks/")
if "" == defID {
return ast.WalkContinue
}
defBlock := treenode.GetBlockTree(defID)
if nil == defBlock {
return ast.WalkSkipChildren
}
var defTree *parse.Tree
var err error
if (*treeCache)[defBlock.RootID] != nil {
defTree = (*treeCache)[defBlock.RootID]
} else {
defTree, err = loadTreeWithCache(defBlock.RootID, treeCache)
if err != nil {
return ast.WalkSkipChildren
}
(*treeCache)[defBlock.RootID] = defTree
}
*defBlockIDs = append(*defBlockIDs, defID)
exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
} else if ast.NodeAttributeView == n.Type {
// 导出数据库所在文档时一并导出绑定块所在文档
// Export the binding block docs when exporting the doc where the database is located https://github.com/siyuan-note/siyuan/issues/11486
avID := n.AttributeViewID
if "" == avID {
return ast.WalkContinue
}
attrView, _ := av.ParseAttributeView(avID)
if nil == attrView {
return ast.WalkContinue
}
blockKeyValues := attrView.GetBlockKeyValues()
if nil == blockKeyValues {
return ast.WalkContinue
}
for _, val := range blockKeyValues.Values {
defBlock := treenode.GetBlockTree(val.BlockID)
if nil == defBlock {
continue
}
var defTree *parse.Tree
var err error
if (*treeCache)[defBlock.RootID] != nil {
defTree = (*treeCache)[defBlock.RootID]
} else {
defTree, err = loadTreeWithCache(defBlock.RootID, treeCache)
if err != nil {
continue
}
(*treeCache)[defBlock.RootID] = defTree
}
*defBlockIDs = append(*defBlockIDs, val.BlockID)
exportRefTrees(defTree, defBlockIDs, retTrees, treeCache)
}
}
return ast.WalkContinue
})
*defBlockIDs = gulu.Str.RemoveDuplicatedElem(*defBlockIDs)
}
func loadTreeWithCache(id string, treeCache *map[string]*parse.Tree) (tree *parse.Tree, err error) {
if tree = (*treeCache)[id]; nil != tree {
return
}
tree, err = LoadTreeByBlockID(id)
if nil == err && nil != tree {
(*treeCache)[id] = tree
}
return
}

View file

@ -592,7 +592,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids
return ast.WalkContinue
}
replaceNodeTokens(n, method, keyword, replacement, r)
replaceNodeTokens(n, method, keyword, strings.TrimSpace(replacement), r)
case ast.NodeLinkText:
if !replaceTypes["imgText"] {
return ast.WalkContinue
@ -673,11 +673,11 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids
if replaceTypes["aHref"] {
if 0 == method {
if strings.Contains(n.TextMarkAHref, keyword) {
n.TextMarkAHref = strings.ReplaceAll(n.TextMarkAHref, keyword, replacement)
n.TextMarkAHref = strings.ReplaceAll(n.TextMarkAHref, keyword, strings.TrimSpace(replacement))
}
} else if 3 == method {
if nil != r && r.MatchString(n.TextMarkAHref) {
n.TextMarkAHref = r.ReplaceAllString(n.TextMarkAHref, replacement)
n.TextMarkAHref = r.ReplaceAllString(n.TextMarkAHref, strings.TrimSpace(replacement))
}
}
}

View file

@ -186,7 +186,7 @@ func humanizeTimeMagnitudes(lang string) (labels map[string]interface{}, magnitu
{humanize.Month, labels["xw"].(string), humanize.Week},
{2 * humanize.Month, labels["1M"].(string), 1},
{humanize.Year, labels["xM"].(string), humanize.Month},
{18 * humanize.Month, labels["1y"].(string), 1},
{23 * humanize.Month, labels["1y"].(string), 1},
{2 * humanize.Year, labels["2y"].(string), 1},
{humanize.LongTime, labels["xy"].(string), humanize.Year},
{math.MaxInt64, labels["max"].(string), 1},

View file

@ -80,7 +80,7 @@ func Boot() {
readOnly := flag.String("readonly", "false", "read-only mode")
accessAuthCode := flag.String("accessAuthCode", "", "access auth code")
ssl := flag.Bool("ssl", false, "for https and wss")
lang := flag.String("lang", "", "zh_CN/zh_CHT/en_US/fr_FR/es_ES/ja_JP/it_IT/de_DE/he_IL/ru_RU/pl_PL")
lang := flag.String("lang", "", "zh_CN/zh_CHT/en_US/fr_FR/es_ES/ja_JP/it_IT/de_DE/he_IL/ru_RU/pl_PL/ar_SA")
mode := flag.String("mode", "prod", "dev/prod")
flag.Parse()