You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-06 09:19:22 +02:00
Desktop: Add ENEX to HTML export (#1795)
* Add `escape` to go back from Dropbox Login screen * Add .vscode/ to .gitignore * Remove call to enexXmlToMd * The 2 enex importers have distinct functionality! * Add tmp #deleteAllNotebooks * checkbox state still not persisting * images now fixed, but checkboxes still broken * Figured out that #ipcProxySendToHost is important for handling checkbox * cleanup closing br and en-todo tags + add notes * Handle en-media, add NOTEs & TODOs, & format html * Clean up some of the logging * cleanHtml is a nice beautifier, but callback hell ensues... * Rm #htmlFormat * Recreating the xml actually seems to work * Add test (not functional rn) * Add test for checkboxes * Add test for image en-media * Separate tests into 2 function calls * Clean up test * Add `en-media-audio` test * Add bad resource test * Misc cleanup * Rm SlateEditor files * Misc cleanup * Remove #deleteAllNotebooks button * Add names to tests * Extract resourceUtils * Rm DropboxLoginScreen esc behavior, part of another PR * Misc cleanup * Improve audioElement, add attachment import support * Misc cleanup * Add svg test for enex_to_html * Clean up test * Set markup_language to MARKUP_LANGUAGE_HTML to tell renderer that the content is only HTML * Rename to newModuleByFormat_ for clarity * Add comment to clarify newModuleFromPath_
This commit is contained in:
committed by
Laurent Cozic
parent
52ace55db0
commit
2f14832c34
@@ -13,8 +13,7 @@ const { toTitleCase } = require('lib/string-utils');
|
||||
|
||||
class InteropService {
|
||||
constructor() {
|
||||
this.modules_ = null;
|
||||
}
|
||||
this.modules_ = null; }
|
||||
|
||||
modules() {
|
||||
if (this.modules_) return this.modules_;
|
||||
@@ -42,7 +41,16 @@ class InteropService {
|
||||
format: 'enex',
|
||||
fileExtensions: ['enex'],
|
||||
sources: ['file'],
|
||||
description: _('Evernote Export File'),
|
||||
description: _('Evernote Export File (as Markdown)'),
|
||||
importerClass: 'InteropService_Importer_EnexToMd',
|
||||
},
|
||||
{
|
||||
format: 'enex',
|
||||
fileExtensions: ['enex'],
|
||||
sources: ['file'],
|
||||
description: _('Evernote Export File (as HTML)'),
|
||||
// TODO: Consider doing this the same way as the multiple `md` importers are handled
|
||||
importerClass: 'InteropService_Importer_EnexToHtml',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -71,7 +79,7 @@ class InteropService {
|
||||
];
|
||||
|
||||
importModules = importModules.map(a => {
|
||||
const className = 'InteropService_Importer_' + toTitleCase(a.format);
|
||||
const className = a.importerClass || 'InteropService_Importer_' + toTitleCase(a.format);
|
||||
const output = Object.assign(
|
||||
{},
|
||||
{
|
||||
@@ -112,8 +120,9 @@ class InteropService {
|
||||
return this.modules_;
|
||||
}
|
||||
|
||||
moduleByFormat_(type, format) {
|
||||
findModuleByFormat_(type, format) {
|
||||
const modules = this.modules();
|
||||
// console.log(JSON.stringify({modules}, null, 2))
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
const m = modules[i];
|
||||
if (m.format === format && m.type === type) return modules[i];
|
||||
@@ -121,8 +130,8 @@ class InteropService {
|
||||
return null;
|
||||
}
|
||||
|
||||
newModule_(type, format) {
|
||||
const module = this.moduleByFormat_(type, format);
|
||||
newModuleByFormat_(type, format) {
|
||||
const module = this.findModuleByFormat_(type, format);
|
||||
if (!module) throw new Error(_('Cannot load "%s" module for format "%s"', type, format));
|
||||
const ModuleClass = require(module.path);
|
||||
const output = new ModuleClass();
|
||||
@@ -130,6 +139,26 @@ class InteropService {
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* The existing `newModuleByFormat_` fn would load by the input format. This
|
||||
* was fine when there was a 1-1 mapping of input formats to output formats,
|
||||
* but now that we have 2 possible outputs for an `enex` input, we need to be
|
||||
* explicit with which importer we want to use.
|
||||
*
|
||||
* In the long run, it might make sense to simply move all the existing
|
||||
* formatters to the `newModuleFromPath_` approach, so that there's only one
|
||||
* way to do this mapping.
|
||||
*
|
||||
* https://github.com/laurent22/joplin/pull/1795#pullrequestreview-281574417
|
||||
*/
|
||||
newModuleFromPath_(options) {
|
||||
if (!options || !options.modulePath) throw new Error('Cannot load module without a defined path to load from.');
|
||||
const ModuleClass = require(options.modulePath);
|
||||
const output = new ModuleClass();
|
||||
output.setMetadata(options); // TODO: Check that this metadata is equivalent to module above
|
||||
return output;
|
||||
}
|
||||
|
||||
moduleByFileExtension_(type, ext) {
|
||||
ext = ext.toLowerCase();
|
||||
|
||||
@@ -173,7 +202,10 @@ class InteropService {
|
||||
|
||||
let result = { warnings: [] };
|
||||
|
||||
const importer = this.newModule_('importer', options.format);
|
||||
// console.log('options passed to InteropService:');
|
||||
// console.log(JSON.stringify({options}, null, 2));
|
||||
|
||||
const importer = this.newModuleFromPath_(options);
|
||||
await importer.init(options.path, options);
|
||||
result = await importer.exec(result);
|
||||
|
||||
@@ -248,7 +280,7 @@ class InteropService {
|
||||
await queueExportItem(BaseModel.TYPE_TAG, exportedTagIds[i]);
|
||||
}
|
||||
|
||||
const exporter = this.newModule_('exporter', exportFormat);
|
||||
const exporter = this.newModuleByFormat_('exporter', exportFormat);
|
||||
await exporter.init(exportPath);
|
||||
|
||||
const typeOrder = [BaseModel.TYPE_FOLDER, BaseModel.TYPE_RESOURCE, BaseModel.TYPE_NOTE, BaseModel.TYPE_TAG, BaseModel.TYPE_NOTE_TAG];
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
const InteropService_Importer_Base = require('lib/services/InteropService_Importer_Base');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const { filename } = require('lib/path-utils.js');
|
||||
|
||||
class InteropService_Importer_EnexToHtml extends InteropService_Importer_Base {
|
||||
async exec(result) {
|
||||
const { importEnex } = require('lib/import-enex');
|
||||
|
||||
let folder = this.options_.destinationFolder;
|
||||
|
||||
if (!folder) {
|
||||
const folderTitle = await Folder.findUniqueItemTitle(filename(this.sourcePath_));
|
||||
folder = await Folder.save({ title: folderTitle });
|
||||
}
|
||||
|
||||
await importEnex(folder.id, this.sourcePath_, {...this.options_, outputFormat: 'html'});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InteropService_Importer_EnexToHtml;
|
||||
@@ -2,7 +2,7 @@ const InteropService_Importer_Base = require('lib/services/InteropService_Import
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const { filename } = require('lib/path-utils.js');
|
||||
|
||||
class InteropService_Importer_Enex extends InteropService_Importer_Base {
|
||||
class InteropService_Importer_EnexToMd extends InteropService_Importer_Base {
|
||||
async exec(result) {
|
||||
const { importEnex } = require('lib/import-enex');
|
||||
|
||||
@@ -19,4 +19,4 @@ class InteropService_Importer_Enex extends InteropService_Importer_Base {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InteropService_Importer_Enex;
|
||||
module.exports = InteropService_Importer_EnexToMd;
|
||||
Reference in New Issue
Block a user