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:
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.