Draft
Conversation
added 15 commits
December 14, 2025 15:14
…lection publicity is changed, featured sounds implementation has started
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Collections improvements: featured sounds, client-side grid
Collections model & backend (
fscollections/)views.py— models.pycollection()andedit_collection()now serialize all sounds as JSON for client-side rendering (serialize_collection_sounds()), replacing server-side pagination. The edit view switched from a singlecollection_soundsfield to a delta-based approach (added/removed/featured). Cleaned up redundant code and simplified permission logic.forms.py— NewCommaSeparatedIdFieldreplacing manual regex parsing.CollectionEditFormnow uses three fields:added_sounds,removed_sounds,featured_sounds(delta-based save).save()usesbulk_createwithignore_conflictsand a DBtransaction.atomic()block.SelectCollectionOrNewCollectionForm.save()now supportsmark_as_featured. Fixed bug inMaintainerForm.clean()(.replaceon list -> proper.strip()per item).tests.pytest_edit_featured_sounds_as_user— verifies adding sounds with featured flags and clearing featured soundstest_edit_featured_sounds_as_maintainer— verifies maintainers cannot change featured sounds (preserved from owner's original value)test_add_sounds_outside_collection_to_featured— verifies that featuring a sound not in the collection is silently filtered outtest_remove_sounds_that_are_featured— verifies removing a sound from the collection also removes it fromfeatured_sound_idsFrontend — new client-side sound grid system
soundStateStore.js— NewSoundStateStoreclass: manages an in-memory map of sounds with per-sound boolean flags (featured,added,remove). Supportsadd(),remove(),toggle(),hasFlag(),idsWithFlag(), and anonChangelistener system.soundGridEditor.js— NewSoundGridEditorclass: client-side paginated grid with search filtering, multi-column sorting, URL sync (?s=,?q=,?page=), and a pluggablerenderCardhook. Handles player initialization, rating widgets, modal bindings, and pagination rendering after each page change.soundCard.js—populateSoundCard()clones a<template>and fills in all sound card fields (player data attributes, links, date, description, rating stars, stat icons).addEditActions()wraps a card with featured-toggle and remove-toggle action buttons for edit mode.formatters.js— Utility functions (escapeAttr,truncate,formatDate,formatNumber,soundPlayerUrls) used by the card renderer.Frontend — page entry points
collection.js— Read-only collection page: loads sounds JSON, createsSoundStateStore+SoundGridEditorwith featured highlighting and URL-synced search/sort/pagination.collectionEdit.js— Edit page: same grid but with action buttons (featured toggle, remove toggle). Wires add-sounds modal to dynamically insert new sounds into the store. On form submit, populates hiddenadded_sounds,removed_sounds, andfeatured_soundsinputs from store state.Frontend — updated components
objectSelector.js— NewinitializeObjectSelectorActions()function andupdateActionUI()helper for toggle buttons (featured/remove) with visual states, disable-chaining (remove disables featured), and store integration.addSoundsModal.js— NewprepareAddSoundsModalDynamic()that works with the client-side grid: excludes already-present sound IDs and feeds selected sounds back into the store, alongside the existingprepareAddSoundsModalAndFields().Templates
collection.html— Replaced server-side sound loop + paginator with a#sounds-grid/#sounds-paginationcontainer, search input, sort dropdown, and JSON script blocks.edit_collection.html— Same client-side grid approach. Form now has hidden fields foradded_sounds,removed_sounds,featured_sounds. Buttons aretype="button"to prevent accidental submits. Added search and sort controls.display_sound_with_actions.html— New template for sound cards with featured-toggle and remove-toggle action buttons.object_selector.html— Addedshow_actionsbranch to renderdisplay_sound_small_with_actionsinstead of the selectable variant._sound_card_template.html— HTML<template>used bypopulateSoundCard()for client-side card rendering.Styles (SCSS)
selectableObject.scss— Major addition: styles for.with-actionssound cards including.bw-object-actionsbutton bar,.featured-toggle(yellow active state, hover-to-unfeature),.remove-toggle(red hover, undo state), and.marked-for-removal(dims the card and disables pointer events).inputs.scss,selects.scss,forms.scss— Minor fixes to keep search inputs, selects, and pill-style wrappers consistent when used inside.bw-formcontainers (no-icon padding variant,nowrapon select options, margin/border resets for embedded search inputs).grid-compat.scss— Added missingoffset-*andorder-*grid helpers that were removed in an upstream Bootstrap update.How the client-side collection grid works
The Django view serializes all collection sounds into a JSON array via
json_script. On load, this is parsed into aSoundStateStore— an in-memory map of sound objects with per-sound boolean flags (featured,added,remove).SoundGridEditorconsumes the store: filters by search, sorts by the active column, slices to the current page size, then renders each sound by cloning an HTML<template>and populating it viapopulateSoundCard()(player data-attributes, links, icons, rating widget). After DOM insertion it initializes players, modals, and ratings for that page. Pagination is built client-side from the filtered result count — clicking a page just re-slices and re-renders, no server request.In edit mode, cards get featured/remove toggle buttons (
addEditActions()). Clicks callstore.toggle(id, flag), which updates the flag and firesonChange— the grid re-renders or updates the count accordingly.The add-sounds modal (
prepareAddSoundsModalDynamic()) receives the current store IDs as an exclusion list. When the modal opens,handleGenericModalfetches the modal URL via XHR and injects the server-rendered HTML into#genericModalWrapper— so the modal has its own fresh DOM of search result sound cards, entirely separate from the page's sounds grid. On confirm,extractSoundFromModalreads sound metadata directly from thedata-*attributes on each selected.bw-playerelement in the modal DOM, then callsstore.add(id, data)for each — the store listener triggers a grid re-render so new cards appear instantly.On form submit, three hidden inputs are populated from store state:
added_sounds,removed_sounds,featured_sounds. The backend applies this delta atomically inCollectionEditForm.save().