Browse Source

code review

Falko Schindler 2 years ago
parent
commit
711f01fbbb

+ 6 - 2
main.py

@@ -329,9 +329,13 @@ def documentation_page_more(name: str):
     if not hasattr(ui, name):
         name = name.replace('_', '')  # NOTE: "AG Grid" leads to anchor name "ag_grid", but class is `ui.aggrid`
     module = importlib.import_module(f'website.more_documentation.{name}_documentation')
-    api = getattr(ui, name)
     more = getattr(module, 'more', None)
-    back_link_target = str(api.__doc__ or api.__init__.__doc__).splitlines()[0].strip()
+    if hasattr(ui, name):
+        api = getattr(ui, name)
+        back_link_target = str(api.__doc__ or api.__init__.__doc__).splitlines()[0].strip()
+    else:
+        api = name
+        back_link_target = name
 
     add_head_html()
     add_header()

+ 4 - 0
website/demo.py

@@ -25,6 +25,10 @@ def demo(f: Callable) -> Callable:
         while not code[0].strip().startswith('def') and not code[0].strip().startswith('async def'):
             del code[0]
         del code[0]
+        if code[0].strip().startswith('"""'):
+            while code[0].strip() != '"""':
+                del code[0]
+            del code[0]
         indentation = len(code[0]) - len(code[0].lstrip())
         code = [line[indentation:] for line in code]
         code = ['from nicegui import ui'] + [remove_prefix(line, '# ') for line in code]

+ 1 - 2
website/documentation.py

@@ -316,8 +316,7 @@ def create_full() -> None:
 
     load_demo(ui.timer)
     load_demo(ui.keyboard)
-
-    load_documentation(ui.bindings)
+    load_demo('bindings')
 
     @text_demo('UI Updates', '''
         NiceGUI tries to automatically synchronize the state of UI elements with the client, e.g. when a label text, an input value or style/classes/props of an element have changed.

+ 6 - 3
website/documentation_tools.py

@@ -87,7 +87,10 @@ class intro_demo(text_demo):
 
 class element_demo:
 
-    def __init__(self, element_class: Union[Callable, type]) -> None:
+    def __init__(self, element_class: Union[Callable, type, str]) -> None:
+        if isinstance(element_class, str):
+            module = importlib.import_module(f'website.more_documentation.{element_class}_documentation')
+            element_class = getattr(module, 'main_demo')
         self.element_class = element_class
 
     def __call__(self, f: Callable, *, more_link: Optional[str] = None) -> Callable:
@@ -99,8 +102,8 @@ class element_demo:
             return demo(f)
 
 
-def load_demo(api: Union[type, Callable]) -> None:
-    name = pascal_to_snake(api.__name__)
+def load_demo(api: Union[type, Callable, str]) -> None:
+    name = pascal_to_snake(api if isinstance(api, str) else api.__name__)
     try:
         module = importlib.import_module(f'website.more_documentation.{name}_documentation')
     except ModuleNotFoundError:

+ 32 - 23
website/more_documentation/bindings_documentation.py

@@ -1,7 +1,17 @@
 from nicegui import ui
+
 from ..documentation_tools import text_demo
 
+
 def main_demo() -> None:
+    """Bindings
+
+    NiceGUI is able to directly bind UI elements to models.
+    Binding is possible for UI element properties like text, value or visibility and for model properties that are (nested) class attributes.
+    Each element provides methods like `bind_value` and `bind_visibility` to create a two-way binding with the corresponding property.
+    To define a one-way binding use the `_from` and `_to` variants of these methods.
+    Just pass a property of the model as parameter to these methods to create the binding.
+    """
     class Demo:
         def __init__(self):
             self.number = 1
@@ -13,33 +23,32 @@ def main_demo() -> None:
         ui.toggle({1: 'A', 2: 'B', 3: 'C'}).bind_value(demo, 'number')
         ui.number().bind_value(demo, 'number')
 
-def more() -> None:
-    @text_demo('Bind to dictionary')
-    def bind_dictionary():
-        dictionary = {'name': 'NiceGUI', 'age': 2}
 
-        with ui.grid(columns=2):
-            ui.label('Name:')
-            ui.label().bind_text_from(dictionary, 'name')
+date = '2023-01-01'
 
-            ui.label('Age:')
-            ui.label().bind_text_from(dictionary, 'age')
 
-        def nicegui_older():
-            dictionary['age'] += 1
+def more() -> None:
+    @text_demo('Bind to dictionary', '''
+        Here we are binding the text of labels to a dictionary.
+    ''')
+    def bind_dictionary():
+        data = {'name': 'Bob', 'age': 17}
 
-        ui.button('Make NiceGUI older!', on_click=nicegui_older)
+        ui.label().bind_text_from(data, 'name', backward=lambda n: f'Name: {n}')
+        ui.label().bind_text_from(data, 'age', backward=lambda a: f'Age: {a}')
 
-    @text_demo('Bind to variable', '''Here we are binding the value from the datepicker to a bare variable. [Using official datepicker example](https://nicegui.io/documentation/date#input_element_with_date_picker)''')
+        ui.button('Turn 18', on_click=lambda: data.update(age=18))
+
+    @text_demo('Bind to variable', '''
+        Here we are binding the value from the datepicker to a bare variable.
+        Therefore we use the dictionary `globals()` which contains all global variables.
+        This demo is based on the [official datepicker example](https://nicegui.io/documentation/date#input_element_with_date_picker).
+    ''')
     def bind_variable():
-        today_date = '1970-01-01'
-
-        def notify_date():
-            global today_date
-            ui.notify(f'Today is: {today_date}')
-            
-        with ui.input('Date') as date:
-            with date.add_slot('append'):
-                ui.icon('edit_calendar').on('click', lambda: menu.open()).classes('cursor-pointer')
+        # date = '2023-01-01'
+
+        with ui.input('Date').bind_value(globals(), 'date') as date_input:
             with ui.menu() as menu:
-                ui.date(on_change=notify_date).bind_value(date).bind_value(globals(), 'today_date')
+                ui.date(on_change=lambda: ui.notify(f'Date: {date}')).bind_value(date_input)
+            with date_input.add_slot('append'):
+                ui.icon('edit_calendar').on('click', menu.open).classes('cursor-pointer')