支持分享功能
This commit is contained in:
parent
58c9144612
commit
ae828cfb56
@ -71,6 +71,7 @@ StackEdit中文版
|
|||||||
- 支持预览区域选择主题样式(2022-12-04)
|
- 支持预览区域选择主题样式(2022-12-04)
|
||||||
- Gitlab的支持优化(2023-02-23)
|
- Gitlab的支持优化(2023-02-23)
|
||||||
- 导出HTML、PDF支持带预览主题导出(2023-02-26)
|
- 导出HTML、PDF支持带预览主题导出(2023-02-26)
|
||||||
|
- 支持分享文档(2023-03-30)
|
||||||
|
|
||||||
## 国外开源版本弊端:
|
## 国外开源版本弊端:
|
||||||
- 作者已经不维护了
|
- 作者已经不维护了
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stackedit",
|
"name": "stackedit",
|
||||||
"version": "5.15.17",
|
"version": "5.15.19",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stackedit",
|
"name": "stackedit",
|
||||||
"version": "5.15.18",
|
"version": "5.15.19",
|
||||||
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
||||||
"author": "Benoit Schweblin, 豆萁",
|
"author": "Benoit Schweblin, 豆萁",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -61,13 +61,15 @@ module.exports = (app) => {
|
|||||||
res.redirect(`./app#providerId=googleDrive&state=${encodeURIComponent(req.query.state)}`));
|
res.redirect(`./app#providerId=googleDrive&state=${encodeURIComponent(req.query.state)}`));
|
||||||
// Serve the static folder with 30 day max-age
|
// Serve the static folder with 30 day max-age
|
||||||
app.use('/themes', serveStatic(resolvePath('static/themes'), {
|
app.use('/themes', serveStatic(resolvePath('static/themes'), {
|
||||||
maxAge: '1d',
|
maxAge: '5d',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Serve style.css with 1 day max-age
|
// Serve style.css with 1 day max-age
|
||||||
app.get('/style.css', (req, res) => res.sendFile(resolvePath('dist/style.css'), {
|
app.get('/style.css', (req, res) => res.sendFile(resolvePath('dist/style.css'), {
|
||||||
maxAge: '1d',
|
maxAge: '1d',
|
||||||
}));
|
}));
|
||||||
|
// Serve share.html
|
||||||
|
app.get('/share.html', (req, res) => res.sendFile(resolvePath('static/landing/share.html')));
|
||||||
|
|
||||||
// Serve static resources
|
// Serve static resources
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
@ -64,6 +64,8 @@ import GiteeOpenModal from './modals/providers/GiteeOpenModal';
|
|||||||
import GiteeSaveModal from './modals/providers/GiteeSaveModal';
|
import GiteeSaveModal from './modals/providers/GiteeSaveModal';
|
||||||
import GiteeWorkspaceModal from './modals/providers/GiteeWorkspaceModal';
|
import GiteeWorkspaceModal from './modals/providers/GiteeWorkspaceModal';
|
||||||
import GiteePublishModal from './modals/providers/GiteePublishModal';
|
import GiteePublishModal from './modals/providers/GiteePublishModal';
|
||||||
|
import GiteeGistSyncModal from './modals/providers/GiteeGistSyncModal';
|
||||||
|
import GiteeGistPublishModal from './modals/providers/GiteeGistPublishModal';
|
||||||
import GitlabAccountModal from './modals/providers/GitlabAccountModal';
|
import GitlabAccountModal from './modals/providers/GitlabAccountModal';
|
||||||
import GitlabOpenModal from './modals/providers/GitlabOpenModal';
|
import GitlabOpenModal from './modals/providers/GitlabOpenModal';
|
||||||
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
||||||
@ -131,6 +133,8 @@ export default {
|
|||||||
GiteeSaveModal,
|
GiteeSaveModal,
|
||||||
GiteeWorkspaceModal,
|
GiteeWorkspaceModal,
|
||||||
GiteePublishModal,
|
GiteePublishModal,
|
||||||
|
GiteeGistSyncModal,
|
||||||
|
GiteeGistPublishModal,
|
||||||
GitlabAccountModal,
|
GitlabAccountModal,
|
||||||
GitlabOpenModal,
|
GitlabOpenModal,
|
||||||
GitlabPublishModal,
|
GitlabPublishModal,
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
<li class="before">
|
<li class="before">
|
||||||
<icon-ellipsis></icon-ellipsis>
|
<icon-ellipsis></icon-ellipsis>
|
||||||
</li>
|
</li>
|
||||||
|
<li title="分享">
|
||||||
|
<a href="javascript:void(0)" @click="share"><icon-share></icon-share></a>
|
||||||
|
</li>
|
||||||
<li title="切换预览主题">
|
<li title="切换预览主题">
|
||||||
<dropdown-menu :selected="selectedTheme" :options="allThemes" :closeOnItemClick="false" @change="changeTheme">
|
<dropdown-menu :selected="selectedTheme" :options="allThemes" :closeOnItemClick="false" @change="changeTheme">
|
||||||
<icon-select-theme></icon-select-theme>
|
<icon-select-theme></icon-select-theme>
|
||||||
@ -21,6 +24,8 @@ import { mapGetters, mapActions } from 'vuex';
|
|||||||
// import juice from 'juice';
|
// import juice from 'juice';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import DropdownMenu from './common/DropdownMenu';
|
import DropdownMenu from './common/DropdownMenu';
|
||||||
|
import publishSvc from '../services/publishSvc';
|
||||||
|
import giteeGistProvider from '../services/providers/giteeGistProvider';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -56,12 +61,16 @@ export default {
|
|||||||
value: 'custom',
|
value: 'custom',
|
||||||
}],
|
}],
|
||||||
baseCss: '',
|
baseCss: '',
|
||||||
|
sharing: false,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('theme', [
|
...mapGetters('theme', [
|
||||||
'currPreviewTheme',
|
'currPreviewTheme',
|
||||||
'customPreviewThemeStyle',
|
'customPreviewThemeStyle',
|
||||||
]),
|
]),
|
||||||
|
...mapGetters('publishLocation', {
|
||||||
|
publishLocations: 'current',
|
||||||
|
}),
|
||||||
selectedTheme() {
|
selectedTheme() {
|
||||||
return {
|
return {
|
||||||
value: this.currPreviewTheme || 'default',
|
value: this.currPreviewTheme || 'default',
|
||||||
@ -84,6 +93,43 @@ export default {
|
|||||||
this.toggleSideBar(true);
|
this.toggleSideBar(true);
|
||||||
store.dispatch('data/setSideBarPanel', 'help');
|
store.dispatch('data/setSideBarPanel', 'help');
|
||||||
},
|
},
|
||||||
|
async share() {
|
||||||
|
if (this.sharing) {
|
||||||
|
store.dispatch('notification/info', '分享链接创建中...请稍后再试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const currentFile = store.getters['file/current'];
|
||||||
|
await store.dispatch('modal/open', { type: 'shareHtmlPre', name: currentFile.name });
|
||||||
|
this.sharing = true;
|
||||||
|
const mainToken = store.getters['workspace/mainWorkspaceToken'];
|
||||||
|
if (!mainToken) {
|
||||||
|
store.dispatch('notification/info', '登录主文档空间之后才可使用分享功能!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let giteeGistId = null;
|
||||||
|
const filterLocations = this.publishLocations.filter(it => it.providerId === 'giteegist' && it.url && it.gistId);
|
||||||
|
if (filterLocations.length > 0) {
|
||||||
|
giteeGistId = filterLocations[0].gistId;
|
||||||
|
}
|
||||||
|
const location = giteeGistProvider.makeLocation(
|
||||||
|
mainToken,
|
||||||
|
`分享-${currentFile.name}`,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
location.templateId = 'styledHtmlWithTheme';
|
||||||
|
location.fileId = currentFile.id;
|
||||||
|
location.gistId = giteeGistId;
|
||||||
|
const { gistId } = await publishSvc.publishLocationAndStore(location);
|
||||||
|
const url = `${window.location.protocol}//${window.location.host}/share.html?id=${gistId}`;
|
||||||
|
await store.dispatch('modal/open', { type: 'shareHtml', name: currentFile.name, url });
|
||||||
|
} catch (err) {
|
||||||
|
/* cancel */
|
||||||
|
} finally {
|
||||||
|
this.sharing = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -94,7 +140,7 @@ export default {
|
|||||||
.preview-in-page-buttons {
|
.preview-in-page-buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
right: -68px;
|
right: -98px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background-color: rgba(84, 96, 114, 0.4);
|
background-color: rgba(84, 96, 114, 0.4);
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<div v-for="token in githubTokens" :key="token.sub">
|
<div v-for="token in githubTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="publishGist(token)">
|
<menu-entry @click.native="publishGist(token)">
|
||||||
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
||||||
<div>发布到 Gist</div>
|
<div>发布到 GitHubGist</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="publishGithub(token)">
|
<menu-entry @click.native="publishGithub(token)">
|
||||||
@ -53,6 +53,11 @@
|
|||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="token in giteeTokens" :key="token.sub">
|
<div v-for="token in giteeTokens" :key="token.sub">
|
||||||
|
<menu-entry @click.native="publishGiteeGist(token)">
|
||||||
|
<icon-provider slot="icon" provider-id="giteegist"></icon-provider>
|
||||||
|
<div>发布到 GiteeGist</div>
|
||||||
|
<span>{{token.name}}</span>
|
||||||
|
</menu-entry>
|
||||||
<menu-entry @click.native="publishGitee(token)">
|
<menu-entry @click.native="publishGitee(token)">
|
||||||
<icon-provider slot="icon" provider-id="gitee"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitee"></icon-provider>
|
||||||
<div>发布到 Gitee</div>
|
<div>发布到 Gitee</div>
|
||||||
@ -289,8 +294,9 @@ export default {
|
|||||||
publishBloggerPage: publishModalOpener('bloggerPagePublish', 'publishToBloggerPage'),
|
publishBloggerPage: publishModalOpener('bloggerPagePublish', 'publishToBloggerPage'),
|
||||||
publishDropbox: publishModalOpener('dropboxPublish', 'publishToDropbox'),
|
publishDropbox: publishModalOpener('dropboxPublish', 'publishToDropbox'),
|
||||||
publishGithub: publishModalOpener('githubPublish', 'publishToGithub'),
|
publishGithub: publishModalOpener('githubPublish', 'publishToGithub'),
|
||||||
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
|
||||||
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
||||||
|
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
||||||
|
publishGiteeGist: publishModalOpener('giteeGistPublish', 'publishGiteeGist'),
|
||||||
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
||||||
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
||||||
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="saveGist(token)">
|
<menu-entry @click.native="saveGist(token)">
|
||||||
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
||||||
<div>在Gist上保存</div>
|
<div>在GitHubGist上保存</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
@ -61,6 +61,11 @@
|
|||||||
<div>在Gitee上保存</div>
|
<div>在Gitee上保存</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
|
<menu-entry @click.native="saveGiteeGist(token)">
|
||||||
|
<icon-provider slot="icon" provider-id="giteegist"></icon-provider>
|
||||||
|
<div>在GiteeGist上保存</div>
|
||||||
|
<span>{{token.name}}</span>
|
||||||
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="token in gitlabTokens" :key="token.sub">
|
<div v-for="token in gitlabTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="openGitlab(token)">
|
<menu-entry @click.native="openGitlab(token)">
|
||||||
@ -330,6 +335,12 @@ export default {
|
|||||||
badgeSvc.addBadge('saveOnGist');
|
badgeSvc.addBadge('saveOnGist');
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
|
async saveGiteeGist(token) {
|
||||||
|
try {
|
||||||
|
await openSyncModal(token, 'giteeGistSync');
|
||||||
|
badgeSvc.addBadge('saveOnGiteeGist');
|
||||||
|
} catch (e) { /* cancel */ }
|
||||||
|
},
|
||||||
async openGitlab(token) {
|
async openGitlab(token) {
|
||||||
try {
|
try {
|
||||||
const syncLocation = await store.dispatch('modal/open', {
|
const syncLocation = await store.dispatch('modal/open', {
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-upload></icon-upload>
|
<icon-upload></icon-upload>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="publishLocations.length"><b>{{currentFileName}}</b> is published to the following location(s):</p>
|
<p v-if="publishLocations.length"><b>{{currentFileName}}</b> 被发布到了以下位置:</p>
|
||||||
<p v-else><b>{{currentFileName}}</b> is not published yet.</p>
|
<p v-else><b>{{currentFileName}}</b> 还没有被发布.</p>
|
||||||
<div>
|
<div>
|
||||||
<div class="publish-entry flex flex--column" v-for="location in publishLocations" :key="location.id">
|
<div class="publish-entry flex flex--column" v-for="location in publishLocations" :key="location.id">
|
||||||
<div class="publish-entry__header flex flex--row flex--align-center">
|
<div class="publish-entry__header flex flex--row flex--align-center">
|
||||||
@ -26,7 +26,7 @@
|
|||||||
{{location.url}}
|
{{location.url}}
|
||||||
</div>
|
</div>
|
||||||
<div class="publish-entry__buttons flex flex--row flex--center" v-if="location.url">
|
<div class="publish-entry__buttons flex flex--row flex--center" v-if="location.url">
|
||||||
<button class="publish-entry__button button" v-clipboard="location.url" @click="info('Location URL copied to clipboard!')" v-title="'复制URL'">
|
<button class="publish-entry__button button" v-clipboard="location.url" @click="info('位置URL已复制到剪贴板!')" v-title="'复制URL'">
|
||||||
<icon-content-copy></icon-content-copy>
|
<icon-content-copy></icon-content-copy>
|
||||||
</button>
|
</button>
|
||||||
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
||||||
@ -34,6 +34,19 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="publish-entry__row flex flex--row flex--align-center" v-if="shareUrl(location)">
|
||||||
|
<div class="publish-entry__url">
|
||||||
|
分享链接: {{shareUrl(location)}}
|
||||||
|
</div>
|
||||||
|
<div class="publish-entry__buttons flex flex--row flex--center">
|
||||||
|
<button class="publish-entry__button button" v-clipboard="shareUrl(location)" @click="info('分享URL已复制到剪贴板!')" v-title="'复制分享URL'">
|
||||||
|
<icon-content-copy></icon-content-copy>
|
||||||
|
</button>
|
||||||
|
<a class="publish-entry__button button" :href="shareUrl(location)" target="_blank" v-title="'打开分享'">
|
||||||
|
<icon-open-in-new></icon-open-in-new>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__info" v-if="publishLocations.length">
|
<div class="modal__info" v-if="publishLocations.length">
|
||||||
@ -75,6 +88,16 @@ export default {
|
|||||||
store.commit('publishLocation/deleteItem', location.id);
|
store.commit('publishLocation/deleteItem', location.id);
|
||||||
badgeSvc.addBadge('removePublishLocation');
|
badgeSvc.addBadge('removePublishLocation');
|
||||||
},
|
},
|
||||||
|
shareUrl(location) {
|
||||||
|
if (location.providerId !== 'giteegist') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!location.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const splitIndex = location.url.lastIndexOf('/');
|
||||||
|
return `${window.location.protocol}//${window.location.host}/share.html?id=${location.url.substr(splitIndex + 1)}`;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="发布到Gist">
|
<modal-inner aria-label="发布到GitHubGist">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gist"></icon-provider>
|
<icon-provider provider-id="gist"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>发布<b> {{CurrentFileName}} </b>到<b>Gist</b>。</p>
|
<p>发布<b> {{CurrentFileName}} </b>到<b>GitHubGist</b>。</p>
|
||||||
<form-entry label="Filename" error="filename">
|
<form-entry label="文件名" error="filename">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<div class="form-entry">
|
<div class="form-entry">
|
||||||
@ -15,10 +15,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="Existing Gist ID" info="可选的">
|
<form-entry label="存在Gist ID" info="可选的">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
如果文件存在于Gist中,则将被覆盖。
|
如果文件存在于GitHubGist中,则将被覆盖。
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Template">
|
<form-entry label="Template">
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="与 Gist 同步">
|
<modal-inner aria-label="与 GitHubGist 同步">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gist"></icon-provider>
|
<icon-provider provider-id="gist"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>将<b> {{currentFileName}} </b>保存到<b>Gist</b>并保持同步。</p>
|
<p>将<b> {{currentFileName}} </b>保存到<b>GitHubGist</b>并保持同步。</p>
|
||||||
<form-entry label="Filename" error="filename">
|
<form-entry label="文件名" error="filename">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<div class="form-entry">
|
<div class="form-entry">
|
||||||
@ -15,10 +15,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="Existing Gist ID" info="可选的">
|
<form-entry label="存在Gist ID" info="可选的">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
如果文件存在于Gist中,则将被覆盖。
|
如果文件存在于GitHubGist中,则将被覆盖。
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
</div>
|
</div>
|
||||||
|
79
src/components/modals/providers/GiteeGistPublishModal.vue
Normal file
79
src/components/modals/providers/GiteeGistPublishModal.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<modal-inner aria-label="发布到GiteeGist">
|
||||||
|
<div class="modal__content">
|
||||||
|
<div class="modal__image">
|
||||||
|
<icon-provider provider-id="giteegist"></icon-provider>
|
||||||
|
</div>
|
||||||
|
<p>发布<b> {{CurrentFileName}} </b>到<b>GiteeGist</b>。</p>
|
||||||
|
<form-entry label="文件名" error="filename">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<div class="form-entry">
|
||||||
|
<div class="form-entry__checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" v-model="isPublic"> 公开的
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form-entry label="存在Gist ID" info="可选的">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
如果文件存在于GiteeGist中,则将被覆盖。
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="Template">
|
||||||
|
<select slot="field" class="textfield" v-model="selectedTemplate" @keydown.enter="resolve()">
|
||||||
|
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
||||||
|
{{ template.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<div class="form-entry__actions">
|
||||||
|
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<div class="modal__info">
|
||||||
|
<b>ProTip:</b> You can provide a value for <code>title</code> in the <a href="javascript:void(0)" @click="openFileProperties">file properties</a>.
|
||||||
|
</div>
|
||||||
|
</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 giteeGistProvider from '../../../services/providers/giteeGistProvider';
|
||||||
|
import modalTemplate from '../common/modalTemplate';
|
||||||
|
|
||||||
|
export default modalTemplate({
|
||||||
|
data: () => ({
|
||||||
|
filename: '',
|
||||||
|
gistId: '',
|
||||||
|
}),
|
||||||
|
computedLocalSettings: {
|
||||||
|
isPublic: 'gistIsPublic',
|
||||||
|
selectedTemplate: 'gistPublishTemplate',
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.filename = `${this.currentFileName}.md`;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
resolve() {
|
||||||
|
if (!this.filename) {
|
||||||
|
this.setError('filename');
|
||||||
|
} else {
|
||||||
|
// Return new location
|
||||||
|
const location = giteeGistProvider.makeLocation(
|
||||||
|
this.config.token,
|
||||||
|
this.filename,
|
||||||
|
this.isPublic,
|
||||||
|
this.gistId,
|
||||||
|
);
|
||||||
|
location.templateId = this.selectedTemplate;
|
||||||
|
this.config.resolve(location);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
64
src/components/modals/providers/GiteeGistSyncModal.vue
Normal file
64
src/components/modals/providers/GiteeGistSyncModal.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<modal-inner aria-label="与 GiteeGist 同步">
|
||||||
|
<div class="modal__content">
|
||||||
|
<div class="modal__image">
|
||||||
|
<icon-provider provider-id="giteegist"></icon-provider>
|
||||||
|
</div>
|
||||||
|
<p>将<b> {{currentFileName}} </b>保存到<b>GiteeGist</b>并保持同步。</p>
|
||||||
|
<form-entry label="文件名" error="filename">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
|
</form-entry>
|
||||||
|
<div class="form-entry">
|
||||||
|
<div class="form-entry__checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" v-model="isPublic"> 公开的
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form-entry label="存在Gist ID" info="可选的">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
如果文件存在于GiteeGist中,则将被覆盖。
|
||||||
|
</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 giteeGistProvider from '../../../services/providers/giteeGistProvider';
|
||||||
|
import modalTemplate from '../common/modalTemplate';
|
||||||
|
|
||||||
|
export default modalTemplate({
|
||||||
|
data: () => ({
|
||||||
|
filename: '',
|
||||||
|
gistId: '',
|
||||||
|
}),
|
||||||
|
computedLocalSettings: {
|
||||||
|
isPublic: 'gistIsPublic',
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.filename = `${this.currentFileName}.md`;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
resolve() {
|
||||||
|
if (!this.filename) {
|
||||||
|
this.setError('filename');
|
||||||
|
} else {
|
||||||
|
// Return new location
|
||||||
|
const location = giteeGistProvider.makeLocation(
|
||||||
|
this.config.token,
|
||||||
|
this.filename,
|
||||||
|
this.isPublic,
|
||||||
|
this.gistId,
|
||||||
|
);
|
||||||
|
this.config.resolve(location);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -316,6 +316,11 @@ export default [
|
|||||||
'GitHub保存',
|
'GitHub保存',
|
||||||
'使用“同步”菜单将文件保存在GitHub仓库中。',
|
'使用“同步”菜单将文件保存在GitHub仓库中。',
|
||||||
),
|
),
|
||||||
|
new Feature(
|
||||||
|
'saveOnGist',
|
||||||
|
'GitHubGist保存',
|
||||||
|
'使用“同步”菜单将文件保存在GitHubGist中。',
|
||||||
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'openFromGitee',
|
'openFromGitee',
|
||||||
'Gitee阅读器',
|
'Gitee阅读器',
|
||||||
@ -327,9 +332,9 @@ export default [
|
|||||||
'使用“同步”菜单将文件保存在Gitee仓库中。',
|
'使用“同步”菜单将文件保存在Gitee仓库中。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'saveOnGist',
|
'saveOnGiteeGist',
|
||||||
'Gist保存',
|
'GiteeGist保存',
|
||||||
'使用“同步”菜单将文件保存在GIST中。',
|
'使用“同步”菜单将文件保存在GiteeGist中。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'openFromGitlab',
|
'openFromGitlab',
|
||||||
@ -405,14 +410,19 @@ export default [
|
|||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGist',
|
'publishToGist',
|
||||||
'Gist发布',
|
'GitHubGist发布',
|
||||||
'使用“发布”菜单将文件发布到GIST。',
|
'使用“发布”菜单将文件发布到GitHubGist。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGitee',
|
'publishToGitee',
|
||||||
'Gitee发布',
|
'Gitee发布',
|
||||||
'使用“发布”菜单将文件发布到Gitee仓库。',
|
'使用“发布”菜单将文件发布到Gitee仓库。',
|
||||||
),
|
),
|
||||||
|
new Feature(
|
||||||
|
'publishToGiteeGist',
|
||||||
|
'GiteeGist发布',
|
||||||
|
'使用“发布”菜单将文件发布到GiteeGist。',
|
||||||
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGitlab',
|
'publishToGitlab',
|
||||||
'GitLab发布',
|
'GitLab发布',
|
||||||
|
@ -60,6 +60,15 @@ export default {
|
|||||||
'取消',
|
'取消',
|
||||||
'确认清理',
|
'确认清理',
|
||||||
),
|
),
|
||||||
|
shareHtml: simpleModal(
|
||||||
|
config => `<p>给文档 "${config.name}" 创建了分享链接如下:<br/><a href="${config.url}" target="_blank">${config.url}</a><br/>关闭该窗口后可以到发布中查看分享链接。</p>`,
|
||||||
|
'关闭窗口',
|
||||||
|
),
|
||||||
|
shareHtmlPre: simpleModal(
|
||||||
|
config => `<p>将给文档 "${config.name}" 创建分享链接,创建后将会把文档公开发布到GiteeGist中。您确定吗?</p>`,
|
||||||
|
'取消',
|
||||||
|
'确认分享',
|
||||||
|
),
|
||||||
signInForComment: simpleModal(
|
signInForComment: simpleModal(
|
||||||
`<p>您必须使用 Google 登录才能开始评论。</p>
|
`<p>您必须使用 Google 登录才能开始评论。</p>
|
||||||
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
||||||
|
@ -29,6 +29,7 @@ export default {
|
|||||||
return 'couchdb';
|
return 'couchdb';
|
||||||
case 'giteeAppData':
|
case 'giteeAppData':
|
||||||
case 'giteeWorkspace':
|
case 'giteeWorkspace':
|
||||||
|
case 'giteegist':
|
||||||
return 'gitee';
|
return 'gitee';
|
||||||
default:
|
default:
|
||||||
return this.providerId;
|
return this.providerId;
|
||||||
|
3
src/icons/Share.vue
Normal file
3
src/icons/Share.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<svg t="1680140298859" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2766" width="32" height="32"><path d="M769.14815 670.390403c-44.430932 0-84.182284 19.999496-110.768803 51.471278L389.219117 565.736878c6.597255-16.571421 10.228969-34.653241 10.228969-53.594639 0-17.006326-2.940982-33.332153-8.320503-48.497551l270.88143-157.119457c26.511817 29.069059 64.702628 47.312562 107.138112 47.312562 80.055291 0 144.95337-64.899102 144.95337-144.95337 0-80.055291-64.898079-144.954393-144.95337-144.954393s-144.95337 64.899102-144.95337 144.954393c0 15.991206 2.600221 31.386848 7.382131 45.776579L359.655801 412.377048c-26.417673-27.833929-63.756069-45.181015-105.161085-45.181015-80.055291 0-144.954393 64.890916-144.954393 144.946206 0 80.055291 64.898079 144.967696 144.954393 144.967696 39.409568 0 75.128071-15.741519 101.256148-41.24845l274.172383 159.024853c-3.725858 12.8384-5.729491 26.409486-5.729491 40.457434 0 80.0645 64.898079 144.954393 144.95337 144.954393s144.95337-64.889893 144.95337-144.954393C914.101519 735.297692 849.20344 670.390403 769.14815 670.390403z" p-id="2767"></path></svg>
|
||||||
|
</template>
|
@ -64,6 +64,7 @@ import FindReplace from './FindReplace';
|
|||||||
import SelectTheme from './SelectTheme';
|
import SelectTheme from './SelectTheme';
|
||||||
import Copy from './Copy';
|
import Copy from './Copy';
|
||||||
import Ellipsis from './Ellipsis';
|
import Ellipsis from './Ellipsis';
|
||||||
|
import Share from './Share';
|
||||||
|
|
||||||
Vue.component('iconProvider', Provider);
|
Vue.component('iconProvider', Provider);
|
||||||
Vue.component('iconFormatBold', FormatBold);
|
Vue.component('iconFormatBold', FormatBold);
|
||||||
@ -130,3 +131,4 @@ Vue.component('iconFindReplace', FindReplace);
|
|||||||
Vue.component('iconSelectTheme', SelectTheme);
|
Vue.component('iconSelectTheme', SelectTheme);
|
||||||
Vue.component('iconCopy', Copy);
|
Vue.component('iconCopy', Copy);
|
||||||
Vue.component('iconEllipsis', Ellipsis);
|
Vue.component('iconEllipsis', Ellipsis);
|
||||||
|
Vue.component('iconShare', Share);
|
||||||
|
95
src/services/providers/giteeGistProvider.js
Normal file
95
src/services/providers/giteeGistProvider.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import store from '../../store';
|
||||||
|
import giteeHelper from './helpers/giteeHelper';
|
||||||
|
import Provider from './common/Provider';
|
||||||
|
import utils from '../utils';
|
||||||
|
import userSvc from '../userSvc';
|
||||||
|
|
||||||
|
export default new Provider({
|
||||||
|
id: 'giteegist',
|
||||||
|
name: 'GiteeGist',
|
||||||
|
getToken({ sub }) {
|
||||||
|
return store.getters['data/giteeTokensBySub'][sub];
|
||||||
|
},
|
||||||
|
getLocationUrl({ gistId }) {
|
||||||
|
return `https://gitee.com/mafgwo/codes/${gistId}`;
|
||||||
|
},
|
||||||
|
getLocationDescription({ filename }) {
|
||||||
|
return filename;
|
||||||
|
},
|
||||||
|
async downloadContent(token, syncLocation) {
|
||||||
|
const content = await giteeHelper.downloadGist({
|
||||||
|
...syncLocation,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
return Provider.parseContent(content, `${syncLocation.fileId}/content`);
|
||||||
|
},
|
||||||
|
async uploadContent(token, content, syncLocation) {
|
||||||
|
const file = store.state.file.itemsById[syncLocation.fileId];
|
||||||
|
const description = utils.sanitizeName(file && file.name);
|
||||||
|
const gist = await giteeHelper.uploadGist({
|
||||||
|
...syncLocation,
|
||||||
|
token,
|
||||||
|
description,
|
||||||
|
content: Provider.serializeContent(content),
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...syncLocation,
|
||||||
|
gistId: gist.id,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async publish(token, html, metadata, publishLocation) {
|
||||||
|
const gist = await giteeHelper.uploadGist({
|
||||||
|
...publishLocation,
|
||||||
|
token,
|
||||||
|
description: metadata.title,
|
||||||
|
content: html,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...publishLocation,
|
||||||
|
gistId: gist.id,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
makeLocation(token, filename, isPublic, gistId) {
|
||||||
|
return {
|
||||||
|
providerId: this.id,
|
||||||
|
sub: token.sub,
|
||||||
|
filename,
|
||||||
|
isPublic,
|
||||||
|
gistId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async listFileRevisions({ token, syncLocation }) {
|
||||||
|
const entries = await giteeHelper.getGistCommits({
|
||||||
|
...syncLocation,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
|
||||||
|
return entries.map((entry) => {
|
||||||
|
const sub = `${giteeHelper.subPrefix}:${entry.user.id}`;
|
||||||
|
userSvc.addUserInfo({ id: sub, name: entry.user.login, imageUrl: entry.user.avatar_url });
|
||||||
|
return {
|
||||||
|
sub,
|
||||||
|
id: entry.version,
|
||||||
|
message: entry.commit && entry.commit.message,
|
||||||
|
created: new Date(entry.committed_at).getTime(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async loadFileRevision() {
|
||||||
|
// Revision are already loaded
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
// async getFileRevisionContent({
|
||||||
|
// token,
|
||||||
|
// contentId,
|
||||||
|
// syncLocation,
|
||||||
|
// revisionId,
|
||||||
|
// }) {
|
||||||
|
// const data = await giteeHelper.downloadGistRevision({
|
||||||
|
// ...syncLocation,
|
||||||
|
// token,
|
||||||
|
// sha: revisionId,
|
||||||
|
// });
|
||||||
|
// return Provider.parseContent(data, contentId);
|
||||||
|
// },
|
||||||
|
});
|
@ -346,8 +346,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://developer.gitee.com/v3/gists/#create-a-gist
|
* https://gitee.com/api/v5/swagger#/postV5Gists
|
||||||
* https://developer.gitee.com/v3/gists/#edit-a-gist
|
* https://gitee.com/api/v5/swagger#/patchV5GistsId
|
||||||
*/
|
*/
|
||||||
async uploadGist({
|
async uploadGist({
|
||||||
token,
|
token,
|
||||||
@ -357,8 +357,7 @@ export default {
|
|||||||
isPublic,
|
isPublic,
|
||||||
gistId,
|
gistId,
|
||||||
}) {
|
}) {
|
||||||
const refreshedToken = await this.refreshToken(token);
|
const { body } = await request(token, gistId ? {
|
||||||
const { body } = await request(refreshedToken, gistId ? {
|
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
||||||
body: {
|
body: {
|
||||||
@ -386,16 +385,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://developer.gitee.com/v3/gists/#get-a-single-gist
|
* https://gitee.com/api/v5/swagger#/getV5Gists
|
||||||
*/
|
*/
|
||||||
async downloadGist({
|
async downloadGist({
|
||||||
token,
|
token,
|
||||||
gistId,
|
gistId,
|
||||||
filename,
|
filename,
|
||||||
}) {
|
}) {
|
||||||
const refreshedToken = await this.refreshToken(token);
|
const result = (await request(token, {
|
||||||
const result = (await request(refreshedToken, {
|
url: `https://api.github.com/gists/${gistId}`,
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
|
||||||
})).body.files[filename];
|
})).body.files[filename];
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new Error('Gist file not found.');
|
throw new Error('Gist file not found.');
|
||||||
@ -404,35 +402,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://developer.gitee.com/v3/gists/#list-gist-commits
|
* https://gitee.com/api/v5/swagger#/getV5GistsIdCommits
|
||||||
*/
|
*/
|
||||||
async getGistCommits({
|
async getGistCommits({
|
||||||
token,
|
token,
|
||||||
gistId,
|
gistId,
|
||||||
}) {
|
}) {
|
||||||
const refreshedToken = await this.refreshToken(token);
|
const { body } = await request(token, {
|
||||||
const { body } = await request(refreshedToken, {
|
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}/commits`,
|
url: `https://gitee.com/api/v5/gists/${gistId}/commits`,
|
||||||
});
|
});
|
||||||
return body;
|
return body;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* https://developer.gitee.com/v3/gists/#get-a-specific-revision-of-a-gist
|
|
||||||
*/
|
|
||||||
async downloadGistRevision({
|
|
||||||
token,
|
|
||||||
gistId,
|
|
||||||
filename,
|
|
||||||
sha,
|
|
||||||
}) {
|
|
||||||
const refreshedToken = await this.refreshToken(token);
|
|
||||||
const result = (await request(refreshedToken, {
|
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}/${sha}`,
|
|
||||||
})).body.files[filename];
|
|
||||||
if (!result) {
|
|
||||||
throw new Error('Gist file not found.');
|
|
||||||
}
|
|
||||||
return result.content;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -139,6 +139,12 @@ const requestPublish = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const publishLocationAndStore = async (publishLocation, commitMsg) => {
|
||||||
|
const publishLocationToStore = await publish(publishLocation, commitMsg);
|
||||||
|
workspaceSvc.addPublishLocation(publishLocationToStore);
|
||||||
|
return publishLocationToStore;
|
||||||
|
};
|
||||||
|
|
||||||
const createPublishLocation = (publishLocation, featureId) => {
|
const createPublishLocation = (publishLocation, featureId) => {
|
||||||
const currentFile = store.getters['file/current'];
|
const currentFile = store.getters['file/current'];
|
||||||
publishLocation.fileId = currentFile.id;
|
publishLocation.fileId = currentFile.id;
|
||||||
@ -157,8 +163,7 @@ const createPublishLocation = (publishLocation, featureId) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const publishLocationToStore = await publish(publishLocation, commitMsg);
|
await publishLocationAndStore(publishLocation, commitMsg);
|
||||||
workspaceSvc.addPublishLocation(publishLocationToStore);
|
|
||||||
store.dispatch('notification/info', `添加了一个新的发布位置 "${currentFile.name}".`);
|
store.dispatch('notification/info', `添加了一个新的发布位置 "${currentFile.name}".`);
|
||||||
if (featureId) {
|
if (featureId) {
|
||||||
badgeSvc.addBadge(featureId);
|
badgeSvc.addBadge(featureId);
|
||||||
@ -169,5 +174,6 @@ const createPublishLocation = (publishLocation, featureId) => {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
requestPublish,
|
requestPublish,
|
||||||
|
publishLocationAndStore,
|
||||||
createPublishLocation,
|
createPublishLocation,
|
||||||
};
|
};
|
||||||
|
165
static/landing/share.html
Normal file
165
static/landing/share.html
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>StackEdit中文版</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="canonical" href="https://stackedit.cn/">
|
||||||
|
<link rel="icon" href="static/landing/favicon.ico" type="image/x-icon">
|
||||||
|
<link rel="shortcut icon" href="static/landing/favicon.ico" type="image/x-icon">
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
|
||||||
|
<meta name="description"
|
||||||
|
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" />
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<style>
|
||||||
|
.share-header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #383c4a;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header .logo {
|
||||||
|
margin: 0 0 -8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header nav ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header nav li {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header nav a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-header nav a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-content {
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function getQueryString(name) {
|
||||||
|
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
|
||||||
|
var r = window.location.search.substr(1).match(reg);
|
||||||
|
if (r != null) {
|
||||||
|
return unescape(r[2]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendTagHtml(newdoc, tagName, targetParentEle) {
|
||||||
|
const tags = newdoc.getElementsByTagName(tagName);
|
||||||
|
if (!tags) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < tags.length; i++) {
|
||||||
|
targetParentEle.append(tags[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const gistId = getQueryString('id');
|
||||||
|
const workspaces = window.localStorage.getItem('data/workspaces');
|
||||||
|
let accessToken = null;
|
||||||
|
if (workspaces) {
|
||||||
|
const workspacesObj = JSON.parse(workspaces);
|
||||||
|
const sub = workspacesObj.data && workspacesObj.data.main && workspacesObj.data.main.sub;
|
||||||
|
if (sub) {
|
||||||
|
const tokens = window.localStorage.getItem('data/tokens');
|
||||||
|
if (tokens) {
|
||||||
|
const tokensObj = JSON.parse(tokens);
|
||||||
|
accessToken = tokensObj.data && tokensObj.data.gitee && tokensObj.data.gitee[sub] && tokensObj.data.gitee[sub].accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let url = `https://gitee.com/api/v5/gists/${gistId}`;
|
||||||
|
if (accessToken) {
|
||||||
|
url = `${url}?access_token=${accessToken}`;
|
||||||
|
}
|
||||||
|
xhr.open('GET', url);
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const newdoc = document.implementation.createHTMLDocument("");
|
||||||
|
const body = JSON.parse(xhr.responseText);
|
||||||
|
for (let key in body.files) {
|
||||||
|
newdoc.documentElement.innerHTML = body.files[key].content;
|
||||||
|
}
|
||||||
|
const currHead = document.head;
|
||||||
|
// 头部
|
||||||
|
appendTagHtml(newdoc, 'style', currHead);
|
||||||
|
// title
|
||||||
|
document.title = newdoc.title + ' - StackEdit中文版';
|
||||||
|
// 内容
|
||||||
|
const shareContent = document.getElementsByClassName('share-content')[0];
|
||||||
|
shareContent.innerHTML = newdoc.body.innerHTML;
|
||||||
|
} else if (xhr.status === 403) {
|
||||||
|
const rateLimit = xhr.responseText && xhr.responseText.indexOf('Rate Limit') >= 0;
|
||||||
|
const appUri = `${window.location.protocol}//${window.location.host}/app`;
|
||||||
|
document.getElementsByClassName('share-content')[0].innerHTML = `${rateLimit ? "请求太过频繁" : "无权限访问"},请登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
||||||
|
} else {
|
||||||
|
console.error('An error occurred: ' + xhr.status);
|
||||||
|
document.getElementsByClassName('share-content')[0].innerHTML = '分享内容获取失败或已失效!';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="share-header">
|
||||||
|
<nav>
|
||||||
|
<a class="logo" href="/" target="_blank">
|
||||||
|
<img src="static/landing/logo.svg" height="30px"/>
|
||||||
|
</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/" target="_blank">首页</a></li>
|
||||||
|
<li><a href="app" target="_blank">写笔记</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="share-content stackedit">
|
||||||
|
<div style="text-align: center; height: 600px;">文章加载中......</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
<script>
|
||||||
|
var _hmt = _hmt || [];
|
||||||
|
(function() {
|
||||||
|
var hm = document.createElement("script");
|
||||||
|
hm.src = "https://hm.baidu.com/hm.js?20a1e7a201b42702c49074c87a1f1035";
|
||||||
|
var s = document.getElementsByTagName("script")[0];
|
||||||
|
s.parentNode.insertBefore(hm, s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user