1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Desktop: Fixes #7329: Fixes import of tasklists from enex files (#7344)

This commit is contained in:
Wartijn 2022-12-27 16:17:42 +01:00 committed by GitHub
parent 40399cf3e1
commit 527a7da2ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 71 additions and 7 deletions

View File

@ -0,0 +1,11 @@
<en-note>
<div>
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
<ul style="--en-todo:true;">
<li style="--en-checked:false;"><div>One</div></li>
<li style="--en-checked:true;"><div>Two</div>
</li><li style="--en-checked:false;"><div>Three</div></li>
</ul>
</div>
</en-note>

View File

@ -0,0 +1,19 @@
<en-note>
<div>
<p>In Evernote a checklist is not the same as a list with checkboxes.</p>
<ul style="--en-todo:true;">
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>One</div>
</li>
<li style="--en-checked:true;">
<input checked="checked" type="checkbox" onclick="return false;">
<div>Two</div>
</li>
<li style="--en-checked:false;">
<input type="checkbox" onclick="return false;">
<div>Three</div>
</li>
</ul>
</div>
</en-note>

View File

@ -0,0 +1,7 @@
<ul style="--en-todo:true;">
<li style="--en-checked:false;"><div>One</div></li>
<li style="--en-checked:true;"><div>Two</div>
</li><li style="--en-checked:false;"><div>Three</div></li>
</ul>
<p>More text</p>

View File

@ -0,0 +1,7 @@
- [ ] One
- [X] Two
- [ ] Three
More text

View File

@ -1,6 +1,7 @@
const stringToStream = require('string-to-stream'); const stringToStream = require('string-to-stream');
// const cleanHtml = require('clean-html'); // const cleanHtml = require('clean-html');
const resourceUtils = require('./resourceUtils.js'); const resourceUtils = require('./resourceUtils.js');
const { cssValue } = require('./import-enex-md-gen');
const htmlUtils = require('./htmlUtils').default; const htmlUtils = require('./htmlUtils').default;
const Entities = require('html-entities').AllHtmlEntities; const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = new Entities().encode; const htmlentities = new Entities().encode;
@ -80,6 +81,7 @@ function enexXmlToHtml_(stream, resources) {
saxStream.on('opentag', function(node) { saxStream.on('opentag', function(node) {
const tagName = node.name.toLowerCase(); const tagName = node.name.toLowerCase();
const attributesStr = resourceUtils.attributesToStr(node.attributes); const attributesStr = resourceUtils.attributesToStr(node.attributes);
const nodeAttributes = attributeToLowerCase(node);
if (tagName === 'en-media') { if (tagName === 'en-media') {
const nodeAttributes = attributeToLowerCase(node); const nodeAttributes = attributeToLowerCase(node);
@ -121,9 +123,11 @@ function enexXmlToHtml_(stream, resources) {
section.lines = addResourceTag(section.lines, resource, nodeAttributes); section.lines = addResourceTag(section.lines, resource, nodeAttributes);
} }
} else if (tagName === 'en-todo') { } else if (tagName === 'en-todo') {
const nodeAttributes = attributeToLowerCase(node);
const checkedHtml = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? ' checked="checked" ' : ' '; const checkedHtml = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? ' checked="checked" ' : ' ';
section.lines.push(`<input${checkedHtml}type="checkbox" onclick="return false;" />`); section.lines.push(`<input${checkedHtml}type="checkbox" onclick="return false;" />`);
} else if (tagName === 'li' && cssValue(this, nodeAttributes.style, '--en-checked')) {
const checkedHtml = cssValue(this, nodeAttributes.style, '--en-checked') === 'true' ? ' checked="checked" ' : ' ';
section.lines.push(`<${tagName}${attributesStr}> <input${checkedHtml}type="checkbox" onclick="return false;" />`);
} else if (htmlUtils.isSelfClosingTag(tagName)) { } else if (htmlUtils.isSelfClosingTag(tagName)) {
section.lines.push(`<${tagName}${attributesStr}/>`); section.lines.push(`<${tagName}${attributesStr}/>`);
} else { } else {

View File

@ -65,7 +65,11 @@ describe('EnexToHtml', function() {
}); });
compareOutputToExpected({ compareOutputToExpected({
testName: 'checklist-list', testName: 'checkbox-list',
});
compareOutputToExpected({
testName: 'checklist',
}); });
compareOutputToExpected({ compareOutputToExpected({

View File

@ -35,8 +35,14 @@ interface ParserStateTag {
isHighlight: boolean; isHighlight: boolean;
} }
enum ListTag {
Ul = 'ul',
Ol = 'ol',
CheckboxList = 'checkboxList',
}
interface ParserStateList { interface ParserStateList {
tag: string; tag: ListTag;
counter: number; counter: number;
startedText: boolean; startedText: boolean;
} }
@ -738,7 +744,9 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
section.lines.push(BLOCK_OPEN); section.lines.push(BLOCK_OPEN);
} else if (isListTag(n)) { } else if (isListTag(n)) {
section.lines.push(BLOCK_OPEN); section.lines.push(BLOCK_OPEN);
state.lists.push({ tag: n, counter: 1, startedText: false }); const isCheckboxList = cssValue(this, nodeAttributes.style, '--en-todo') === 'true';
const tag = isCheckboxList ? ListTag.CheckboxList : n as ListTag;
state.lists.push({ tag: tag, counter: 1, startedText: false });
} else if (n === 'li') { } else if (n === 'li') {
section.lines.push(BLOCK_OPEN); section.lines.push(BLOCK_OPEN);
if (!state.lists.length) { if (!state.lists.length) {
@ -750,7 +758,11 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
container.startedText = false; container.startedText = false;
const indent = ' '.repeat(state.lists.length - 1); const indent = ' '.repeat(state.lists.length - 1);
if (container.tag === 'ul') {
if (container.tag === ListTag.CheckboxList) {
const x = cssValue(this, nodeAttributes.style, '--en-checked') === 'true' ? 'X' : ' ';
section.lines.push(`${indent}- [${x}] `);
} else if (container.tag === ListTag.Ul) {
section.lines.push(`${indent}- `); section.lines.push(`${indent}- `);
} else { } else {
section.lines.push(`${indent + container.counter}. `); section.lines.push(`${indent + container.counter}. `);
@ -782,7 +794,7 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[]): Promise<Ene
} else if (isEmTag(n)) { } else if (isEmTag(n)) {
section.lines.push('*'); section.lines.push('*');
} else if (n === 'en-todo') { } else if (n === 'en-todo') {
const x = nodeAttributes && nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? 'X' : ' '; const x = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() === 'true' ? 'X' : ' ';
section.lines.push(`- [${x}] `); section.lines.push(`- [${x}] `);
} else if (n === 'hr') { } else if (n === 'hr') {
// Needs to be surrounded by new lines so that it's properly rendered as a line when converting to HTML // Needs to be surrounded by new lines so that it's properly rendered as a line when converting to HTML
@ -1380,4 +1392,4 @@ async function enexXmlToMd(xmlString: string, resources: ResourceEntity[]) {
return output.join('\n'); return output.join('\n');
} }
export { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag }; export { enexXmlToMd, processMdArrayNewLines, NEWLINE, addResourceTag, cssValue };