mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-24 18:36:44 -06:00
Merge branch 'rb-549' into batch/t6
This commit is contained in:
@@ -1552,6 +1552,10 @@ impl<'d> Exporter<'d> {
|
||||
.map(|(st, id)| {
|
||||
let mut ef: Fields = vec![("styleID", u(id))];
|
||||
style_fields(st, &mut ef);
|
||||
// An empty link clears the text's own (a missing one would inherit it).
|
||||
if st.link.is_none() && td.style.link.is_some() {
|
||||
ef.push(("hyperlink", o(vec![("url", s(""))])));
|
||||
}
|
||||
if let Some(p) = st.fills.as_deref().or(td.style.fills.as_ref().map(|_| fills)) {
|
||||
ef.push(("fillPaints", self.paints(p, true, &Bound::default())));
|
||||
}
|
||||
|
||||
@@ -1762,7 +1762,8 @@ fn text_style(v: &View, size: Option<f64>) -> Obj {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(u) = v.get("hyperlink").and_then(|h| h.get("url")).and_then(Kv::str).filter(|u| !u.is_empty()) {
|
||||
// An empty URL is kept: on an override entry it clears the text's own link.
|
||||
if let Some(u) = v.get("hyperlink").and_then(|h| h.get("url")).and_then(Kv::str) {
|
||||
s.insert("hyperlink".into(), json!({"type": "URL", "url": u}));
|
||||
}
|
||||
s
|
||||
|
||||
@@ -130,6 +130,8 @@ fn type_style(cx: &mut Ctx, s: &Value, base: &TextStyle) -> TextStyle {
|
||||
// and clipping a URL changed it into a different, working-looking one without a word
|
||||
// (#459). The FIG importer already keeps it whole.
|
||||
(Some("URL") | None, Some(url)) if !url.is_empty() => t.link = Some(url.to_string()),
|
||||
// An empty URL clears the link the base style has.
|
||||
(Some("URL") | None, Some(_)) => t.link = None,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//! A hyperlink cleared on part of a text layer stays cleared through FIG export and import.
|
||||
|
||||
use figcraft_doc::{Document, NodeKind, TextData};
|
||||
use figcraft_format::fig;
|
||||
|
||||
fn links(doc: &Document, name: &str) -> Vec<Option<String>> {
|
||||
let Some(NodeKind::Text(text)) = doc.nodes().find(|n| n.name == name).map(|n| &n.kind) else { return Vec::new() };
|
||||
text.spans().into_iter().flat_map(|(start, end, style)| std::iter::repeat_n(style.link.clone(), end - start)).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cleared_range_hyperlink_round_trip() {
|
||||
let mut document = Document::new("File");
|
||||
let page = document.first_page().unwrap();
|
||||
let url = "https://example.com/".to_string();
|
||||
|
||||
let mut text = TextData { characters: "AB".into(), ..Default::default() };
|
||||
text.style.link = Some(url.clone());
|
||||
text.restyle(1, 2, |style| style.link = None);
|
||||
document.create(page, NodeKind::Text(text), "Cleared", 0.0, 0.0, 100.0, 30.0).unwrap();
|
||||
|
||||
let mut control = TextData { characters: "AB".into(), ..Default::default() };
|
||||
control.restyle(1, 2, |style| style.link = Some(url.clone()));
|
||||
document.create(page, NodeKind::Text(control), "Explicit", 0.0, 40.0, 100.0, 30.0).unwrap();
|
||||
|
||||
let expected = vec![Some(url.clone()), None];
|
||||
assert_eq!(links(&document, "Cleared"), expected);
|
||||
let native_bytes = figcraft_format::save_bytes(&document, None).unwrap();
|
||||
let native = figcraft_format::load_bytes(&native_bytes).unwrap().0;
|
||||
assert_eq!(links(&native, "Cleared"), expected);
|
||||
|
||||
let (bytes, export_warnings) = fig::export(&document, None).unwrap();
|
||||
let (loaded, import_warnings) = fig::import(&bytes, "File").unwrap();
|
||||
assert!(export_warnings.is_empty(), "{export_warnings:?}");
|
||||
assert!(import_warnings.is_empty(), "{import_warnings:?}");
|
||||
assert_eq!(links(&loaded, "Explicit"), vec![None, Some(url)]);
|
||||
assert_eq!(links(&loaded, "Cleared"), expected);
|
||||
}
|
||||
Reference in New Issue
Block a user