Skip to content

Commit

Permalink
Desktop: Fixes #11600: OneNote imported notes have broken links when …
Browse files Browse the repository at this point in the history
…there are chineses characters on link (#11602)
  • Loading branch information
pedr authored Jan 9, 2025
1 parent 8c24928 commit ab286b6
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 13 deletions.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,13 @@ describe('InteropService_Importer_OneNote', () => {
}
BaseModel.setIdGenerator(originalIdGenerator);
});

skipIfNotCI('should group link parts even if they have different css styles', async () => {
const notes = await importNote(`${supportDir}/onenote/remove_hyperlink_on_title.zip`);

const noteToTest = notes.find(n => n.title === 'Tips from a Pro Using Trees for Dramatic Landscape Photography');

expect(noteToTest).toBeTruthy();
expect(noteToTest.body.includes('<a href="onenote:https://d.docs.live.net/c8d3bbab7f1acf3a/Documents/Photography/风景.one#Tips%20from%20a%20Pro%20Using%20Trees%20for%20Dramatic%20Landscape%20Photography&section-id={262ADDFB-A4DC-4453-A239-0024D6769962}&page-id={88D803A5-4F43-48D4-9B16-4C024F5787DC}&end" style="">Tips from a Pro: Using Trees for Dramatic Landscape Photography</a>')).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,149 @@ exports[`InteropService_Importer_OneNote should import a simple OneNote notebook
</html>"
`;
exports[`InteropService_Importer_OneNote should remove hyperlink from title: Quick Notes 1`] = `
"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Quick Notes</title>
<style>
html, body { margin: 0; padding: 0; }
body {
display: flex;
}
nav {
height: 100vh;
min-width: 200px;
max-width: 300px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
border-right: 1px solid rgb(235, 235, 235);
}
nav ul {
padding: 0;
margin: 0;
overflow-y: auto;
height: 100%;
}
nav li {
padding: 10px 20px;
border-bottom: 1px solid rgb(235, 235, 235);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
nav li.active {
background-color: rgb(233, 233, 233);
}
nav a {
color: black;
text-decoration: none;
}
.content {
flex: 1;
}
</style>
</head>
<body>
<nav>
<ul>
<li class="l1"><a href=":/5" target="content" title="风景 (Web view)">风景 (Web view)</a></li>
<li class="l1"><a href=":/4" target="content" title="wikipedia link">wikipedia link</a></li>
<li class="l1"><a href=":/6" target="content" title="风景">风景</a></li>
<li class="l1"><a href=":/3" target="content" title="Tips from a Pro: Using Trees for Dramatic Landscape Photography">Tips from a Pro: Using Trees for Dramatic Landscape Photography</a></li>
</ul>
</nav>
<iframe src="" frameborder="0" name="content" class="content"></iframe>
<style>
.l2 { padding: 10px 20px 10px 40px }
.l3 { padding: 10px 20px 10px 60px }
.l4 { padding: 10px 20px 10px 80px }
.l5 { padding: 10px 20px 10px 100px }
</style>
<script>
document.addEventListener('click', function (event) {
// If the clicked element doesn't have the right selector, bail
if (!event.target.matches('nav a')) return;
for (const child of event.target.parentElement.parentElement.children) {
child.classList.remove('active');
}
event.target.parentElement.classList.add('active');
}, false);
window.addEventListener('message', (event) => {
const activeTarget = event.data;
for (const link of document.querySelectorAll('nav ul li a')) {
if (link.href === activeTarget) {
link.parentElement.classList.add('active');
}
}
});
if (window.parent !== null) {
window.parent.postMessage(window.location.href, '*');
}
</script>
</body>
</html>"
`;
exports[`InteropService_Importer_OneNote should remove hyperlink from title: Tips from a Pro Using Trees for Dramatic Landscape Photography 1`] = `
"<!DOCTYPE html>
<html lang="en">
<head>
<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 { position: absolute; }
.icon-secondary > svg { 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; }
</style>
</head>
<body>
<div class="title" style="left: 48px; position: absolute; top: 24px;"><div class="container-outline" style="width: 624px;"><div class="outline-element" style="margin-left: 0px;"><span style="font-family: Calibri Light; font-size: 20pt; line-height: 32px;">&nbsp;</span></div>
</div><div class="container-outline" style="width: 624px;"><div class="outline-element" style="margin-left: 0px;"><span style="color: rgb(118,118,118); font-family: Calibri; font-size: 10pt; line-height: 16px;">Saturday, February 11, 2023</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;">12:56 AM</span></div>
</div></div><div class="container-outline" style="left: 48px; position: absolute; top: 115px; width: 624px;"><div class="outline-element" style="margin-left: 0px;"><p style="font-family: Calibri; font-size: 14pt; line-height: 22px;"><a href="onenote:https://d.docs.live.net/c8d3bbab7f1acf3a/Documents/Photography/风景.one#Tips%20from%20a%20Pro%20Using%20Trees%20for%20Dramatic%20Landscape%20Photography&section-id={262ADDFB-A4DC-4453-A239-0024D6769962}&page-id={88D803A5-4F43-48D4-9B16-4C024F5787DC}&end" style="">Tips from a Pro: Using Trees for Dramatic Landscape Photography</a></p></div>
</div>
<script>
if (window.parent !== null) {
window.parent.postMessage(window.location.href, '*');
}
</script>
</body>
</html>"
`;
exports[`InteropService_Importer_OneNote should remove hyperlink from title: wikipedia link 1`] = `
"<!DOCTYPE html>
<html lang="en">
Expand Down
49 changes: 36 additions & 13 deletions packages/onenote-converter/src/page/rich_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,25 @@ impl<'a> Renderer<'a> {
}

let mut in_hyperlink = false;
let mut is_href_finished = true;

let content = parts
.into_iter()
.rev()
.zip(styles.iter())
.map(|(text, style)| {
if style.hyperlink() {
let text = self.render_hyperlink(text, style, in_hyperlink);
in_hyperlink = true;

text
let result = self.render_hyperlink(text.clone(), style, in_hyperlink, is_href_finished);
if result.is_ok() {
in_hyperlink = true;
is_href_finished = result.as_ref().unwrap().1;
Ok(result.unwrap().0)
} else {
Ok(text)
}
} else {
in_hyperlink = false;
is_href_finished = true;

let style = self.parse_style(style);

Expand All @@ -128,31 +134,48 @@ impl<'a> Renderer<'a> {
Ok(fix_newlines(&content))
}

/// The hyperlink is delimited by the HYPERLINK_MARKER until the closing double quote
/// In some cases the hyperlink is broken in more than one style (e.g.: when there are
/// chinese characters on the url path), so we must keep track of the href status
/// https://github.com/laurent22/joplin/issues/11600
fn render_hyperlink(
&self,
text: String,
style: &ParagraphStyling,
in_hyperlink: bool,
) -> Result<String> {
is_href_finished: bool,
) -> Result<(String, bool)> {
const HYPERLINK_MARKER: &str = "\u{fddf}HYPERLINK \"";

let style = self.parse_style(style);

if text.starts_with(HYPERLINK_MARKER) {
let url = text
.strip_prefix(HYPERLINK_MARKER)
.wrap_err("Hyperlink has no start marker")?
.strip_suffix('"')
.wrap_err("Hyperlink has no end marker")?;
.wrap_err("Hyperlink has no start marker")?;

Ok(format!("<a href=\"{}\" style=\"{}\">", url, style))
} else if in_hyperlink {
Ok(text + "</a>")
let url_2 = url.strip_suffix('"');

if url_2.is_some() {
return Ok((format!("<a href=\"{}\" style=\"{}\">", url_2.unwrap(), style), true));
} else {
// If we didn't find the double quotes means that href still has content in following styles
Ok((format!("<a href=\"{}", url), false))
}
} else if in_hyperlink && is_href_finished {
Ok((text + "</a>", true))
} else if in_hyperlink && !is_href_finished {
let url = text.strip_suffix('"');
if url.is_some() {
return Ok((format!("{}\" style=\"{}\">", url.unwrap(), style), true));
} else {
Ok((text, false))
}
} else {
Ok(format!(
Ok((format!(
"<a href=\"{}\" style=\"{}\">{}</a>",
text, style, text
))
), true))
}
}

Expand Down

0 comments on commit ab286b6

Please sign in to comment.