Pārlūkot izejas kodu

Merge branch 'main' into feature/anchorlinks

# Conflicts:
#	main.py
Falko Schindler 3 gadi atpakaļ
vecāks
revīzija
bf4380a0d7
5 mainītis faili ar 39 papildinājumiem un 8 dzēšanām
  1. 14 7
      main.py
  2. 5 1
      nicegui/elements/button.py
  3. 17 0
      nicegui/elements/open.py
  4. 2 0
      nicegui/events.py
  5. 1 0
      nicegui/ui.py

+ 14 - 7
main.py

@@ -3,11 +3,10 @@ from nicegui import ui
 from contextlib import contextmanager
 from contextlib import contextmanager
 import inspect
 import inspect
 import sys
 import sys
-from typing import Union
+from typing import Callable, Union
 import docutils.core
 import docutils.core
 import re
 import re
 import asyncio
 import asyncio
-from nicegui.elements.element import Element
 from nicegui.elements.html import Html
 from nicegui.elements.html import Html
 from nicegui.elements.markdown import Markdown
 from nicegui.elements.markdown import Markdown
 from nicegui.events import KeyEventArguments
 from nicegui.events import KeyEventArguments
@@ -17,7 +16,7 @@ from nicegui.globals import page_stack
 page_stack[0].head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
 page_stack[0].head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
 
 
 @contextmanager
 @contextmanager
-def example(content: Union[Element, str]):
+def example(content: Union[Callable, type, str]):
     callFrame = inspect.currentframe().f_back.f_back
     callFrame = inspect.currentframe().f_back.f_back
     begin = callFrame.f_lineno
     begin = callFrame.f_lineno
 
 
@@ -27,7 +26,7 @@ def example(content: Union[Element, str]):
         if not match:
         if not match:
             return
             return
 
 
-        headline_id = re.sub('[^(a-z)(A-Z)(0-9)._-]', '', match.groups()[0].strip())
+        headline_id = re.sub('[^(a-z)(A-Z)(0-9)-]', '_', match.groups()[0].strip())
         if not headline_id:
         if not headline_id:
             return
             return
 
 
@@ -41,7 +40,8 @@ def example(content: Union[Element, str]):
         if isinstance(content, str):
         if isinstance(content, str):
             add_html_anchor(ui.markdown(content).classes('mr-8 w-4/12'))
             add_html_anchor(ui.markdown(content).classes('mr-8 w-4/12'))
         else:
         else:
-            html = docutils.core.publish_parts(content.__init__.__doc__, writer_name='html')['html_body']
+            doc = content.__doc__ or content.__init__.__doc__
+            html = docutils.core.publish_parts(doc, writer_name='html')['html_body']
             html = html.replace('<p>', '<h3>', 1)
             html = html.replace('<p>', '<h3>', 1)
             html = html.replace('</p>', '</h3>', 1)
             html = html.replace('</p>', '</h3>', 1)
             html = Markdown.apply_tailwind(html)
             html = Markdown.apply_tailwind(html)
