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:
@@ -110,14 +110,25 @@ class Node:
|
||||
"""Total media of this node and its subtree."""
|
||||
return self.media
|
||||
|
||||
# `__html__` marks the value HTML-safe for Django (conditional_escape).
|
||||
# `__str__` lets f-strings, ``str()`` and ``"".join(str(...))`` render the
|
||||
# node — the bridge that keeps most existing composition working.
|
||||
def __html__(self) -> str:
|
||||
return self._render()
|
||||
def with_media(self, media: Media) -> "Node":
|
||||
"""Attach JS dependencies to this node and return it (for fluent use).
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self._render()
|
||||
Lets a function-built node declare its media without becoming a full
|
||||
``BaseComponent`` subclass: ``return Div(...).with_media(Media(js=...))``.
|
||||
"""
|
||||
self.media = self.media + media
|
||||
return self
|
||||
|
||||
# A node's rendered output is always safe HTML by construction (Element
|
||||
# escapes unsafe children; Safe wraps trusted markup; Fragment escapes plain
|
||||
# strings). So both `__html__` (Django's conditional_escape hook) and
|
||||
# `__str__` return a SafeString — this is what keeps ``str(node)`` safe when
|
||||
# fed back into a child list or template, matching the old SafeText shims.
|
||||
def __html__(self) -> SafeText:
|
||||
return mark_safe(self._render())
|
||||
|
||||
def __str__(self) -> SafeText:
|
||||
return mark_safe(self._render())
|
||||
|
||||
|
||||
def _child_key(child: object) -> tuple[str, bool]:
|
||||
|
||||
Reference in New Issue
Block a user