支持SM.MS图床

This commit is contained in:
xiaoqi.cxq 2022-07-01 13:02:06 +08:00
parent 7a5a4e65c2
commit 698ddb9abd
23 changed files with 518 additions and 105 deletions

View File

@ -17,7 +17,7 @@ StackEdit的作者可能因为什么原因已经很久不维护了Github
- 支持**Gitea**、**Gogs**两个轻量级且适于自建的Git仓库毕竟Gitlab对机器配置要求较高。想支持这两个主要也是考虑到其实很多公司已经禁用了Github或Gitee仓库在公司都没法连上自己的Git仓库。 -- 已完成Gogs无法支持
- 汉化,毕竟大家最熟悉的还是母语,并且该编辑器功能页面也不多,汉化工作量并不会很大。-- 已完成
- 替换主文档空间为Gitee原版本主文档空间是Google Drive国内只有fan墙才可以用-- 已完成
- 支持图片粘贴自动上传到指定图床。-- 进行中
- 支持图片粘贴自动上传到指定图床。-- 进行中已完成SM.MS图床接入)
- 引入mdnice右边预览增加mdnice预览选项主要含选主题(含mdnice常用20多个主题)、支持自定义主题、复制到公众号、复制到知乎、复制到稀土掘金等基本功能,便于喜欢写公众号、博客的同学可以更好更快的排版。
- ... 另外朋友们有好的想法也可以在Issue或者加我微信 qicoding 提给我。
@ -34,6 +34,9 @@ StackEdit的作者可能因为什么原因已经很久不维护了Github
**已完成修改主文档空间为Gitee2022-06-04**
对应Docker版本5.15.6, tag: v5.15.6
**已完成粘贴/拖拽图片自动上传SM.MS图床功能2022-07-01**
对应Docker版本5.15.7, tag: v5.15.7
### 目前已部署地址
https://stackedit.cn/

View File

