From 359fef6e447dd8fce8f38d1f1912b0afd6a99a04 Mon Sep 17 00:00:00 2001 From: namnguyen Date: Mon, 30 Dec 2024 16:50:03 +0700 Subject: [PATCH 1/7] init commit --- .../src/components/pages/TaipyRendered.tsx | 16 +++++++++ taipy/gui/_page.py | 2 ++ taipy/gui/gui.py | 3 +- taipy/gui/page.py | 35 +++++++++++++++++++ taipy/gui/server.py | 3 +- 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx index 510d3a971b..73f40a6302 100644 --- a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx +++ b/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,20 @@ const setStyle = (id: string, styleString: string): void => { } }; +// set script tag for the page +const setScript = (id: string, scriptPaths: string[]): void => { + scriptPaths.forEach((path, index) => { + let script = document.getElementById(`${id}_${index}`) as HTMLScriptElement | null; + if (!script) { + script = document.createElement("script"); + script.id = `${id}_${index}`; + script.src = path; + script.defer = true; + document.head.append(script); + } + }); +}; + interface PageState { jsx?: string; module?: string; @@ -100,6 +115,7 @@ const TaipyRendered = (props: TaipyRenderedProps) => { 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) => { diff --git a/taipy/gui/_page.py b/taipy/gui/_page.py index 6505926c13..897c736f38 100644 --- a/taipy/gui/_page.py +++ b/taipy/gui/_page.py @@ -16,6 +16,7 @@ import re import typing as t import warnings +from pathlib import Path from ._warnings import TaipyGuiAlwaysWarning @@ -34,6 +35,7 @@ def __init__(self) -> None: 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: diff --git a/taipy/gui/gui.py b/taipy/gui/gui.py index 8aa6edf35c..337129cf0e 100644 --- a/taipy/gui/gui.py +++ b/taipy/gui/gui.py @@ -2074,6 +2074,7 @@ def add_page( 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) @@ -2558,7 +2559,7 @@ def __render_page(self, page_name: str) -> t.Any: 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) diff --git a/taipy/gui/page.py b/taipy/gui/page.py index 0d1218db09..f9719ffd13 100644 --- a/taipy/gui/page.py +++ b/taipy/gui/page.py @@ -13,8 +13,11 @@ 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 @@ def __init__(self, **kwargs) -> None: 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 @@ def set_style(self, style: t.Dict[str, t.Dict[str, t.Any]]) -> 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 diff --git a/taipy/gui/server.py b/taipy/gui/server.py index 697f1f52c0..3c6bca7c38 100644 --- a/taipy/gui/server.py +++ b/taipy/gui/server.py @@ -240,7 +240,7 @@ def my_index(path): 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 @@ def _render(self, html_fragment, style, head, context): "style": (style + os.linesep) if style else "", "head": head or [], "context": context or self._gui._get_default_module_name(), + "scriptPaths": script_paths } ) From 50790ce1590e9583b2f2b74152a7acf3acb7fe3a Mon Sep 17 00:00:00 2001 From: namnguyen Date: Tue, 31 Dec 2024 00:48:32 +0700 Subject: [PATCH 2/7] add logic to remove all script of current page before moving to new page --- .../src/components/pages/TaipyRendered.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx index 73f40a6302..100f264e59 100644 --- a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx +++ b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx @@ -64,15 +64,13 @@ 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) => { - let script = document.getElementById(`${id}_${index}`) as HTMLScriptElement | null; - if (!script) { - script = document.createElement("script"); - script.id = `${id}_${index}`; - script.src = path; - script.defer = true; - document.head.append(script); - } + const script = document.createElement("script"); + script.id = `${id}_${index}`; + script.src = path; + script.defer = true; + document.head.append(script); }); }; From c5fda738637e133ee5b667ab3d7e20b99044380c Mon Sep 17 00:00:00 2001 From: namnguyen Date: Fri, 3 Jan 2025 16:30:21 +0700 Subject: [PATCH 3/7] not using Helmet for script --- .../src/components/pages/TaipyRendered.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx index 827e681721..e6a29d8070 100644 --- a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx +++ b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx @@ -110,7 +110,7 @@ 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); @@ -131,11 +131,20 @@ const TaipyRendered = (props: TaipyRenderedProps) => { return ( - {head.length ? ( - - {head.map((v, i) => React.createElement(v.tag, { key: `head${i}`, ...v.props }, v.content))} - - ) : null} + {head.length ? head.map((v, i) => { + if (v.tag === "script") { + const element = document.createElement(v.tag); + Object.entries(v.props).forEach(([key, value]) => element.setAttribute(key, value)); + element.innerHTML = v.content; + document.head.appendChild(element); + return null; + } + return ( + + {React.createElement(v.tag, { ...v.props }, v.content)} + + ); + }) : null} Date: Mon, 6 Jan 2025 16:26:04 +0700 Subject: [PATCH 4/7] remove the extra script --- .../src/components/pages/TaipyRendered.tsx | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx index e6a29d8070..111c33157f 100644 --- a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx +++ b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx @@ -129,22 +129,15 @@ const TaipyRendered = (props: TaipyRenderedProps) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [path, state.id, dispatch, partial, fromBlock, baseURL]); + console.log(head) + return ( - {head.length ? head.map((v, i) => { - if (v.tag === "script") { - const element = document.createElement(v.tag); - Object.entries(v.props).forEach(([key, value]) => element.setAttribute(key, value)); - element.innerHTML = v.content; - document.head.appendChild(element); - return null; - } - return ( - - {React.createElement(v.tag, { ...v.props }, v.content)} - - ); - }) : null} + {head.length ? ( + + {head.map((v, i) => React.createElement(v.tag, { key: `head${i}`, ...v.props }, v.content))} + + ) : null} Date: Mon, 6 Jan 2025 17:40:50 +0700 Subject: [PATCH 5/7] remove console.log --- frontend/taipy-gui/src/components/pages/TaipyRendered.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx index 111c33157f..e22b755f87 100644 --- a/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx +++ b/frontend/taipy-gui/src/components/pages/TaipyRendered.tsx @@ -129,8 +129,6 @@ const TaipyRendered = (props: TaipyRenderedProps) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [path, state.id, dispatch, partial, fromBlock, baseURL]); - console.log(head) - return ( {head.length ? ( From 676caa97bdc189e28a56261a7ec95581046b751b Mon Sep 17 00:00:00 2001 From: namnguyen Date: Thu, 9 Jan 2025 18:00:08 +0700 Subject: [PATCH 6/7] make private --- taipy/gui/page.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taipy/gui/page.py b/taipy/gui/page.py index 2400c693a2..e87984dc89 100644 --- a/taipy/gui/page.py +++ b/taipy/gui/page.py @@ -78,7 +78,7 @@ def __init__(self, **kwargs) -> None: 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)) + self._script_paths(kwargs.get("script_paths", None)) def create_page(self) -> t.Optional[Page]: """Create the page content for page modules. @@ -185,7 +185,7 @@ def set_style(self, style: t.Dict[str, t.Dict[str, t.Any]]) -> 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: + 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. From 2feaa55551f523a26972200291c582451167bec7 Mon Sep 17 00:00:00 2001 From: namnguyen Date: Fri, 10 Jan 2025 15:59:58 +0700 Subject: [PATCH 7/7] space after # --- taipy/gui/gui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taipy/gui/gui.py b/taipy/gui/gui.py index d745468218..b83b7b8aa8 100644 --- a/taipy/gui/gui.py +++ b/taipy/gui/gui.py @@ -2559,7 +2559,7 @@ def __render_page(self, page_name: str) -> t.Any: with self._set_locals_context(context): self._call_on_page_load(nav_page) return self._server._render( - 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 + 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)