@@ -135,9 +135,6 @@ class DataFrameHtmlFormatter:
135135 session
136136 """
137137
138- # Class variable to track if styles have been loaded in the notebook
139- _styles_loaded = False
140-
141138 def __init__ (
142139 self ,
143140 max_cell_length : int = 25 ,
@@ -260,23 +257,6 @@ def set_custom_header_builder(self, builder: Callable[[Any], str]) -> None:
260257 """
261258 self ._custom_header_builder = builder
262259
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-
280260 def format_html (
281261 self ,
282262 batches : list ,
@@ -315,18 +295,7 @@ def format_html(
315295 # Build HTML components
316296 html = []
317297
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 ())
330299
331300 html .extend (self ._build_table_container_start ())
332301
@@ -338,7 +307,7 @@ def format_html(
338307 html .append ("</div>" )
339308
340309 # Add footer (JavaScript and messages)
341- if include_styles and self .enable_cell_expansion :
310+ if self .enable_cell_expansion :
342311 html .append (self ._get_javascript ())
343312
344313 # Always add truncation message if needed (independent of styles)
@@ -375,14 +344,20 @@ def format_str(
375344
376345 def _build_html_header (self ) -> list [str ]:
377346 """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 ]
383359 if self .custom_css :
384- html .append (self .custom_css )
385- html .append ("</style>" )
360+ html .append (f"<style>{ self .custom_css } </style>" )
386361 return html
387362
388363 def _build_table_container_start (self ) -> list [str ]:
@@ -570,28 +545,31 @@ def _get_default_css(self) -> str:
570545 def _get_javascript (self ) -> str :
571546 """Get JavaScript code for interactive elements."""
572547 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+ """
595573
596574
597575class FormatterManager :
@@ -712,24 +690,9 @@ def reset_formatter() -> None:
712690 >>> reset_formatter() # Reset formatter to default settings
713691 """
714692 formatter = DataFrameHtmlFormatter ()
715- # Reset the styles_loaded flag to ensure styles will be reloaded
716- DataFrameHtmlFormatter ._styles_loaded = False
717693 set_formatter (formatter )
718694
719695
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-
733696def _refresh_formatter_reference () -> None :
734697 """Refresh formatter reference in any modules using it.
735698
0 commit comments