You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-23 22:36:32 +02:00
This commit is contained in:
@@ -9,6 +9,7 @@ import InteropService from './InteropService';
|
||||
import InteropService_Importer_OneNote from './InteropService_Importer_OneNote';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { ImportModuleOutputFormat } from './types';
|
||||
import HtmlToMd from '../../HtmlToMd';
|
||||
|
||||
const instructionMessage = `
|
||||
--------------------------------------
|
||||
@@ -26,6 +27,21 @@ const removeItemIds = (body: string) => {
|
||||
return body.replace(/:\/[a-z0-9]{32}/g, ':/id-here');
|
||||
};
|
||||
|
||||
const removeDefaultCss = (body: string) => {
|
||||
const defaultCssStart = body.indexOf('/*** Start default CSS ***/');
|
||||
const endMarker = '/*** End default CSS ***/';
|
||||
const defaultCssEnd = body.indexOf(endMarker);
|
||||
if (defaultCssEnd === -1 || defaultCssStart === -1) return body;
|
||||
|
||||
const before = body.substring(0, defaultCssStart);
|
||||
const after = body.substring(defaultCssEnd + endMarker.length);
|
||||
return [before, '/* (For testing: Removed default CSS) */', after].join('\n');
|
||||
};
|
||||
|
||||
const normalizeNoteForSnapshot = (body: string) => {
|
||||
return removeItemIds(removeDefaultCss(body));
|
||||
};
|
||||
|
||||
// This file is ignored if not running in CI. Look at onenote-converter/README.md and jest.config.js for more information
|
||||
describe('InteropService_Importer_OneNote', () => {
|
||||
let tempDir: string;
|
||||
@@ -68,7 +84,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
|
||||
expectWithInstructions(mainNote.title).toBe('Page title');
|
||||
expectWithInstructions(mainNote.markup_language).toBe(MarkupToHtml.MARKUP_LANGUAGE_HTML);
|
||||
expectWithInstructions(mainNote.body).toMatchSnapshot(mainNote.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(mainNote.body)).toMatchSnapshot(mainNote.title);
|
||||
});
|
||||
|
||||
it('should preserve indentation of subpages in Section page', async () => {
|
||||
@@ -121,7 +137,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
expectWithInstructions(notes.filter(n => n.parent_id === parentSection.id).length).toBe(6);
|
||||
|
||||
for (const note of notes) {
|
||||
expectWithInstructions(note.body).toMatchSnapshot(note.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(note.body)).toMatchSnapshot(note.title);
|
||||
}
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -186,7 +202,9 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
const originalIdGenerator = BaseModel.setIdGenerator(() => String(idx++));
|
||||
const notes = await importNote(`${supportDir}/onenote/bug_broken_character.zip`);
|
||||
|
||||
expectWithInstructions(notes.find(n => n.title === 'Action research - Wikipedia').body).toMatchSnapshot();
|
||||
expectWithInstructions(
|
||||
normalizeNoteForSnapshot(notes.find(n => n.title === 'Action research - Wikipedia').body),
|
||||
).toMatchSnapshot();
|
||||
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -197,7 +215,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
const notes = await importNote(`${supportDir}/onenote/remove_hyperlink_on_title.zip`);
|
||||
|
||||
for (const note of notes) {
|
||||
expectWithInstructions(note.body).toMatchSnapshot(note.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(note.body)).toMatchSnapshot(note.title);
|
||||
}
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -217,7 +235,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
const notes = await importNote(`${supportDir}/onenote/hyperlink_marker_as_first_character.zip`);
|
||||
|
||||
for (const note of notes) {
|
||||
expectWithInstructions(note.body).toMatchSnapshot(note.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(note.body)).toMatchSnapshot(note.title);
|
||||
}
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -230,7 +248,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
expectWithInstructions(notes.length).toBe(2);
|
||||
|
||||
for (const note of notes) {
|
||||
expectWithInstructions(note.body).toMatchSnapshot(note.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(note.body)).toMatchSnapshot(note.title);
|
||||
}
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -243,7 +261,7 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
expectWithInstructions(notes.length).toBe(2);
|
||||
|
||||
for (const note of notes) {
|
||||
expectWithInstructions(note.body).toMatchSnapshot(note.title);
|
||||
expectWithInstructions(normalizeNoteForSnapshot(note.body)).toMatchSnapshot(note.title);
|
||||
}
|
||||
BaseModel.setIdGenerator(originalIdGenerator);
|
||||
});
|
||||
@@ -253,11 +271,11 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
|
||||
// InkBias bug
|
||||
const note1Content = notes.find(n => n.title === 'Marketing Funnel & Training').body;
|
||||
expect(removeItemIds(note1Content)).toMatchSnapshot();
|
||||
expect(normalizeNoteForSnapshot(note1Content)).toMatchSnapshot();
|
||||
|
||||
// EntityGuid
|
||||
const note2Content = notes.find(n => n.title === 'Decrease support costs').body;
|
||||
expect(removeItemIds(note2Content)).toMatchSnapshot();
|
||||
expect(normalizeNoteForSnapshot(note2Content)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support directly importing .one files', async () => {
|
||||
@@ -277,7 +295,16 @@ describe('InteropService_Importer_OneNote', () => {
|
||||
it('should support importing .one files that contain checkboxes', async () => {
|
||||
const notes = await importNote(`${supportDir}/onenote/checkboxes_and_unicode.one`);
|
||||
expectWithInstructions(
|
||||
removeItemIds(notes.find(n => n.title.startsWith('Test Todo')).body),
|
||||
normalizeNoteForSnapshot(notes.find(n => n.title.startsWith('Test Todo')).body),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should correctly convert imported notes to Markdown', async () => {
|
||||
const notes = await importNote(`${supportDir}/onenote/checkboxes_and_unicode.one`);
|
||||
const checklistNote = notes.find(n => n.title.startsWith('Test Todo'));
|
||||
const converter = new HtmlToMd();
|
||||
const markdown = converter.parse(checklistNote.body);
|
||||
|
||||
expect(markdown).toMatchSnapshot('Test Todo: As Markdown');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,19 +104,9 @@ exports[`InteropService_Importer_OneNote should be able to create notes from cor
|
||||
<meta charset="UTF-8">
|
||||
<title>title</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -138,25 +128,41 @@ exports[`InteropService_Importer_OneNote should be able to create notes from cor
|
||||
</html>"
|
||||
`;
|
||||
|
||||
exports[`InteropService_Importer_OneNote should correctly convert imported notes to Markdown: Test Todo: As Markdown 1`] = `
|
||||
" Test Todo : cases à cocher lien vers doc sur partage
|
||||
|
||||
Test Todo : cases à cocher lien vers doc sur partage
|
||||
|
||||
jeudi 23 octobre 2025
|
||||
|
||||
09:24
|
||||
|
||||
## Todo HBA
|
||||
|
||||
- [x] Rédiger carnet MS-OneNote jeu d'essai (case cochée)
|
||||
- [ ] Transmettre aux dev Joplin (case non cochée)
|
||||
- [x] Exporter le carnet en \\*.packageone (case cochée)
|
||||
- [ ] Exporter des page en \\*.one (case non cochée)
|
||||
|
||||
|
||||
|
||||
## Todo Team appli
|
||||
|
||||
- [ ] Rédiger compte-rendu réunion de service
|
||||
- [ ] Rédiger présentation service Joplin et fonctionnalités complémentaires associée à JBS
|
||||
la doc sur le partage : [\\\\\\\\mondomaine.local\\\\partage\\\\DSI\\\\Projets Techniques 2025\\\\Remplacement Office\\\\JOPLIN_Alternatives_OneNote\\\\formation](file:///\\\\mondomaine.local\\partage\\DSI\\Projets%20Techniques%202025\\Remplacement%20Office\\JOPLIN_Alternatives_OneNote\\formation)
|
||||
- [x] Documenter configuration synchro JBS saml pour un utilisateur (case cochée)"
|
||||
`;
|
||||
|
||||
exports[`InteropService_Importer_OneNote should expect notes to be rendered the same: A page can have any width it wants 1`] = `
|
||||
"<!DOCTYPE HTML>
|
||||
<html lang="en"><head>
|
||||
<meta charset="UTF-8">
|
||||
<title>A page can have any width it wants?</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -186,19 +192,9 @@ exports[`InteropService_Importer_OneNote should expect notes to be rendered the
|
||||
<meta charset="UTF-8">
|
||||
<title>A page with a lot of svgs</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -226,19 +222,9 @@ exports[`InteropService_Importer_OneNote should expect notes to be rendered the
|
||||
<meta charset="UTF-8">
|
||||
<title>A page with text and drawing above it</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -272,19 +258,9 @@ exports[`InteropService_Importer_OneNote should expect notes to be rendered the
|
||||
<meta charset="UTF-8">
|
||||
<title>A simple filename</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -312,19 +288,9 @@ exports[`InteropService_Importer_OneNote should expect notes to be rendered the
|
||||
<meta charset="UTF-8">
|
||||
<title>Page with more than one font size</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -462,19 +428,9 @@ exports[`InteropService_Importer_OneNote should expect notes to be rendered the
|
||||
<meta charset="UTF-8">
|
||||
<title>text</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -814,19 +770,9 @@ exports[`InteropService_Importer_OneNote should ignore broken characters at the
|
||||
<meta charset="UTF-8">
|
||||
<title>Action research - Wikipedia</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
.list-0 li { padding-left: 10px; }
|
||||
.list-0 li::marker { content: '•'; font-family: Georgia; }
|
||||
@@ -887,19 +833,9 @@ exports[`InteropService_Importer_OneNote should import a simple OneNote notebook
|
||||
<meta charset="UTF-8">
|
||||
<title>Page title</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1031,19 +967,9 @@ exports[`InteropService_Importer_OneNote should remove hyperlink from title: Tip
|
||||
<meta charset="UTF-8">
|
||||
<title>Tips from a Pro: Using Trees for Dramatic Landscape Photography</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1072,19 +998,9 @@ exports[`InteropService_Importer_OneNote should remove hyperlink from title: wik
|
||||
<meta charset="UTF-8">
|
||||
<title>wikipedia link</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1113,19 +1029,9 @@ exports[`InteropService_Importer_OneNote should remove hyperlink from title: 风
|
||||
<meta charset="UTF-8">
|
||||
<title>风景 (Web view)</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1154,19 +1060,9 @@ exports[`InteropService_Importer_OneNote should remove hyperlink from title: 风
|
||||
<meta charset="UTF-8">
|
||||
<title>风景</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1194,19 +1090,9 @@ exports[`InteropService_Importer_OneNote should render audio as links to resourc
|
||||
<meta charset="UTF-8">
|
||||
<title>My title</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1337,19 +1223,9 @@ exports[`InteropService_Importer_OneNote should render links properly by ignorin
|
||||
<meta charset="UTF-8">
|
||||
<title>Is Mexico safe for shooting Street Photography?</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1476,27 +1352,17 @@ exports[`InteropService_Importer_OneNote should support importing .one files tha
|
||||
<meta charset="UTF-8">
|
||||
<title>Test Todo : cases à cocher lien vers doc sur partage</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
.icon-0 > svg, .icon-0 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-1 > svg, .icon-1 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-2 > svg, .icon-2 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-3 > svg, .icon-3 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-4 > svg, .icon-4 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-5 > svg, .icon-5 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
.icon-6 > svg, .icon-6 > img { fill: #4673b7; height: 20px; left: -25px; width: 20px; }
|
||||
|
||||
.icon-0 > svg, .icon-0 > img { fill: #4673b7; }
|
||||
.icon-1 > svg, .icon-1 > img { fill: #4673b7; }
|
||||
.icon-2 > svg, .icon-2 > img { fill: #4673b7; }
|
||||
.icon-3 > svg, .icon-3 > img { fill: #4673b7; }
|
||||
.icon-4 > svg, .icon-4 > img { fill: #4673b7; }
|
||||
.icon-5 > svg, .icon-5 > img { fill: #4673b7; }
|
||||
.icon-6 > svg, .icon-6 > img { fill: #4673b7; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
@@ -1506,23 +1372,23 @@ exports[`InteropService_Importer_OneNote should support importing .one files tha
|
||||
</div><div class="container-outline"><div class="outline-element" style="margin-left: 0px;"><span style="color: rgb(118,118,118); font-family: Calibri; font-size: 10pt; line-height: 16px;">jeudi 23 octobre 2025</span></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><span style="color: rgb(118,118,118); font-family: Calibri; font-size: 10pt; line-height: 16px;">09:24</span></div>
|
||||
</div></div><div class="container-outline" style="left: 48px; position: absolute; top: 115px; width: 720px;"><div class="outline-element" style="margin-left: 0px;"><h2 style="color: rgb(46,117,181); font-family: Calibri; font-size: 14pt; line-height: 22px;">Todo HBA</h2></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-0"><img alt="Checked" src=":/id-here">
|
||||
</span>Rédiger carnet MS-OneNote jeu d'essai (case cochée)</p></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-1"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Transmettre aux dev Joplin (case non cochée)</p></div><div class="outline-element" style="margin-left: 36px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-2"><img alt="Checked" src=":/id-here">
|
||||
</span>Exporter le carnet en *.packageone (case cochée)</p></div>
|
||||
<div class="outline-element" style="margin-left: 36px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-3"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Exporter des page en *.one (case non cochée)</p></div>
|
||||
|
||||
<div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"> </p></div>
|
||||
<ul class="tagged-list"><li class="outline-element" style="margin-left: 0px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="true" aria-disabled="true" class="note-tag-icon icon-0 -checkbox -large" role="checkbox"><img alt="Checked" src=":/id-here">
|
||||
</span>Rédiger carnet MS-OneNote jeu d'essai (case cochée)</span></li>
|
||||
<li class="outline-element" style="margin-left: 0px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="false" aria-disabled="true" class="note-tag-icon icon-1 -checkbox -large" role="checkbox"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Transmettre aux dev Joplin (case non cochée)</span><ul class="tagged-list"><li class="outline-element" style="margin-left: 36px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="true" aria-disabled="true" class="note-tag-icon icon-2 -checkbox -large" role="checkbox"><img alt="Checked" src=":/id-here">
|
||||
</span>Exporter le carnet en *.packageone (case cochée)</span></li>
|
||||
<li class="outline-element" style="margin-left: 36px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="false" aria-disabled="true" class="note-tag-icon icon-3 -checkbox -large" role="checkbox"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Exporter des page en *.one (case non cochée)</span></li>
|
||||
</ul></li>
|
||||
</ul><div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"> </p></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><h2 style="color: rgb(46,117,181); font-family: Calibri; font-size: 14pt; line-height: 22px;">Todo Team appli</h2></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-4"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Rédiger compte-rendu réunion de service</p></div>
|
||||
<div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-5"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Rédiger présentation service Joplin et fonctionnalités complémentaires associée à JBS<br>la doc sur le partage : <a href="file:///\\\\mondomaine.local\\partage\\DSI\\Projets%20Techniques%202025\\Remplacement%20Office\\JOPLIN_Alternatives_OneNote\\formation" style="">\\\\mondomaine.local\\partage\\DSI\\Projets Techniques 2025\\Remplacement Office\\JOPLIN_Alternatives_OneNote\\formation</a> </p></div><div class="outline-element" style="margin-left: 36px;"><p style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span class="note-tag-icon icon-6"><img alt="Checked" src=":/id-here">
|
||||
</span>Documenter configuration synchro JBS saml pour un utilisateur (case cochée)</p></div>
|
||||
|
||||
</div>
|
||||
<ul class="tagged-list"><li class="outline-element" style="margin-left: 0px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="false" aria-disabled="true" class="note-tag-icon icon-4 -checkbox -large" role="checkbox"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Rédiger compte-rendu réunion de service</span></li>
|
||||
<li class="outline-element" style="margin-left: 0px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="false" aria-disabled="true" class="note-tag-icon icon-5 -checkbox -large" role="checkbox"><img class="checkbox-icon" alt="Unchecked" src=":/id-here">
|
||||
</span>Rédiger présentation service Joplin et fonctionnalités complémentaires associée à JBS<br>la doc sur le partage : <a href="file:///\\\\mondomaine.local\\partage\\DSI\\Projets%20Techniques%202025\\Remplacement%20Office\\JOPLIN_Alternatives_OneNote\\formation" style="">\\\\mondomaine.local\\partage\\DSI\\Projets Techniques 2025\\Remplacement Office\\JOPLIN_Alternatives_OneNote\\formation</a> </span><ul class="tagged-list"><li class="outline-element" style="margin-left: 36px;"><span style="font-family: Calibri; font-size: 11pt; line-height: 17px;"><span aria-checked="true" aria-disabled="true" class="note-tag-icon icon-6 -checkbox -large" role="checkbox"><img alt="Checked" src=":/id-here">
|
||||
</span>Documenter configuration synchro JBS saml pour un utilisateur (case cochée)</span></li>
|
||||
</ul></li>
|
||||
</ul></div>
|
||||
|
||||
<script>
|
||||
if (window.parent !== null) {
|
||||
@@ -1539,19 +1405,9 @@ exports[`InteropService_Importer_OneNote should use default value for EntityGuid
|
||||
<meta charset="UTF-8">
|
||||
<title>Marketing Funnel & Training</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1586,19 +1442,9 @@ exports[`InteropService_Importer_OneNote should use default value for EntityGuid
|
||||
<meta charset="UTF-8">
|
||||
<title>Decrease support costs</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
.title .outline-element { display: inline; }
|
||||
.title .outline-element:nth-child(2) { margin-left: 10px !important; }
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/* (For testing: Removed default CSS) */
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@@ -18,13 +18,17 @@ impl<'a> Renderer<'a> {
|
||||
let mut list_end = None;
|
||||
|
||||
for (element, parent_level, current_level) in elements {
|
||||
if !in_list && self.is_list(element) {
|
||||
if !in_list && self.is_onenote_list(element) {
|
||||
let tags = self.list_tags(element);
|
||||
let list_start = tags.0;
|
||||
list_end = Some(tags.1);
|
||||
|
||||
contents.push_str(&list_start);
|
||||
in_list = true;
|
||||
} else if !in_list && self.is_tag_list(element) {
|
||||
contents.push_str("<ul class=\"tagged-list\">");
|
||||
list_end = Some("</ul>".into());
|
||||
in_list = true;
|
||||
}
|
||||
|
||||
if in_list && !self.is_list(element) {
|
||||
@@ -176,7 +180,15 @@ impl<'a> Renderer<'a> {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn is_onenote_list(&self, element: &OutlineElement) -> bool {
|
||||
!element.list_contents().is_empty()
|
||||
}
|
||||
|
||||
fn is_tag_list(&self, element: &OutlineElement) -> bool {
|
||||
self.has_note_tag(element)
|
||||
}
|
||||
|
||||
pub(crate) fn is_list(&self, element: &OutlineElement) -> bool {
|
||||
element.list_contents().first().is_some()
|
||||
self.is_onenote_list(element) || self.is_tag_list(element)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::page::Renderer;
|
||||
use crate::utils::StyleSet;
|
||||
use crate::utils::{AttributeSet, StyleSet};
|
||||
use parser::contents::{NoteTag, OutlineElement};
|
||||
use parser::property::common::ColorRef;
|
||||
use parser::property::note_tag::{ActionItemStatus, NoteTagShape};
|
||||
@@ -45,6 +45,35 @@ enum IconSize {
|
||||
Large,
|
||||
}
|
||||
|
||||
struct NoteTagIcon {
|
||||
html: Cow<'static, str>,
|
||||
size: IconSize,
|
||||
styles: StyleSet,
|
||||
is_checkbox: bool,
|
||||
}
|
||||
|
||||
impl From<(Cow<'static, str>, IconSize)> for NoteTagIcon {
|
||||
fn from((html, size): (Cow<'static, str>, IconSize)) -> Self {
|
||||
Self {
|
||||
html,
|
||||
size,
|
||||
styles: StyleSet::new(),
|
||||
is_checkbox: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Cow<'static, str>, IconSize, StyleSet)> for NoteTagIcon {
|
||||
fn from((html, size, styles): (Cow<'static, str>, IconSize, StyleSet)) -> Self {
|
||||
Self {
|
||||
html,
|
||||
size,
|
||||
styles,
|
||||
is_checkbox: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Renderer<'a> {
|
||||
pub(crate) fn render_with_note_tags(
|
||||
&mut self,
|
||||
@@ -63,6 +92,55 @@ impl<'a> Renderer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_note_tag_class_names(&mut self, icon: &NoteTagIcon) -> Vec<String> {
|
||||
let mut icon_classes = vec!["note-tag-icon".to_string()];
|
||||
|
||||
if icon.styles.len() > 0 {
|
||||
let class = self.gen_class("icon");
|
||||
icon_classes.push(class.to_string());
|
||||
|
||||
self.global_styles
|
||||
// Select both `svg` and `img`: `svg`s may be replaced with `img` later in the import process:
|
||||
.insert(
|
||||
format!(".{} > svg, .{} > img", class, class),
|
||||
icon.styles.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
if icon.is_checkbox {
|
||||
icon_classes.push("-checkbox".into());
|
||||
}
|
||||
|
||||
if icon.size == IconSize::Large {
|
||||
icon_classes.push("-large".into());
|
||||
} else if icon.size == IconSize::Normal {
|
||||
icon_classes.push("-normal".into());
|
||||
}
|
||||
|
||||
icon_classes
|
||||
}
|
||||
|
||||
fn get_note_tag_attrs(
|
||||
&mut self,
|
||||
icon: &NoteTagIcon,
|
||||
status: ActionItemStatus,
|
||||
class_names: &[String],
|
||||
) -> AttributeSet {
|
||||
let mut attrs = AttributeSet::new();
|
||||
attrs.set("class", class_names.join(" "));
|
||||
|
||||
if icon.is_checkbox {
|
||||
attrs.set("role", "checkbox".into());
|
||||
attrs.set(
|
||||
"aria-checked",
|
||||
if status.completed() { "true" } else { "false" }.into(),
|
||||
);
|
||||
attrs.set("aria-disabled", "true".into());
|
||||
}
|
||||
|
||||
attrs
|
||||
}
|
||||
|
||||
pub(crate) fn render_note_tags(&mut self, note_tags: &[NoteTag]) -> Option<(String, StyleSet)> {
|
||||
let mut markup = String::new();
|
||||
let mut styles = StyleSet::new();
|
||||
@@ -82,24 +160,12 @@ impl<'a> Renderer<'a> {
|
||||
}
|
||||
|
||||
if def.shape() != NoteTagShape::NoIcon {
|
||||
let (icon, icon_style) =
|
||||
self.note_tag_icon(def.shape(), note_tag.item_status());
|
||||
let mut icon_classes = vec!["note-tag-icon".to_string()];
|
||||
let icon = self.note_tag_icon(def.shape(), note_tag.item_status());
|
||||
let icon_classes = self.build_note_tag_class_names(&icon);
|
||||
let attrs =
|
||||
self.get_note_tag_attrs(&icon, note_tag.item_status(), &icon_classes);
|
||||
|
||||
if icon_style.len() > 0 {
|
||||
let class = self.gen_class("icon");
|
||||
icon_classes.push(class.to_string());
|
||||
|
||||
self.global_styles
|
||||
// Select both `svg` and `img`: `svg`s may be replaced with `img` later in the import process:
|
||||
.insert(format!(".{} > svg, .{} > img", class, class), icon_style);
|
||||
}
|
||||
|
||||
markup.push_str(&format!(
|
||||
"<span class=\"{}\">{}</span>",
|
||||
icon_classes.join(" "),
|
||||
icon
|
||||
));
|
||||
markup.push_str(&format!("<span {}>{}</span>", attrs, icon.html,));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,291 +181,197 @@ impl<'a> Renderer<'a> {
|
||||
.any(|text| !text.note_tags().is_empty())
|
||||
}
|
||||
|
||||
fn note_tag_icon(
|
||||
&self,
|
||||
shape: NoteTagShape,
|
||||
status: ActionItemStatus,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
let mut style = StyleSet::new();
|
||||
|
||||
fn note_tag_icon(&self, shape: NoteTagShape, status: ActionItemStatus) -> NoteTagIcon {
|
||||
match shape {
|
||||
NoteTagShape::GreenCheckBox => self.icon_checkbox(status, style, COLOR_GREEN),
|
||||
NoteTagShape::YellowCheckBox => self.icon_checkbox(status, style, COLOR_YELLOW),
|
||||
NoteTagShape::BlueCheckBox => self.icon_checkbox(status, style, COLOR_BLUE),
|
||||
NoteTagShape::GreenStarCheckBox => {
|
||||
self.icon_checkbox_with_star(status, style, COLOR_GREEN)
|
||||
}
|
||||
NoteTagShape::YellowStarCheckBox => {
|
||||
self.icon_checkbox_with_star(status, style, COLOR_YELLOW)
|
||||
}
|
||||
NoteTagShape::BlueStarCheckBox => {
|
||||
self.icon_checkbox_with_star(status, style, COLOR_BLUE)
|
||||
}
|
||||
NoteTagShape::GreenCheckBox => self.icon_checkbox(status, COLOR_GREEN),
|
||||
NoteTagShape::YellowCheckBox => self.icon_checkbox(status, COLOR_YELLOW),
|
||||
NoteTagShape::BlueCheckBox => self.icon_checkbox(status, COLOR_BLUE),
|
||||
NoteTagShape::GreenStarCheckBox => self.icon_checkbox_with_star(status, COLOR_GREEN),
|
||||
NoteTagShape::YellowStarCheckBox => self.icon_checkbox_with_star(status, COLOR_YELLOW),
|
||||
NoteTagShape::BlueStarCheckBox => self.icon_checkbox_with_star(status, COLOR_BLUE),
|
||||
NoteTagShape::GreenExclamationCheckBox => {
|
||||
self.icon_checkbox_with_exclamation(status, style, COLOR_GREEN)
|
||||
self.icon_checkbox_with_exclamation(status, COLOR_GREEN)
|
||||
}
|
||||
NoteTagShape::YellowExclamationCheckBox => {
|
||||
self.icon_checkbox_with_exclamation(status, style, COLOR_YELLOW)
|
||||
self.icon_checkbox_with_exclamation(status, COLOR_YELLOW)
|
||||
}
|
||||
NoteTagShape::BlueExclamationCheckBox => {
|
||||
self.icon_checkbox_with_exclamation(status, style, COLOR_BLUE)
|
||||
self.icon_checkbox_with_exclamation(status, COLOR_BLUE)
|
||||
}
|
||||
NoteTagShape::GreenRightArrowCheckBox => {
|
||||
self.icon_checkbox_with_right_arrow(status, style, COLOR_GREEN)
|
||||
self.icon_checkbox_with_right_arrow(status, COLOR_GREEN)
|
||||
}
|
||||
NoteTagShape::YellowRightArrowCheckBox => {
|
||||
self.icon_checkbox_with_right_arrow(status, style, COLOR_YELLOW)
|
||||
self.icon_checkbox_with_right_arrow(status, COLOR_YELLOW)
|
||||
}
|
||||
NoteTagShape::BlueRightArrowCheckBox => {
|
||||
self.icon_checkbox_with_right_arrow(status, style, COLOR_BLUE)
|
||||
self.icon_checkbox_with_right_arrow(status, COLOR_BLUE)
|
||||
}
|
||||
NoteTagShape::YellowStar => {
|
||||
let mut style = StyleSet::new();
|
||||
style.set("fill", COLOR_YELLOW.to_string());
|
||||
|
||||
(
|
||||
Cow::from(ICON_STAR),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
)
|
||||
(Cow::from(ICON_STAR), IconSize::Normal, style).into()
|
||||
}
|
||||
|
||||
NoteTagShape::QuestionMark => (
|
||||
Cow::from(ICON_QUESTION_MARK),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::QuestionMark => (Cow::from(ICON_QUESTION_MARK), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::HighPriority => (
|
||||
Cow::from(ICON_ERROR),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::ContactInformation => (
|
||||
Cow::from(ICON_PHONE),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::HighPriority => (Cow::from(ICON_ERROR), IconSize::Normal).into(),
|
||||
NoteTagShape::ContactInformation => (Cow::from(ICON_PHONE), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::LightBulb => (
|
||||
Cow::from(ICON_LIGHT_BULB),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::LightBulb => (Cow::from(ICON_LIGHT_BULB), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::Home => (
|
||||
Cow::from(ICON_HOME),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::CommentBubble => (
|
||||
Cow::from(ICON_BUBBLE),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::Home => (Cow::from(ICON_HOME), IconSize::Normal).into(),
|
||||
NoteTagShape::CommentBubble => (Cow::from(ICON_BUBBLE), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::AwardRibbon => (
|
||||
Cow::from(ICON_AWARD),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::AwardRibbon => (Cow::from(ICON_AWARD), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::BlueCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_BLUE),
|
||||
NoteTagShape::BlueCheckBox1 => self.icon_checkbox_with_1(status, COLOR_BLUE),
|
||||
|
||||
NoteTagShape::BlueCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_BLUE),
|
||||
NoteTagShape::BlueCheckBox2 => self.icon_checkbox_with_2(status, COLOR_BLUE),
|
||||
|
||||
NoteTagShape::BlueCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_BLUE),
|
||||
NoteTagShape::BlueCheckBox3 => self.icon_checkbox_with_3(status, COLOR_BLUE),
|
||||
|
||||
NoteTagShape::BlueCheckMark => self.icon_checkmark(style, COLOR_BLUE),
|
||||
NoteTagShape::BlueCircle => self.icon_circle(style, COLOR_BLUE),
|
||||
NoteTagShape::BlueCheckMark => self.icon_checkmark(COLOR_BLUE),
|
||||
NoteTagShape::BlueCircle => self.icon_circle(COLOR_BLUE),
|
||||
|
||||
NoteTagShape::GreenCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_GREEN),
|
||||
NoteTagShape::GreenCheckBox1 => self.icon_checkbox_with_1(status, COLOR_GREEN),
|
||||
|
||||
NoteTagShape::GreenCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_GREEN),
|
||||
NoteTagShape::GreenCheckBox2 => self.icon_checkbox_with_2(status, COLOR_GREEN),
|
||||
|
||||
NoteTagShape::GreenCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_GREEN),
|
||||
NoteTagShape::GreenCheckBox3 => self.icon_checkbox_with_3(status, COLOR_GREEN),
|
||||
|
||||
NoteTagShape::GreenCheckMark => self.icon_checkmark(style, COLOR_GREEN),
|
||||
NoteTagShape::GreenCircle => self.icon_circle(style, COLOR_GREEN),
|
||||
NoteTagShape::GreenCheckMark => self.icon_checkmark(COLOR_GREEN),
|
||||
NoteTagShape::GreenCircle => self.icon_circle(COLOR_GREEN),
|
||||
|
||||
NoteTagShape::YellowCheckBox1 => self.icon_checkbox_with_1(status, style, COLOR_YELLOW),
|
||||
NoteTagShape::YellowCheckBox1 => self.icon_checkbox_with_1(status, COLOR_YELLOW),
|
||||
|
||||
NoteTagShape::YellowCheckBox2 => self.icon_checkbox_with_2(status, style, COLOR_YELLOW),
|
||||
NoteTagShape::YellowCheckBox2 => self.icon_checkbox_with_2(status, COLOR_YELLOW),
|
||||
|
||||
NoteTagShape::YellowCheckBox3 => self.icon_checkbox_with_3(status, style, COLOR_YELLOW),
|
||||
NoteTagShape::YellowCheckBox3 => self.icon_checkbox_with_3(status, COLOR_YELLOW),
|
||||
|
||||
NoteTagShape::YellowCheckMark => self.icon_checkmark(style, COLOR_YELLOW),
|
||||
NoteTagShape::YellowCircle => self.icon_circle(style, COLOR_YELLOW),
|
||||
NoteTagShape::YellowCheckMark => self.icon_checkmark(COLOR_YELLOW),
|
||||
NoteTagShape::YellowCircle => self.icon_circle(COLOR_YELLOW),
|
||||
|
||||
NoteTagShape::BluePersonCheckBox => {
|
||||
self.icon_checkbox_with_person(status, style, COLOR_BLUE)
|
||||
}
|
||||
NoteTagShape::BluePersonCheckBox => self.icon_checkbox_with_person(status, COLOR_BLUE),
|
||||
NoteTagShape::YellowPersonCheckBox => {
|
||||
self.icon_checkbox_with_person(status, style, COLOR_YELLOW)
|
||||
self.icon_checkbox_with_person(status, COLOR_YELLOW)
|
||||
}
|
||||
NoteTagShape::GreenPersonCheckBox => {
|
||||
self.icon_checkbox_with_person(status, style, COLOR_GREEN)
|
||||
self.icon_checkbox_with_person(status, COLOR_GREEN)
|
||||
}
|
||||
NoteTagShape::BlueFlagCheckBox => {
|
||||
self.icon_checkbox_with_flag(status, style, COLOR_BLUE)
|
||||
}
|
||||
NoteTagShape::RedFlagCheckBox => self.icon_checkbox_with_flag(status, style, COLOR_RED),
|
||||
NoteTagShape::GreenFlagCheckBox => {
|
||||
self.icon_checkbox_with_flag(status, style, COLOR_GREEN)
|
||||
}
|
||||
NoteTagShape::RedSquare => self.icon_square(style, COLOR_RED),
|
||||
NoteTagShape::YellowSquare => self.icon_square(style, COLOR_YELLOW),
|
||||
NoteTagShape::BlueSquare => self.icon_square(style, COLOR_BLUE),
|
||||
NoteTagShape::GreenSquare => self.icon_square(style, COLOR_GREEN),
|
||||
NoteTagShape::OrangeSquare => self.icon_square(style, COLOR_ORANGE),
|
||||
NoteTagShape::PinkSquare => self.icon_square(style, COLOR_PINK),
|
||||
NoteTagShape::EMailMessage => (
|
||||
Cow::from(ICON_EMAIL),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::BlueFlagCheckBox => self.icon_checkbox_with_flag(status, COLOR_BLUE),
|
||||
NoteTagShape::RedFlagCheckBox => self.icon_checkbox_with_flag(status, COLOR_RED),
|
||||
NoteTagShape::GreenFlagCheckBox => self.icon_checkbox_with_flag(status, COLOR_GREEN),
|
||||
NoteTagShape::RedSquare => self.icon_square(COLOR_RED),
|
||||
NoteTagShape::YellowSquare => self.icon_square(COLOR_YELLOW),
|
||||
NoteTagShape::BlueSquare => self.icon_square(COLOR_BLUE),
|
||||
NoteTagShape::GreenSquare => self.icon_square(COLOR_GREEN),
|
||||
NoteTagShape::OrangeSquare => self.icon_square(COLOR_ORANGE),
|
||||
NoteTagShape::PinkSquare => self.icon_square(COLOR_PINK),
|
||||
NoteTagShape::EMailMessage => (Cow::from(ICON_EMAIL), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::Contact => (
|
||||
Cow::from(ICON_CONTACT),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::Contact => (Cow::from(ICON_CONTACT), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::MusicalNote => (
|
||||
Cow::from(ICON_MUSIC),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::MovieClip => (
|
||||
Cow::from(ICON_FILM),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::MusicalNote => (Cow::from(ICON_MUSIC), IconSize::Normal).into(),
|
||||
NoteTagShape::MovieClip => (Cow::from(ICON_FILM), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::HyperlinkGlobe => (
|
||||
Cow::from(ICON_LINK),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::HyperlinkGlobe => (Cow::from(ICON_LINK), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::Padlock => (
|
||||
Cow::from(ICON_LOCK),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::OpenBook => (
|
||||
Cow::from(ICON_BOOK),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::Padlock => (Cow::from(ICON_LOCK), IconSize::Normal).into(),
|
||||
NoteTagShape::OpenBook => (Cow::from(ICON_BOOK), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::BlankPaperWithLines => (
|
||||
Cow::from(ICON_PAPER),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::BlankPaperWithLines => (Cow::from(ICON_PAPER), IconSize::Normal).into(),
|
||||
|
||||
NoteTagShape::Pen => (
|
||||
Cow::from(ICON_PEN),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
),
|
||||
NoteTagShape::Pen => (Cow::from(ICON_PEN), IconSize::Normal).into(),
|
||||
|
||||
shape => self.icon_fallback(style, shape),
|
||||
shape => self.icon_fallback(shape),
|
||||
}
|
||||
}
|
||||
|
||||
fn icon_fallback(&self, style: StyleSet, shape: NoteTagShape) -> (Cow<'static, str>, StyleSet) {
|
||||
fn icon_fallback(&self, shape: NoteTagShape) -> NoteTagIcon {
|
||||
log_warn!("Unsupported icon type: {:?}", shape);
|
||||
|
||||
(
|
||||
Cow::from(ICON_QUESTION_MARK),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
)
|
||||
(Cow::from(ICON_QUESTION_MARK), IconSize::Normal).into()
|
||||
}
|
||||
|
||||
fn icon_checkbox(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
mut style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
style.set("fill", color.to_string());
|
||||
fn icon_checkbox(&self, status: ActionItemStatus, color: &'static str) -> NoteTagIcon {
|
||||
let mut styles = StyleSet::new();
|
||||
styles.set("fill", color.to_string());
|
||||
|
||||
if status.completed() {
|
||||
(
|
||||
Cow::from(ICON_CHECKBOX_COMPLETE),
|
||||
self.icon_style(IconSize::Large, style),
|
||||
)
|
||||
let html = if status.completed() {
|
||||
Cow::from(ICON_CHECKBOX_COMPLETE)
|
||||
} else {
|
||||
(
|
||||
Cow::from(ICON_CHECKBOX_EMPTY),
|
||||
self.icon_style(IconSize::Large, style),
|
||||
)
|
||||
Cow::from(ICON_CHECKBOX_EMPTY)
|
||||
};
|
||||
|
||||
NoteTagIcon {
|
||||
html,
|
||||
size: IconSize::Large,
|
||||
styles,
|
||||
is_checkbox: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_person(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, ICON_PERSON)
|
||||
) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, ICON_PERSON)
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_right_arrow(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, ICON_ARROW_RIGHT)
|
||||
) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, ICON_ARROW_RIGHT)
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_star(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, ICON_STAR)
|
||||
) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, ICON_STAR)
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_flag(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, ICON_FLAG)
|
||||
) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, ICON_FLAG)
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_1(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, "<span class=\"content\">1</span>")
|
||||
fn icon_checkbox_with_1(&self, status: ActionItemStatus, color: &'static str) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, "<span class=\"content\">1</span>")
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_2(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, "<span class=\"content\">2</span>")
|
||||
fn icon_checkbox_with_2(&self, status: ActionItemStatus, color: &'static str) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, "<span class=\"content\">2</span>")
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_3(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, "<span class=\"content\">3</span>")
|
||||
fn icon_checkbox_with_3(&self, status: ActionItemStatus, color: &'static str) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, "<span class=\"content\">3</span>")
|
||||
}
|
||||
|
||||
fn icon_checkbox_with_exclamation(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
self.icon_checkbox_with(status, style, color, "<span class=\"content\">!</span>")
|
||||
) -> NoteTagIcon {
|
||||
self.icon_checkbox_with(status, color, "<span class=\"content\">!</span>")
|
||||
}
|
||||
|
||||
fn icon_checkbox_with(
|
||||
&self,
|
||||
status: ActionItemStatus,
|
||||
mut style: StyleSet,
|
||||
color: &'static str,
|
||||
secondary_icon: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
) -> NoteTagIcon {
|
||||
let mut style = StyleSet::new();
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
let mut content = String::new();
|
||||
@@ -414,75 +386,37 @@ impl<'a> Renderer<'a> {
|
||||
secondary_icon
|
||||
));
|
||||
|
||||
(Cow::from(content), self.icon_style(IconSize::Large, style))
|
||||
}
|
||||
|
||||
fn icon_checkmark(
|
||||
&self,
|
||||
mut style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
(
|
||||
Cow::from(ICON_CHECK_MARK),
|
||||
self.icon_style(IconSize::Large, style),
|
||||
)
|
||||
}
|
||||
|
||||
fn icon_circle(
|
||||
&self,
|
||||
mut style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
(
|
||||
Cow::from(ICON_CIRCLE),
|
||||
self.icon_style(IconSize::Normal, style),
|
||||
)
|
||||
}
|
||||
|
||||
fn icon_square(
|
||||
&self,
|
||||
mut style: StyleSet,
|
||||
color: &'static str,
|
||||
) -> (Cow<'static, str>, StyleSet) {
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
(
|
||||
Cow::from(ICON_SQUARE),
|
||||
self.icon_style(IconSize::Large, style),
|
||||
)
|
||||
}
|
||||
|
||||
fn icon_style(&self, size: IconSize, mut style: StyleSet) -> StyleSet {
|
||||
match size {
|
||||
IconSize::Normal => {
|
||||
style.set("height", "16px".to_string());
|
||||
style.set("width", "16px".to_string());
|
||||
}
|
||||
IconSize::Large => {
|
||||
style.set("height", "20px".to_string());
|
||||
style.set("width", "20px".to_string());
|
||||
}
|
||||
NoteTagIcon {
|
||||
html: Cow::from(content),
|
||||
size: IconSize::Large,
|
||||
styles: style,
|
||||
is_checkbox: true,
|
||||
}
|
||||
}
|
||||
|
||||
match (self.in_list, size) {
|
||||
(false, IconSize::Normal) => {
|
||||
style.set("left", "-23px".to_string());
|
||||
}
|
||||
(false, IconSize::Large) => {
|
||||
style.set("left", "-25px".to_string());
|
||||
}
|
||||
(true, IconSize::Normal) => {
|
||||
style.set("left", "-38px".to_string());
|
||||
}
|
||||
(true, IconSize::Large) => {
|
||||
style.set("left", "-40px".to_string());
|
||||
}
|
||||
};
|
||||
fn icon_checkmark(&self, color: &'static str) -> NoteTagIcon {
|
||||
let mut style = StyleSet::new();
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
style
|
||||
NoteTagIcon {
|
||||
is_checkbox: true,
|
||||
html: Cow::from(ICON_CHECK_MARK),
|
||||
size: IconSize::Large,
|
||||
styles: style,
|
||||
}
|
||||
}
|
||||
|
||||
fn icon_circle(&self, color: &'static str) -> NoteTagIcon {
|
||||
let mut style = StyleSet::new();
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
(Cow::from(ICON_CIRCLE), IconSize::Normal, style).into()
|
||||
}
|
||||
|
||||
fn icon_square(&self, color: &'static str) -> NoteTagIcon {
|
||||
let mut style = StyleSet::new();
|
||||
style.set("fill", color.to_string());
|
||||
|
||||
(Cow::from(ICON_SQUARE), IconSize::Large, style).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl<'a> Renderer<'a> {
|
||||
let is_list = self.is_list(element);
|
||||
|
||||
let mut attrs = AttributeSet::new();
|
||||
attrs.set("class", "outline-element".to_string());
|
||||
attrs.set("class", "outline-element".into());
|
||||
|
||||
let mut styles = StyleSet::new();
|
||||
styles.set("margin-left", px(indent_width as f32));
|
||||
|
||||
@@ -100,7 +100,7 @@ impl<'a> Renderer<'a> {
|
||||
fn table_cell_level(&self, elements: &[OutlineElement]) -> u8 {
|
||||
let needs_nesting = elements
|
||||
.iter()
|
||||
.any(|element| self.is_list(element) || self.has_note_tag(element));
|
||||
.any(|element| self.is_list(element));
|
||||
|
||||
if needs_nesting { 2 } else { 1 }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ name }}</title>
|
||||
<style>
|
||||
/*** Start default CSS ***/
|
||||
* { margin: 0; padding: 0; font-weight: normal; }
|
||||
table, tr, td { border-color: #A3A3A3; }
|
||||
ul, ol { padding: 0; }
|
||||
@@ -12,11 +13,31 @@
|
||||
.container-outline { font-family: Calibri, sans-serif; font-size: 6pt; }
|
||||
.ink-text, .ink-space { display: inline-block; position: relative; vertical-align: bottom; }
|
||||
.ink-text { top: 0; left: 0; }
|
||||
.note-tag-icon { position: relative; }
|
||||
|
||||
/* Icons */
|
||||
.note-tag-icon {
|
||||
position: relative;
|
||||
--note-tag-left: -23px;
|
||||
--note-tag-width: 16px;
|
||||
--note-tag-height: 16px;
|
||||
}
|
||||
.note-tag-icon.-large {
|
||||
--note-tag-left: -25px;
|
||||
--note-tag-width: 20px;
|
||||
--note-tag-height: 20px;
|
||||
}
|
||||
.note-tag-icon > img, .note-tag-icon > svg {
|
||||
width: var(--note-tag-width);
|
||||
height: var(--note-tag-height);
|
||||
left: var(--note-tag-left);
|
||||
}
|
||||
|
||||
.tagged-list { list-style: none; padding-left: 0; }
|
||||
{# Select both SVGs and IMGs: Joplin post-processes the converter's output, converting SVGs to IMGs. #}
|
||||
.note-tag-icon > svg, .note-tag-icon > img { position: absolute; }
|
||||
.icon-secondary > svg, .icon-secondary > img { position: absolute; fill: black; filter: drop-shadow(0 0 2px white); height: 12px; top: -1px; }
|
||||
.icon-secondary > .content { position: absolute; color: black; filter: drop-shadow(0 0 2px white); font-size: 10px; color: black; top: -1px; user-select: none; }
|
||||
/*** End default CSS ***/
|
||||
|
||||
{% for entry in global_styles -%}
|
||||
{{ entry.0 }} { {{ entry.1 }} }
|
||||
|
||||
@@ -9,6 +9,7 @@ pub(crate) fn px(inches: f32) -> String {
|
||||
format!("{}px", (inches * 48.0).round())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct AttributeSet(HashMap<&'static str, String>);
|
||||
|
||||
impl AttributeSet {
|
||||
@@ -21,6 +22,12 @@ impl AttributeSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> From<[(&'static str, String); N]> for AttributeSet {
|
||||
fn from(data: [(&'static str, String); N]) -> Self {
|
||||
Self(data.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AttributeSet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
|
||||
@@ -3,15 +3,20 @@ export default function taskListItems (turndownService) {
|
||||
filter: function (node) {
|
||||
const parent = node.parentNode;
|
||||
const grandparent = parent.parentNode;
|
||||
return node.type === 'checkbox' && (
|
||||
const grandparentIsListItem = !!grandparent && grandparent.nodeName === 'LI';
|
||||
return (node.type === 'checkbox' || node.role === 'checkbox') && (
|
||||
parent.nodeName === 'LI'
|
||||
// Handles the case where the label contains the checkbox. For example,
|
||||
// <label><input ...> ...label text...</label>
|
||||
|| (parent.nodeName === 'LABEL' && grandparent && grandparent.nodeName === 'LI')
|
||||
|| (parent.nodeName === 'LABEL' && grandparentIsListItem)
|
||||
// Handles the case where the input is contained within a <span>
|
||||
// <li><span><input ...></span></li>
|
||||
|| (parent.nodeName === 'SPAN' && grandparentIsListItem)
|
||||
)
|
||||
},
|
||||
replacement: function (content, node) {
|
||||
return (node.checked ? '[x]' : '[ ]') + ' '
|
||||
const checked = node.nodeName === 'INPUT' ? node.checked : node.getAttribute('aria-checked') === 'true';
|
||||
return (checked ? '[x]' : '[ ]') + ' '
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -864,8 +864,12 @@ function joplinCheckboxInfo(liNode) {
|
||||
};
|
||||
}
|
||||
|
||||
// Should handle both <ul class='joplin-checklist'><li>...</li></ul>
|
||||
// and <ul><li class='joplin-checklist-item'>...</li></ul>. The second is present
|
||||
// in certain types of imported notes.
|
||||
const parentChecklist = findParent(liNode, 'class', 'joplin-checklist');
|
||||
if (parentChecklist) {
|
||||
const currentChecklist = liNode.classList.contains('joplin-checklist-item');
|
||||
if (parentChecklist || currentChecklist) {
|
||||
return {
|
||||
checked: !!liNode.classList && liNode.classList.contains('checked'),
|
||||
renderingType: 2,
|
||||
|
||||
Reference in New Issue
Block a user