diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
new file mode 100644
index 0000000..4a5a337
--- /dev/null
+++ b/.github/workflows/preview.yml
@@ -0,0 +1,20 @@
+name: Surge Preview
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened, closed]
+
+jobs:
+ preview:
+ runs-on: ubuntu-latest
+ if: github.repository == 'doocs/md'
+ steps:
+ - uses: actions/checkout@v2
+ - uses: afc163/surge-preview@main
+ with:
+ surge_token: ${{ secrets.SURGE_TOKEN }}
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ dist: dist
+ build: |
+ npm install
+ npm run build:h5-netlify
diff --git a/README.md b/README.md
index 87febe7..65b0229 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,7 @@ npm run build:h5-netlify
- [x] 支持 Ctrl + F 快速格式化文档
- [x] 支持色盘取色,快速替换文章整体色调
- [x] 支持多图上传,可自定义配置图床
+- [x] 支持自定义上传逻辑
- [x] 支持在编辑框右键弹出功能选项卡
## 目前支持哪些图床
@@ -80,6 +81,7 @@ npm run build:h5-netlify
| 4 | [阿里云](https://www.aliyun.com/product/oss) | 配置 `AccessKey ID`、`AccessKey Secret`、`Bucket`、`Region` 参数 | [如何使用阿里云 OSS?](https://help.aliyun.com/document_detail/31883.html) |
| 5 | [腾讯云](https://cloud.tencent.com/act/pro/cos) | 配置 `SecretId`、`SecretKey`、`Bucket`、`Region` 参数 | [如何使用腾讯云 COS?](https://cloud.tencent.com/document/product/436/38484) |
| 6 | [七牛云](https://www.qiniu.com/products/kodo) | 配置 `AccessKey`、`SecretKey`、`Bucket`、`Domain`、`Region` 参数 | [如何使用七牛云 Kodo?](https://developer.qiniu.com/kodo) |
+| - | 自定义上传逻辑 | 是 | 参考[自定义上传逻辑参数详情](#自定义上传逻辑) |
![select-and-change-color-theme](https://doocs.oss-cn-shenzhen.aliyuncs.com/img//1606034542281-a8c99fa7-c11e-4e43-98da-e36012f54dc8.gif)
@@ -89,6 +91,49 @@ npm run build:h5-netlify
![doocs-md-upload-image](https://doocs.oss-cn-shenzhen.aliyuncs.com/img//1606034542512-0769a336-b9eb-4d58-83c1-29db7b54f71b.gif)
+## 自定义上传逻辑
+
+在工具上没有提供预定义图床的情况下,你只需要自定义上传逻辑即可,这对于例如你不方便使用公共图床,而是使用自己的上传服务时非常有用。
+
+你只需要在给定的函数中更改上传代码即可,为了方便,这个函数提供了可能使用的一些参数:
+
+示例代码:
+
+```js
+const {file, util, okCb, errCb} = CUSTOM_ARG
+const param = new FormData()
+param.append('file', file)
+util.axios.post('http://127.0.0.1:9000/upload', param, {
+ headers: { 'Content-Type': 'multipart/form-data' }
+}).then(res => {
+ okCb(res.url)
+}).catch(err => {
+ errCb(err)
+})
+
+// 提供的可用参数:
+// CUSTOM_ARG = {
+// content, // 待上传图片的 base64
+// file, // 待上传图片的 file 对象
+// util: {
+// axios, // axios 实例
+// CryptoJS, // 加密库
+// OSS, // ali-oss
+// COS, // cos-js-sdk-v5
+// Buffer, // buffer-from
+// uuidv4, // uuid
+// qiniu, // qiniu-js
+// tokenTools, // 一些编码转换函数
+// getDir, // 获取 年/月/日 形式的目录
+// getDateFilename, // 根据文件名获取它以 时间戳+uuid 的形式
+// },
+// okCb: resolve, // 重要: 上传成功后给此回调传 url 即可
+// errCb: reject, // 上传失败调用的函数
+// }
+```
+
+如果你创建了适用于其他第三方图床的上传代码,我们非常欢迎你分享它。
+
## 注意事项
如果你使用了某些浏览器脚本修改了网页背景色,可能导致渲染后的文章出现背景色分块的现象,详见 [#63](https://github.com/doocs/md/issues/63)。
diff --git a/mm.config.js b/mm.config.js
index 416e41d..92ee749 100644
--- a/mm.config.js
+++ b/mm.config.js
@@ -3,15 +3,25 @@
* https://hongqiye.com/doc/mockm/config/option.html
* @type {import('mockm/@types/config').Config}
*/
-module.exports = {
- static: [
- { // 测试 netlify 部署
- fileDir: `./dist`,
- path: `/`,
+module.exports = (util) => {
+ return {
+ api: {
+ '/upload'(req, res) {
+ res.json({
+ msg: `上传成功`,
+ url: util.libObj.mockjs.mock(`@image`),
+ })
+ },
},
- { // 测试 gitee/github 部署
- fileDir: `./dist`,
- path: `/md`,
- },
- ],
+ static: [
+ { // 测试 netlify 部署
+ fileDir: `./dist`,
+ path: `/`,
+ },
+ { // 测试 gitee/github 部署
+ fileDir: `./dist`,
+ path: `/md`,
+ },
+ ],
+ }
}
diff --git a/src/api/file.js b/src/api/file.js
index ad18679..342aff5 100644
--- a/src/api/file.js
+++ b/src/api/file.js
@@ -7,6 +7,7 @@ import Buffer from "buffer-from";
import { v4 as uuidv4 } from "uuid";
import * as qiniu from "qiniu-js";
import { utf16to8, base64encode, safe64 } from "../assets/scripts/tokenTools";
+import * as tokenTools from "../assets/scripts/tokenTools";
function getConfig(useDefault, platform) {
if (useDefault) {
@@ -42,6 +43,10 @@ function getConfig(useDefault, platform) {
};
}
+/**
+ * 获取 `年/月/日` 形式的目录
+ * @returns string
+ */
function getDir() {
const date = new Date();
const year = date.getFullYear();
@@ -50,6 +55,11 @@ function getDir() {
return `${year}/${month}/${day}`;
}
+/**
+ * 根据文件名获取它以 `时间戳+uuid` 的形式
+ * @param {string} filename 文件名
+ * @returns
+ */
function getDateFilename(filename) {
const currentTimestamp = new Date().getTime();
const fileSuffix = filename.split(".")[1];
@@ -216,6 +226,42 @@ async function txCOSFileUpload(file) {
});
}
+//-----------------------------------------------------------------------
+// formCustom File Upload
+//-----------------------------------------------------------------------
+
+async function formCustomUpload(content, file) {
+ const str = `
+ async (CUSTOM_ARG) => {
+ ${localStorage.getItem(`formCustomConfig`)}
+ }
+ `
+ return new Promise((resolve, reject) => {
+ const exportObj = {
+ content, // 待上传图片的 base64
+ file, // 待上传图片的 file 对象
+ util: {
+ axios: fetch, // axios 实例
+ CryptoJS, // 加密库
+ OSS, // ali-oss
+ COS, // cos-js-sdk-v5
+ Buffer, // buffer-from
+ uuidv4, // uuid
+ qiniu, // qiniu-js
+ tokenTools, // 一些编码转换函数
+ getDir, // 获取 年/月/日 形式的目录
+ getDateFilename, // 根据文件名获取它以 时间戳+uuid 的形式
+ },
+ okCb: resolve, // 重要: 上传成功后给此回调传 url 即可
+ errCb: reject, // 上传失败调用的函数
+ }
+ eval(str)(exportObj).catch(err => {
+ console.error(err)
+ reject(err)
+ })
+ });
+}
+
function fileUpload(content, file) {
const imgHost = localStorage.getItem("imgHost");
!imgHost && localStorage.setItem("imgHost", "default");
@@ -230,6 +276,8 @@ function fileUpload(content, file) {
return giteeUpload(content, file.name);
case "github":
return ghFileUpload(content, file.name);
+ case "formCustom":
+ return formCustomUpload(content, file);
default:
// return file.size / 1024 < 1024
// ? giteeUpload(content, file.name)
diff --git a/src/assets/scripts/util.js b/src/assets/scripts/util.js
index 0f7e9d6..7d5340d 100644
--- a/src/assets/scripts/util.js
+++ b/src/assets/scripts/util.js
@@ -374,3 +374,21 @@ function getElementStyles(element, excludes = ["width", "height"]) {
.map(([key, value]) => `${key}:${value};`)
.join("");
}
+
+/**
+ * 移除左边多余空格
+ * @param {*} str
+ * @returns
+ */
+export function removeLeft(str) {
+ const lines = str.split('\n')
+ // 获取应该删除的空白符数量
+ const minSpaceNum = lines.filter(item => item.trim())
+ .map(item => item.match(/(^\s+)?/)[0].length)
+ .sort((a, b) => a - b)[0]
+ // 删除空白符
+ const newStr = lines
+ .map(item => item.slice(minSpaceNum))
+ .join('\n')
+ return newStr
+}
\ No newline at end of file
diff --git a/src/components/CodemirrorEditor/uploadImgDialog.vue b/src/components/CodemirrorEditor/uploadImgDialog.vue
index ebe7be5..6284c52 100644
--- a/src/components/CodemirrorEditor/uploadImgDialog.vue
+++ b/src/components/CodemirrorEditor/uploadImgDialog.vue
@@ -5,7 +5,7 @@
:visible="value"
@close="$emit('close')"
>
-
+
+
+
+
+
+
+ 参数详情?
+
+
+ 保存配置
+
+
+
@@ -518,6 +593,20 @@ export default {
.github-panel {
display: flex;
justify-content: center;
+ &.formCustom {
+ width: 100%;
+ }
+ .formCustomElInput {
+ /deep/ .CodeMirror {
+ border: 1px solid #eee;
+ height: 300px !important;
+ font-family: "Fira Mono", "DejaVu Sans Mono", Menlo, Consolas, "Liberation Mono", Monaco, "Lucida Console", monospace !important;
+ line-height: 20px;
+ .CodeMirror-scroll {
+ padding: 10px;
+ }
+ }
+ }
}
.setting-form {