New import menu with HTML to Markdown conversion

This commit is contained in:
benweet 2018-02-13 23:04:54 +00:00
parent 5b6b9ebeb8
commit 1e8fa944a1
4 changed files with 93 additions and 31 deletions

View File

@ -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:

View File

@ -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: () => ({

View 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(/&#160;/g, ' '), // Replace non-breaking spaces with classic spaces
)),
name: file.name,
}))
.then(item => this.$store.commit('file/setCurrentId', item.id));
},
},
};
</script>

View File

@ -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"> Import from disk
<icon-content-save></icon-content-save> </menu-entry>
</div>
<div class="flex flex--column">
Import from disk
</div>
</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