mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-01 22:26:49 -06:00
#2108: preserve full filenames at the browser import boundary
Pass the original filename to file.openBytes so the engine removes one native extension. Cover Open and Drop, repeated suffixes, Unicode, bare and missing extensions, and IDML through the import inbox. Keep the full filename in import warnings. Co-Authored-By: OpenAI Codex <noreply@openai.com>
This commit is contained in:
+1
-1
@@ -388,7 +388,7 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-10-31** · A `.designcraft` file opened from bytes (`file.openBytes` with its file name, as a browser or host passes it) is titled without the extension, as an IDML file opened that way is. Saving it in the browser downloaded `Brochure.designcraft.designcraft`, and the File Name variable showed the doubled name. No readiness percentage change.
|
||||
- **2026-10-31** · A `.designcraft` file opened from bytes (`file.openBytes` with its file name, as a browser or host passes it) is titled without the extension, as an IDML file opened that way is. Saving it in the browser downloaded `Brochure.designcraft.designcraft`, and the File Name variable showed the doubled name. Browser Open and Drop pass the full file name, so only the engine removes the extension and a repeated suffix is kept in the title. No readiness percentage change.
|
||||
- **2026-10-30** · Import warnings about a story have a Show button: it closes the warnings (the status line keeps them) and selects the story's first frame, fitted in the window. `file.open` returns `warningItems`, the frame each IDML or InDesign warning is about (or null), matching the converter's INDD story numbers (`story 30892`, written to IDML as `u78ac`) and IDML `Self` names to the imported stories. No readiness percentage change.
|
||||
- **2026-10-30** · Parent pages: a running-header variable shows its name in angle brackets on the parent itself (it was blank), as InDesign shows it; on the document pages, and in text with no page, it shows its text as before. No readiness percentage change.
|
||||
- **2026-10-30** · Without facing pages, a page of a multi-page spread shows the parent page in its place, as in InDesign: the second page of a two-page spread shows the parent's second page. Every single-sided page showed the parent's first page, so an InDesign book set up without facing pages but laid out in two-page spreads repeated the left parent page's items (a black heading bar) on its right pages and lost the right parent page's. No readiness percentage change.
|
||||
|
||||
@@ -161,8 +161,7 @@ impl DesignApp {
|
||||
} else if place {
|
||||
self.open_file("file.place", json!({"name": file.name, "base64": b64}))
|
||||
} else {
|
||||
let title = file.name.rsplit_once('.').map_or(file.name.as_str(), |(stem, _)| stem);
|
||||
self.open_file("file.openBytes", json!({"name": title, "base64": b64}))
|
||||
self.open_file("file.openBytes", json!({"name": file.name, "base64": b64}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +376,7 @@ mod import_warning_tests {
|
||||
let request = app.import_request("open");
|
||||
app.services.inbox.as_ref().unwrap().lock().unwrap().push(ImportedFile { request, name: "partial.idml".into(), bytes: idml(true) });
|
||||
app.drain_inbox();
|
||||
assert_partial_import_warning(&mut app, "partial");
|
||||
assert_partial_import_warning(&mut app, "partial.idml");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -424,6 +423,34 @@ pub(crate) mod browser_import_tests {
|
||||
app.services.inbox.as_ref().unwrap().lock().unwrap().push(ImportedFile { request, name: name.into(), bytes });
|
||||
app.drain_inbox();
|
||||
}
|
||||
|
||||
/// A document chosen or dropped in the browser is titled by its file name less one extension,
|
||||
/// as on the desktop: the extension comes off once, in the engine.
|
||||
#[test]
|
||||
fn browser_opens_title_a_document_by_its_name_without_one_extension() {
|
||||
let mut app = app();
|
||||
let native = designcraft_engine::cmd::base64_decode(app.run("file.serialize", json!({})).unwrap()["base64"].as_str().unwrap());
|
||||
for purpose in ["open", "drop"] {
|
||||
for (name, title) in [
|
||||
("Brochure.designcraft", "Brochure"),
|
||||
("Brochure.designcraft.designcraft", "Brochure.designcraft"),
|
||||
("Brochure.v2.designcraft", "Brochure.v2"),
|
||||
("日本.DESIGNCRAFT", "日本"),
|
||||
(".designcraft", ".designcraft"),
|
||||
("Brochure", "Brochure"),
|
||||
] {
|
||||
let request = app.import_request(purpose);
|
||||
deliver(&mut app, request, name, native.clone());
|
||||
assert_eq!(app.session.doc().unwrap().doc.title, title, "{purpose}: {name}");
|
||||
}
|
||||
}
|
||||
let idml = designcraft_idml::export_idml(&app.session.doc().unwrap().doc);
|
||||
for purpose in ["open", "drop"] {
|
||||
let request = app.import_request(purpose);
|
||||
deliver(&mut app, request, "Brochure.idml", idml.clone());
|
||||
assert_eq!(app.session.doc().unwrap().doc.title, "Brochure", "{purpose}: IDML");
|
||||
}
|
||||
}
|
||||
fn image() -> Vec<u8> {
|
||||
br##"<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect width="10" height="10" fill="#ff0000"/></svg>"##.to_vec()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user