mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
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:
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user