@@ -284,7 +284,7 @@ design = '''### Styling
 NiceGUI uses the [Quasar Framework](https://quasar.dev/) and hence has its full design power.
 NiceGUI uses the [Quasar Framework](https://quasar.dev/) and hence has its full design power.
 Each NiceGUI element provides a `props` method whose content is passed [to the Quasar component](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components):
 Each NiceGUI element provides a `props` method whose content is passed [to the Quasar component](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components):
 Have a look at [the Quasar documentation](https://quasar.dev/vue-components/button#design) for all styling props.
 Have a look at [the Quasar documentation](https://quasar.dev/vue-components/button#design) for all styling props.
-You can also apply [Tailwind](https://tailwindcss.com/) utility classes with the `classes` method. 
+You can also apply [Tailwind](https://tailwindcss.com/) utility classes with the `classes` method.
 
 
 If you really need to apply CSS, you can use the `styles` method. Here the delimiter is `;` instead of a blank space.
 If you really need to apply CSS, you can use the `styles` method. Here the delimiter is `;` instead of a blank space.
 
 
@@ -397,7 +397,7 @@ with example(ui.page):
 
 
 add_route = """### Route
 add_route = """### Route
 
 
-Add a new route by calling `ui.add_route` with a starlette route including a path and a function to be called. 
+Add a new route by calling `ui.add_route` with a starlette route including a path and a function to be called.
 Routed paths must start with a `'/'`.
 Routed paths must start with a `'/'`.
 """
 """
 with example(add_route):
 with example(add_route):
@@ -447,4 +447,11 @@ with example(ui.keyboard):
     ui.label('Key events can be caught globally by using the keyboard element.')
     ui.label('Key events can be caught globally by using the keyboard element.')
     ui.checkbox('Track key events').bind_value_to(keyboard, 'active')
     ui.checkbox('Track key events').bind_value_to(keyboard, 'active')
 
 
+with example(ui.open):
+    with ui.page('/yet_another_page') as other:
+        ui.label('Welcome to yet another page')
+        ui.button('RETURN', on_click=lambda e: ui.open('/', e.socket))
+
+    ui.button('REDIRECT', on_click=lambda e: ui.open('/yet_another_page', e.socket))
+
 ui.run(port=8080)
 ui.run(port=8080)

+ 5 - 1
nicegui/elements/button.py

@@ -25,7 +25,11 @@ class Button(Element):
         self.text = text
         self.text = text
         self.bind_text_to(self.view, 'label')
         self.bind_text_to(self.view, 'label')
 
 
-        view.on('click', lambda *_: handle_event(on_click, ClickEventArguments(sender=self), update=self.parent_view))
+        def process_event(view, event):
+            socket = event.get('websocket')
+            handle_event(on_click, ClickEventArguments(sender=self, socket=socket), update=self.parent_view)
+
+        view.on('click', process_event)
 
 
     def set_text(self, text: str):
     def set_text(self, text: str):
         self.text = text
         self.text = text

+ 17 - 0
nicegui/elements/open.py

@@ -0,0 +1,17 @@
+from starlette.websockets import WebSocket
+from ..task_logger import create_task
+
+
+def open(self, path: str, socket: WebSocket):
+    """
+    Open
+
+    Can be used to programmatically trigger redirects for a specific client.
+
+    :param path: string that is a relative url path or an absolute url
+    :param socket: WebSocket defining the target client
+    """
+    create_task(open_async(path, socket))
+
+async def open_async(path: str, socket: WebSocket):
+    await socket.send_json({'type': 'page_update', 'page_options': {'redirect': path}})

+ 2 - 0
nicegui/events.py

@@ -4,6 +4,7 @@ from justpy.htmlcomponents import HTMLBaseComponent
 from pydantic import BaseModel
 from pydantic import BaseModel
 import traceback
 import traceback
 from typing import Any, Awaitable, Callable, List, Optional, Union
 from typing import Any, Awaitable, Callable, List, Optional, Union
+from starlette.websockets import WebSocket
 
 
 from .elements.element import Element
 from .elements.element import Element
 from .task_logger import create_task
 from .task_logger import create_task
@@ -12,6 +13,7 @@ class EventArguments(BaseModel):
     class Config:
     class Config:
         arbitrary_types_allowed = True
         arbitrary_types_allowed = True
     sender: Element
     sender: Element
+    socket: Optional[WebSocket]
 
 
 class ClickEventArguments(EventArguments):
 class ClickEventArguments(EventArguments):
     pass
     pass

+ 1 - 0
nicegui/ui.py

@@ -20,6 +20,7 @@ class Ui:
     from .elements.menu_separator import MenuSeparator as menu_separator
     from .elements.menu_separator import MenuSeparator as menu_separator
     from .elements.notify import Notify as notify
     from .elements.notify import Notify as notify
     from .elements.number import Number as number
     from .elements.number import Number as number
+    from .elements.open import open, open_async
     from .elements.page import Page as page
     from .elements.page import Page as page
     from .elements.radio import Radio as radio
     from .elements.radio import Radio as radio
     from .elements.scene import Scene as scene
     from .elements.scene import Scene as scene