mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-02 06:36:51 -06:00
file.openBytes: title a .designcraft file without its extension
file.openBytes used the name it was given as the document's title as is. The IDML path strips .idml/.indd/.indt, but a native document opened as "Brochure.designcraft" kept the extension, and everything that adds it back doubled it: Save in the browser downloaded Brochure.designcraft.designcraft, Save As suggested that name, and the File Name variable showed it. The app's own drop and open paths strip the extension before calling, so only hosts and scripts that pass a file name hit it. The title now drops one trailing .designcraft (any case). Other names are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ea214dd44d
commit
f0c86e77e0
@@ -388,6 +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-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.
|
||||
|
||||
@@ -27,6 +27,16 @@ pub fn with_document_extension(path: &str) -> String {
|
||||
format!("{path}.{}", designcraft_format::EXTENSION)
|
||||
}
|
||||
|
||||
/// `name` without a trailing `.designcraft` (any case): the title of a document opened from bytes
|
||||
/// under its file name. Save, Save As and the File Name variable add the extension back, so a title
|
||||
/// that kept it would name the file `Brochure.designcraft.designcraft`. A bare `.designcraft` stays.
|
||||
pub(super) fn without_native_extension(name: &str) -> &str {
|
||||
match name.rsplit_once('.') {
|
||||
Some((stem, ext)) if !stem.is_empty() && ext.eq_ignore_ascii_case(designcraft_format::EXTENSION) => stem,
|
||||
_ => name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `bytes` are a document `file.open` reads: a DesignCraft package or an IDML package.
|
||||
/// The first [`DOCUMENT_SNIFF_BYTES`] of a file are enough for packages that start with their
|
||||
/// `mimetype` entry, as both formats write them.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#[cfg(test)]
|
||||
use super::bytes::{PREVIEW_PX, to_bytes};
|
||||
use super::bytes::{base64_decode, load_bytes};
|
||||
use super::bytes::{base64_decode, load_bytes, without_native_extension};
|
||||
use super::{Arc, DocState, Document, EngineError, Result, Session, Value, bad, json, str_param};
|
||||
|
||||
pub(super) fn has_recent(s: &Session) -> std::result::Result<(), String> {
|
||||
@@ -150,7 +150,8 @@ pub(super) fn file_open_bytes(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let (mut d, warnings) = load_bytes(&b)?;
|
||||
crate::cmd::datamerge::resolve_sources_on_open(&mut d, None);
|
||||
if let Some(n) = str_param(p, "name") {
|
||||
d.title = n.to_string();
|
||||
// Titled as an IDML file opened from bytes is: without its extension.
|
||||
d.title = without_native_extension(n).to_string();
|
||||
}
|
||||
let i = s.add_document(DocState::new(d, None));
|
||||
Ok(json!({"index": i, "warnings": warnings}))
|
||||
@@ -413,6 +414,35 @@ mod document_fonts_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod open_bytes_tests {
|
||||
use serde_json::json;
|
||||
|
||||
use crate::Session;
|
||||
|
||||
/// A `.designcraft` file opened from bytes under its file name (a browser or host passes the
|
||||
/// name it has) is titled without the extension, as an IDML file is, so saving it gives
|
||||
/// `Brochure.designcraft` and not `Brochure.designcraft.designcraft`.
|
||||
#[test]
|
||||
fn open_bytes_titles_a_native_document_without_its_extension() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
let native = s.execute("file.serialize", &json!({})).unwrap();
|
||||
for (name, title) in [
|
||||
("Brochure.designcraft", "Brochure"),
|
||||
("Brochure.DesignCraft", "Brochure"),
|
||||
("Brochure", "Brochure"),
|
||||
("Brochure.v2", "Brochure.v2"),
|
||||
("Brochure.designcraft.designcraft", "Brochure.designcraft"),
|
||||
(".designcraft", ".designcraft"),
|
||||
] {
|
||||
let r = s.execute("file.openBytes", &json!({"name": name, "base64": native["base64"]})).unwrap();
|
||||
let st = &s.documents()[r["index"].as_u64().unwrap() as usize];
|
||||
assert_eq!((st.doc.title.as_str(), st.title()), (title, title.to_string()), "{name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod recent_tests {
|
||||
use serde_json::json;
|
||||
|
||||
Reference in New Issue
Block a user