Skip to content

Commit 30e6d82

Browse files
committed
fix
1 parent 8f255c1 commit 30e6d82

File tree

14 files changed

+778497
-58
lines changed

14 files changed

+778497
-58
lines changed

.DS_Store

0 Bytes
Binary file not shown.

site/.DS_Store

2 KB
Binary file not shown.

site/src/.DS_Store

8 KB
Binary file not shown.

site/src/components/command_palette.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ pub fn CommandPalette(
715715
}
716716
});
717717

718-
// Set up global keyboard handling when palette is open
718+
// Set up global keyboard handling when palette is open with proper cleanup
719719
let nav = navigate.clone();
720720
Effect::new(move |_| {
721721
if is_open.get() {
@@ -728,6 +728,10 @@ pub fn CommandPalette(
728728
set_selected_index.set(0);
729729
}
730730
"Enter" => {
731+
// Double-check that palette is still open before processing
732+
if !is_open.get() {
733+
return; // Palette closed, don't process Enter
734+
}
731735
e.prevent_default();
732736
let results = filtered_results.get();
733737
if !results.is_empty() {
@@ -767,8 +771,11 @@ pub fn CommandPalette(
767771
}
768772
};
769773

770-
let _cleanup = window_event_listener(leptos::ev::keydown, handle_keydown);
771-
// cleanup will happen when effect re-runs or component unmounts
774+
let cleanup = window_event_listener(leptos::ev::keydown, handle_keydown);
775+
on_cleanup(move || {
776+
// Explicitly clean up when palette closes
777+
drop(cleanup);
778+
});
772779
}
773780
});
774781

@@ -785,7 +792,8 @@ pub fn CommandPalette(
785792
}
786793
});
787794

