New import menu with HTML to Markdown conversion
This commit is contained in:
parent
5b6b9ebeb8
commit
1e8fa944a1
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[![Build Status](https://img.shields.io/travis/benweet/stackedit.svg?style=flat)](https://travis-ci.org/benweet/stackedit) [![NPM version](https://img.shields.io/npm/v/stackedit.svg?style=flat)](https://www.npmjs.org/package/stackedit)
|
[![Build Status](https://img.shields.io/travis/benweet/stackedit.svg?style=flat)](https://travis-ci.org/benweet/stackedit) [![NPM version](https://img.shields.io/npm/v/stackedit.svg?style=flat)](https://www.npmjs.org/package/stackedit)
|
||||||
|
|
||||||
StackEdit is a full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.
|
> Full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.
|
||||||
|
|
||||||
https://stackedit.io/.
|
https://stackedit.io/.
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ https://stackedit.io/.
|
|||||||
- Edit existing Markdown files from Google Drive, Dropbox and your local hard drive
|
- Edit existing Markdown files from Google Drive, Dropbox and your local hard drive
|
||||||
- Post your Markdown file on Blogger/Blogspot, WordPress, Zendesk
|
- Post your Markdown file on Blogger/Blogspot, WordPress, Zendesk
|
||||||
- Publish your Markdown file on GitHub, Gist, Google Drive, Dropbox
|
- Publish your Markdown file on GitHub, Gist, Google Drive, Dropbox
|
||||||
- Share a workspace over Google Drive
|
- Share a workspace over Google Drive, CouchDB
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<publish-menu v-else-if="panel === 'publish'"></publish-menu>
|
<publish-menu v-else-if="panel === 'publish'"></publish-menu>
|
||||||
<history-menu v-else-if="panel === 'history'"></history-menu>
|
<history-menu v-else-if="panel === 'history'"></history-menu>
|
||||||
<export-menu v-else-if="panel === 'export'"></export-menu>
|
<export-menu v-else-if="panel === 'export'"></export-menu>
|
||||||
|
<import-menu v-else-if="panel === 'import'"></import-menu>
|
||||||
<more-menu v-else-if="panel === 'more'"></more-menu>
|
<more-menu v-else-if="panel === 'more'"></more-menu>
|
||||||
<div v-else-if="panel === 'help'" class="side-bar__panel side-bar__panel--help">
|
<div v-else-if="panel === 'help'" class="side-bar__panel side-bar__panel--help">
|
||||||
<pre class="markdown-highlighting" v-html="markdownSample"></pre>
|
<pre class="markdown-highlighting" v-html="markdownSample"></pre>
|
||||||
@ -39,6 +40,7 @@ import SyncMenu from './menus/SyncMenu';
|
|||||||
import PublishMenu from './menus/PublishMenu';
|
import PublishMenu from './menus/PublishMenu';
|
||||||
import HistoryMenu from './menus/HistoryMenu';
|
import HistoryMenu from './menus/HistoryMenu';
|
||||||
import ExportMenu from './menus/ExportMenu';
|
import ExportMenu from './menus/ExportMenu';
|
||||||
|
import ImportMenu from './menus/ImportMenu';
|
||||||
import MoreMenu from './menus/MoreMenu';
|
import MoreMenu from './menus/MoreMenu';
|
||||||
import markdownSample from '../data/markdownSample.md';
|
import markdownSample from '../data/markdownSample.md';
|
||||||
import markdownConversionSvc from '../services/markdownConversionSvc';
|
import markdownConversionSvc from '../services/markdownConversionSvc';
|
||||||
@ -52,6 +54,7 @@ const panelNames = {
|
|||||||
publish: 'Publish',
|
publish: 'Publish',
|
||||||
history: 'File history',
|
history: 'File history',
|
||||||
export: 'Export to disk',
|
export: 'Export to disk',
|
||||||
|
import: 'Import from disk',
|
||||||
more: 'More',
|
more: 'More',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,6 +67,7 @@ export default {
|
|||||||
PublishMenu,
|
PublishMenu,
|
||||||
HistoryMenu,
|
HistoryMenu,
|
||||||
ExportMenu,
|
ExportMenu,
|
||||||
|
ImportMenu,
|
||||||
MoreMenu,
|
MoreMenu,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
83
src/components/menus/ImportMenu.vue
Normal file
83
src/components/menus/ImportMenu.vue
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div class="side-bar__panel side-bar__panel--menu">
|
||||||
|
<input class="hidden-file" id="import-markdown-file-input" type="file" @change="onImportMarkdown">
|
||||||
|
<label class="menu-entry button flex flex--row flex--align-center" for="import-markdown-file-input">
|
||||||
|
<div class="menu-entry__icon flex flex--column flex--center">
|
||||||
|
<icon-upload></icon-upload>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex--column">
|
||||||
|
<div>Import Markdown</div>
|
||||||
|
<span>Open a plain text file.</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<input class="hidden-file" id="import-html-file-input" type="file" @change="onImportHtml">
|
||||||
|
<label class="menu-entry button flex flex--row flex--align-center" for="import-html-file-input">
|
||||||
|
<div class="menu-entry__icon flex flex--column flex--center">
|
||||||
|
<icon-upload></icon-upload>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex--column">
|
||||||
|
<div>Import HTML</div>
|
||||||
|
<span>Convert an HTML file to Markdown.</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TurndownService from 'turndown/lib/turndown.browser.umd';
|
||||||
|
import htmlSanitizer from '../../libs/htmlSanitizer';
|
||||||
|
import MenuEntry from './common/MenuEntry';
|
||||||
|
import providerUtils from '../../services/providers/providerUtils';
|
||||||
|
|
||||||
|
const turndownService = new TurndownService({
|
||||||
|
headingStyle: 'atx',
|
||||||
|
hr: '----------',
|
||||||
|
bulletListMarker: '-',
|
||||||
|
codeBlockStyle: 'fenced',
|
||||||
|
});
|
||||||
|
|
||||||
|
const readFile = file => new Promise((resolve) => {
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const content = e.target.result;
|
||||||
|
if (content.match(/\uFFFD/)) {
|
||||||
|
this.$store.dispatch('notification/error', 'File is not readable.');
|
||||||
|
} else {
|
||||||
|
resolve(content);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
MenuEntry,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onImportMarkdown(evt) {
|
||||||
|
const file = evt.target.files[0];
|
||||||
|
readFile(file)
|
||||||
|
.then(content => this.$store.dispatch('createFile', {
|
||||||
|
...providerUtils.parseContent(content),
|
||||||
|
name: file.name,
|
||||||
|
})
|
||||||
|
.then(item => this.$store.commit('file/setCurrentId', item.id)));
|
||||||
|
},
|
||||||
|
onImportHtml(evt) {
|
||||||
|
const file = evt.target.files[0];
|
||||||
|
readFile(file)
|
||||||
|
.then(content => this.$store.dispatch('createFile', {
|
||||||
|
...providerUtils.parseContent(
|
||||||
|
turndownService.turndown(
|
||||||
|
htmlSanitizer.sanitizeHtml(content)
|
||||||
|
.replace(/ /g, ' '), // Replace non-breaking spaces with classic spaces
|
||||||
|
)),
|
||||||
|
name: file.name,
|
||||||
|
}))
|
||||||
|
.then(item => this.$store.commit('file/setCurrentId', item.id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -65,15 +65,10 @@
|
|||||||
<icon-content-save slot="icon"></icon-content-save>
|
<icon-content-save slot="icon"></icon-content-save>
|
||||||
Export to disk
|
Export to disk
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<input class="hidden-file" id="import-disk-file-input" type="file" @change="onImportFile">
|
<menu-entry @click.native="setPanel('import')">
|
||||||
<label class="menu-entry button flex flex--row flex--align-center" for="import-disk-file-input">
|
<icon-content-save slot="icon"></icon-content-save>
|
||||||
<div class="menu-entry__icon flex flex--column flex--center">
|
|
||||||
<icon-content-save></icon-content-save>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex--column">
|
|
||||||
Import from disk
|
Import from disk
|
||||||
</div>
|
</menu-entry>
|
||||||
</label>
|
|
||||||
<menu-entry @click.native="print">
|
<menu-entry @click.native="print">
|
||||||
<icon-printer slot="icon"></icon-printer>
|
<icon-printer slot="icon"></icon-printer>
|
||||||
Print
|
Print
|
||||||
@ -91,7 +86,6 @@ import MenuEntry from './common/MenuEntry';
|
|||||||
import UserImage from '../UserImage';
|
import UserImage from '../UserImage';
|
||||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
import providerUtils from '../../services/providers/providerUtils';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -116,25 +110,6 @@ export default {
|
|||||||
() => {}, // Cancel
|
() => {}, // Cancel
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onImportFile(evt) {
|
|
||||||
const file = evt.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (e) => {
|
|
||||||
const content = e.target.result;
|
|
||||||
if (content.match(/\uFFFD/)) {
|
|
||||||
this.$store.dispatch('notification/error', 'File is not readable.');
|
|
||||||
} else {
|
|
||||||
this.$store.dispatch('createFile', {
|
|
||||||
...providerUtils.parseContent(content),
|
|
||||||
name: file.name,
|
|
||||||
})
|
|
||||||
.then(item => this.$store.commit('file/setCurrentId', item.id));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.readAsText(file);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fileProperties() {
|
fileProperties() {
|
||||||
return this.$store.dispatch('modal/open', 'fileProperties')
|
return this.$store.dispatch('modal/open', 'fileProperties')
|
||||||
.catch(() => {}); // Cancel
|
.catch(() => {}); // Cancel
|
||||||
|
Loading…
Reference in New Issue
Block a user