@@ -135,9 +135,6 @@ class DataFrameHtmlFormatter:
135
135
session
136
136
"""
137
137
138
- # Class variable to track if styles have been loaded in the notebook
139
- _styles_loaded = False
140
-
141
138
def __init__ (
142
139
self ,
143
140
max_cell_length : int = 25 ,
@@ -260,23 +257,6 @@ def set_custom_header_builder(self, builder: Callable[[Any], str]) -> None:
260
257
"""
261
258
self ._custom_header_builder = builder
262
259
263
- @classmethod
264
- def is_styles_loaded (cls ) -> bool :
265
- """Check if HTML styles have been loaded in the current session.
266
-
267
- This method is primarily intended for debugging UI rendering issues
268
- related to style loading.
269
-
270
- Returns:
271
- True if styles have been loaded, False otherwise
272
-
273
- Example:
274
- >>> from datafusion.dataframe_formatter import DataFrameHtmlFormatter
275
- >>> DataFrameHtmlFormatter.is_styles_loaded()
276
- False
277
- """
278
- return cls ._styles_loaded
279
-
280
260
def format_html (
281
261
self ,
282
262
batches : list ,
@@ -315,18 +295,7 @@ def format_html(
315
295
# Build HTML components
316
296
html = []
317
297
318
- # Only include styles and scripts if:
319
- # 1. Not using shared styles, OR
320
- # 2. Using shared styles but they haven't been loaded yet
321
- include_styles = (
322
- not self .use_shared_styles or not DataFrameHtmlFormatter ._styles_loaded
323
- )
324
-
325
- if include_styles :
326
- html .extend (self ._build_html_header ())
327
- # If we're using shared styles, mark them as loaded
328
- if self .use_shared_styles :
329
- DataFrameHtmlFormatter ._styles_loaded = True
298
+ html .extend (self ._build_html_header ())
330
299
331
300
html .extend (self ._build_table_container_start ())
332
301
@@ -338,7 +307,7 @@ def format_html(
338
307
html .append ("</div>" )
339
308
340
309
# Add footer (JavaScript and messages)
341
- if include_styles and self .enable_cell_expansion :
310
+ if self .enable_cell_expansion :
342
311
html .append (self ._get_javascript ())
343
312
344
313
# Always add truncation message if needed (independent of styles)
@@ -375,14 +344,20 @@ def format_str(
375
344
376
345
def _build_html_header (self ) -> list [str ]:
377
346
"""Build the HTML header with CSS styles."""
378
- html = []
379
- html .append ("<style>" )
380
- # Only include expandable CSS if cell expansion is enabled
381
- if self .enable_cell_expansion :
382
- html .append (self ._get_default_css ())
347
+ default_css = self ._get_default_css () if self .enable_cell_expansion else ""
348
+ script = f"""
349
+ <script>
350
+ if (!document.getElementById('df-styles')) {{
351
+ const style = document.createElement('style');
352
+ style.id = 'df-styles';
353
+ style.textContent = `{ default_css } `;
354
+ document.head.appendChild(style);
355
+ }}
356
+ </script>
357
+ """
358
+ html = [script ]
383
359
if self .custom_css :
384
- html .append (self .custom_css )
385
- html .append ("</style>" )
360
+ html .append (f"<style>{ self .custom_css } </style>" )
386
361
return html
387
362
388
363
def _build_table_container_start (self ) -> list [str ]:
@@ -570,28 +545,31 @@ def _get_default_css(self) -> str:
570
545
def _get_javascript (self ) -> str :
571
546
"""Get JavaScript code for interactive elements."""
572
547
return """
573
- <script>
574
- function toggleDataFrameCellText(table_uuid, row, col) {
575
- var shortText = document.getElementById(
576
- table_uuid + "-min-text-" + row + "-" + col
577
- );
578
- var fullText = document.getElementById(
579
- table_uuid + "-full-text-" + row + "-" + col
580
- );
581
- var button = event.target;
582
-
583
- if (fullText.style.display === "none") {
584
- shortText.style.display = "none";
585
- fullText.style.display = "inline";
586
- button.textContent = "(less)";
587
- } else {
588
- shortText.style.display = "inline";
589
- fullText.style.display = "none";
590
- button.textContent = "...";
591
- }
592
- }
593
- </script>
594
- """
548
+ <script>
549
+ if (!window.__df_formatter_js_loaded__) {
550
+ window.__df_formatter_js_loaded__ = true;
551
+ window.toggleDataFrameCellText = function (table_uuid, row, col) {
552
+ var shortText = document.getElementById(
553
+ table_uuid + "-min-text-" + row + "-" + col
554
+ );
555
+ var fullText = document.getElementById(
556
+ table_uuid + "-full-text-" + row + "-" + col
557
+ );
558
+ var button = event.target;
559
+
560
+ if (fullText.style.display === "none") {
561
+ shortText.style.display = "none";
562
+ fullText.style.display = "inline";
563
+ button.textContent = "(less)";
564
+ } else {
565
+ shortText.style.display = "inline";
566
+ fullText.style.display = "none";
567
+ button.textContent = "...";
568
+ }
569
+ };
570
+ }
571
+ </script>
572
+ """
595
573
596
574
597
575
class FormatterManager :
@@ -712,24 +690,9 @@ def reset_formatter() -> None:
712
690
>>> reset_formatter() # Reset formatter to default settings
713
691
"""
714
692
formatter = DataFrameHtmlFormatter ()
715
- # Reset the styles_loaded flag to ensure styles will be reloaded
716
- DataFrameHtmlFormatter ._styles_loaded = False
717
693
set_formatter (formatter )
718
694
719
695
720
- def reset_styles_loaded_state () -> None :
721
- """Reset the styles loaded state to force reloading of styles.
722
-
723
- This can be useful when switching between notebook sessions or
724
- when styles need to be refreshed.
725
-
726
- Example:
727
- >>> from datafusion.html_formatter import reset_styles_loaded_state
728
- >>> reset_styles_loaded_state() # Force styles to reload in next render
729
- """
730
- DataFrameHtmlFormatter ._styles_loaded = False
731
-
732
-
733
696
def _refresh_formatter_reference () -> None :
734
697
"""Refresh formatter reference in any modules using it.
735
698
0 commit comments