Forráskód Böngészése

Merge pull request #2375 from Avaiga/2366-allow-custom-javascript-files-for-specific-page

Allow custom Javascript files for specific page
Nam Nguyen 4 hónapja
szülő
commit
f11fc4764e

+ 15 - 1
frontend/taipy-gui/src/components/pages/TaipyRendered.tsx

@@ -42,6 +42,7 @@ interface AxiosRenderer {
     style: string;
     head: HeadProps[];
     context: string;
+    scriptPaths: string[];
 }
 
 // set global style the traditional way
@@ -61,6 +62,18 @@ const setStyle = (id: string, styleString: string): void => {
     }
 };
 
+// set script tag for the page
+const setScript = (id: string, scriptPaths: string[]): void => {
+    document.querySelectorAll(`script[id^="${id}_"]`).forEach(script => script.remove());
+    scriptPaths.forEach((path, index) => {
+        const script = document.createElement("script");
+        script.id = `${id}_${index}`;
+        script.src = path;
+        script.defer = true;
+        document.head.append(script);
+    });
+};
+
 interface PageState {
     jsx?: string;
     module?: string;
@@ -97,9 +110,10 @@ const TaipyRendered = (props: TaipyRenderedProps) => {
                     if (!fromBlock) {
                         setStyle(
                             path == "/TaiPy_root_page" ? "Taipy_root_style" : "Taipy_style",
-                            result.data.style || ""
+                            result.data.style || "",
                         );
                         Array.isArray(result.data.head) && setHead(result.data.head);
+                        Array.isArray(result.data.scriptPaths) && setScript("Taipy_script", result.data.scriptPaths);
                     }
                 })
                 .catch((error) => {

+ 2 - 0
taipy/gui/_page.py

@@ -16,6 +16,7 @@ import logging
 import re
 import typing as t
 import warnings
+from pathlib import Path
 
 from ._warnings import TaipyGuiAlwaysWarning
 
@@ -34,6 +35,7 @@ class _Page(object):
         self._style: t.Optional[t.Union[str, t.Dict[str, t.Any]]] = None
         self._route: t.Optional[str] = None
         self._head: t.Optional[list] = None
+        self._script_paths: t.Optional[t.Union[str, Path, t.List[t.Union[str, Path]]]] = None
 
     def render(self, gui: Gui, silent: t.Optional[bool] = False):
         if self._renderer is None:

+ 2 - 1
taipy/gui/gui.py

@@ -2087,6 +2087,7 @@ class Gui:
         new_page._route = name
         new_page._renderer = page
         new_page._style = style or page._get_style()
+        new_page._script_paths = page._get_script_paths()
         # Append page to _config
         self._config.pages.append(new_page)
         self._config.routes.append(name)
@@ -2571,7 +2572,7 @@ class Gui:
             with self._set_locals_context(context):
                 self._call_on_page_load(nav_page)
             return self._server._render(
-                page._rendered_jsx, page._style if page._style is not None else "", page._head, context
+                page._rendered_jsx, page._script_paths if page._script_paths is not None else [], page._style if page._style is not None else "", page._head, context # noqa: E501
             )
         else:
             return ("No page template", 404)

+ 35 - 0
taipy/gui/page.py

@@ -13,8 +13,11 @@ from __future__ import annotations
 
 import inspect
 import typing as t
+from pathlib import Path
 from types import FrameType
+from urllib.parse import urlparse
 
+from ._warnings import _warn
 from .utils import _filter_locals, _get_module_name_from_frame
 
 if t.TYPE_CHECKING:
@@ -75,6 +78,7 @@ class Page:
         self._notebook_gui: t.Optional["Gui"] = None
         self._notebook_page: t.Optional["_Page"] = None
         self.set_style(kwargs.get("style", None))
+        self._script_paths(kwargs.get("script_paths", None))
 
     def create_page(self) -> t.Optional[Page]:
         """Create the page content for page modules.
@@ -180,3 +184,34 @@ class Page:
 
     def _get_style(self):
         return self.__style
+
+    def _script_paths(self, script_paths: t.Optional[t.Union[str, Path, t.List[t.Union[str, Path]]]]) -> Page:
+        """
+        Load a script or a list of scripts to be used in the page.
+
+        Arguments:
+            script_paths (str, Path, list): The path to the script file or a list of paths to the script files.
+
+        Returns:
+            This `Page` instance.
+        """
+        if script_paths:
+            if isinstance(script_paths, (str, Path)):
+                script_paths = [script_paths]
+            for script_path in script_paths:
+                if isinstance(script_path, str):
+                    parsed_url = urlparse(script_path)
+                    if parsed_url.netloc:
+                        continue
+                    script_path = Path(script_path)
+
+                if isinstance(script_path,
+                              Path) and script_path.exists() and script_path.is_file() and script_path.suffix == ".js":
+                    continue
+                else:
+                    _warn(f"Script path '{script_path}' does not exist, is not a file, or is not a JavaScript file.")
+        self.__script_paths = script_paths if script_paths else None
+        return self
+
+    def _get_script_paths(self):
+        return self.__script_paths

+ 2 - 1
taipy/gui/server.py

@@ -240,7 +240,7 @@ class _Server:
         return taipy_bp
 
     # Update to render as JSX
-    def _render(self, html_fragment, style, head, context):
+    def _render(self, html_fragment, script_paths, style, head, context):
         template_str = _Server.__RE_OPENING_CURLY.sub(_Server.__OPENING_CURLY, html_fragment)
         template_str = _Server.__RE_CLOSING_CURLY.sub(_Server.__CLOSING_CURLY, template_str)
         template_str = template_str.replace('"{!', "{")
@@ -252,6 +252,7 @@ class _Server:
                 "style": (style + os.linesep) if style else "",
                 "head": head or [],
                 "context": context or self._gui._get_default_module_name(),
+                "scriptPaths": script_paths
             }
         )