Merge branch 'dev' into chore/eslint

This commit is contained in:
V 2022-06-02 11:40:51 +08:00 committed by GitHub
commit 36dd51817a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 345 additions and 1191 deletions

View file

@ -1,4 +1,5 @@
{
"freeSub": "Free Trial Subscription",
"sortByUpdateTimeDesc": "Descending by update time",
"sortByUpdateTimeAsc": "Ascending by update time",
"sortByDownloadsDesc": "Descending by downloads",
@ -458,11 +459,10 @@
"account3Tip": "Local backup will overwrite cloud backup. Do you want to upload?",
"account1": "Click to pay",
"account3": "Upload",
"account2": "<div>End-to-end encrypted data synchronization</div><div>End-to-end encrypted data backup</div><div>Cloud assets serving</div>",
"account4": "Renewal price remains unchanged for life",
"account5": "Cloud Assets serving",
"account6": "Remaining before subscription expires",
"account7": "More advanced features",
"account8": "End-to-End encryption sync",
"account10": "Annual subscription",
"account11": "Until the end of the early bird discount",
"account12": "Life companion",

View file

@ -1,4 +1,5 @@
{
"freeSub": "Abonnement d'essai gratuit",
"sortByUpdateTimeDesc": "Descendant par heure de mise à jour",
"sortByUpdateTimeAsc": "Croissant par heure de mise à jour",
"sortByDownloadsDesc": "Décroissant par téléchargements",
@ -457,12 +458,10 @@
"downloadCloudTip": "Après le téléchargement, la sauvegarde dans le Cloud sera utilisée pour écraser la sauvegarde locale. Voulez-vous télécharger ?",
"account3Tip": "Va-t-il écraser la sauvegarde cloud avec la sauvegarde locale, télécharger ?",
"account1": "Cliquez pour payer",
"account2": "Sauvegarde par cryptage de bout en bout",
"account2": "<div>Synchronisation des données chiffrées de bout en bout</div><div>Sauvegarde des données chiffrées de bout en bout</div><div>Servant les ressources cloud</div>",
"account4": "Le prix du renouvellement reste inchangé à vie",
"account5": "Les Assets du Cloud au service",
"account6": "Restant avant l'expiration de l'abonnement",
"account7": "Fonctions plus avancées",
"account8": "Synchro du cryptage de bout en bout",
"account10": "Abonnement annuel",
"account11": "Jusqu'à la fin de la réduction pour les early bird",
"account12": "Compagnon de vie",

View file

@ -1,4 +1,5 @@
{
"freeSub": "免費試用訂閱",
"sortByUpdateTimeDesc": "更新時間降序",
"sortByUpdateTimeAsc": "更新時間升序",
"sortByDownloadsDesc": "下載次數降序",
@ -457,12 +458,10 @@
"downloadCloudTip": "下載後將使用雲端備份覆蓋本地備份,是否下載?",
"account3Tip": "將使用本地備份覆蓋雲端備份,是否上傳?",
"account1": "點擊前往支付",
"account2": "端到端加密備份",
"account2": "<div>端到端加密數據同步</div><div>端到端加密數據備份</div><div>資源文件圖床</div><div>定時微信提醒</div><div>收集箱</div>",
"account4": "續訂價格終身不變",
"account5": "雲端圖庫服務",
"account6": "距訂閱過期還剩",
"account7": "更多進階特性",
"account8": "端到端加密同步",
"account10": "年付訂閱",
"account11": "早鳥優惠活動結束還剩",
"account12": "相伴一生",

View file

@ -1,4 +1,5 @@
{
"freeSub": "免费试用订阅",
"sortByUpdateTimeDesc": "更新时间降序",
"sortByUpdateTimeAsc": "更新时间升序",
"sortByDownloadsDesc": "下载次数降序",
@ -457,12 +458,11 @@
"downloadCloudTip": "下载后将使用云端备份覆盖本地备份,是否下载?",
"account3Tip": "将使用本地备份覆盖云端备份,是否上传?",
"account1": "点击前往支付",
"account2": "端到端加密备份",
"account2": "<div>端到端加密数据同步</div><div>端到端加密数据备份</div><div>资源文件图床</div><div>定时微信提醒</div><div>收集箱</div>",
"account4": "续订价格终身不变",
"account5": "云端图床服务",
"account6": "距订阅过期还剩",
"account7": "更多高级特性",
"account8": "端到端加密同步",
"account10": "年付订阅",
"account11": "早鸟优惠活动结束还剩",
"account12": "相伴一生",

View file

@ -6,7 +6,7 @@
"title": "Formatting elements",
"title-img": "background-color:#269;background-image: linear-gradient(white 2px, transparent 2px),linear-gradient(90deg, white 2px, transparent 2px),linear-gradient(rgba(255,255,255,.3) 1px, transparent 1px),linear-gradient(90deg, rgba(255,255,255,.3) 1px, transparent 1px);background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px;background-position:-2px -2px, -2px -2px, -1px -1px, -1px -1px;",
"type": "doc",
"updated": "20220521234603"
"updated": "20220602101151"
},
"Children": [
{
@ -3464,7 +3464,7 @@
"IsFencedCodeBlock": true,
"Properties": {
"id": "20211221131201-600dcnw",
"updated": "20211221130624"
"updated": "20220602101151"
},
"Children": [
{
@ -3476,12 +3476,8 @@
"CodeBlockInfo": "bWVybWFpZA=="
},
{
"ID": "20220307092214-ajekwh5",
"Type": "NodeCodeBlockCode",
"Data": "gitGraph:\noptions\n{\n \u0026quot;nodeSpacing\u0026quot;: 150,\n \u0026quot;nodeRadius\u0026quot;: 10\n}\nend\ncommit\nbranch newbranch\ncheckout newbranch\ncommit\ncommit\ncheckout master\ncommit\ncommit\nmerge newbranch",
"Properties": {
"id": "20220307092214-ajekwh5"
}
"Data": " gitGraph\n commit\n commit\n branch develop\n commit\n commit\n commit\n checkout main\n commit\n commit"
},
{
"Type": "NodeCodeBlockFenceCloseMarker",

View file

@ -6,7 +6,7 @@
"title": "排版元素",
"title-img": "background-color: hsl(2, 57%, 40%);background-image: repeating-linear-gradient(transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(270deg, transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(125deg, transparent, transparent 2px, rgba(0,0,0,.2) 2px, rgba(0,0,0,.2) 3px, transparent 3px, transparent 5px, rgba(0,0,0,.2) 5px);",
"type": "doc",
"updated": "20220521234027"
"updated": "20220602100957"
},
"Children": [
{
@ -3438,7 +3438,7 @@
"IsFencedCodeBlock": true,
"Properties": {
"id": "20211221130609-z04k7rn",
"updated": "20211221130624"
"updated": "20220602100957"
},
"Children": [
{
@ -3450,12 +3450,8 @@
"CodeBlockInfo": "bWVybWFpZA=="
},
{
"ID": "20220307091943-5q3bn4j",
"Type": "NodeCodeBlockCode",
"Data": "gitGraph:\noptions\n{\n \u0026quot;nodeSpacing\u0026quot;: 150,\n \u0026quot;nodeRadius\u0026quot;: 10\n}\nend\ncommit\nbranch newbranch\ncheckout newbranch\ncommit\ncommit\ncheckout master\ncommit\ncommit\nmerge newbranch",
"Properties": {
"id": "20220307091943-5q3bn4j"
}
"Data": " gitGraph\n commit\n commit\n branch develop\n commit\n commit\n commit\n checkout main\n commit\n commit"
},
{
"Type": "NodeCodeBlockFenceCloseMarker",

View file

@ -5,7 +5,7 @@
"id": "20211226121319-emrk2yy",
"title": "排版元素",
"title-img": "background-color: hsl(2, 57%, 40%);background-image: repeating-linear-gradient(transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(270deg, transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(125deg, transparent, transparent 2px, rgba(0,0,0,.2) 2px, rgba(0,0,0,.2) 3px, transparent 3px, transparent 5px, rgba(0,0,0,.2) 5px);",
"updated": "20220521234434"
"updated": "20220602101300"
},
"Children": [
{
@ -3419,7 +3419,7 @@
"IsFencedCodeBlock": true,
"Properties": {
"id": "20211226122008-4u0uxuf",
"updated": "20211221130624"
"updated": "20220602101300"
},
"Children": [
{
@ -3431,12 +3431,8 @@
"CodeBlockInfo": "bWVybWFpZA=="
},
{
"ID": "20220307092237-7c49s02",
"Type": "NodeCodeBlockCode",
"Data": "gitGraph:\noptions\n{\n \u0026quot;nodeSpacing\u0026quot;: 150,\n \u0026quot;nodeRadius\u0026quot;: 10\n}\nend\ncommit\nbranch newbranch\ncheckout newbranch\ncommit\ncommit\ncheckout master\ncommit\ncommit\nmerge newbranch",
"Properties": {
"id": "20220307092237-7c49s02"
}
"Data": "gitGraph\n commit\n commit\n branch develop\n commit\n commit\n commit\n checkout main\n commit\n commit"
},
{
"Type": "NodeCodeBlockFenceCloseMarker",

View file

@ -69,7 +69,7 @@
"iconv-lite": "^0.6.3",
"ifdef-loader": "^2.3.0",
"mini-css-extract-plugin": "2.3.0",
"node-sass": "^7.0.1",
"sass": "^1.52.1",
"path-browserify": "^1.0.1",
"safer-buffer": "^2.1.2",
"sass-loader": "^12.1.0",

1023
app/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -198,19 +198,29 @@
}
.config-account {
&__bg {
position: relative;
margin-bottom: 82px;
width: 100%;
flex: 1;
}
&__cover {
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
height: 70vh;
}
&__avatar {
position: absolute;
top: 50vh;
bottom: 24px;
width: 128px;
height: 128px;
left: 50%;
margin: -64px 0 0 -64px;
margin-left: -64px;
background-repeat: no-repeat;
background-position: 50%;
background-size: cover;
@ -219,7 +229,16 @@
box-shadow: var(--b3-point-shadow);
}
&__info {
width: 100%;
box-sizing: border-box;
padding: 16px;
}
&__name {
bottom: -58px;
position: absolute;
width: 100%;
text-align: center;
}
}

View file

@ -15,21 +15,24 @@ export const account = {
<div class="fn__hr--b"></div>
<a class="b3-button b3-button--outline" style="min-width: 214px" href="https://ld246.com/subscribe/siyuan" target="_blank">
<span>
<span class="fn__hr"></span>
<div class="fn__hr"></div>
<span class="ft__smaller">${window.siyuan.languages.account4}</span>
<span class="fn__hr"></span>
<div class="fn__hr--small"></div>
<big class="ft__secondary">${window.siyuan.languages.priceAnnual}</big>
<span class="ft__on-background">/${window.siyuan.languages.year}</span>
<span class="fn__hr"></span>
<div class="fn__hr--small"></div>
<span class="ft__smaller ft__on-surface">${window.siyuan.languages.account1}</span>
<span class="fn__hr"></span>
<div class="fn__hr"></div>
</span>
</a>
<div class="fn__hr--b"></div>
<div>${window.siyuan.languages.account2}</div>
<div>${window.siyuan.languages.account8}</div>
<div>${window.siyuan.languages.account5}</div>
${window.siyuan.languages.account2}
<div><a href="https://b3log.org/siyuan/pricing.html" target="_blank">${window.siyuan.languages.account7}</a></div>
<div class="fn__hr--b"></div>
<span class="b3-chip b3-chip--primary fn__pointer" id="trialSub">
<svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg>
${window.siyuan.languages.freeSub}
</>
<div class="fn__hr--b"></div>`;
if (window.siyuan.user) {
let userTitlesHTML = "";
@ -154,6 +157,14 @@ export const account = {
</div>`;
},
bindEvent: () => {
const trialSubElement = account.element.querySelector("#trialSub");
if (trialSubElement) {
trialSubElement.addEventListener("click", () => {
fetchPost("/api/account/startFreeTrial", {}, () => {
account.element.querySelector("#refresh").dispatchEvent(new Event("click"));
});
});
}
const agreeLoginElement = account.element.querySelector("#agreeLogin") as HTMLInputElement;
const userNameElement = account.element.querySelector("#userName") as HTMLInputElement;
if (!userNameElement) {

View file

@ -708,20 +708,23 @@ export const openMenu = (src: string, onlyMenu = false) => {
const submenu = [];
if (isLocalPath(src)) {
submenu.push({
label: window.siyuan.languages.openInNewTab,
label: window.siyuan.languages.insertRight,
accelerator: "Click",
click() {
openAsset(src.trim(), parseInt(getSearch("page", src)));
openAsset(src.trim(), parseInt(getSearch("page", src)), "right");
}
});
/// #if !BROWSER
submenu.push({
label: window.siyuan.languages.useDefault,
accelerator: "⇧Click",
click() {
openBy(src, "app");
}
});
submenu.push({
label: window.siyuan.languages.showInFolder,
accelerator: "⌘Click",
click: () => {
openBy(src, "folder");
}
@ -730,13 +733,18 @@ export const openMenu = (src: string, onlyMenu = false) => {
} else {
submenu.push({
label: window.siyuan.languages.useBrowserView,
accelerator: "Click",
click: () => {
/// #if !BROWSER
shell.openExternal(src).catch((e) => {
console.log("openExternal error:" + e);
});
/// #else
window.open(src);
if (window.siyuan.config.system.container === "ios") {
window.location.href = src;
} else {
window.open(src);
}
/// #endif
}
});

View file

@ -32,6 +32,7 @@ import {removeFoldHeading} from "../protyle/util/heading";
import {lineNumberRender} from "../protyle/markdown/highlightRender";
import * as dayjs from "dayjs";
import {blockRender} from "../protyle/markdown/blockRender";
import {isLocalPath} from "../util/pathName";
export const refMenu = (protyle: IProtyle, element: HTMLElement) => {
const nodeElement = hasClosestBlock(element);
@ -535,6 +536,133 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme
window.siyuan.menus.menu.element.querySelector("input").focus();
};
export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText = false) => {
window.siyuan.menus.menu.remove();
protyle.toolbar.isNewEmptyInline = false;
const nodeElement = hasClosestBlock(linkElement);
if (!nodeElement) {
return;
}
const id = nodeElement.getAttribute("data-node-id");
let html = nodeElement.outerHTML;
const linkAddress = linkElement.getAttribute("data-href");
window.siyuan.menus.menu.append(new MenuItem({
label: `<div class="fn__hr--small"></div><input class="b3-text-field fn__size200" placeholder="${window.siyuan.languages.link}"><div class="fn__hr--small"></div>`,
bind(element) {
const inputElement = element.querySelector("input");
inputElement.value = linkAddress || "";
inputElement.addEventListener("change", () => {
linkElement.setAttribute("data-href", inputElement.value);
updateTransaction(protyle, id, nodeElement.outerHTML, html);
html = nodeElement.outerHTML;
});
inputElement.addEventListener("keydown", (event) => {
if ((event.key === "Enter" || event.key === "Escape") && !event.isComposing) {
event.preventDefault();
event.stopPropagation();
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
focusByRange(protyle.toolbar.range);
window.siyuan.menus.menu.remove();
}
});
}
}).element);
window.siyuan.menus.menu.append(new MenuItem({
label: `<div class="fn__hr--small"></div><input class="b3-text-field fn__size200" placeholder="${window.siyuan.languages.anchor}"><div class="fn__hr--small"></div>`,
bind(element) {
const inputElement = element.querySelector("input");
inputElement.value = linkElement.textContent.replace(Constants.ZWSP, "");
inputElement.addEventListener("change", () => {
if (!inputElement.value) {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
window.siyuan.menus.menu.remove();
}
updateTransaction(protyle, id, nodeElement.outerHTML, html);
html = nodeElement.outerHTML;
});
inputElement.addEventListener("compositionend", () => {
linkElement.innerHTML = Lute.EscapeHTMLStr(inputElement.value) || "";
});
inputElement.addEventListener("input", (event: KeyboardEvent) => {
if (!event.isComposing) {
linkElement.innerHTML = Lute.EscapeHTMLStr(inputElement.value) || "";
}
});
inputElement.addEventListener("keydown", (event) => {
if ((event.key === "Enter" || event.key === "Escape") && !event.isComposing) {
event.preventDefault();
event.stopPropagation();
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
focusByRange(protyle.toolbar.range);
window.siyuan.menus.menu.remove();
}
});
}
}).element);
window.siyuan.menus.menu.append(new MenuItem({
label: `<div class="fn__hr--small"></div><input class="b3-text-field fn__size200" placeholder="${window.siyuan.languages.title}"><div class="fn__hr--small"></div>`,
bind(element) {
const inputElement = element.querySelector("input");
inputElement.value = Lute.UnEscapeHTMLStr(linkElement.getAttribute("data-title") || "");
inputElement.addEventListener("change", () => {
if (inputElement.value) {
linkElement.setAttribute("data-title", Lute.EscapeHTMLStr(inputElement.value));
} else {
linkElement.removeAttribute("data-title");
}
updateTransaction(protyle, id, nodeElement.outerHTML, html);
html = nodeElement.outerHTML;
});
inputElement.addEventListener("keydown", (event) => {
if ((event.key === "Enter" || event.key === "Escape") && !event.isComposing) {
event.preventDefault();
event.stopPropagation();
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
focusByRange(protyle.toolbar.range);
window.siyuan.menus.menu.remove();
}
});
}
}).element);
window.siyuan.menus.menu.append(new MenuItem({
icon: "iconTrashcan",
label: window.siyuan.languages.remove,
click() {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
}
}).element);
if (linkAddress?.startsWith("siyuan://blocks/")) {
window.siyuan.menus.menu.append(new MenuItem({
icon: "iconRefresh",
label: window.siyuan.languages.turnInto + " " + window.siyuan.languages.blockRef,
click() {
linkElement.setAttribute("data-subtype", "s");
linkElement.setAttribute("data-type", "block-ref");
linkElement.setAttribute("data-id", linkAddress?.replace("siyuan://blocks/", ""));
linkElement.removeAttribute("data-href");
linkElement.removeAttribute("data-title");
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, id, nodeElement.outerHTML, html);
protyle.toolbar.range.selectNode(linkElement);
protyle.toolbar.range.collapse(false);
focusByRange(protyle.toolbar.range);
}
}).element);
}
if (isLocalPath(linkAddress)) {
openMenu(linkAddress);
}
window.siyuan.menus.menu.element.classList.remove("fn__none");
if (focusText || protyle.lute.IsValidLinkDest(linkAddress)) {
window.siyuan.menus.menu.element.querySelectorAll("input")[1].select();
} else {
window.siyuan.menus.menu.element.querySelector("input").select();
}
};
const genImageWidthMenu = (label: string, assetElement: HTMLElement, imgElement: HTMLElement, protyle: IProtyle, id: string, nodeElement: HTMLElement, html: string) => {
return {
label,

View file

@ -27,35 +27,27 @@ const showAccountInfo = (modelElement: HTMLElement, modelMainElement: Element) =
modelElement.querySelector(".toolbar__icon").innerHTML = '<use xlink:href="#iconAccount"></use>';
modelElement.querySelector(".toolbar__text").textContent = window.siyuan.languages.accountManage;
modelMainElement.innerHTML = `<div class="fn__flex-column">
<div style="position: relative">
<div class="config-account__bg">
<div class="config-account__cover" style="background-image: url(${window.siyuan.user.userHomeBImgURL})"></div>
<a target="_blank" href="https://ld246.com/settings/avatar" class="config-account__avatar" style="background-image: url(${window.siyuan.user.userAvatarURL})" target="_blank"></a>
</div>
<div class="fn__hr"></div>
<div class="fn__flex-1">
<a href="https://ld246.com/settings/avatar" class="config-account__avatar" style="background-image: url(${window.siyuan.user.userAvatarURL})" target="_blank"></a>
<h1 class="config-account__name">
<a target="_blank" class="fn__a" href="https://ld246.com/member/${window.siyuan.user.userName}">${window.siyuan.user.userName}</a>
</h1>
${userTitlesHTML}
</div>
<div class="fn__hr"></div>
<div class="fn__flex">
<span class="fn__space"></span>
<a class="b3-button b3-button--text" href="https://ld246.com/settings" target="_blank">${window.siyuan.languages.accountManage}</a>
<span class="fn__space"></span>
<button class="b3-button b3-button--cancel" id="logout">
${window.siyuan.languages.logout}
</button>
<span class="fn__space"></span>
<button class="b3-button b3-button--cancel" id="deactivateUser">
${window.siyuan.languages.deactivateUser}
</button>
<span class="fn__flex-1"></span>
<button class="b3-button b3-button--cancel" id="refresh">
<svg><use xlink:href="#iconRefresh"></use></svg>
</button>
<span class="fn__space"></span>
</div>`;
<div class="config-account__info">
<div class="fn__flex">
<a class="b3-button b3-button--text" href="https://ld246.com/settings" target="_blank">${window.siyuan.languages.accountManage}</a>
<span class="fn__space"></span>
<button class="b3-button b3-button--cancel" id="logout">
${window.siyuan.languages.logout}
</button>
<span class="fn__flex-1"></span>
<button class="b3-button b3-button--cancel" id="refresh">
<svg><use xlink:href="#iconRefresh"></use></svg>
</button>
</div>
</div></div>`;
modelMainElement.querySelector("#logout").addEventListener(getEventName(), () => {
fetchPost("/api/setting/logoutCloudUser", {}, () => {

View file

@ -18,12 +18,9 @@ export const mermaidRender = (element: Element, cdn = Constants.PROTYLE_CDN) =>
if (mermaidElements.length === 0) {
return;
}
addScript(`${cdn}/js/mermaid/mermaid.min.js?v=0.0.0`, "protyleMermaidScript").then(() => {
addScript(`${cdn}/js/mermaid/mermaid.min.js?v=9.1.1`, "protyleMermaidScript").then(() => {
const config: any = {
// https://github.com/siyuan-note/siyuan/issues/3587
// graph LR
// id1["<iframe src=javascript:alert('xss')></iframe>"]
// securityLevel: "loose", 如上会 xss
securityLevel: "loose", // 升级后无 https://github.com/siyuan-note/siyuan/issues/3587可使用该选项
altFontFamily: "sans-serif",
fontFamily: "sans-serif",
startOnLoad: false,

View file

@ -39,6 +39,7 @@ import {matchHotKey} from "../util/hotKey";
import {unicode2Emoji} from "../../emoji";
import {escapeHtml} from "../../util/escape";
import {hideElements} from "../ui/hideElements";
import {linkMenu} from "../../menus/protyle";
export class Toolbar {
public element: HTMLElement;
@ -252,7 +253,10 @@ export class Toolbar {
const types = this.getCurrentType();
if (action === "add" && types.length > 0 && types.includes(type) && !focusAdd) {
if (type === "link") {
this.showLink(protyle, this.range.startContainer.parentElement);
this.element.classList.add("fn__none");
linkMenu(protyle, this.range.startContainer.parentElement);
const rect = this.range.startContainer.parentElement.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
}
return;
}
@ -312,7 +316,9 @@ export class Toolbar {
}
if (types.length > 0 && types.includes("link") && action === "range") {
// 链接快捷键不应取消,应该显示链接信息
this.showLink(protyle, this.range.startContainer.parentElement);
linkMenu(protyle, this.range.startContainer.parentElement);
const rect = this.range.startContainer.parentElement.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
return;
}
const wbrElement = document.createElement("wbr");
@ -491,7 +497,9 @@ export class Toolbar {
console.log(e);
}
if (needShowLink) {
this.showLink(protyle, newElement as HTMLElement, focusText);
linkMenu(protyle, newElement as HTMLElement, focusText);
const rect = newElement.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
}
}
}
@ -507,161 +515,6 @@ export class Toolbar {
wbrElement.remove();
}
public showLink(protyle: IProtyle, linkElement: HTMLElement, focusText = false) {
const nodeElement = hasClosestBlock(linkElement);
if (!nodeElement) {
return;
}
const id = nodeElement.getAttribute("data-node-id");
this.subElement.style.width = isMobile() ? "80vw" : Math.min(480, window.innerWidth) + "px";
this.subElement.style.padding = "";
this.subElement.innerHTML = `<div class="b3-form__space--small">
<label class="fn__flex">
<span class="ft__on-surface fn__flex-center" style="width: 72px">${window.siyuan.languages.link}</span>
<div class="fn__space"></div>
<input class="b3-text-field fn__block" placeholder="${window.siyuan.languages.link}" />
</label>
<div class="fn__hr"></div>
<label class="fn__flex">
<span class="ft__on-surface fn__flex-center" style="width: 72px">${window.siyuan.languages.anchor}</span>
<div class="fn__space"></div>
<input class="b3-text-field fn__block" placeholder="${window.siyuan.languages.anchor}" />
</label>
<div class="fn__hr"></div>
<label class="fn__flex">
<span class="ft__on-surface fn__flex-center" style="width: 72px">${window.siyuan.languages.title}</span>
<div class="fn__space"></div>
<input class="b3-text-field fn__block" placeholder="${window.siyuan.languages.title}" />
</label>
<div class="fn__hr"></div>
<div class="fn__hr"></div>
<div class="fn__flex"><span class="fn__flex-1"></span>
<button class="b3-button b3-button--outline${linkElement.getAttribute("data-href")?.startsWith("siyuan://blocks/") ? "" : " fn__none"}">${window.siyuan.languages.turnInto} ${window.siyuan.languages.blockRef}</button>
<span class="fn__space"></span>
<button class="b3-button b3-button--cancel">${window.siyuan.languages.remove}</button>
</div></div>`;
let preventChange = false;
let oldHTML = nodeElement.outerHTML;
this.subElement.querySelector(".b3-button--outline").addEventListener(getEventName(), (event) => {
preventChange = true;
linkElement.setAttribute("data-subtype", "s");
linkElement.setAttribute("data-type", "block-ref");
linkElement.setAttribute("data-id", linkElement.getAttribute("data-href")?.replace("siyuan://blocks/", ""));
linkElement.removeAttribute("data-href");
linkElement.removeAttribute("data-title");
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML);
protyle.toolbar.range.selectNode(linkElement);
protyle.toolbar.range.collapse(false);
focusByRange(protyle.toolbar.range);
this.subElement.classList.add("fn__none");
event.stopPropagation();
});
this.subElement.querySelector(".b3-button--cancel").addEventListener(getEventName(), (event) => {
preventChange = true;
this.setInlineMark(protyle, "link", "remove");
this.subElement.classList.add("fn__none");
event.stopPropagation();
});
const titleElements = this.subElement.querySelectorAll(".b3-text-field") as NodeListOf<HTMLInputElement>;
titleElements[0].value = linkElement.getAttribute("data-href") || "";
titleElements[1].value = linkElement.textContent.replace(Constants.ZWSP, "");
titleElements[2].value = Lute.UnEscapeHTMLStr(linkElement.getAttribute("data-title") || "");
const updateChange = (event: KeyboardEvent) => {
this.isNewEmptyInline = false;
event.stopPropagation();
if (event.isComposing) {
return;
}
window.setTimeout(() => {
if (preventChange) {
return;
}
if (titleElements[1].value === "" || titleElements[0].value === "") {
if (this.subElement.classList.contains("fn__none")) {
this.setInlineMark(protyle, "link", "remove");
}
return;
}
linkElement.innerHTML = Lute.EscapeHTMLStr(titleElements[1].value);
if (titleElements[2].value) {
linkElement.setAttribute("data-title", Lute.EscapeHTMLStr(titleElements[2].value));
} else {
linkElement.removeAttribute("data-title");
}
linkElement.setAttribute("data-href", titleElements[0].value);
if (nodeElement.outerHTML !== oldHTML) {
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, id, nodeElement.outerHTML, oldHTML);
oldHTML = nodeElement.outerHTML;
}
if (this.subElement.classList.contains("fn__none")) {
this.range.setEnd(linkElement.lastChild, linkElement.lastChild.textContent.length);
this.range.collapse(false);
focusByRange(this.range);
}
}, Constants.TIMEOUT_SEARCH);
};
const hideSubElement = (event: KeyboardEvent) => {
if ((event.key === "Enter" || event.key === "Escape") && !event.isComposing) {
event.stopPropagation();
event.preventDefault();
this.subElement.classList.add("fn__none");
}
};
titleElements[0].addEventListener("keydown", (event: KeyboardEvent) => {
hideSubElement(event);
});
titleElements[1].addEventListener("keydown", (event: KeyboardEvent) => {
hideSubElement(event);
});
titleElements[2].addEventListener("keydown", (event: KeyboardEvent) => {
hideSubElement(event);
});
titleElements[0].addEventListener("blur", (event: KeyboardEvent) => {
updateChange(event);
});
titleElements[1].addEventListener("blur", (event: KeyboardEvent) => {
updateChange(event);
});
titleElements[1].addEventListener("compositionend", () => {
linkElement.innerHTML = Lute.EscapeHTMLStr(titleElements[1].value) || "";
});
titleElements[1].addEventListener("input", (event: KeyboardEvent) => {
if (!event.isComposing) {
linkElement.innerHTML = Lute.EscapeHTMLStr(titleElements[1].value) || "";
}
});
titleElements[2].addEventListener("blur", (event: KeyboardEvent) => {
updateChange(event);
});
titleElements[2].addEventListener("compositionend", () => {
if (titleElements[2].value) {
linkElement.setAttribute("data-title", Lute.EscapeHTMLStr(titleElements[2].value) || "");
} else {
linkElement.removeAttribute("data-title");
}
});
titleElements[2].addEventListener("input", (event: KeyboardEvent) => {
if (!event.isComposing) {
if (titleElements[2].value) {
linkElement.setAttribute("data-title", Lute.EscapeHTMLStr(titleElements[2].value) || "");
} else {
linkElement.removeAttribute("data-title");
}
}
});
this.subElement.classList.remove("fn__none");
const nodeRect = linkElement.getBoundingClientRect();
setPosition(this.subElement, nodeRect.left, nodeRect.bottom, nodeRect.height + 4);
this.element.classList.add("fn__none");
if (focusText || protyle.lute.IsValidLinkDest(titleElements[0].value)) {
titleElements[1].select();
} else {
titleElements[0].select();
}
}
public showFileAnnotationRef(protyle: IProtyle, refElement: HTMLElement) {
const nodeElement = hasClosestBlock(refElement);
if (!nodeElement) {

View file

@ -20,7 +20,7 @@ import {isLocalPath, pathPosix} from "../../util/pathName";
import {genEmptyElement} from "../../block/util";
import {previewImage} from "../preview/image";
import {openGlobalSearch} from "../../search/util";
import {contentMenu, imgMenu, refMenu, setFold, zoomOut} from "../../menus/protyle";
import {contentMenu, imgMenu, linkMenu, refMenu, setFold, zoomOut} from "../../menus/protyle";
import * as dayjs from "dayjs";
import {dropEvent} from "../util/editorCommonEvent";
import {input} from "./input";
@ -428,7 +428,8 @@ export class WYSIWYG {
const type = target.getAttribute("data-type");
if (type === "block-ref") {
refMenu(protyle, target);
setPosition(window.siyuan.menus.menu.element, event.clientX, event.clientY + 13, 26);
const rect =target.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
// 阻止 popover
target.removeAttribute("data-type");
setTimeout(() => {
@ -441,8 +442,10 @@ export class WYSIWYG {
return false;
}
if (type === "a") {
protyle.toolbar.showLink(protyle, target);
if (target.getAttribute("data-href").startsWith("siyuan://blocks")) {
linkMenu(protyle, target);
const rect =target.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
if (target.getAttribute("data-href")?.startsWith("siyuan://blocks")) {
// 阻止 popover
target.setAttribute("prevent-popover", "true");
setTimeout(() => {

View file

@ -34,7 +34,7 @@ import {isLocalPath} from "../../util/pathName";
import {clipboard} from "electron";
import {getCurrentWindow} from "@electron/remote";
/// #endif
import {refMenu, setFold, zoomOut} from "../../menus/protyle";
import {linkMenu, refMenu, setFold, zoomOut} from "../../menus/protyle";
import {setPosition} from "../../util/setPosition";
import {removeEmbed} from "./removeEmbed";
import {openAttr} from "../../menus/commonMenuItem";
@ -477,7 +477,9 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
protyle.toolbar.showFileAnnotationRef(protyle, inlineElement);
return;
} else if (type === "a") {
protyle.toolbar.showLink(protyle, inlineElement);
linkMenu(protyle, inlineElement);
const rect = inlineElement.getBoundingClientRect();
setPosition(window.siyuan.menus.menu.element, rect.left, rect.top + 13, 26);
return;
}
}

View file

@ -97,6 +97,8 @@ interface ISiyuan {
userNickname: string
userPaymentSum: string
userSiYuanProExpireTime: number // -1 终身会员0 普通用户;> 0 过期时间
userSiYuanSubscriptionPlan: number // 0 年付订阅/终生1 教育优惠2 订阅试用
userSiYuanSubscriptionType: number // 0 年付1 终生2 月付
userToken: string
userTitles: { name: string, icon: string, desc: string }[]
},

View file

@ -29,6 +29,9 @@ export const getDisplayName = (filePath: string, basename = true, removeSY = fal
};
export const isLocalPath = (link: string) => {
if (!link) {
return false;
}
return link.startsWith("assets/") || link.startsWith("file://");
};
@ -93,7 +96,7 @@ export const movePathTo = async (notebookId: string, path: string, focus = true)
k: inputElement.value
}, (data) => {
let fileHTML = "";
data.data.forEach((item: { boxIcon:string, box: string, hPath: string, path: string }) => {
data.data.forEach((item: { boxIcon: string, box: string, hPath: string, path: string }) => {
if (item.path === pathPosix().dirname(path) + "/" || item.path === path) {
return;
}

File diff suppressed because one or more lines are too long

View file

@ -25,6 +25,18 @@ import (
"github.com/siyuan-note/siyuan/kernel/util"
)
func startFreeTrial(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
err := model.StartFreeTrial()
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
}
}
func useActivationcode(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -54,6 +54,7 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/account/checkActivationcode", model.CheckAuth, checkActivationcode)
ginServer.Handle("POST", "/api/account/useActivationcode", model.CheckAuth, useActivationcode)
ginServer.Handle("POST", "/api/account/deactivate", model.CheckAuth, deactivateUser)
ginServer.Handle("POST", "/api/account/startFreeTrial", model.CheckAuth, startFreeTrial)
ginServer.Handle("POST", "/api/notebook/lsNotebooks", model.CheckAuth, lsNotebooks)
ginServer.Handle("POST", "/api/notebook/openNotebook", model.CheckAuth, openNotebook)

View file

@ -31,6 +31,23 @@ import (
var ErrFailedToConnectCloudServer = errors.New("failed to connect cloud server")
func StartFreeTrial() (err error) {
requestResult := gulu.Ret.NewResult()
request := util.NewCloudRequest(Conf.System.NetworkProxy.String())
_, err = request.
SetResult(requestResult).
SetCookies(&http.Cookie{Name: "symphony", Value: Conf.User.UserToken}).
Post(util.AliyunServer + "/apis/siyuan/user/startFreeTrial")
if nil != err {
util.LogErrorf("start free trial failed: %s", err)
return ErrFailedToConnectCloudServer
}
if 0 != requestResult.Code {
return errors.New(requestResult.Msg)
}
return
}
func DeactivateUser() (err error) {
requestResult := gulu.Ret.NewResult()
request := util.NewCloudRequest(Conf.System.NetworkProxy.String())