8181
8282# --- HTML rendering
8383
84+ # Tom Select is vendored (not loaded from a CDN) so the cohort form makes no
85+ # third-party network calls at runtime and works offline. The assets are inlined
86+ # into the fragment because the library has no static-serving mechanism of its
87+ # own -- consumers just embed the string returned by render_html_form(). Note
88+ # that inline tags still require the host's CSP to permit inline script/style
89+ # (or that callers pass include_assets=False and load Tom Select themselves).
90+ _TOM_SELECT_CSS = "tmpl/vendor/tom-select-2.3.1.default.min.css"
91+ _TOM_SELECT_JS = "tmpl/vendor/tom-select-2.3.1.complete.min.js"
92+
93+ _VENDOR_CACHE : dict [str , str ] = {}
94+
95+
96+ def _read_vendor_asset (relative_path : str ) -> str :
97+ if relative_path not in _VENDOR_CACHE :
98+ file_path = path .join (path .dirname (path .abspath (__file__ )), relative_path )
99+ with open (file_path , encoding = "utf-8" ) as f :
100+ _VENDOR_CACHE [relative_path ] = f .read ()
101+ return _VENDOR_CACHE [relative_path ]
102+
84103
85104def render_html_form (
86105 action_url ,
@@ -97,6 +116,7 @@ def render_html_form(
97116 num_results : int = 31 ,
98117 num_of_rows : int = 12 ,
99118 start_date : Optional [str ] = None ,
119+ include_assets : bool = True ,
100120):
101121 """
102122 Render a HTML form that can be used to query the data in bitmapist.
@@ -111,6 +131,11 @@ def render_html_form(
111131 :param :select1b What is the current selected filter (extra, optional)
112132 :param :select2 What is the current selected filter (second)
113133 :param :select2b What is the current selected filter (extra, optional)
134+ :param :include_assets Whether to inline the vendored Tom Select CSS/JS into
135+ the fragment. Defaults to `True`. Set to `False` when rendering more than
136+ one form on a page, or when the host page already loads Tom Select, to
137+ avoid shipping the library more than once. The searchable dropdowns still
138+ initialize as long as Tom Select is available on the page.
114139
115140 """
116141 # mandatory
@@ -141,6 +166,11 @@ def render_html_form(
141166 num_results = int (num_results ),
142167 num_of_rows = int (num_of_rows ),
143168 start_date = start_date ,
169+ include_assets = include_assets ,
170+ tom_select_css = _read_vendor_asset (_TOM_SELECT_CSS )
171+ if include_assets
172+ else "" ,
173+ tom_select_js = _read_vendor_asset (_TOM_SELECT_JS ) if include_assets else "" ,
144174 )
145175 )
146176
0 commit comments