Phase 3: declare component media that bubbles through the node tree
The JS-bearing widgets now declare their script dependencies, so a view no longer needs to know which scripts a component requires: - SearchSelect / FilterSelect → search_select.js - RangeSlider → range_slider.js - DateRangePicker → date_range_picker.js - YearPicker → datepicker.umd.js (external, from Phase 2) - FilterBar chrome → filter_bar.js Because the filter-bar internals now build a node tree (the legacy Component() string-builder calls became Element/Div), each bar's collect_media() returns its own filter_bar.js merged with the scripts that bubble up from the FilterSelect / RangeSlider / DateRangePicker widgets it contains — exactly the set the views thread by hand today. Adds Node.with_media() so a function-built node can declare media without a full BaseComponent subclass, and tests proving the bubbling. Note: the six *FilterBar functions still share the _filter_bar chrome helper rather than a BaseComponent class hierarchy; folding them into one is a follow-up that does not affect media collection (Phase 4). https://claude.ai/code/session_01BKurBhE3Qj25p7Bfsg7EeK
This commit is contained in:
@@ -133,5 +133,53 @@ class MediaCollectionTest(unittest.TestCase):
|
||||
self.assertFalse(collect_media("just a string"))
|
||||
|
||||
|
||||
class RealComponentMediaTest(unittest.TestCase):
|
||||
"""Phase 3: JS-bearing components declare media that bubbles up the tree."""
|
||||
|
||||
def test_search_select_declares_its_script(self):
|
||||
from common.components import SearchSelect
|
||||
|
||||
self.assertEqual(
|
||||
collect_media(SearchSelect(name="games")).js, ("search_select.js",)
|
||||
)
|
||||
|
||||
def test_filter_select_declares_its_script(self):
|
||||
from common.components import FilterSelect
|
||||
|
||||
self.assertIn(
|
||||
"search_select.js", collect_media(FilterSelect(field_name="type")).js
|
||||
)
|
||||
|
||||
def test_date_range_picker_declares_its_script(self):
|
||||
from common.components import DateRangePicker
|
||||
|
||||
media = collect_media(
|
||||
DateRangePicker(label="Played", input_name_prefix="played")
|
||||
)
|
||||
self.assertEqual(media.js, ("date_range_picker.js",))
|
||||
|
||||
def test_range_slider_declares_its_script(self):
|
||||
from common.components.filters import RangeSlider
|
||||
|
||||
media = collect_media(
|
||||
RangeSlider(
|
||||
label="Year", input_name_prefix="year", range_min=2000, range_max=2025
|
||||
)
|
||||
)
|
||||
self.assertEqual(media.js, ("range_slider.js",))
|
||||
|
||||
def test_filter_bar_collects_chrome_and_widget_media(self):
|
||||
"""A FilterBar's media merges its own chrome script with the scripts that
|
||||
bubble up from the FilterSelect and RangeSlider widgets it contains —
|
||||
exactly the set the view used to thread by hand. (FilterBar wraps its DB
|
||||
aggregates in try/except, so it builds without a database.)"""
|
||||
from common.components import FilterBar
|
||||
|
||||
media = collect_media(FilterBar())
|
||||
self.assertIn("filter_bar.js", media.js)
|
||||
self.assertIn("search_select.js", media.js)
|
||||
self.assertIn("range_slider.js", media.js)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user