@ -1,6 +1,6 @@
{
"name": "StackEdit中文版",
"description": "支持Gitee仓库的浏览器内 Markdown 编辑器",
"description": "支持Gitee仓库/粘贴图片自动上传的浏览器内 Markdown 编辑器",
"version": "1.0.13",
"manifest_version": 2,
"container" : "GOOGLE_DRIVE",

200
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "stackedit",
"version": "5.14.10",
"version": "5.15.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -16704,25 +16704,29 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"bundled": true,
"resolved": false,
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"dev": true,
"optional": true,
"requires": {
@ -16732,13 +16736,15 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
@ -16748,37 +16754,43 @@
},
"chownr": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "2.6.9",
"bundled": true,
"resolved": false,
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
@ -16787,25 +16799,29 @@
},
"deep-extend": {
"version": "0.5.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
"requires": {
@ -16814,13 +16830,15 @@
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"resolved": false,
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
@ -16836,7 +16854,8 @@
},
"glob": {
"version": "7.1.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"optional": true,
"requires": {
@ -16850,13 +16869,15 @@
},
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
"bundled": true,
"resolved": false,
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"dev": true,
"optional": true,
"requires": {
@ -16865,7 +16886,8 @@
},
"ignore-walk": {
"version": "3.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
"requires": {
@ -16874,7 +16896,8 @@
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"resolved": false,
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
"requires": {
@ -16884,19 +16907,22 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
@ -16905,13 +16931,15 @@
},
"isarray": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
@ -16920,13 +16948,15 @@
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true,
"optional": true,
"requires": {
@ -16936,7 +16966,8 @@
},
"minizlib": {
"version": "1.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"dev": true,
"optional": true,
"requires": {
@ -16945,7 +16976,8 @@
},
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
@ -16954,13 +16986,15 @@
},
"ms": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true,
"optional": true
},
"needle": {
"version": "2.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
"dev": true,
"optional": true,
"requires": {
@ -16971,7 +17005,8 @@
},
"node-pre-gyp": {
"version": "0.10.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
"dev": true,
"optional": true,
"requires": {
@ -16989,7 +17024,8 @@
},
"nopt": {
"version": "4.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
@ -16999,13 +17035,15 @@
},
"npm-bundled": {
"version": "1.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
"bundled": true,
"resolved": false,
"integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
"dev": true,
"optional": true,
"requires": {
@ -17015,7 +17053,8 @@
},
"npmlog": {
"version": "4.1.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
@ -17027,19 +17066,22 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
@ -17048,19 +17090,22 @@
},
"os-homedir": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
"requires": {
@ -17070,19 +17115,22 @@
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.7",
"bundled": true,
"resolved": false,
"integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
"dev": true,
"optional": true,
"requires": {
@ -17094,7 +17142,8 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
@ -17102,7 +17151,8 @@
},
"readable-stream": {
"version": "2.3.6",
"bundled": true,
"resolved": false,
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
"requires": {
@ -17117,7 +17167,8 @@
},
"rimraf": {
"version": "2.6.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"optional": true,
"requires": {
@ -17126,43 +17177,50 @@
},
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.5.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
@ -17173,7 +17231,8 @@
},
"string_decoder": {
"version": "1.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
"requires": {
@ -17182,7 +17241,8 @@
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
@ -17191,13 +17251,15 @@
},
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
"dev": true,
"optional": true,
"requires": {
@ -17212,13 +17274,15 @@
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"dev": true,
"optional": true,
"requires": {
@ -17227,13 +17291,15 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true,
"optional": true
}

View File

@ -1,6 +1,6 @@
{
"name": "stackedit",
"version": "5.15.6",
"version": "5.15.7",
"description": "Free, open-source, full-featured Markdown editor",
"author": "Benoit Schweblin",
"license": "Apache-2.0",

25
src/assets/iconSmms.svg Normal file
View File

@ -0,0 +1,25 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve"> <image id="image0" width="32" height="32" x="0" y="0"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAB7FBMVEUAAAB3AP+IAP+IAP+H
AP+IAP+IAP+GAP+HAP+AAP+GAP+IAP+IAP+HAP+KAP+OAP+IAP+IAP+IAP9xAP+IAP+IAP+KAP+F
AP+HAP+IAP+IAP+DAP+AAP+HAP+HAP+AAP+IAP+IAP+JAP+HAP+IAP+HAP+IAP+HAP+HAP+IAP+J
AP+GAP+IAP+IAP+IAP+HAP+HAP+HAP+HAP+IAP+IAP+IAP+HAP+IAP+HAP+IAP+IAP+HAP+HAP+H
AP+DAP+HAP+DAP+HAP+IAP+IAP+JAv+mQv+8cP+9c/+sTv+MCf+iOP/s1//////05/+mQf+hNv/6
9v/37/+QE//kx//Yrf+pR/+nRP/YrP+1Yf+SF//+/v+TGP/Df/+gNP/Egf+lPv+5af+aKP/8+P+j
O//asf/27f+RFf+IAv/x4//37v/NlP/x4v+jOv+4Z//Rn/+LB/+IAf/Xqv+/eP+LBv/Wqf+7b/+3
Zv/euP+vVf/Nlv/8+v+bKf/Dgf/Ghv/Ol/+eMf/9/P+vU/+QEf/48f/Sof+UG//ctP/48P/v3v+M
CP/z5f/16/+aJ/+SFv/Zr//ozv/euf+cKv+WHv+tUP/r1P+mQP/Egv/Lkf+PEP/v3P/Jjf/duf/+
/f/fu/+kPf+2Y//Cff/Bev+xWP+TGf+sor+CAAAAQ3RSTlMAD1qczOv7nFkOJp72nSUJjfqLCdTS
IzLqL+kjCtXRCI+JJ/v5oJoR9/QNXVafmNDI8Oj++PzszJsP9SSO0iWKJ5/LDpe2AgAAAAFiS0dE
TPdvEPMAAAAHdElNRQfmBhwAJyh2NlUnAAAByUlEQVQ4y2NggANGJmYWVjY2VhZ2Dk4GTMDFzeMM
Bzy8fGjS/AKCzihAUEgYWZ5PxBkDiIoh5MVZnbEACUm4fiR5F1c3dw9PCFtKGiIvI4uQ9/L2AQJf
PwhPTh6sQAEh7x/gAwaBQRC+IkheSRmhINjHJyQ0LNzHJwLCVwFZooqQj4zyiYp0do728YmBiqgx
MKhrIBTEAk2Pc3aO9/FJgIpoajFoI3ksEaggKdk5xSc1DSakw6CLpCA9A6giM8snOwcupMegjxw2
uWA/5OUjRAwYDJEVFBSCFEQVIUSMGIxRgre4BKyiFC5gwmCKkC0rr3AuqASpqKqGiZkymMHla3x8
amG21MEEzRjMYcz6Bh+fRiDd1AxU4A0TZWFghjFbgOKtIEYbkNEOE7VgYIIxO4DinTAFXTBRDgZL
WFLsBor3AOlekBV9UEErYPLlhrL7geITJk6aPAXkz6lQQWZQcoYm12k+CDAdKi9oDUoQNhDOjJkw
6ahZLlAFQpAkB03SrbOjQNJz5s6DudAWmvTtYIm2Z/6ChYsWw0NOSozYZI8949hKI2ctGQFlVGlB
e5SsBwQOjkiZ14rZDkv+tmRiNjdjU2Z1skDO/gDtseT0Fzic2AAAACV0RVh0ZGF0ZTpjcmVhdGUA
MjAyMi0wNi0yOFQwMDozOTo0MCswMDowMPmC6NgAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDYt
MjhUMDA6Mzk6NDArMDA6MDCI31BkAAAAAElFTkSuQmCC" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,5 +1,5 @@
<template>
<div class="editor">
<div class="editor" ondrop="return false;">
<pre class="editor__inner markdown-highlighting" :style="{padding: styles.editorPadding}" :class="{monospaced: computedSettings.editor.monospacedFontOnly}"></pre>
<div class="gutter" :style="{left: styles.editorGutterLeft + 'px'}">
<comment-list v-if="styles.editorGutterWidth"></comment-list>
@ -13,6 +13,7 @@ import { mapGetters } from 'vuex';
import CommentList from './gutters/CommentList';
import EditorNewDiscussionButton from './gutters/EditorNewDiscussionButton';
import store from '../store';
import editorSvc from '../services/editorSvc';
export default {
components: {
@ -30,7 +31,31 @@ export default {
'computedSettings',
]),
},
methods: {
setImgAndDoClick(items) {
let file = null;
if (!items || items.length === 0) {
return;
}
for (let i = 0; i < items.length; i += 1) {
if (items[i].type.indexOf('image') !== -1) {
file = items[i].getAsFile();
break;
}
}
if (!file) {
return;
}
store.dispatch('img/setImg', file);
editorSvc.pagedownEditor.uiManager.doClick('image');
},
},
mounted() {
//
const currImgStorageStr = localStorage.getItem('img/checkedStorage');
if (currImgStorageStr) {
store.commit('img/changeCheckedStorage', JSON.parse(currImgStorageStr));
}
const editorElt = this.$el.querySelector('.editor__inner');
const onDiscussionEvt = cb => (evt) => {
let elt = evt.target;
@ -56,6 +81,15 @@ export default {
store.commit('discussion/setCurrentDiscussionId', discussionId);
}));
editorElt.addEventListener('drop', (event) => {
const transItems = event.dataTransfer.items;
this.setImgAndDoClick(transItems);
});
editorElt.addEventListener('paste', (event) => {
const pasteItems = (event.clipboardData || window.clipboardData).items;
this.setImgAndDoClick(pasteItems);
});
this.$watch(
() => store.state.discussion.currentDiscussionId,
(discussionId, oldDiscussionId) => {

View File

@ -78,6 +78,7 @@ import ZendeskAccountModal from './modals/providers/ZendeskAccountModal';
import ZendeskPublishModal from './modals/providers/ZendeskPublishModal';
import CouchdbWorkspaceModal from './modals/providers/CouchdbWorkspaceModal';
import CouchdbCredentialsModal from './modals/providers/CouchdbCredentialsModal';
import SmmsAccountModal from './modals/providers/SmmsAccountModal';
const getTabbables = container => container.querySelectorAll('a[href], button, .textfield, input[type=checkbox]')
// Filter enabled and visible element
@ -139,6 +140,7 @@ export default {
ZendeskPublishModal,
CouchdbWorkspaceModal,
CouchdbCredentialsModal,
SmmsAccountModal,
},
computed: {
...mapGetters([

View File

@ -39,7 +39,7 @@
</div>
<div class="tour-step__inner" v-else-if="step === 'end'">
<h2>Enjoy!</h2>
<p>如果您喜欢StackEdit请在<a href="#">Chrome网络商店</a>上给5颗星打分</p>
<p>如果您喜欢StackEdit中文版请在<a href="https://gitee.com/mafgwo/stackedit">Gitee仓库</a>上点一下starred谢谢</p>
<div class="tour-step__button-bar">
<button class="button button--resolve" @click="finish">确认</button>
</div>

View File

@ -77,6 +77,10 @@
<icon-provider slot="icon" provider-id="zendesk"></icon-provider>
<span>添加Zendesk账号</span>
</menu-entry>
<menu-entry @click.native="addSmmsAccount">
<icon-provider slot="icon" provider-id="smms"></icon-provider>
<span>添加SM.MS账号</span>
</menu-entry>
</div>
<div class="modal__button-bar">
<button class="button button--resolve" @click="config.resolve()">关闭</button>
@ -98,6 +102,7 @@ import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
import giteaHelper from '../../services/providers/helpers/giteaHelper';
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
import smmsHelper from '../../services/providers/helpers/smmsHelper';
import badgeSvc from '../../services/badgeSvc';
export default {
@ -176,6 +181,13 @@ export default {
name: token.name,
scopes: ['read', 'hc:write'],
})),
...Object.values(store.getters['data/smmsTokensBySub']).map(token => ({
token,
providerId: 'smms',
userId: token.sub,
name: token.name,
scopes: ['api'],
})),
];
},
},
@ -245,6 +257,12 @@ export default {
await zendeskHelper.addAccount(subdomain, clientId);
} catch (e) { /* cancel */ }
},
async addSmmsAccount() {
try {
const { proxyUrl, apiSecretToken } = await store.dispatch('modal/open', { type: 'smmsAccount' });
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
} catch (e) { /* cancel */ }
},
},
};
</script>

View File

@ -1,18 +1,30 @@
<template>
<modal-inner aria-label="插入图像">
<div class="modal__content">
<p>请为您的图像提供<b> url </b></p>
<form-entry label="URL" error="url">
<p v-if="hasFile">
<span v-if="uploading">粘贴/拖拽图片上传中...</span>
<span v-if="!this.uploading && url">
<img :src="url">
</span>
<span v-if="!this.uploading && !url">图片上传失败如未添加SM.MS账号请先添加并选择之后关闭窗口再重试</span>
</p>
<p v-if="!hasFile">请为您的图像提供<b> url </b></p>
<form-entry v-if="!hasFile" label="URL" error="url">
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
</form-entry>
<menu-entry @click.native="openGooglePhotos(token)" v-for="token in googlePhotosTokens" :key="token.sub">
<icon-provider slot="icon" provider-id="googlePhotos"></icon-provider>
<div>从Google照片打开</div>
<span>{{token.name}}</span>
<p>添加并选择图床后可实现粘贴/拖拽自动上传图片</p>
<menu-entry @click.native="checkedImgDest(token, 'smms')" v-for="token in smmsTokens" :key="token.sub">
<icon-check-circle v-if="checkedStorage.sub === token.sub" slot="icon"></icon-check-circle>
<icon-check-circle-un v-if="checkedStorage.sub !== token.sub" slot="icon"></icon-check-circle-un>
<menu-entry>
<icon-provider slot="icon" provider-id="smms"></icon-provider>
<div>SM.MS图床</div>
<span>{{token.name}}</span>
</menu-entry>
</menu-entry>
<menu-entry @click.native="addGooglePhotosAccount">
<icon-provider slot="icon" provider-id="googlePhotos"></icon-provider>
<span>添加Google Photos账号</span>
<menu-entry @click.native="addSmmsAccount">
<icon-provider slot="icon" provider-id="smms"></icon-provider>
<span>添加SM.MS账号</span>
</menu-entry>
</div>
<div class="modal__button-bar">
@ -25,7 +37,7 @@
<script>
import modalTemplate from './common/modalTemplate';
import MenuEntry from '../menus/common/MenuEntry';
import googleHelper from '../../services/providers/helpers/googleHelper';
import smmsHelper from '../../services/providers/helpers/smmsHelper';
import store from '../../store';
export default modalTemplate({
@ -33,16 +45,50 @@ export default modalTemplate({
MenuEntry,
},
data: () => ({
hasFile: false,
uploading: false,
url: '',
}),
computed: {
googlePhotosTokens() {
const googleTokensBySub = store.getters['data/googleTokensBySub'];
return Object.values(googleTokensBySub)
.filter(token => token.isPhotos)
checkedStorage() {
return store.getters['img/getCheckedStorage'];
},
smmsTokens() {
const smmsTokensBySub = store.getters['data/smmsTokensBySub'];
return Object.values(smmsTokensBySub)
.sort((token1, token2) => token1.name.localeCompare(token2.name));
},
},
async mounted() {
this.hasFile = false;
const imgFile = store.getters['img/getImg'];
if (imgFile) {
this.hasFile = true;
this.uploading = true;
try {
//
// provider smms
const currStorage = this.checkedStorage;
if (!currStorage || !currStorage.sub) {
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
return;
}
const filterTokens = this.smmsTokens.filter(it => it.sub === currStorage.sub);
if (!filterTokens.length) {
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
return;
}
const token = filterTokens[0];
this.url = await smmsHelper.uploadFile({
token,
file: imgFile,
});
} finally {
store.dispatch('img/clearImg');
this.uploading = false;
}
}
},
methods: {
resolve(evt) {
evt.preventDefault(); // Fixes https://github.com/mafgwo/stackedit/issues/1503
@ -59,22 +105,26 @@ export default modalTemplate({
this.config.reject();
callback(null);
},
async addGooglePhotosAccount() {
try {
await googleHelper.addPhotosAccount();
} catch (e) { /* cancel */ }
async addSmmsAccount() {
const { proxyUrl, apiSecretToken } = await store.dispatch('modal/open', { type: 'smmsAccount' });
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
},
async openGooglePhotos(token) {
const { callback } = this.config;
this.config.reject();
const res = await googleHelper.openPicker(token, 'img');
if (res[0]) {
store.dispatch('modal/open', {
type: 'googlePhoto',
url: res[0].url,
callback,
});
}
async checkedImgDest(token, provider) {
store.dispatch('img/changeCheckedStorage', {
type: 'token',
provider,
sub: token.sub,
});
// const { callback } = this.config;
// this.config.reject();
// const res = await googleHelper.openPicker(token, 'img');
// if (res[0]) {
// store.dispatch('modal/open', {
// type: 'googlePhoto',
// url: res[0].url,
// callback,
// });
// }
},
},
});

View File

@ -0,0 +1,54 @@
<template>
<modal-inner aria-label="链接SM.MS账号">
<div class="modal__content">
<div class="modal__image">
<icon-provider provider-id="smms"></icon-provider>
</div>
<p>将您的<b>SM.MS</b>账号链接到<b>StackEdit</b></p>
<form-entry label="跨域代理URL" error="proxyUrl">
<input slot="field" class="textfield" type="text" v-model.trim="proxyUrl" @keydown.enter="resolve()">
<div class="form-entry__info">
跨域代理URL用于图片上传跨域支持(因SM.MS图床已限制了跨域)跨域代理如https://cors.zme.ink/ https://cors.eu.org/
</div>
</form-entry>
<form-entry label="Api Secret Token" error="apiSecretToken">
<input slot="field" class="textfield" type="text" v-model.trim="apiSecretToken" @keydown.enter="resolve()">
<div class="form-entry__info">
<a href="https://sm.ms/home/apitoken" target="_blank">SM.MS</a> 获取Api Secret Token.
</div>
</form-entry>
</div>
<div class="modal__button-bar">
<button class="button" @click="config.reject()">取消</button>
<button class="button button--resolve" @click="resolve()">确认</button>
</div>
</modal-inner>
</template>
<script>
import modalTemplate from '../common/modalTemplate';
export default modalTemplate({
computedLocalSettings: {
proxyUrl: 'proxyUrl',
apiSecretToken: 'apiSecretToken',
},
methods: {
resolve() {
if (!this.proxyUrl) {
this.setError('proxyUrl');
}
if (!this.apiSecretToken) {
this.setError('apiSecretToken');
}
if (this.proxyUrl && this.apiSecretToken) {
this.config.resolve({
proxyUrl: this.proxyUrl,
apiSecretToken: this.apiSecretToken,
});
}
},
},
});
</script>

View File

@ -259,6 +259,11 @@ export default [
'Zendesk账号',
'将您的Zendesk账号链接到Stackedit。',
),
new Feature(
'addSmmsAccount',
'SM.MS账号',
'将您的SM.MS账号链接到Stackedit。',
),
new Feature(
'removeAccount',
'移除账号',

View File

@ -2,6 +2,10 @@
你好!我是你在 **StackEdit中文版** 中的第一个 Markdown 文件。如果你想了解 StackEdit中文版可以阅读此文章。如果你想玩 Markdown你也可以编辑次文章。另外您可以通过打开导航栏左角的**文件资源管理器**来创建新文件。
> **新功能**
>
> 已支持直接粘贴/拖拽上传文件目前仅支持了SM.MS图床(2022.07.01)
# 文件

View File

@ -0,0 +1,5 @@
<template>
<svg t="1656481179782" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1901" width="32" height="32">
<path d="M512 938.666667C276.362667 938.666667 85.333333 747.637333 85.333333 512S276.362667 85.333333 512 85.333333s426.666667 191.029333 426.666667 426.666667-191.029333 426.666667-426.666667 426.666667z m0-64c200.298667 0 362.666667-162.368 362.666667-362.666667S712.298667 149.333333 512 149.333333 149.333333 311.701333 149.333333 512s162.368 362.666667 362.666667 362.666667z" p-id="1902"></path>
</svg>
</template>

View File

@ -98,4 +98,8 @@ export default {
.icon-provider--gitee {
background-image: url(../assets/iconGitee.svg);
}
.icon-provider--smms {
background-image: url(../assets/iconSmms.svg);
}
</style>

View File

@ -50,6 +50,7 @@ import Database from './Database';
import Magnify from './Magnify';
import FormatListChecks from './FormatListChecks';
import CheckCircle from './CheckCircle';
import CheckCircleUn from './CheckCircleUn';
import ContentCopy from './ContentCopy';
import Key from './Key';
import DotsHorizontal from './DotsHorizontal';
@ -106,6 +107,7 @@ Vue.component('iconDatabase', Database);
Vue.component('iconMagnify', Magnify);
Vue.component('iconFormatListChecks', FormatListChecks);
Vue.component('iconCheckCircle', CheckCircle);
Vue.component('iconCheckCircleUn', CheckCircleUn);
Vue.component('iconContentCopy', ContentCopy);
Vue.component('iconKey', Key);
Vue.component('iconDotsHorizontal', DotsHorizontal);

View File

@ -25,7 +25,7 @@ var defaultsStrings = {
codeexample: "enter code here",
image: "Image <img> Ctrl/Cmd+G",
imagedescription: "enter image description here",
imagedescription: "",
imagedialog: "<p><b>Insert Image</b></p><p>http://example.com/images/diagram.jpg \"optional title\"<br><br>Need <a href='http://www.google.com/search?q=free+image+hosting' target='_blank'>free image hosting?</a></p>",
olist: "Numbered List <ol> Ctrl/Cmd+O",

View File

@ -247,8 +247,14 @@ export default {
if (sanitizedConfig.body && typeof sanitizedConfig.body === 'object') {
sanitizedConfig.body = JSON.stringify(sanitizedConfig.body);
sanitizedConfig.headers['Content-Type'] = 'application/json';
} else if (sanitizedConfig.formData) {
const data = new FormData();
Object.keys(sanitizedConfig.formData).forEach((key) => {
const formVal = sanitizedConfig.formData[key];
data.append(key, formVal);
});
sanitizedConfig.formData = data;
}
const attempt = async () => {
try {
return await new Promise((resolve, reject) => {
@ -315,7 +321,7 @@ export default {
if (sanitizedConfig.blob) {
xhr.responseType = 'blob';
}
xhr.send(sanitizedConfig.body || null);
xhr.send(sanitizedConfig.body || sanitizedConfig.formData || null);
});
} catch (err) {
// Try again later in case of retriable error

View File

@ -0,0 +1,76 @@
import networkSvc from '../../networkSvc';
import store from '../../../store';
import userSvc from '../../userSvc';
import badgeSvc from '../../badgeSvc';
/**
* https://doc.sm.ms/#api-User-Get_Profile
*/
const subPrefix = 'sm';
export default {
subPrefix,
async getTokenObj(proxyUrl, apiSecretToken) {
// Call the user info endpoint
try {
const { body } = await networkSvc.request({
method: 'POST',
url: `${proxyUrl}https://sm.ms/api/v2/profile`,
headers: {
Authorization: apiSecretToken,
},
});
// Check user result
if (!body.success) {
throw new Error(`SM.MS个人信息获取失败失败信息${body.message}`);
}
userSvc.addUserInfo({
id: `${subPrefix}:${body.data.username}`,
name: body.data.username,
imageUrl: 'https://gravatar.loli.net/avatar/ccc459536d65637c192c00f639569864',
});
// Build token object including sub
const token = {
proxyUrl,
accessToken: apiSecretToken,
name: body.data.username,
sub: body.data.username,
};
// Add token to smms tokens
store.dispatch('data/addSmmsToken', token);
return token;
} catch (err) {
console.error(err); // eslint-disable-line no-console
store.dispatch('notification/error', err);
throw new Error(`SM.MS个人信息获取异常异常信息${err.message}`);
}
},
async addAccount(proxyUrl, apiSecretToken) {
const token = await this.getTokenObj(proxyUrl, apiSecretToken);
badgeSvc.addBadge('addSmmsAccount');
return token;
},
async uploadFile({
token,
file,
}) {
const { body } = await networkSvc.request({
method: 'POST',
url: `${token.proxyUrl}https://sm.ms/api/v2/upload`,
headers: {
Authorization: token.accessToken,
},
formData: {
smfile: file,
},
});
if (!body.success) {
if (body.code === 'image_repeated') {
return body.images;
}
store.dispatch('notification/error', `SM.MS上传图片失败失败信息${body.message}`);
throw new Error(`SM.MS上传图片失败失败信息${body.message}`);
}
return body.data.url;
},
};

View File

@ -216,6 +216,7 @@ export default {
giteaTokensBySub: (state, { tokensByType }) => tokensByType.gitea || {},
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
smmsTokensBySub: (state, { tokensByType }) => tokensByType.smms || {},
badgeCreations: getter('badgeCreations'),
badgeTree: (state, { badgeCreations }) => features
.map(feature => feature.toBadge(badgeCreations)),
@ -311,5 +312,6 @@ export default {
addWordpressToken: tokenAdder('wordpress'),
addZendeskToken: tokenAdder('zendesk'),
patchBadgeCreations: patcher('badgeCreations'),
addSmmsToken: tokenAdder('smms'),
},
};

55
src/store/img.js Normal file
View File

@ -0,0 +1,55 @@
const localKey = 'img/checkedStorage';
export default {
namespaced: true,
state: {
// 来自粘贴板 或者 拖拽的图片的文件对象
currImg: null,
// 选择的存储图床信息
checkedStorage: {
type: null, // 目前存储类型分两种 token 与 tokenRepo
provider: null, // 对应是何种账号
sub: null, // 对应 token 中的sub
},
},
mutations: {
setNewImg: (state, value) => {
state.currImg = value;
},
clearCurrImg: (state) => {
state.currImg = null;
},
changeCheckedStorage: (state, value) => {
if (value) {
state.checkedStorage = {
type: value.type, // 目前存储类型分两种 token 与 tokenRepo
provider: value.provider, // 对应是何种账号
sub: value.sub, // 对应 token 中的sub
};
} else {
state.checkedStorage = {
type: null, // 目前存储类型分两种 token 与 tokenRepo
provider: null, // 对应是何种账号
sub: null, // 对应 token 中的sub
};
}
},
},
getters: {
getImg: state => state.currImg,
getCheckedStorage: state => state.checkedStorage,
getCheckedStorageSub: state => state.checkedStorage.sub,
},
actions: {
setImg({ commit }, img) {
commit('setNewImg', img);
},
clearImg({ commit }) {
commit('clearCurrImg');
},
changeCheckedStorage({ commit }, checkedStorage) {
commit('changeCheckedStorage', checkedStorage);
localStorage.setItem(localKey, JSON.stringify(checkedStorage));
},
},
};

View File

@ -18,6 +18,7 @@ import queue from './queue';
import syncedContent from './syncedContent';
import userInfo from './userInfo';
import workspace from './workspace';
import img from './img';
import locationTemplate from './locationTemplate';
import emptyPublishLocation from '../data/empties/emptyPublishLocation';
import emptySyncLocation from '../data/empties/emptySyncLocation';
@ -47,6 +48,7 @@ const store = new Vuex.Store({
syncLocation: locationTemplate(emptySyncLocation),
userInfo,
workspace,
img,
},
state: {
light: false,

View File

@ -9,7 +9,7 @@
<meta charset="UTF-8">
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
<meta name="description"
content="支持直接将码云Gitee、GitHub、Gitea等仓库的Markdown直接在页面编辑同步和管理的Markdown编辑器。">
content="支持直接将码云Gitee、GitHub、Gitea等仓库且支持拖拽/粘贴上传图片,并且可以直接在页面编辑同步和管理的Markdown编辑器。">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta name="baidu-site-verification" content="code-tGpn2BT069" />
<meta name="msvalidate.01" content="90A9558158543277BD284CFA054E7F5B" />