fix(web): derive file picker accept list from engine extensions

The web import picker hard-coded a 13-extension accept list, so raws the engine imports (CR3, NRW, RAF, ORF, RW2, RWL, RAW, PEF, SRW, …) were silently filtered out of the dialog on Windows/Edge, which matches accept case-sensitively. Generate the list from EXTENSIONS, each extension in both cases. Fixes #2212.
This commit is contained in:
joblonfk001
2026-10-21 08:09:19 +08:00
parent 5fe74557ec
commit b8e335370d
2 changed files with 35 additions and 2 deletions
+6 -2
View File
@@ -23,7 +23,11 @@ use crate::store::{Originals, content_hash, download_name, storage_key};
use crate::wire::ThumbIndex;
use crate::workers::{THUMB_INDEX, Workers};
const ACCEPT: &str = ".jpg,.jpeg,.png,.tif,.tiff,.webp,.dng,.cr2,.nef,.arw,.psd,.jxl,.gif,.bmp";
/// The web picker's accept list, derived from the engine's import extensions (both
/// cases) so no format the engine can import is silently filtered out of the dialog.
fn accept_list() -> String {
lightcraft_engine::import::accept_list()
}
/// After a failed save, wait this long before trying again (ms).
const SAVE_RETRY_MS: f64 = 2000.0;
@@ -123,7 +127,7 @@ fn open_picker(originals: Originals, backend: Option<Backend>, ctx: egui::Contex
let Ok(input) = doc.create_element("input").map(|e| e.unchecked_into::<web_sys::HtmlInputElement>()) else { return };
input.set_type("file");
input.set_multiple(true);
input.set_accept(ACCEPT);
input.set_accept(&accept_list());
let inp = input.clone();
let on_change = Closure::<dyn FnMut()>::new(move || {
if let Some(files) = inp.files() {
+29
View File
@@ -373,6 +373,26 @@ pub fn is_supported(path: &Path) -> bool {
path.extension().is_some_and(|e| EXTENSIONS.contains(&e.to_string_lossy().to_lowercase().as_str()))
}
/// The web file picker's accept list, derived from [`EXTENSIONS`]. Each extension
/// is listed in both cases: browsers' `accept` matching is case-insensitive per
/// spec, but some implementations (e.g. Windows/Edge) match case-sensitively and
/// rejected uppercase `.NEF` files, so a lowercase-only list silently hid raws
/// such as CR3, NRW, RAF, ORF, RW2, RWL, RAW, PEF and SRW from the picker.
pub fn accept_list() -> String {
let mut out = String::new();
for &ext in EXTENSIONS {
if !out.is_empty() {
out.push(',');
}
out.push('.');
out.push_str(ext);
out.push(',');
out.push('.');
out.push_str(&ext.to_uppercase());
}
out
}
/// Expand files and folders (recursively) into supported files. `skip` (e.g. the library folder)
/// is never descended into. Each folder's walk is bounded ([`crate::walk::Limits::default`]); a
/// walk that stops at a bound is logged.
@@ -1589,6 +1609,15 @@ mod tests_known;
mod prepared_tests {
use super::*;
#[test]
fn accept_list_covers_every_extension_in_both_cases() {
let list = accept_list();
for &ext in EXTENSIONS {
assert!(list.contains(&format!(".{ext}")), "lowercase .{ext} missing from accept list");
assert!(list.contains(&format!(".{}", ext.to_uppercase())), "uppercase .{} missing from accept list", ext.to_uppercase());
}
}
#[test]
fn revalidate_add_only_converts_matching_ready_item() {
let mut s = Session::new();