simple-web-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 0c1d430e4f5b840df5b392770cbfbb4feff875a7
parent 5be90e38ef14a2134b181bb9d8e12e8088e8719b
Author: Silas Brack <silasbrack@gmail.com>
Date:   Sat, 13 Jun 2026 15:44:30 +0200

refactor: remove inline JS for tag checkboxes

Use native HTML checkbox name attribute instead of JS collecting
checked values into a hidden input. Form now submits tags=3&tags=7
which serde deserializes into Vec<i64> directly. Removed duplicate
updateTags script from submit.html and edit.html.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Msrc/handlers/story.rs | 21+++++++--------------
Mtemplates/edit.html | 15++-------------
Mtemplates/submit.html | 15++-------------
3 files changed, 11 insertions(+), 40 deletions(-)

diff --git a/src/handlers/story.rs b/src/handlers/story.rs @@ -151,17 +151,13 @@ pub async fn show_submit( Ok(Html(app.render()?)) } -fn parse_tags(s: &str) -> Vec<i64> { - s.split(',').filter_map(|s| s.trim().parse().ok()).collect() -} - #[derive(Debug, Deserialize)] pub struct SubmitForm { pub title: String, pub url: Option<String>, pub text: Option<String>, #[serde(default)] - pub tags: String, + pub tags: Vec<i64>, } pub async fn submit_story( @@ -203,7 +199,7 @@ pub async fn submit_story( let title = form.title.trim().to_string(); let url_val = url.map(|s| s.to_string()); let text_val = text.map(|s| s.to_string()).unwrap_or_default(); - let tags_str = form.tags.clone(); + let tag_ids = form.tags.clone(); let story = state.db_query(move |db| { db.create_story( @@ -216,9 +212,7 @@ pub async fn submit_story( ) }).await.map_err(|e| render_submit_error(&form, &all_tags, &format!("Failed to create story: {}", e)))?; - // Add tags let story_id = story.id; - let tag_ids = parse_tags(&tags_str); if !tag_ids.is_empty() { let _ = state.db_query(move |db| { for tag_id in tag_ids { @@ -240,7 +234,7 @@ fn render_submit_error(form: &SubmitForm, all_tags: &[database::Category], error url: form.url.clone().unwrap_or_default(), text: form.text.clone().unwrap_or_default(), all_tags: all_tags.to_vec(), - selected_tags: parse_tags(&form.tags), + selected_tags: form.tags.clone(), }; let app = ApplicationTemplate { content: submit.render().unwrap_or_default(), @@ -302,7 +296,7 @@ pub struct EditForm { pub url: Option<String>, pub text: Option<String>, #[serde(default)] - pub tags: String, + pub tags: Vec<i64>, } pub async fn edit_story( @@ -339,14 +333,13 @@ pub async fn edit_story( let title = form.title.trim().to_string(); let url_val = url.map(|s| s.to_string()); let text_val = text.map(|s| s.to_string()).unwrap_or_default(); - let tags_str = form.tags.clone(); + let tag_ids = form.tags.clone(); state.db_query(move |db| { db.update_story(id, &title, url_val.as_deref(), &text_val, domain.as_deref())?; - // Update tags: remove all, then re-add selected db.remove_all_tags_from_story(id)?; - for tag_id in parse_tags(&tags_str) { + for tag_id in tag_ids { if let Err(e) = db.add_tag_to_story(id, tag_id) { eprintln!("Failed to add tag {} to story {}: {}", tag_id, id, e); } @@ -458,7 +451,7 @@ fn render_edit_error(story_id: i64, form: &EditForm, all_tags: &[database::Categ url: form.url.clone().unwrap_or_default(), text: form.text.clone().unwrap_or_default(), all_tags: all_tags.to_vec(), - selected_tags: parse_tags(&form.tags), + selected_tags: form.tags.clone(), }; let app = ApplicationTemplate { content: edit.render().unwrap_or_default(), diff --git a/templates/edit.html b/templates/edit.html @@ -37,9 +37,8 @@ {% match tag.name %} {% when Some with (name) %} <label class="tag-checkbox"> - <input type="checkbox" value="{{ tag.id }}" - {% if selected_tags.contains(tag.id) %} checked{% endif %} - onchange="updateTags(this.closest('form'))" /> + <input type="checkbox" name="tags" value="{{ tag.id }}" + {% if selected_tags.contains(tag.id) %} checked{% endif %} /> {{ name }} </label> {% when None %} @@ -49,20 +48,10 @@ </div> {% endif %} - <input type="hidden" name="tags" id="tags-hidden" value="" /> <div class="form-actions"> <button type="submit">Save Changes</button> <a href="/story/{{ story_id }}">Cancel</a> </div> </form> </validation-enhancer> - <script> - function updateTags(form) { - var checked = form.querySelectorAll('.tag-checkboxes input[type=checkbox]:checked'); - var ids = Array.from(checked).map(function(cb) { return cb.value; }); - form.querySelector('#tags-hidden').value = ids.join(','); - } - // Initialize on load - document.querySelectorAll('.submit-form').forEach(updateTags); - </script> </div> diff --git a/templates/submit.html b/templates/submit.html @@ -37,9 +37,8 @@ {% match tag.name %} {% when Some with (name) %} <label class="tag-checkbox"> - <input type="checkbox" value="{{ tag.id }}" - {% if selected_tags.contains(tag.id) %} checked{% endif %} - onchange="updateTags(this.closest('form'))" /> + <input type="checkbox" name="tags" value="{{ tag.id }}" + {% if selected_tags.contains(tag.id) %} checked{% endif %} /> {{ name }} </label> {% when None %} @@ -49,21 +48,11 @@ </div> {% endif %} - <input type="hidden" name="tags" id="tags-hidden" value="" /> <div class="form-actions"> <button type="submit">Submit</button> </div> </form> </validation-enhancer> - <script> - function updateTags(form) { - var checked = form.querySelectorAll('.tag-checkboxes input[type=checkbox]:checked'); - var ids = Array.from(checked).map(function(cb) { return cb.value; }); - form.querySelector('#tags-hidden').value = ids.join(','); - } - // Initialize on load - document.querySelectorAll('.submit-form').forEach(updateTags); - </script> <p class="submit-info"> Leave URL blank to submit a question or discussion.