粘贴拖拽图片体验优化
This commit is contained in:
parent
058fcaa147
commit
e7450df251
@ -14,6 +14,8 @@ import CommentList from './gutters/CommentList';
|
|||||||
import EditorNewDiscussionButton from './gutters/EditorNewDiscussionButton';
|
import EditorNewDiscussionButton from './gutters/EditorNewDiscussionButton';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import editorSvc from '../services/editorSvc';
|
import editorSvc from '../services/editorSvc';
|
||||||
|
import imageSvc from '../services/imageSvc';
|
||||||
|
import utils from '../services/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -32,7 +34,7 @@ export default {
|
|||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setImgAndDoClick(items) {
|
async setImgAndDoClick(items) {
|
||||||
let file = null;
|
let file = null;
|
||||||
if (!items || items.length === 0) {
|
if (!items || items.length === 0) {
|
||||||
return;
|
return;
|
||||||
@ -46,8 +48,23 @@ export default {
|
|||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch('img/setImg', file);
|
const imgId = utils.uid();
|
||||||
editorSvc.pagedownEditor.uiManager.doClick('image');
|
store.dispatch('img/setCurrImgId', imgId);
|
||||||
|
editorSvc.pagedownEditor.uiManager.doClick('imageUploading');
|
||||||
|
try {
|
||||||
|
const { url, error } = await imageSvc.updateImg(file);
|
||||||
|
// 存在错误
|
||||||
|
if (error) {
|
||||||
|
editorSvc.clEditor.replaceAll(`[图片上传中...(image-${imgId})]`, `[图片上传失败...(image-${imgId})]`);
|
||||||
|
store.dispatch('notification/error', error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editorSvc.clEditor.replaceAll(`[图片上传中...(image-${imgId})]`, `![输入图片说明](${url})`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err); // eslint-disable-line no-console
|
||||||
|
editorSvc.clEditor.replaceAll(`[图片上传中...(image-${imgId})]`, `[图片上传失败...(image-${imgId})]`);
|
||||||
|
store.dispatch('notification/error', err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="插入图像">
|
<modal-inner aria-label="插入图像">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<p v-if="hasFile">
|
<p>请为您的图像提供<b> url </b>。<span v-if="uploading">(图片上传中...)</span></p>
|
||||||
<span v-if="uploading">粘贴/拖拽图片上传中...</span>
|
<form-entry label="URL" error="url">
|
||||||
<span v-if="!this.uploading && url">
|
|
||||||
<img :src="url">
|
|
||||||
</span>
|
|
||||||
<span v-if="!this.uploading && !url">图片上传失败,如未添加图床请先添加并选择,之后关闭窗口再重试!</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">
|
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<p>添加并选择图床后可实现粘贴/拖拽自动上传图片</p>
|
</div>
|
||||||
|
<div class="modal__button-bar">
|
||||||
|
<input class="hidden-file" id="upload-image-file-input" type="file" accept="image/*" :disabled="uploading" @change="uploadImage">
|
||||||
|
<label for="upload-image-file-input"><a class="button">上传图片</a></label>
|
||||||
|
<button class="button" @click="reject()">取消</button>
|
||||||
|
<button class="button button--resolve" @click="resolve" :disabled="uploading">确认</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<hr />
|
||||||
|
<p>添加并选择图床后可在编辑区中粘贴/拖拽图片自动上传</p>
|
||||||
<menu-entry @click.native="checkedImgDest(token.sub, token.providerId)" v-for="token in imageTokens" :key="token.sub">
|
<menu-entry @click.native="checkedImgDest(token.sub, token.providerId)" v-for="token in imageTokens" :key="token.sub">
|
||||||
<icon-check-circle v-if="checkedStorage.sub === token.sub" slot="icon"></icon-check-circle>
|
<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>
|
<icon-check-circle-un v-if="checkedStorage.sub !== token.sub" slot="icon"></icon-check-circle-un>
|
||||||
@ -30,9 +32,9 @@
|
|||||||
<span class="line-entry" v-if="token.params">自定义Form参数:{{token.params}}</span>
|
<span class="line-entry" v-if="token.params">自定义Form参数:{{token.params}}</span>
|
||||||
</menu-item>
|
</menu-item>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="checkedImgDest(tokenStorage.sid, tokenStorage.providerId)" v-for="tokenStorage in tokensImgStorages" :key="tokenStorage.sid">
|
<menu-entry @click.native="checkedImgDest(tokenStorage.token.sub, tokenStorage.providerId, tokenStorage.sid)" v-for="tokenStorage in tokensImgStorages" :key="tokenStorage.sid">
|
||||||
<icon-check-circle v-if="checkedStorage.sub === tokenStorage.sid" slot="icon"></icon-check-circle>
|
<icon-check-circle v-if="checkedStorage.sid === tokenStorage.sid" slot="icon"></icon-check-circle>
|
||||||
<icon-check-circle-un v-if="checkedStorage.sub !== tokenStorage.sid" slot="icon"></icon-check-circle-un>
|
<icon-check-circle-un v-if="checkedStorage.sid !== tokenStorage.sid" slot="icon"></icon-check-circle-un>
|
||||||
<menu-item>
|
<menu-item>
|
||||||
<icon-provider slot="icon" :provider-id="tokenStorage.providerId"></icon-provider>
|
<icon-provider slot="icon" :provider-id="tokenStorage.providerId"></icon-provider>
|
||||||
<div>{{tokenStorage.providerName}}
|
<div>{{tokenStorage.providerName}}
|
||||||
@ -43,12 +45,6 @@
|
|||||||
<span> {{tokenStorage.uname}}, 仓库URL: {{tokenStorage.repoUrl}}, 路径: {{tokenStorage.path}}, 分支: {{tokenStorage.branch}}</span>
|
<span> {{tokenStorage.uname}}, 仓库URL: {{tokenStorage.repoUrl}}, 路径: {{tokenStorage.path}}, 分支: {{tokenStorage.branch}}</span>
|
||||||
</menu-item>
|
</menu-item>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
|
||||||
<div class="modal__button-bar">
|
|
||||||
<button class="button" @click="reject()">取消</button>
|
|
||||||
<button class="button button--resolve" @click="resolve" :disabled="uploading">确认</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<menu-entry @click.native="addSmmsAccount">
|
<menu-entry @click.native="addSmmsAccount">
|
||||||
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
||||||
<span>添加SM.MS图床账号</span>
|
<span>添加SM.MS图床账号</span>
|
||||||
@ -79,6 +75,7 @@ import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
|||||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
import githubHelper from '../../services/providers/helpers/githubHelper';
|
||||||
import customHelper from '../../services/providers/helpers/customHelper';
|
import customHelper from '../../services/providers/helpers/customHelper';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
import imageSvc from '../../services/imageSvc';
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
components: {
|
components: {
|
||||||
@ -86,7 +83,6 @@ export default modalTemplate({
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
hasFile: false,
|
|
||||||
uploading: false,
|
uploading: false,
|
||||||
url: '',
|
url: '',
|
||||||
}),
|
}),
|
||||||
@ -137,92 +133,12 @@ export default modalTemplate({
|
|||||||
uname: it.token.name,
|
uname: it.token.name,
|
||||||
providerId: it.providerId,
|
providerId: it.providerId,
|
||||||
providerName: it.providerName,
|
providerName: it.providerName,
|
||||||
repoUrl: it.providerId === 'gitea' ? `${it.serverUrl}/${storage.repoUri}` : `${storage.owner}/${storage.repo}`,
|
repoUrl: it.providerId === 'gitea' ? `${it.token.serverUrl}/${storage.repoUri}` : `${storage.owner}/${storage.repo}`,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return imgStorages;
|
return imgStorages;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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) {
|
|
||||||
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currStorage.provider === 'smms' || currStorage.provider === 'custom') {
|
|
||||||
const filterTokens = this.imageTokens.filter(it => it.sub === currStorage.sub);
|
|
||||||
if (!filterTokens.length) {
|
|
||||||
store.dispatch('notification/info', '图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const token = filterTokens[0];
|
|
||||||
const helper = currStorage.provider === 'smms' ? smmsHelper : customHelper;
|
|
||||||
try {
|
|
||||||
this.url = await helper.uploadFile({
|
|
||||||
token,
|
|
||||||
file: imgFile,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
store.dispatch('notification/error', err);
|
|
||||||
}
|
|
||||||
} else if (currStorage.provider === 'gitea' || currStorage.provider === 'github') {
|
|
||||||
const filterTokenStorages = this.tokensImgStorages
|
|
||||||
.filter(it => it.sid === currStorage.sub);
|
|
||||||
if (!filterTokenStorages.length) {
|
|
||||||
store.dispatch('notification/info', 'Gitea图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const tokenStorage = filterTokenStorages[0];
|
|
||||||
const time = new Date();
|
|
||||||
const date = time.getDate();
|
|
||||||
const month = time.getMonth() + 1;
|
|
||||||
const year = time.getFullYear();
|
|
||||||
let path = tokenStorage.path.replace('{YYYY}', year)
|
|
||||||
.replace('{MM}', `0${month}`.slice(-2)).replace('{DD}', `0${date}`.slice(-2));
|
|
||||||
path = `${path}${path.endsWith('/') ? '' : '/'}${utils.uid()}.${imgFile.type.split('/')[1]}`;
|
|
||||||
try {
|
|
||||||
if (currStorage.provider === 'gitea') {
|
|
||||||
const result = await giteaHelper.uploadFile({
|
|
||||||
token: tokenStorage.token,
|
|
||||||
projectId: tokenStorage.repoUri,
|
|
||||||
branch: tokenStorage.branch,
|
|
||||||
path,
|
|
||||||
content: imgFile,
|
|
||||||
isFile: true,
|
|
||||||
});
|
|
||||||
this.url = result.content.download_url;
|
|
||||||
} else if (currStorage.provider === 'github') {
|
|
||||||
const result = await githubHelper.uploadFile({
|
|
||||||
token: tokenStorage.token,
|
|
||||||
owner: tokenStorage.owner,
|
|
||||||
repo: tokenStorage.repo,
|
|
||||||
branch: tokenStorage.branch,
|
|
||||||
path,
|
|
||||||
content: imgFile,
|
|
||||||
isFile: true,
|
|
||||||
});
|
|
||||||
this.url = result.content.download_url;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
store.dispatch('notification/error', err);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
store.dispatch('img/clearImg');
|
|
||||||
this.uploading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
resolve(evt) {
|
resolve(evt) {
|
||||||
evt.preventDefault(); // Fixes https://github.com/mafgwo/stackedit/issues/1503
|
evt.preventDefault(); // Fixes https://github.com/mafgwo/stackedit/issues/1503
|
||||||
@ -239,6 +155,27 @@ export default modalTemplate({
|
|||||||
this.config.reject();
|
this.config.reject();
|
||||||
callback(null);
|
callback(null);
|
||||||
},
|
},
|
||||||
|
async uploadImage(evt) {
|
||||||
|
if (!evt.target.files || !evt.target.files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const imgFile = evt.target.files[0];
|
||||||
|
try {
|
||||||
|
this.uploading = true;
|
||||||
|
const { url, error } = await imageSvc.updateImg(imgFile);
|
||||||
|
if (error) {
|
||||||
|
store.dispatch('notification/error', error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.url = url;
|
||||||
|
} catch (err) {
|
||||||
|
store.dispatch('notification/error', err);
|
||||||
|
} finally {
|
||||||
|
this.uploading = false;
|
||||||
|
// 上传后清空
|
||||||
|
evt.target.value = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
async remove(proivderId, item) {
|
async remove(proivderId, item) {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('modal/open', 'imgStorageDeletion');
|
await store.dispatch('modal/open', 'imgStorageDeletion');
|
||||||
@ -288,7 +225,7 @@ export default modalTemplate({
|
|||||||
githubHelper.updateToken(token, imgStorageInfo);
|
githubHelper.updateToken(token, imgStorageInfo);
|
||||||
} catch (e) { /* Cancel */ }
|
} catch (e) { /* Cancel */ }
|
||||||
},
|
},
|
||||||
async checkedImgDest(sub, provider) {
|
async checkedImgDest(sub, provider, sid) {
|
||||||
let type = 'token';
|
let type = 'token';
|
||||||
if (provider === 'gitea' || provider === 'github') {
|
if (provider === 'gitea' || provider === 'github') {
|
||||||
type = 'tokenRepo';
|
type = 'tokenRepo';
|
||||||
@ -297,6 +234,7 @@ export default modalTemplate({
|
|||||||
type,
|
type,
|
||||||
provider,
|
provider,
|
||||||
sub,
|
sub,
|
||||||
|
sid,
|
||||||
});
|
});
|
||||||
// const { callback } = this.config;
|
// const { callback } = this.config;
|
||||||
// this.config.reject();
|
// this.config.reject();
|
||||||
|
@ -1,78 +1,78 @@
|
|||||||
Headers
|
标题
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
# Header 1
|
# 标题1
|
||||||
|
|
||||||
## Header 2
|
## 标题2
|
||||||
|
|
||||||
### Header 3
|
### 标题3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Styling
|
样式
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
*Emphasize* _emphasize_
|
*强调* _强调_
|
||||||
|
|
||||||
**Strong** __strong__
|
**加粗** __加粗__
|
||||||
|
|
||||||
==Marked text.==
|
==标记文本==
|
||||||
|
|
||||||
~~Mistaken text.~~
|
~~删除线文本~~
|
||||||
|
|
||||||
> Quoted text.
|
> 块引用文本
|
||||||
|
|
||||||
H~2~O is a liquid.
|
H~2~O是一种液体
|
||||||
|
|
||||||
2^10^ is 1024.
|
2^10^是1024
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lists
|
列表
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
- Item
|
- 列表项
|
||||||
* Item
|
* 列表项
|
||||||
+ Item
|
+ 列表项
|
||||||
|
|
||||||
1. Item 1
|
1. 列表项 1
|
||||||
2. Item 2
|
2. 列表项 2
|
||||||
3. Item 3
|
3. 列表项 3
|
||||||
|
|
||||||
- [ ] Incomplete item
|
- [ ] 未完成项
|
||||||
- [x] Complete item
|
- [x] 已完成项
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Links
|
链接
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
A [link](http://example.com).
|
一个[链接](http://example.com).
|
||||||
|
|
||||||
An image: ![Alt](img.jpg)
|
一张图片: ![图片描述](img.jpg)
|
||||||
|
|
||||||
A sized image: ![Alt](img.jpg =60x50)
|
一张调整大小的图片: ![图片描述](img.jpg =60x50)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Code
|
代码
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Some `inline code`.
|
一些`行内代码`.
|
||||||
|
|
||||||
```
|
```
|
||||||
// A code block
|
// 一个代码块
|
||||||
var foo = 'bar';
|
var foo = 'bar';
|
||||||
```
|
```
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// An highlighted block
|
// 一个高亮代码块
|
||||||
var foo = 'bar';
|
var foo = 'bar';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Tables
|
表格
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Item | Value
|
Item | Value
|
||||||
@ -88,41 +88,41 @@ Pipe | $1
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Definition lists
|
定义列表
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Markdown
|
Markdown
|
||||||
: Text-to-HTML conversion tool
|
: 文本到HTML转换工具
|
||||||
|
|
||||||
Authors
|
作者
|
||||||
: John
|
: 张三
|
||||||
: Luke
|
: 李四
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Footnotes
|
脚注
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Some text with a footnote.[^1]
|
一些带有脚注的文本。[^1]
|
||||||
|
|
||||||
[^1]: The footnote.
|
[^1]: 脚注内容。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Abbreviations
|
缩写
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Markdown converts text to HTML.
|
Markdown将文本转换为 HTML。
|
||||||
|
|
||||||
*[HTML]: HyperText Markup Language
|
*[HTML]: 超文本标记语言
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LaTeX math
|
LaTeX数学表达式
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
The Gamma function satisfying $\Gamma(n) = (n-1)!\quad\forall
|
满足 $\Gamma(n) = (n-1)!\quad\forall
|
||||||
n\in\mathbb N$ is via the Euler integral
|
n\in\mathbb N$ 的Gamma函数是通过欧拉积分
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.
|
\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.
|
||||||
|
@ -6,34 +6,34 @@ var util = {},
|
|||||||
|
|
||||||
var defaultsStrings = {
|
var defaultsStrings = {
|
||||||
bold: "Strong <strong> Ctrl/Cmd+B",
|
bold: "Strong <strong> Ctrl/Cmd+B",
|
||||||
boldexample: "strong text",
|
boldexample: "加粗文本",
|
||||||
|
|
||||||
italic: "Emphasis <em> Ctrl/Cmd+I",
|
italic: "Emphasis <em> Ctrl/Cmd+I",
|
||||||
italicexample: "emphasized text",
|
italicexample: "强调文本",
|
||||||
|
|
||||||
strikethrough: "Strikethrough <s> Ctrl/Cmd+I",
|
strikethrough: "Strikethrough <s> Ctrl/Cmd+I",
|
||||||
strikethroughexample: "strikethrough text",
|
strikethroughexample: "删除线文本",
|
||||||
|
|
||||||
link: "Hyperlink <a> Ctrl/Cmd+L",
|
link: "Hyperlink <a> Ctrl/Cmd+L",
|
||||||
linkdescription: "enter link description here",
|
linkdescription: "这里输入链接描述",
|
||||||
linkdialog: "<p><b>Insert Hyperlink</b></p><p>http://example.com/ \"optional title\"</p>",
|
linkdialog: "<p><b>Insert Hyperlink</b></p><p>http://example.com/ \"optional title\"</p>",
|
||||||
|
|
||||||
quote: "Blockquote <blockquote> Ctrl/Cmd+Q",
|
quote: "Blockquote <blockquote> Ctrl/Cmd+Q",
|
||||||
quoteexample: "Blockquote",
|
quoteexample: "块引用",
|
||||||
|
|
||||||
code: "Code Sample <pre><code> Ctrl/Cmd+K",
|
code: "Code Sample <pre><code> Ctrl/Cmd+K",
|
||||||
codeexample: "enter code here",
|
codeexample: "这里输入代码",
|
||||||
|
|
||||||
image: "Image <img> Ctrl/Cmd+G",
|
image: "Image <img> Ctrl/Cmd+G",
|
||||||
imagedescription: "",
|
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>",
|
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",
|
olist: "Numbered List <ol> Ctrl/Cmd+O",
|
||||||
ulist: "Bulleted List <ul> Ctrl/Cmd+U",
|
ulist: "Bulleted List <ul> Ctrl/Cmd+U",
|
||||||
litem: "List item",
|
litem: "这里是列表文本",
|
||||||
|
|
||||||
heading: "Heading <h1>/<h2> Ctrl/Cmd+H",
|
heading: "Heading <h1>/<h2> Ctrl/Cmd+H",
|
||||||
headingexample: "Heading",
|
headingexample: "标题",
|
||||||
|
|
||||||
hr: "Horizontal Rule <hr> Ctrl/Cmd+R",
|
hr: "Horizontal Rule <hr> Ctrl/Cmd+R",
|
||||||
|
|
||||||
@ -125,6 +125,8 @@ function Pagedown(options) {
|
|||||||
* image url (or null if the user cancelled). If this hook returns false, the default dialog will be used.
|
* image url (or null if the user cancelled). If this hook returns false, the default dialog will be used.
|
||||||
*/
|
*/
|
||||||
hooks.addFalse("insertLinkDialog");
|
hooks.addFalse("insertLinkDialog");
|
||||||
|
// 插入图片占位字符
|
||||||
|
hooks.addFalse("insertImageUploading");
|
||||||
|
|
||||||
var that = this,
|
var that = this,
|
||||||
input;
|
input;
|
||||||
@ -463,6 +465,7 @@ function UIManager(input, commandManager) {
|
|||||||
buttons.bold = bindCommand("doBold");
|
buttons.bold = bindCommand("doBold");
|
||||||
buttons.italic = bindCommand("doItalic");
|
buttons.italic = bindCommand("doItalic");
|
||||||
buttons.strikethrough = bindCommand("doStrikethrough");
|
buttons.strikethrough = bindCommand("doStrikethrough");
|
||||||
|
buttons.imageUploading = bindCommand("doImageUploading");
|
||||||
buttons.link = bindCommand(function (chunk, postProcessing) {
|
buttons.link = bindCommand(function (chunk, postProcessing) {
|
||||||
return this.doLinkOrImage(chunk, postProcessing, false);
|
return this.doLinkOrImage(chunk, postProcessing, false);
|
||||||
});
|
});
|
||||||
@ -615,6 +618,17 @@ commandProto.doStrikethrough = function (chunk, postProcessing) {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
commandProto.doImageUploading = function (chunk, postProcessing) {
|
||||||
|
var enteredCallback = function (imgId) {
|
||||||
|
if (imgId !== null) {
|
||||||
|
chunk.before = `${chunk.before}[图片上传中...(image-${imgId})]`;
|
||||||
|
chunk.selection = '';
|
||||||
|
}
|
||||||
|
postProcessing();
|
||||||
|
};
|
||||||
|
this.hooks.insertImageUploading(enteredCallback);
|
||||||
|
}
|
||||||
|
|
||||||
commandProto.stripLinkDefs = function (text, defsToAdd) {
|
commandProto.stripLinkDefs = function (text, defsToAdd) {
|
||||||
|
|
||||||
text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,
|
text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,
|
||||||
@ -983,37 +997,15 @@ commandProto.doCode = function (chunk) {
|
|||||||
// Use 'four space' markdown if the selection is on its own
|
// Use 'four space' markdown if the selection is on its own
|
||||||
// line or is multiline.
|
// line or is multiline.
|
||||||
if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) {
|
if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) {
|
||||||
|
if (/[\n]+```\n$/.test(chunk.before) && /^\n```[ ]*\n/.test(chunk.after)) {
|
||||||
chunk.before = chunk.before.replace(/[ ]{4}$/,
|
chunk.before = chunk.before.replace(/```\n$/, "");
|
||||||
function (totalMatch) {
|
chunk.after = chunk.after.replace(/^\n```/, "");
|
||||||
chunk.selection = totalMatch + chunk.selection;
|
} else {
|
||||||
return "";
|
chunk.before += '```\n';
|
||||||
});
|
chunk.after = '\n```' + chunk.after;
|
||||||
|
|
||||||
var nLinesBack = 1;
|
|
||||||
var nLinesForward = 1;
|
|
||||||
|
|
||||||
if (/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)) {
|
|
||||||
nLinesBack = 0;
|
|
||||||
}
|
}
|
||||||
if (/^\n(\t|[ ]{4,})/.test(chunk.after)) {
|
|
||||||
nLinesForward = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk.skipLines(nLinesBack, nLinesForward);
|
|
||||||
|
|
||||||
if (!chunk.selection) {
|
if (!chunk.selection) {
|
||||||
chunk.startTag = " ";
|
|
||||||
chunk.selection = this.getString("codeexample");
|
chunk.selection = this.getString("codeexample");
|
||||||
} else {
|
|
||||||
if (/^[ ]{0,3}\S/m.test(chunk.selection)) {
|
|
||||||
if (/\n/.test(chunk.selection))
|
|
||||||
chunk.selection = chunk.selection.replace(/^/gm, " ");
|
|
||||||
else // if it's not multiline, do not select the four added spaces; this is more consistent with the doList behavior
|
|
||||||
chunk.before += " ";
|
|
||||||
} else {
|
|
||||||
chunk.selection = chunk.selection.replace(/^(?:[ ]{4}|[ ]{0,3}\t)/gm, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use backticks (`) to delimit the code block.
|
// Use backticks (`) to delimit the code block.
|
||||||
|
@ -383,7 +383,10 @@ const editorSvc = Object.assign(new Vue(), editorSvcDiscussions, editorSvcUtils,
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
this.pagedownEditor.hooks.set('insertImageUploading', (callback) => {
|
||||||
|
callback(store.getters['img/currImgId']);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
this.editorElt.parentNode.addEventListener('scroll', () => this.saveContentState(true));
|
this.editorElt.parentNode.addEventListener('scroll', () => this.saveContentState(true));
|
||||||
this.previewElt.parentNode.addEventListener('scroll', () => this.saveContentState(true));
|
this.previewElt.parentNode.addEventListener('scroll', () => this.saveContentState(true));
|
||||||
|
|
||||||
|
67
src/services/imageSvc.js
Normal file
67
src/services/imageSvc.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import store from '../store';
|
||||||
|
import utils from './utils';
|
||||||
|
import smmsHelper from '../services/providers/helpers/smmsHelper';
|
||||||
|
import giteaHelper from '../services/providers/helpers/giteaHelper';
|
||||||
|
import githubHelper from '../services/providers/helpers/githubHelper';
|
||||||
|
import customHelper from '../services/providers/helpers/customHelper';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// 上传图片 返回图片链接
|
||||||
|
// { url: 'http://xxxx', error: 'xxxxxx'}
|
||||||
|
async updateImg(imgFile) {
|
||||||
|
// 操作图片上传
|
||||||
|
const currStorage = store.getters['img/getCheckedStorage'];
|
||||||
|
if (!currStorage || !currStorage.provider) {
|
||||||
|
return { error: '暂无已选择的图床!' };
|
||||||
|
}
|
||||||
|
const token = store.getters[`data/${currStorage.provider}TokensBySub`][currStorage.sub];
|
||||||
|
if (!token) {
|
||||||
|
return { error: '暂无已选择的图床!' };
|
||||||
|
}
|
||||||
|
let url = '';
|
||||||
|
// token图床类型
|
||||||
|
if (currStorage.type === 'token') {
|
||||||
|
const helper = currStorage.provider === 'smms' ? smmsHelper : customHelper;
|
||||||
|
url = await helper.uploadFile({
|
||||||
|
token,
|
||||||
|
file: imgFile,
|
||||||
|
});
|
||||||
|
} else if (currStorage.type === 'tokenRepo') { // git repo图床类型
|
||||||
|
const checkStorages = token.imgStorages.filter(it => it.sid === currStorage.sid);
|
||||||
|
if (!checkStorages || checkStorages.length === 0) {
|
||||||
|
return { error: '暂无已选择的图床!' };
|
||||||
|
}
|
||||||
|
const checkStorage = checkStorages[0];
|
||||||
|
const time = new Date();
|
||||||
|
const date = time.getDate();
|
||||||
|
const month = time.getMonth() + 1;
|
||||||
|
const year = time.getFullYear();
|
||||||
|
let path = checkStorage.path.replace('{YYYY}', year)
|
||||||
|
.replace('{MM}', `0${month}`.slice(-2)).replace('{DD}', `0${date}`.slice(-2));
|
||||||
|
path = `${path}${path.endsWith('/') ? '' : '/'}${utils.uid()}.${imgFile.type.split('/')[1]}`;
|
||||||
|
if (currStorage.provider === 'gitea') {
|
||||||
|
const result = await giteaHelper.uploadFile({
|
||||||
|
token,
|
||||||
|
projectId: checkStorage.repoUri,
|
||||||
|
branch: checkStorage.branch,
|
||||||
|
path,
|
||||||
|
content: imgFile,
|
||||||
|
isFile: true,
|
||||||
|
});
|
||||||
|
url = result.content.download_url;
|
||||||
|
} else if (currStorage.provider === 'github') {
|
||||||
|
const result = await githubHelper.uploadFile({
|
||||||
|
token,
|
||||||
|
owner: checkStorage.owner,
|
||||||
|
repo: checkStorage.repo,
|
||||||
|
branch: checkStorage.branch,
|
||||||
|
path,
|
||||||
|
content: imgFile,
|
||||||
|
isFile: true,
|
||||||
|
});
|
||||||
|
url = result.content.download_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { url };
|
||||||
|
},
|
||||||
|
};
|
@ -5,6 +5,8 @@ export default {
|
|||||||
state: {
|
state: {
|
||||||
// 来自粘贴板 或者 拖拽的图片的文件对象
|
// 来自粘贴板 或者 拖拽的图片的文件对象
|
||||||
currImg: null,
|
currImg: null,
|
||||||
|
// 当前图片ID
|
||||||
|
currImgId: null,
|
||||||
// 选择的存储图床信息
|
// 选择的存储图床信息
|
||||||
checkedStorage: {
|
checkedStorage: {
|
||||||
type: null, // 目前存储类型分两种 token 与 tokenRepo
|
type: null, // 目前存储类型分两种 token 与 tokenRepo
|
||||||
@ -16,6 +18,9 @@ export default {
|
|||||||
setNewImg: (state, value) => {
|
setNewImg: (state, value) => {
|
||||||
state.currImg = value;
|
state.currImg = value;
|
||||||
},
|
},
|
||||||
|
setCurrImgId: (state, value) => {
|
||||||
|
state.currImgId = value;
|
||||||
|
},
|
||||||
clearCurrImg: (state) => {
|
clearCurrImg: (state) => {
|
||||||
state.currImg = null;
|
state.currImg = null;
|
||||||
},
|
},
|
||||||
@ -25,18 +30,21 @@ export default {
|
|||||||
type: value.type, // 目前存储类型分两种 token 与 tokenRepo
|
type: value.type, // 目前存储类型分两种 token 与 tokenRepo
|
||||||
provider: value.provider, // 对应是何种账号
|
provider: value.provider, // 对应是何种账号
|
||||||
sub: value.sub, // 对应 token 中的sub
|
sub: value.sub, // 对应 token 中的sub
|
||||||
|
sid: value.sid,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
state.checkedStorage = {
|
state.checkedStorage = {
|
||||||
type: null, // 目前存储类型分两种 token 与 tokenRepo
|
type: null, // 目前存储类型分两种 token 与 tokenRepo
|
||||||
provider: null, // 对应是何种账号
|
provider: null, // 对应是何种账号
|
||||||
sub: null, // 对应 token 中的sub
|
sub: null, // 对应 token 中的sub
|
||||||
|
sid: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
getImg: state => state.currImg,
|
getImg: state => state.currImg,
|
||||||
|
currImgId: state => state.currImgId,
|
||||||
getCheckedStorage: state => state.checkedStorage,
|
getCheckedStorage: state => state.checkedStorage,
|
||||||
getCheckedStorageSub: state => state.checkedStorage.sub,
|
getCheckedStorageSub: state => state.checkedStorage.sub,
|
||||||
},
|
},
|
||||||
@ -44,6 +52,9 @@ export default {
|
|||||||
setImg({ commit }, img) {
|
setImg({ commit }, img) {
|
||||||
commit('setNewImg', img);
|
commit('setNewImg', img);
|
||||||
},
|
},
|
||||||
|
setCurrImgId({ commit }, imgId) {
|
||||||
|
commit('setCurrImgId', imgId);
|
||||||
|
},
|
||||||
clearImg({ commit }) {
|
clearImg({ commit }) {
|
||||||
commit('clearCurrImg');
|
commit('clearCurrImg');
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user