Sfoglia il codice sorgente

add on page load (#1883) (#1884)

* add on page load

* fix lint

* per Fabien
Dinh Long Nguyen 7 mesi fa
parent
commit
cac0615020

+ 33 - 0
taipy/gui/gui.py

@@ -143,6 +143,15 @@ class Gui:
             The signature of the *on_init* callback function must be:
 
             - *state*: the `State^` instance of the caller.
+        on_page_load (Callable): This callback is invoked just before the page content is sent
+            to the front-end.<br/>
+            It defaults to the `on_page_load()` global function defined in the Python
+            application. If there is no such function, page loads will not trigger
+            anything.<br/>
+
+            The signature of the *on_page_load* callback function must be:
+            - *state*: the `State^` instance of the caller.
+            - *page_name*: the name of the page that is being loaded.
         on_navigate (Callable): The function that is called when a page is requested.<br/>
             It defaults to the `on_navigate()` global function defined in the Python
             application. If there is no such function, page requests will not trigger
@@ -329,6 +338,7 @@ class Gui:
         self.on_action: t.Optional[t.Callable] = None
         self.on_change: t.Optional[t.Callable] = None
         self.on_init: t.Optional[t.Callable] = None
+        self.on_page_load: t.Optional[t.Callable] = None
         self.on_navigate: t.Optional[t.Callable] = None
         self.on_exception: t.Optional[t.Callable] = None
         self.on_status: t.Optional[t.Callable] = None
@@ -2359,6 +2369,26 @@ class Gui:
                     _warn("Exception raised in on_navigate()", e)
         return nav_page
 
+    def _call_on_page_load(self, page_name: str) -> None:
+        if page_name == Gui.__root_page_name:
+            page_name = "/"
+        on_page_load_fn = self._get_user_function("on_page_load")
+        if not callable(on_page_load_fn):
+            return
+        try:
+            arg_count = on_page_load_fn.__code__.co_argcount
+            if arg_count > 0 and inspect.ismethod(on_page_load_fn):
+                arg_count -= 1
+            args: t.List[t.Any] = [None for _ in range(arg_count)]
+            if arg_count > 0:
+                args[0] = self.__get_state()
+            if arg_count > 1:
+                args[1] = page_name
+            on_page_load_fn(*args)
+        except Exception as e:
+            if not self._call_on_exception("on_page_load", e):
+                _warn("Exception raised in on_page_load()", e)
+
     def _get_page(self, page_name: str):
         return next((page_i for page_i in self._config.pages if page_i._route == page_name), None)
 
@@ -2415,6 +2445,8 @@ class Gui:
             page._rendered_jsx += "<PageContent />"
         # Return jsx page
         if page._rendered_jsx is not None:
+            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
             )
@@ -2562,6 +2594,7 @@ class Gui:
             self.__bind_local_func("on_init")
             self.__bind_local_func("on_change")
             self.__bind_local_func("on_action")
+            self.__bind_local_func("on_page_load")
             self.__bind_local_func("on_navigate")
             self.__bind_local_func("on_exception")
             self.__bind_local_func("on_status")

+ 10 - 0
tests/gui/e2e/page_scopes/assets6_page_load/__init__.py

@@ -0,0 +1,10 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.

+ 21 - 0
tests/gui/e2e/page_scopes/assets6_page_load/page1.py

@@ -0,0 +1,21 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+
+from taipy.gui import Markdown
+
+a = 10
+
+
+def on_page_load(state):
+    state.a = 20
+
+
+page = Markdown("<|{a}|id=text_a|>")

+ 53 - 0
tests/gui/e2e/page_scopes/test_page_load.py

@@ -0,0 +1,53 @@
+# Copyright 2021-2024 Avaiga Private Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+
+import inspect
+import logging
+from importlib import util
+
+import pytest
+
+from taipy.gui import Gui
+
+if util.find_spec("playwright"):
+    from playwright._impl._page import Page
+
+from .assets6_page_load.page1 import page as page1
+
+
+@pytest.mark.timeout(300)
+@pytest.mark.teste2e
+def test_page_scopes(page: "Page", gui: Gui, helpers):
+    gui._set_frame(inspect.currentframe())
+
+    x = 15  # noqa: F841
+
+    def on_page_load(state):
+        state.x = 30
+
+    gui.add_page(Gui._get_root_page_name(), "<|{x}|id=text_x|>")
+    gui.add_page("page1", page1)
+    helpers.run_e2e(gui)
+
+    page.goto("./page1")
+    page.expect_websocket()
+    page.wait_for_selector("#text_a")
+    function_evaluated = True
+    try:
+        page.wait_for_function("document.querySelector('#text_a').innerText !== '10'")
+        function_evaluated = True
+    except Exception as e:
+        function_evaluated = False
+        logging.getLogger().debug(f"Function evaluation timeout.\n{e}")
+    if not function_evaluated:
+        return
+    assert page.query_selector("#text_a").inner_text() == "20"
+    assert page.query_selector("#text_x").inner_text() == "30"