mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +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:
parent
52ace55db0
commit
2f14832c34
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,3 +43,4 @@ ReactNativeClient/lib/rnInjectedJs/
|
|||||||
ElectronClient/app/gui/note-viewer/fonts/
|
ElectronClient/app/gui/note-viewer/fonts/
|
||||||
ElectronClient/app/gui/note-viewer/lib.js
|
ElectronClient/app/gui/note-viewer/lib.js
|
||||||
Tools/commit_hook.txt
|
Tools/commit_hook.txt
|
||||||
|
.vscode/*
|
||||||
|
106
CliClient/package-lock.json
generated
106
CliClient/package-lock.json
generated
@ -312,6 +312,22 @@
|
|||||||
"source-map": "0.5.x"
|
"source-map": "0.5.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"clean-html": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/clean-html/-/clean-html-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-eDu0vN44ZBvoEU0oRIKwWPIccGWXtdnUNmKJuTukZ1de00Uoqavb5pfIMKiC7/r+knQ5RbvAjGuVZiN3JwJL4Q==",
|
||||||
|
"requires": {
|
||||||
|
"htmlparser2": "^3.8.2",
|
||||||
|
"minimist": "^1.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"cliss": {
|
"cliss": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/cliss/-/cliss-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/cliss/-/cliss-0.0.2.tgz",
|
||||||
@ -550,6 +566,32 @@
|
|||||||
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
|
||||||
"integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg=="
|
"integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg=="
|
||||||
},
|
},
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
|
||||||
|
},
|
||||||
"domexception": {
|
"domexception": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
||||||
@ -558,6 +600,23 @@
|
|||||||
"webidl-conversions": "^4.0.2"
|
"webidl-conversions": "^4.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "0",
|
||||||
|
"domelementtype": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ecc-jsbn": {
|
"ecc-jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||||
@ -1015,22 +1074,41 @@
|
|||||||
"uglify-js": "3.3.x"
|
"uglify-js": "3.3.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http-errors": {
|
"htmlparser2": {
|
||||||
"version": "1.7.3",
|
"version": "3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||||
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
|
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"depd": "~1.1.2",
|
"domelementtype": "^1.3.1",
|
||||||
"inherits": "2.0.4",
|
"domhandler": "^2.3.0",
|
||||||
"setprototypeof": "1.1.1",
|
"domutils": "^1.5.1",
|
||||||
"statuses": ">= 1.5.0 < 2",
|
"entities": "^1.1.1",
|
||||||
"toidentifier": "1.0.0"
|
"inherits": "^2.0.1",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"inherits": {
|
"readable-stream": {
|
||||||
"version": "2.0.4",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3130,7 +3208,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "^2.1.0",
|
"chalk": "^2.1.0",
|
||||||
"emphasize": "^1.5.0",
|
"emphasize": "^1.5.0",
|
||||||
"node-emoji": "git+https://github.com/laurent22/node-emoji.git",
|
"node-emoji": "git+https://github.com/laurent22/node-emoji.git#9fa01eac463e94dde1316ef8c53089eeef4973b5",
|
||||||
"slice-ansi": "^1.0.0",
|
"slice-ansi": "^1.0.0",
|
||||||
"string-width": "^2.1.1",
|
"string-width": "^2.1.1",
|
||||||
"terminal-kit": "^1.13.11",
|
"terminal-kit": "^1.13.11",
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
"app-module-path": "^2.2.0",
|
"app-module-path": "^2.2.0",
|
||||||
"async-mutex": "^0.1.3",
|
"async-mutex": "^0.1.3",
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
|
"clean-html": "^1.5.0",
|
||||||
"compare-version": "^0.1.2",
|
"compare-version": "^0.1.2",
|
||||||
"diacritics": "^1.3.0",
|
"diacritics": "^1.3.0",
|
||||||
"diff-match-patch": "^1.0.4",
|
"diff-match-patch": "^1.0.4",
|
||||||
|
108
CliClient/tests/EnexToHtml.js
Normal file
108
CliClient/tests/EnexToHtml.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
|
const { asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('test-utils.js');
|
||||||
|
const { shim } = require('lib/shim');
|
||||||
|
const { enexXmlToHtml } = require('lib/import-enex-html-gen.js');
|
||||||
|
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60 * 60 * 1000; // Can run for a while since everything is in the same test unit
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.warn('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileWithPath = (filename) =>
|
||||||
|
`${__dirname}/enex_to_html/${filename}`;
|
||||||
|
|
||||||
|
const audioResource = {
|
||||||
|
filename: 'audio test',
|
||||||
|
id: '9168ee833d03c5ea7c730ac6673978c1',
|
||||||
|
mime: 'audio/x-m4a',
|
||||||
|
size: 82011,
|
||||||
|
title: 'audio test',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the importer for a single note, checking that the result of
|
||||||
|
* processing the given `.enex` input file matches the contents of the given
|
||||||
|
* `.html` file.
|
||||||
|
*
|
||||||
|
* Note that this does not test the importing of an entire exported `.enex`
|
||||||
|
* archive, but rather a single node of such a file. Thus, the test data files
|
||||||
|
* (e.g. `./enex_to_html/code1.enex`) correspond to the contents of a single
|
||||||
|
* `<note>...</note>` node in an `.enex` file already extracted from
|
||||||
|
* `<content><![CDATA[...]]</content>`.
|
||||||
|
*/
|
||||||
|
const compareOutputToExpected = (options) => {
|
||||||
|
const inputFile = fileWithPath(`${options.testName}.enex`);
|
||||||
|
const outputFile = fileWithPath(`${options.testName}.html`);
|
||||||
|
const testTitle = `should convert from Enex to Html: ${options.testName}`;
|
||||||
|
|
||||||
|
it(testTitle, asyncTest(async () => {
|
||||||
|
const enexInput = await shim.fsDriver().readFile(inputFile);
|
||||||
|
const expectedOutput = await shim.fsDriver().readFile(outputFile);
|
||||||
|
const actualOutput = await enexXmlToHtml(enexInput, options.resources);
|
||||||
|
|
||||||
|
expect(actualOutput).toEqual(expectedOutput);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('EnexToHtml', function() {
|
||||||
|
beforeEach(async (done) => {
|
||||||
|
await setupDatabaseAndSynchronizer(1);
|
||||||
|
await switchClient(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
compareOutputToExpected({
|
||||||
|
testName: 'checklist-list',
|
||||||
|
resources: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
compareOutputToExpected({
|
||||||
|
testName: 'svg',
|
||||||
|
resources: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
compareOutputToExpected({
|
||||||
|
testName: 'en-media--image',
|
||||||
|
resources: [{
|
||||||
|
filename: '',
|
||||||
|
id: '89ce7da62c6b2832929a6964237e98e9', // Mock id
|
||||||
|
mime: 'image/jpeg',
|
||||||
|
size: 50347,
|
||||||
|
title: '',
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
compareOutputToExpected({
|
||||||
|
testName: 'en-media--audio',
|
||||||
|
resources: [audioResource],
|
||||||
|
});
|
||||||
|
|
||||||
|
compareOutputToExpected({
|
||||||
|
testName: 'attachment',
|
||||||
|
resources: [{
|
||||||
|
filename: 'attachment-1',
|
||||||
|
id: '21ca2b948f222a38802940ec7e2e5de3',
|
||||||
|
mime: 'application/pdf', // Any non-image/non-audio mime type will do
|
||||||
|
size: 1000,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails when not given a matching resource', asyncTest(async () => {
|
||||||
|
// To test the promise-unexpectedly-resolved case, add `audioResource` to the array.
|
||||||
|
const resources = [];
|
||||||
|
const inputFile = fileWithPath('en-media--image.enex');
|
||||||
|
const enexInput = await shim.fsDriver().readFile(inputFile);
|
||||||
|
const promisedOutput = enexXmlToHtml(enexInput, resources);
|
||||||
|
|
||||||
|
promisedOutput.then(() => {
|
||||||
|
// Promise should not be resolved
|
||||||
|
expect(false).toEqual(true);
|
||||||
|
}, (reason) => {
|
||||||
|
expect(reason)
|
||||||
|
.toBe('Hash with no associated resource: 89ce7da62c6b2832929a6964237e98e9');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
8
CliClient/tests/enex_to_html/attachment.enex
Normal file
8
CliClient/tests/enex_to_html/attachment.enex
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<en-note>
|
||||||
|
<div>
|
||||||
|
<en-media hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</en-note>
|
7
CliClient/tests/enex_to_html/attachment.html
Normal file
7
CliClient/tests/enex_to_html/attachment.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<en-note>
|
||||||
|
<div><a href="#" hash="21ca2b948f222a38802940ec7e2e5de3" type="application/pdf" style="cursor:pointer;" alt="attachment-1" onclick="ipcProxySendToHost('joplin://21ca2b948f222a38802940ec7e2e5de3'); return false;">attachment-1</a></div>
|
||||||
|
<div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</en-note>
|
11
CliClient/tests/enex_to_html/checklist-list.enex
Normal file
11
CliClient/tests/enex_to_html/checklist-list.enex
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<en-note>
|
||||||
|
<div>
|
||||||
|
<p>For example, consider an exported Evernote list with todo checkboxes like this:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><div><en-todo checked="true"/>Foo</div></li>
|
||||||
|
<li><div><en-todo checked="false"/><b>Bar</b></div></li>
|
||||||
|
<li><div><en-todo checked="false"/><i>Baz</i></div></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</en-note>
|
16
CliClient/tests/enex_to_html/checklist-list.html
Normal file
16
CliClient/tests/enex_to_html/checklist-list.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<en-note>
|
||||||
|
<div>
|
||||||
|
<p>For example, consider an exported Evernote list with todo checkboxes like this:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div><input type="checkbox" onclick="return false;">Foo</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div><input type="checkbox" onclick="return false;"><b>Bar</b></div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div><input type="checkbox" onclick="return false;"><i>Baz</i></div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</en-note>
|
3
CliClient/tests/enex_to_html/en-media--audio.enex
Normal file
3
CliClient/tests/enex_to_html/en-media--audio.enex
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
|
||||||
|
<en-note><div><en-media hash="9168ee833d03c5ea7c730ac6673978c1" type="audio/x-m4a" title="Attachment"/></div><div><br/></div></en-note>
|
13
CliClient/tests/enex_to_html/en-media--audio.html
Normal file
13
CliClient/tests/enex_to_html/en-media--audio.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<en-note>
|
||||||
|
<div>
|
||||||
|
<audio controls="" preload="none" style="width:480px;">
|
||||||
|
<source src=":/9168ee833d03c5ea7c730ac6673978c1" type="audio/mp4">
|
||||||
|
<p>Your browser does not support HTML5 audio.</p>
|
||||||
|
</audio>
|
||||||
|
<p><a href=":/9168ee833d03c5ea7c730ac6673978c1" onclick="ipcProxySendToHost('joplin://9168ee833d03c5ea7c730ac6673978c1'); return false;">audio test</a></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</en-note>
|
1
CliClient/tests/enex_to_html/en-media--image.enex
Normal file
1
CliClient/tests/enex_to_html/en-media--image.enex
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div><en-todo checked="false" />This is a test</div><div><en-todo checked="false" />A test for <span style="font-weight: bold;">bold</span></div><div><en-todo checked="false" />A test for <i>italic</i><br /></div><div><br /></div><div><i><en-media hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" /></i></div></en-note>
|
14
CliClient/tests/enex_to_html/en-media--image.html
Normal file
14
CliClient/tests/enex_to_html/en-media--image.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<en-note>
|
||||||
|
<div><input type="checkbox" onclick="return false;">This is a test</div>
|
||||||
|
<div><input type="checkbox" onclick="return false;">A test for <span style="font-weight: bold;">bold</span></div>
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" onclick="return false;">A test for <i>italic</i>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div><i><img src=":/89ce7da62c6b2832929a6964237e98e9" hash="89ce7da62c6b2832929a6964237e98e9" type="image/jpeg" alt=""></i></div>
|
||||||
|
</en-note>
|
5
CliClient/tests/enex_to_html/svg.enex
Normal file
5
CliClient/tests/enex_to_html/svg.enex
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<en-note>
|
||||||
|
<div>
|
||||||
|
<img style="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/use%3e%3c/svg%3e"/>
|
||||||
|
</div>
|
||||||
|
</en-note>
|
3
CliClient/tests/enex_to_html/svg.html
Normal file
3
CliClient/tests/enex_to_html/svg.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<en-note>
|
||||||
|
<div><img style="margin:0px;padding:0px;outline:0px;width:74px;height:36px;position:absolute;bottom:-5px;left:0px;transform:translate(0px, 100%);stroke-dasharray:90;transition:stroke-dashoffset 0.5s cubic-bezier(0.97, 0.16, 0.62, 0.76) 0s;stroke-dashoffset:0;" src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' data-evernote-id='97' class='js-evernote-checked'%3e%3cuse xlink:href='https://wordminds.com/wp-content/themes/wordminds/assets/img/hint_left.svg%23hint_left' data-evernote-id='98' class='js-evernote-checked'%3e%3c/use%3e%3c/svg%3e"></div>
|
||||||
|
</en-note>
|
@ -378,12 +378,15 @@ class Application extends BaseApplication {
|
|||||||
message: _('Importing from "%s" as "%s" format. Please wait...', path, module.format),
|
message: _('Importing from "%s" as "%s" format. Please wait...', path, module.format),
|
||||||
});
|
});
|
||||||
|
|
||||||
const importOptions = {};
|
const importOptions = {
|
||||||
importOptions.path = path;
|
path,
|
||||||
importOptions.format = module.format;
|
format: module.format,
|
||||||
importOptions.destinationFolderId = !module.isNoteArchive && moduleSource === 'file' ? selectedFolderId : null;
|
modulePath: module.path,
|
||||||
importOptions.onError = (error) => {
|
onError: console.warn,
|
||||||
console.warn(error);
|
destinationFolderId:
|
||||||
|
!module.isNoteArchive && moduleSource === 'file'
|
||||||
|
? selectedFolderId
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
|
159
ElectronClient/app/package-lock.json
generated
159
ElectronClient/app/package-lock.json
generated
@ -557,15 +557,13 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
||||||
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"is-glob": {
|
"is-glob": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
|
||||||
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
|
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-extglob": "^1.0.0"
|
"is-extglob": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -1390,6 +1388,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"clean-html": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/clean-html/-/clean-html-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-eDu0vN44ZBvoEU0oRIKwWPIccGWXtdnUNmKJuTukZ1de00Uoqavb5pfIMKiC7/r+knQ5RbvAjGuVZiN3JwJL4Q==",
|
||||||
|
"requires": {
|
||||||
|
"htmlparser2": "^3.8.2",
|
||||||
|
"minimist": "^1.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"cli-boxes": {
|
"cli-boxes": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
|
||||||
@ -1839,6 +1853,32 @@
|
|||||||
"@babel/runtime": "^7.1.2"
|
"@babel/runtime": "^7.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domelementtype": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
|
||||||
|
},
|
||||||
"domexception": {
|
"domexception": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
|
||||||
@ -1847,6 +1887,23 @@
|
|||||||
"webidl-conversions": "^4.0.2"
|
"webidl-conversions": "^4.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "0",
|
||||||
|
"domelementtype": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dot-prop": {
|
"dot-prop": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
|
||||||
@ -2746,8 +2803,7 @@
|
|||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -2771,15 +2827,13 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -2796,22 +2850,19 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -2932,8 +2983,7 @@
|
|||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -2947,7 +2997,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -2964,7 +3013,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@ -2973,15 +3021,13 @@
|
|||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
||||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -2991,8 +3037,7 @@
|
|||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||||
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
|
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3011,7 +3056,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@ -3100,8 +3144,7 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -3115,7 +3158,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -3211,8 +3253,7 @@
|
|||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -3254,7 +3295,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -3276,7 +3316,6 @@
|
|||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -3334,15 +3373,13 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3431,15 +3468,13 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
||||||
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"is-glob": {
|
"is-glob": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
|
||||||
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
|
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-extglob": "^1.0.0"
|
"is-extglob": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -3615,6 +3650,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"htmlparser2": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^1.3.1",
|
||||||
|
"domhandler": "^2.3.0",
|
||||||
|
"domutils": "^1.5.1",
|
||||||
|
"entities": "^1.1.1",
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"http-errors": {
|
"http-errors": {
|
||||||
"version": "1.7.1",
|
"version": "1.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz",
|
||||||
@ -4824,7 +4897,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
||||||
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"remove-trailing-separator": "^1.0.1"
|
"remove-trailing-separator": "^1.0.1"
|
||||||
}
|
}
|
||||||
@ -5196,8 +5268,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
|
||||||
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"is-glob": {
|
"is-glob": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@ -5837,15 +5908,13 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||||
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
|
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"repeat-element": {
|
"repeat-element": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
|
||||||
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
|
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"repeat-string": {
|
"repeat-string": {
|
||||||
"version": "1.6.1",
|
"version": "1.6.1",
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
"async-mutex": "^0.1.3",
|
"async-mutex": "^0.1.3",
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
"chokidar": "^3.0.0",
|
"chokidar": "^3.0.0",
|
||||||
|
"clean-html": "^1.5.0",
|
||||||
"compare-versions": "^3.2.1",
|
"compare-versions": "^3.2.1",
|
||||||
"diacritics": "^1.3.0",
|
"diacritics": "^1.3.0",
|
||||||
"diff-match-patch": "^1.0.4",
|
"diff-match-patch": "^1.0.4",
|
||||||
|
11
ElectronClient/package-lock.json
generated
Normal file
11
ElectronClient/package-lock.json
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"requires": true,
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"html-format": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-format/-/html-format-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-ePp+h+akaQiLeCGPefWQ4QJXVXhWx4sU4ZxJVFlaY0AeVgh/tnHGTL27ao09JrdEEelXYMAWi4ynKKheck4tdw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
ReactNativeClient/lib/import-enex-html-gen.js
Normal file
170
ReactNativeClient/lib/import-enex-html-gen.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
const stringToStream = require('string-to-stream');
|
||||||
|
const cleanHtml = require('clean-html');
|
||||||
|
const resourceUtils = require('lib/resourceUtils.js');
|
||||||
|
|
||||||
|
function addResourceTag(lines, resource, attributes) {
|
||||||
|
// Note: refactor to use Resource.markdownTag
|
||||||
|
if (!attributes.alt) attributes.alt = resource.title;
|
||||||
|
if (!attributes.alt) attributes.alt = resource.filename;
|
||||||
|
if (!attributes.alt) attributes.alt = '';
|
||||||
|
|
||||||
|
const src = `:/${resource.id}`;
|
||||||
|
|
||||||
|
if (resourceUtils.isImageMimeType(resource.mime)) {
|
||||||
|
lines.push(resourceUtils.imgElement({src, attributes}));
|
||||||
|
} else if (resource.mime === 'audio/x-m4a') {
|
||||||
|
/**
|
||||||
|
* TODO: once https://github.com/laurent22/joplin/issues/1794 is resolved,
|
||||||
|
* come back to this and make sure it works.
|
||||||
|
*/
|
||||||
|
lines.push(resourceUtils.audioElement({
|
||||||
|
src,
|
||||||
|
alt: attributes.alt,
|
||||||
|
id: resource.id,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// TODO: figure out what other mime types can be handled more gracefully
|
||||||
|
lines.push(resourceUtils.attachmentElement({
|
||||||
|
src,
|
||||||
|
attributes,
|
||||||
|
id: resource.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
function attributeToLowerCase(node) {
|
||||||
|
if (!node.attributes) return {};
|
||||||
|
let output = {};
|
||||||
|
for (let n in node.attributes) {
|
||||||
|
if (!node.attributes.hasOwnProperty(n)) continue;
|
||||||
|
output[n.toLowerCase()] = node.attributes[n];
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enexXmlToHtml_(stream, resources) {
|
||||||
|
let remainingResources = resources.slice();
|
||||||
|
|
||||||
|
const removeRemainingResource = id => {
|
||||||
|
for (let i = 0; i < remainingResources.length; i++) {
|
||||||
|
const r = remainingResources[i];
|
||||||
|
if (r.id === id) {
|
||||||
|
remainingResources.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = {};
|
||||||
|
const strict = false;
|
||||||
|
var saxStream = require('sax').createStream(strict, options);
|
||||||
|
|
||||||
|
let section = {
|
||||||
|
type: 'text',
|
||||||
|
lines: [],
|
||||||
|
parent: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
saxStream.on('error', function(e) {
|
||||||
|
console.warn(e);
|
||||||
|
// reject(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
saxStream.on('text', function(text) {
|
||||||
|
section.lines.push(text);
|
||||||
|
});
|
||||||
|
|
||||||
|
saxStream.on('opentag', function(node) {
|
||||||
|
const tagName = node.name.toLowerCase();
|
||||||
|
const attributesStr = resourceUtils.attributesToStr(node.attributes);
|
||||||
|
|
||||||
|
if (tagName === 'en-media') {
|
||||||
|
const nodeAttributes = attributeToLowerCase(node);
|
||||||
|
const hash = nodeAttributes.hash;
|
||||||
|
|
||||||
|
let resource = null;
|
||||||
|
for (let i = 0; i < resources.length; i++) {
|
||||||
|
let r = resources[i];
|
||||||
|
if (r.id == hash) {
|
||||||
|
resource = r;
|
||||||
|
removeRemainingResource(r.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
// TODO: Extract this duplicate of code in ./import-enex-md-gen.js
|
||||||
|
let found = false;
|
||||||
|
for (let i = 0; i < remainingResources.length; i++) {
|
||||||
|
let r = remainingResources[i];
|
||||||
|
if (!r.id) {
|
||||||
|
resource = Object.assign({}, r);
|
||||||
|
resource.id = hash;
|
||||||
|
remainingResources.splice(i, 1);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
reject('Hash with no associated resource: ' + hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the resource does not appear among the note's resources, it
|
||||||
|
// means it's an attachement. It will be appended along with the
|
||||||
|
// other remaining resources at the bottom of the markdown text.
|
||||||
|
if (resource && !!resource.id) {
|
||||||
|
section.lines = addResourceTag(section.lines, resource, nodeAttributes);
|
||||||
|
}
|
||||||
|
} else if (tagName == 'en-todo') {
|
||||||
|
section.lines.push('<input type="checkbox" onclick="return false;" />');
|
||||||
|
} else if (node.isSelfClosing) {
|
||||||
|
section.lines.push(`<${tagName}${attributesStr}>`);
|
||||||
|
} else {
|
||||||
|
section.lines.push(`<${tagName}${attributesStr} />`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
saxStream.on('closetag', function(n) {
|
||||||
|
const tagName = n ? n.toLowerCase() : n;
|
||||||
|
section.lines.push(`</${tagName}>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
saxStream.on('attribute', function(attr) {});
|
||||||
|
|
||||||
|
saxStream.on('end', function() {
|
||||||
|
resolve({
|
||||||
|
content: section,
|
||||||
|
resources: remainingResources,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.pipe(saxStream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enexXmlToHtml(xmlString, resources, options = {}) {
|
||||||
|
const stream = stringToStream(xmlString);
|
||||||
|
let result = await enexXmlToHtml_(stream, resources, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const preCleaning = result.content.lines.join(''); // xmlString
|
||||||
|
const final = await beautifyHtml(preCleaning);
|
||||||
|
return final.join('');
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const beautifyHtml = (html) => {
|
||||||
|
return new Promise((resolve, _reject) => {
|
||||||
|
const options = {wrap: 0};
|
||||||
|
cleanHtml.clean(html, options, (...cleanedHtml) => resolve(cleanedHtml));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {enexXmlToHtml};
|
@ -1,5 +1,6 @@
|
|||||||
const stringPadding = require('string-padding');
|
const stringPadding = require('string-padding');
|
||||||
const stringToStream = require('string-to-stream');
|
const stringToStream = require('string-to-stream');
|
||||||
|
const resourceUtils = require('lib/resourceUtils.js');
|
||||||
|
|
||||||
const BLOCK_OPEN = '[[BLOCK_OPEN]]';
|
const BLOCK_OPEN = '[[BLOCK_OPEN]]';
|
||||||
const BLOCK_CLOSE = '[[BLOCK_CLOSE]]';
|
const BLOCK_CLOSE = '[[BLOCK_CLOSE]]';
|
||||||
@ -295,12 +296,6 @@ function collapseWhiteSpaceAndAppend(lines, state, text) {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageMimeTypes = ['image/cgm', 'image/fits', 'image/g3fax', 'image/gif', 'image/ief', 'image/jp2', 'image/jpeg', 'image/jpm', 'image/jpx', 'image/naplps', 'image/png', 'image/prs.btif', 'image/prs.pti', 'image/t38', 'image/tiff', 'image/tiff-fx', 'image/vnd.adobe.photoshop', 'image/vnd.cns.inf2', 'image/vnd.djvu', 'image/vnd.dwg', 'image/vnd.dxf', 'image/vnd.fastbidsheet', 'image/vnd.fpx', 'image/vnd.fst', 'image/vnd.fujixerox.edmics-mmr', 'image/vnd.fujixerox.edmics-rlc', 'image/vnd.globalgraphics.pgb', 'image/vnd.microsoft.icon', 'image/vnd.mix', 'image/vnd.ms-modi', 'image/vnd.net-fpx', 'image/vnd.sealed.png', 'image/vnd.sealedmedia.softseal.gif', 'image/vnd.sealedmedia.softseal.jpg', 'image/vnd.svf', 'image/vnd.wap.wbmp', 'image/vnd.xiff'];
|
|
||||||
|
|
||||||
function isImageMimeType(m) {
|
|
||||||
return imageMimeTypes.indexOf(m) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tagAttributeToMdText(attr) {
|
function tagAttributeToMdText(attr) {
|
||||||
// HTML attributes may contain newlines so remove them.
|
// HTML attributes may contain newlines so remove them.
|
||||||
// https://github.com/laurent22/joplin/issues/1583
|
// https://github.com/laurent22/joplin/issues/1583
|
||||||
@ -318,7 +313,7 @@ function addResourceTag(lines, resource, alt = '') {
|
|||||||
if (!alt) alt = '';
|
if (!alt) alt = '';
|
||||||
|
|
||||||
alt = tagAttributeToMdText(alt);
|
alt = tagAttributeToMdText(alt);
|
||||||
if (isImageMimeType(resource.mime)) {
|
if (resourceUtils.isImageMimeType(resource.mime)) {
|
||||||
lines.push('![');
|
lines.push('![');
|
||||||
lines.push(alt);
|
lines.push(alt);
|
||||||
lines.push('](:/' + resource.id + ')');
|
lines.push('](:/' + resource.id + ')');
|
||||||
|
@ -5,6 +5,7 @@ const Note = require('lib/models/Note.js');
|
|||||||
const Tag = require('lib/models/Tag.js');
|
const Tag = require('lib/models/Tag.js');
|
||||||
const Resource = require('lib/models/Resource.js');
|
const Resource = require('lib/models/Resource.js');
|
||||||
const { enexXmlToMd } = require('./import-enex-md-gen.js');
|
const { enexXmlToMd } = require('./import-enex-md-gen.js');
|
||||||
|
const { enexXmlToHtml } = require('./import-enex-html-gen.js');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
const Levenshtein = require('levenshtein');
|
const Levenshtein = require('levenshtein');
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
@ -164,6 +165,7 @@ async function saveNoteToStorage(note, fuzzyMatching = false) {
|
|||||||
|
|
||||||
function importEnex(parentFolderId, filePath, importOptions = null) {
|
function importEnex(parentFolderId, filePath, importOptions = null) {
|
||||||
if (!importOptions) importOptions = {};
|
if (!importOptions) importOptions = {};
|
||||||
|
// console.info(JSON.stringify({importOptions}, null, 2));
|
||||||
if (!('fuzzyMatching' in importOptions)) importOptions.fuzzyMatching = false;
|
if (!('fuzzyMatching' in importOptions)) importOptions.fuzzyMatching = false;
|
||||||
if (!('onProgress' in importOptions)) importOptions.onProgress = function() {};
|
if (!('onProgress' in importOptions)) importOptions.onProgress = function() {};
|
||||||
if (!('onError' in importOptions)) importOptions.onError = function() {};
|
if (!('onError' in importOptions)) importOptions.onError = function() {};
|
||||||
@ -216,9 +218,15 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
|
|||||||
|
|
||||||
while (notes.length) {
|
while (notes.length) {
|
||||||
let note = notes.shift();
|
let note = notes.shift();
|
||||||
const body = await enexXmlToMd(note.bodyXml, note.resources);
|
const body = importOptions.outputFormat === 'html' ?
|
||||||
|
await enexXmlToHtml(note.bodyXml, note.resources) :
|
||||||
|
await enexXmlToMd(note.bodyXml, note.resources);
|
||||||
delete note.bodyXml;
|
delete note.bodyXml;
|
||||||
|
|
||||||
|
note.markup_language = importOptions.outputFormat === 'html' ?
|
||||||
|
Note.MARKUP_LANGUAGE_HTML :
|
||||||
|
Note.MARKUP_LANGUAGE_MARKDOWN;
|
||||||
|
|
||||||
// console.info('*************************************************************************');
|
// console.info('*************************************************************************');
|
||||||
// console.info(body);
|
// console.info(body);
|
||||||
// console.info('*************************************************************************');
|
// console.info('*************************************************************************');
|
||||||
|
84
ReactNativeClient/lib/resourceUtils.js
Normal file
84
ReactNativeClient/lib/resourceUtils.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
const imageMimeTypes = [
|
||||||
|
'image/cgm',
|
||||||
|
'image/fits',
|
||||||
|
'image/g3fax',
|
||||||
|
'image/gif',
|
||||||
|
'image/ief',
|
||||||
|
'image/jp2',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/jpm',
|
||||||
|
'image/jpx',
|
||||||
|
'image/naplps',
|
||||||
|
'image/png',
|
||||||
|
'image/prs.btif',
|
||||||
|
'image/prs.pti',
|
||||||
|
'image/t38',
|
||||||
|
'image/tiff',
|
||||||
|
'image/tiff-fx',
|
||||||
|
'image/vnd.adobe.photoshop',
|
||||||
|
'image/vnd.cns.inf2',
|
||||||
|
'image/vnd.djvu',
|
||||||
|
'image/vnd.dwg',
|
||||||
|
'image/vnd.dxf',
|
||||||
|
'image/vnd.fastbidsheet',
|
||||||
|
'image/vnd.fpx',
|
||||||
|
'image/vnd.fst',
|
||||||
|
'image/vnd.fujixerox.edmics-mmr',
|
||||||
|
'image/vnd.fujixerox.edmics-rlc',
|
||||||
|
'image/vnd.globalgraphics.pgb',
|
||||||
|
'image/vnd.microsoft.icon',
|
||||||
|
'image/vnd.mix',
|
||||||
|
'image/vnd.ms-modi',
|
||||||
|
'image/vnd.net-fpx',
|
||||||
|
'image/vnd.sealed.png',
|
||||||
|
'image/vnd.sealedmedia.softseal.gif',
|
||||||
|
'image/vnd.sealedmedia.softseal.jpg',
|
||||||
|
'image/vnd.svf',
|
||||||
|
'image/vnd.wap.wbmp',
|
||||||
|
'image/vnd.xiff',
|
||||||
|
];
|
||||||
|
|
||||||
|
const escapeQuotes = (str) => str.replace(/"/g, '"');
|
||||||
|
|
||||||
|
const attributesToStr = (attributes) =>
|
||||||
|
Object.entries(attributes)
|
||||||
|
.map(([key, value]) => ` ${key}="${escapeQuotes(value)}"`)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
const ipcProxySendToHost = (id) =>
|
||||||
|
`onclick="ipcProxySendToHost('joplin://${id}'); return false;"`;
|
||||||
|
|
||||||
|
const attachmentElement = ({src, attributes, id}) =>
|
||||||
|
[
|
||||||
|
`<a href='#' ${attributesToStr(attributes)} ${ipcProxySendToHost(id)}>`,
|
||||||
|
` ${attributes.alt || src}`,
|
||||||
|
'</a>',
|
||||||
|
].join('');
|
||||||
|
|
||||||
|
const imgElement = ({src, attributes}) =>
|
||||||
|
`<img src="${src}" ${attributesToStr(attributes)} />`;
|
||||||
|
|
||||||
|
const audioElement = ({src, alt, id}) =>
|
||||||
|
[
|
||||||
|
'<audio controls preload="none" style="width:480px;">',
|
||||||
|
` <source src="${src}" type="audio/mp4" />`,
|
||||||
|
' <p>',
|
||||||
|
' Your browser does not support HTML5 audio.',
|
||||||
|
' </p>',
|
||||||
|
'</audio>',
|
||||||
|
'<p>',
|
||||||
|
` <a href="${src}" ${ipcProxySendToHost(id)}>`,
|
||||||
|
` ${alt || src || id || 'Download audio'}`,
|
||||||
|
' </a>',
|
||||||
|
'</p>',
|
||||||
|
].join('');
|
||||||
|
|
||||||
|
const resourceUtils = {
|
||||||
|
imgElement,
|
||||||
|
audioElement,
|
||||||
|
attachmentElement,
|
||||||
|
attributesToStr,
|
||||||
|
isImageMimeType: (m) => imageMimeTypes.indexOf(m) >= 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = resourceUtils;
|
@ -13,8 +13,7 @@ const { toTitleCase } = require('lib/string-utils');
|
|||||||
|
|
||||||
class InteropService {
|
class InteropService {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.modules_ = null;
|
this.modules_ = null; }
|
||||||
}
|
|
||||||
|
|
||||||
modules() {
|
modules() {
|
||||||
if (this.modules_) return this.modules_;
|
if (this.modules_) return this.modules_;
|
||||||
@ -42,7 +41,16 @@ class InteropService {
|
|||||||
format: 'enex',
|
format: 'enex',
|
||||||
fileExtensions: ['enex'],
|
fileExtensions: ['enex'],
|
||||||
sources: ['file'],
|
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 => {
|
importModules = importModules.map(a => {
|
||||||
const className = 'InteropService_Importer_' + toTitleCase(a.format);
|
const className = a.importerClass || 'InteropService_Importer_' + toTitleCase(a.format);
|
||||||
const output = Object.assign(
|
const output = Object.assign(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@ -112,8 +120,9 @@ class InteropService {
|
|||||||
return this.modules_;
|
return this.modules_;
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleByFormat_(type, format) {
|
findModuleByFormat_(type, format) {
|
||||||
const modules = this.modules();
|
const modules = this.modules();
|
||||||
|
// console.log(JSON.stringify({modules}, null, 2))
|
||||||
for (let i = 0; i < modules.length; i++) {
|
for (let i = 0; i < modules.length; i++) {
|
||||||
const m = modules[i];
|
const m = modules[i];
|
||||||
if (m.format === format && m.type === type) return modules[i];
|
if (m.format === format && m.type === type) return modules[i];
|
||||||
@ -121,8 +130,8 @@ class InteropService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
newModule_(type, format) {
|
newModuleByFormat_(type, format) {
|
||||||
const module = this.moduleByFormat_(type, format);
|
const module = this.findModuleByFormat_(type, format);
|
||||||
if (!module) throw new Error(_('Cannot load "%s" module for format "%s"', type, format));
|
if (!module) throw new Error(_('Cannot load "%s" module for format "%s"', type, format));
|
||||||
const ModuleClass = require(module.path);
|
const ModuleClass = require(module.path);
|
||||||
const output = new ModuleClass();
|
const output = new ModuleClass();
|
||||||
@ -130,6 +139,26 @@ class InteropService {
|
|||||||
return output;
|
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) {
|
moduleByFileExtension_(type, ext) {
|
||||||
ext = ext.toLowerCase();
|
ext = ext.toLowerCase();
|
||||||
|
|
||||||
@ -173,7 +202,10 @@ class InteropService {
|
|||||||
|
|
||||||
let result = { warnings: [] };
|
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);
|
await importer.init(options.path, options);
|
||||||
result = await importer.exec(result);
|
result = await importer.exec(result);
|
||||||
|
|
||||||
@ -248,7 +280,7 @@ class InteropService {
|
|||||||
await queueExportItem(BaseModel.TYPE_TAG, exportedTagIds[i]);
|
await queueExportItem(BaseModel.TYPE_TAG, exportedTagIds[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exporter = this.newModule_('exporter', exportFormat);
|
const exporter = this.newModuleByFormat_('exporter', exportFormat);
|
||||||
await exporter.init(exportPath);
|
await exporter.init(exportPath);
|
||||||
|
|
||||||
const typeOrder = [BaseModel.TYPE_FOLDER, BaseModel.TYPE_RESOURCE, BaseModel.TYPE_NOTE, BaseModel.TYPE_TAG, BaseModel.TYPE_NOTE_TAG];
|
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 Folder = require('lib/models/Folder.js');
|
||||||
const { filename } = require('lib/path-utils.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) {
|
async exec(result) {
|
||||||
const { importEnex } = require('lib/import-enex');
|
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;
|
Loading…
Reference in New Issue
Block a user