788-
// Handle navigation
795+
// Handle navigation - process immediately regardless of palette state
796+
// Navigation should happen even after palette closes to complete the user's action
789797
Effect::new(move |_| {
790798
if let Some(path) = navigate_to.get() {
791799
// Debug log to track navigation
@@ -986,7 +994,7 @@ pub fn CommandPalette(
986994
SearchResult::RecentChapter { .. } => {
987995
view! {
988996
<div class="text-xs opacity-75 mt-1 flex items-center">
989-
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
997+
<svg class="w-2 h-2 mr-1" fill="currentColor" viewBox="0 0 20 20">
990998
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"></path>
991999
</svg>
9921000
"Recent chapter"

site/src/components/cross_references_sidebar.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,16 @@ fn reference_to_url(reference: &Reference) -> String {
176176
// Convert canonical book name back to display book name used in the Bible
177177
let display_book_name = get_display_book_name(&reference.to_book_name);
178178
let encoded_book = encode(&display_book_name);
179+
180+
// Ensure chapter and verse are valid positive numbers
181+
let chapter = reference.to_chapter.max(1);
182+
let verse_start = reference.to_verse_start.max(1);
183+
179184
if let Some(end_verse) = reference.to_verse_end {
180-
format!("/{}/{}?verses={}-{}", encoded_book, reference.to_chapter, reference.to_verse_start, end_verse)
185+
let verse_end = end_verse.max(verse_start);
186+
format!("/{}/{}?verses={}-{}", encoded_book, chapter, verse_start, verse_end)
181187
} else {
182-
format!("/{}/{}?verses={}", encoded_book, reference.to_chapter, reference.to_verse_start)
188+
format!("/{}/{}?verses={}", encoded_book, chapter, verse_start)
183189
}
184190
}
185191

@@ -265,6 +271,11 @@ pub fn CrossReferencesSidebar(
265271
let (_sidebar_has_focus, set_sidebar_has_focus) = signal(false);
266272
let navigate = use_navigate();
267273

274+
// Use a simple Arc<AtomicBool> for disposal tracking that doesn't rely on reactive system
275+
use std::sync::atomic::{AtomicBool, Ordering};
276+
use std::sync::Arc;
277+
let is_disposed = Arc::new(AtomicBool::new(false));
278+
268279
// Convert display book name (e.g. "I Samuël") to canonical English name (e.g. "1 Samuel")
269280
// for cross-reference lookup
270281
let canonical_book_name = get_canonical_book_name(&book_name);
@@ -351,24 +362,32 @@ pub fn CrossReferencesSidebar(
351362
});
352363

353364
// Keyboard navigation for references - with comprehensive safety checks and debouncing
365+
let is_disposed_clone = is_disposed.clone();
366+
let _component_book_name = book_name.clone();
367+
let _component_chapter = chapter;
368+
let _component_verse = verse;
354369
let handle_keydown = move |e: KeyboardEvent| {
355-
// Don't handle navigation when command palette is open (let palette handle it)
356-
if palette_open.get() {
370+
// Early exit if component is disposed
371+
if is_disposed_clone.load(Ordering::Relaxed) {
357372
return;
358373
}
359374

360-
// Only handle specific Ctrl combinations to avoid conflicts with vim navigation
361-
if !e.ctrl_key() {
362-
return; // Let vim navigation handle non-Ctrl keys
363-
}
364375

365-
// Only handle navigation when references are available and we're specifically targeting cross-refs
366-
if !sorted_references.get().is_some_and(|refs| !refs.is_empty()) {
376+
// Don't handle navigation when command palette is open (let palette handle it)
377+
if palette_open.get() {
367378
return;
368379
}
369380

370-
// Only handle Ctrl+J and Ctrl+K specifically for cross-references
371-
if !matches!((e.key().as_str(), e.ctrl_key()), ("j", true) | ("k", true)) {
381+
// Safe access to sorted_references with disposal check
382+
let refs = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
383+
sorted_references.get()
384+
})) {
385+
Ok(Some(refs)) if !refs.is_empty() => refs,
386+
_ => return, // Component is disposed or no references available
387+
};
388+
389+
// Only handle specific keys: Ctrl+J, Ctrl+K for navigation, or Enter for selection
390+
if !matches!((e.key().as_str(), e.ctrl_key()), ("j", true) | ("k", true) | ("Enter", false)) {
372391
return;
373392
}
374393

@@ -377,11 +396,6 @@ pub fn CrossReferencesSidebar(
377396
return; // Skip if already processing navigation
378397
}
379398

380-
// Get current references safely with additional checks
381-
let refs = match sorted_references.get() {
382-
Some(refs) if !refs.is_empty() => refs,
383-
_ => return, // No references available
384-
};
385399

386400
// Bounds check current selection before processing with recovery
387401
let current = selected_reference_index.get();
@@ -463,16 +477,18 @@ pub fn CrossReferencesSidebar(
463477
("Enter", false, false) => {
464478
// Enter: Navigate to selected reference with bounds checking
465479
e.prevent_default();
480+
web_sys::console::log_1(&format!("Enter pressed, current index: {}, refs length: {}", current, refs.len()).into());
466481
if let Some(reference) = refs.get(current) {
467482
let reference_url = reference_to_url(reference);
483+
web_sys::console::log_1(&format!("Navigating to: {}", reference_url).into());
468484
navigate(&reference_url, NavigateOptions { scroll: false, ..Default::default() });
469485
// Close sidebar on mobile when reference is selected
470486
if is_mobile_screen() {
471487
set_sidebar_open.set(false);
472488
save_references_sidebar_open(false);
473489
}
474490
} else {
475-
web_sys::console::warn_1(&"Attempted to navigate to reference at invalid index".into());
491+
web_sys::console::warn_1(&format!("Attempted to navigate to reference at invalid index: {} (refs.len: {})", current, refs.len()).into());
476492
}
477493
set_is_navigating.set(false); // Clear navigation flag
478494
}
@@ -482,8 +498,14 @@ pub fn CrossReferencesSidebar(
482498
}
483499
};
484500

485-
// Add keyboard event listener - with proper bounds checking to prevent WASM errors
486-
window_event_listener(ev::keydown, handle_keydown);
501+
// Add keyboard event listener - with proper cleanup to prevent disposed reactive value access
502+
let _cleanup = window_event_listener(ev::keydown, handle_keydown);
503+
on_cleanup(move || {
504+
// Mark component as disposed to prevent reactive value access
505+
is_disposed.store(true, Ordering::Relaxed);
506+
// Cleanup is handled automatically when _cleanup is dropped
507+
drop(_cleanup);
508+
});
487509

488510
view! {
489511
<div

site/src/instructions/processor.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,15 @@ where
245245
// Add reference and link
246246
copy_text.push_str("\n\n");
247247

248-
let book_name = context.current_chapter.name
249-
.split_whitespace()
250-
.next()
251-
.unwrap_or("");
252-
let translated_book_name = self.get_translated_book_name(book_name);
253-
let chapter_num = context.current_chapter.name
254-
.split_whitespace()
255-
.nth(1)
256-
.unwrap_or("1");
248+
// Extract book name from chapter name (everything except the last word which is the chapter number)
249+
let name_parts: Vec<&str> = context.current_chapter.name.split_whitespace().collect();
250+
let book_name = if name_parts.len() > 1 {
251+
name_parts[..name_parts.len() - 1].join(" ")
252+
} else {
253+
context.current_chapter.name.clone()
254+
};
255+
let translated_book_name = self.get_translated_book_name(&book_name);
256+
let chapter_num = context.current_chapter.chapter.to_string();
257257

258258
// Format reference
259259
if verse_ranges.len() == 1 && verse_ranges[0].start == verse_ranges[0].end {
@@ -272,7 +272,7 @@ where
272272

273273
// Add link
274274
copy_text.push('\n');
275-
let book_name_url = book_name.replace(' ', "_").to_lowercase();
275+
let book_name_url = urlencoding::encode(&book_name);
276276
let verses_param = context.search_params
277277
.split("verses=")
278278
.nth(1)

site/src/main.rs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -256,30 +256,17 @@ fn BibleWithSidebar() -> impl IntoView {
256256
}
257257
)
258258
on:click=move |_| {
259-
if cross_references_data.get().is_some() {
260-
set_is_right_sidebar_open.update(|open| {
261-
*open = !*open;
262-
save_references_sidebar_open(*open);
263-
});
264-
} else {
265-
// Show sidebar with helpful message
266-
set_is_right_sidebar_open.set(true);
267-
save_references_sidebar_open(true);
268-
}
259+
// Always toggle like the "r" key does
260+
set_is_right_sidebar_open.update(|open| {
261+
*open = !*open;
262+
save_references_sidebar_open(*open);
263+
});
269264
}
270265
aria-label=move || {
271-
if cross_references_data.get().is_some() {
272-
if is_right_sidebar_open.get() { "Hide cross-references" } else { "Show cross-references" }
273-
} else {
274-
"Show references help"
275-
}
266+
if is_right_sidebar_open.get() { "Hide cross-references" } else { "Show cross-references" }
276267
}
277268
title=move || {
278-
if cross_references_data.get().is_some() {
279-
if is_right_sidebar_open.get() { "Hide cross-references" } else { "Show cross-references" }
280-
} else {
281-
"References (select a verse first)"
282-
}
269+
if is_right_sidebar_open.get() { "Hide cross-references" } else { "Show cross-references" }
283270
}
284271
>
285272
<svg

site/src/storage/translations.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn get_translations() -> Vec<BibleTranslation> {
99
wikipedia: String::from("https://nl.wikipedia.org/wiki/Statenvertaling"),
1010
release_year: 1637,
1111
languages: vec![Language::Dutch],
12-
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg4NjlmY2VlMTNjNGI2YzhhMmU3MzQx:NWFlN2IwYmIyZDQ0OWI3OTQ1ZmJhYWI4NGFjODJkYjYyMmM1MWJkZmEzYmI1NTA1NzgyZWEwNGQwOGMyMGM3MQ"),
12+
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg5MjEyOTM0NzVmZTAwZjg3Y2VjN2Iy:MjhiNDNiOTMyNDllYTAwMzRmYWM4ZTdmOTdlZDU3NGExNzQxNjA4MzBiNzU3MThmNjE5ZGEzODZiNjVlOWE2MA"),
1313
},
1414
BibleTranslation {
1515
name: String::from("Petrus Canisiusvertaling"),
@@ -18,7 +18,7 @@ pub fn get_translations() -> Vec<BibleTranslation> {
1818
wikipedia: String::from("https://nl.wikipedia.org/wiki/Petrus_Canisiusvertaling"),
1919
release_year: 1939,
2020
languages: vec![Language::Dutch],
21-
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg4NjYwZTZlMTNjNGI2YzhhMmU0Zjc0:MGYyYTlkYmRiZDhhNThjYjRmNzk4NzA2ODZkODY0M2NlMzJjZDRkMjM3YWJmNjQ5MWU4NmFkMTRmNDMwZWMzYQ"),
21+
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg5MjEyOGY0NzVmZTAwZjg3Y2VjN2Iw:N2U3ZTg1MTkxMmFiZGY5NTU0ZjM5MTdhZThkMDIzYWYxZDg4ZDQ1N2EyMDA1NzhiZWRiYmY4NmUzZTA3ZWIyOA"),
2222
},
2323
BibleTranslation {
2424
name: String::from("King james version"),
@@ -27,7 +27,16 @@ pub fn get_translations() -> Vec<BibleTranslation> {
2727
wikipedia: String::from("https://en.wikipedia.org/wiki/King_James_Version"),
2828
release_year: 1611,
2929
languages: vec![Language::English],
30-
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg4NjYzMDBlMTNjNGI2YzhhMmU1Yzc2:MzI3ZTY3NjBmMDAwMzBlMDVlZGM3NGQxNjU5MDIxMDdlNTE0MDA2ZWJkNTRkMjAyZGJjZWE1ZTlhMTQzNmYzNg"),
30+
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg5MjEyZGM0NzVmZTAwZjg3Y2VkNDU0:Yjc0MjAwNzMzN2RmM2UyMGVkZDgzYThiMWRjZWIxMjM0OTUwMjZhNDVhMWFkOGZmMThjOTU4NTUzMmUwY2FhYQ"),
31+
},
32+
BibleTranslation {
33+
name: String::from("American King james version"),
34+
short_name: String::from("akjv"),
35+
description: String::from("The American King James Version (AKJV) is a modernized update of the original 1769 Oxford edition of the King James Bible. Created by Michael Peter Engelbrite, this version retains the literary beauty and structure of the original KJV while updating some archaic English words and spellings to make the text more accessible to contemporary readers. Importantly, the AKJV makes no changes to the underlying meaning of the scriptures, preserving the integrity and style of the King James tradition. It is in the public domain and widely used by those who appreciate the KJV but prefer a slightly more readable form."),
36+
wikipedia: String::from("https://studybible.info/version/AKJV"),
37+
release_year: 1999,
38+
languages: vec![Language::English],
39+
iagon: String::from("https://gw.iagon.com/api/v2/storage/shareable/link/Njg5MjEyZGI0NzVmZTAwZjg3Y2VkNDQ2:MWRjOGI2N2Y3OGE1MWY5MmU1YmMwYjhiZjY2NjM3ZWRkMjY0OWZiMWY4ZDg3MTZmMmU1ODViOTgwNDM4ZjU3Zg"),
3140
}
3241
]
3342
}

sources/.DS_Store

6 KB
Binary file not shown.

sources/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# sources
2+
3+
There sources are hosted on [iagon](https://iagon.com/). These files are not read by the rust code directly but these files are published and fetched by the rust code.
4+
If you want to use these for your own bible project feel free to do so.

0 commit comments

Comments
 (0)