瀏覽代碼

remove JustPy, make hello-world working again

Falko Schindler 2 年之前
父節點
當前提交
f6194c03ec
共有 100 個文件被更改,包括 944 次插入3792 次删除
  1. 5 1
      nicegui.code-workspace
  2. 2 2
      nicegui/__init__.py
  3. 60 0
      nicegui/client.py
  4. 138 0
      nicegui/element.py
  5. 5 7
      nicegui/elements/column.py
  6. 13 9
      nicegui/elements/label.py
  7. 0 0
      nicegui/elements/old/badge.py
  8. 0 0
      nicegui/elements/old/bool_element.py
  9. 0 0
      nicegui/elements/old/button.py
  10. 0 0
      nicegui/elements/old/card.py
  11. 0 0
      nicegui/elements/old/chart.py
  12. 0 0
      nicegui/elements/old/checkbox.py
  13. 0 0
      nicegui/elements/old/choice_element.py
  14. 0 0
      nicegui/elements/old/color_input.py
  15. 0 0
      nicegui/elements/old/color_picker.py
  16. 0 0
      nicegui/elements/old/colors.js
  17. 0 0
      nicegui/elements/old/colors.py
  18. 0 0
      nicegui/elements/old/custom_view.py
  19. 0 0
      nicegui/elements/old/dialog.py
  20. 0 0
      nicegui/elements/old/expansion.py
  21. 0 0
      nicegui/elements/old/float_element.py
  22. 0 0
      nicegui/elements/old/group.py
  23. 0 0
      nicegui/elements/old/html.py
  24. 0 0
      nicegui/elements/old/icon.py
  25. 0 0
      nicegui/elements/old/image.py
  26. 0 0
      nicegui/elements/old/input.py
  27. 0 0
      nicegui/elements/old/interactive_image.js
  28. 0 0
      nicegui/elements/old/interactive_image.py
  29. 0 0
      nicegui/elements/old/joystick.js
  30. 0 0
      nicegui/elements/old/joystick.py
  31. 0 0
      nicegui/elements/old/keyboard.js
  32. 0 0
      nicegui/elements/old/keyboard.py
  33. 0 0
      nicegui/elements/old/line_plot.py
  34. 0 0
      nicegui/elements/old/link.py
  35. 0 0
      nicegui/elements/old/log.js
  36. 0 0
      nicegui/elements/old/log.py
  37. 0 0
      nicegui/elements/old/markdown.py
  38. 0 0
      nicegui/elements/old/menu.py
  39. 0 0
      nicegui/elements/old/menu_item.py
  40. 0 0
      nicegui/elements/old/menu_separator.py
  41. 0 0
      nicegui/elements/old/number.py
  42. 0 0
      nicegui/elements/old/open.py
  43. 0 0
      nicegui/elements/old/plot.py
  44. 0 0
      nicegui/elements/old/progress.py
  45. 0 0
      nicegui/elements/old/radio.py
  46. 0 0
      nicegui/elements/old/scene.js
  47. 0 0
      nicegui/elements/old/scene.py
  48. 0 0
      nicegui/elements/old/scene_object3d.py
  49. 0 0
      nicegui/elements/old/scene_objects.py
  50. 0 0
      nicegui/elements/old/select.py
  51. 0 0
      nicegui/elements/old/slider.py
  52. 0 0
      nicegui/elements/old/string_element.py
  53. 0 0
      nicegui/elements/old/switch.py
  54. 0 0
      nicegui/elements/old/table.py
  55. 0 0
      nicegui/elements/old/toggle.py
  56. 0 0
      nicegui/elements/old/tree.py
  57. 0 0
      nicegui/elements/old/upload.py
  58. 0 0
      nicegui/elements/old/value_element.py
  59. 5 7
      nicegui/elements/row.py
  60. 10 0
      nicegui/event.py
  61. 9 36
      nicegui/globals.py
  62. 1 1
      nicegui/helpers.py
  63. 35 51
      nicegui/nicegui.py
  64. 10 0
      nicegui/notify.py
  65. 0 0
      nicegui/old/element.py
  66. 45 0
      nicegui/old/globals.py
  67. 66 0
      nicegui/old/nicegui.py
  68. 0 0
      nicegui/old/notify.py
  69. 332 0
      nicegui/old/page.py
  70. 89 0
      nicegui/old/run.py
  71. 63 0
      nicegui/old/ui.py
  72. 32 316
      nicegui/page.py
  73. 3 77
      nicegui/run.py
  74. 21 0
      nicegui/slot.py
  75. 0 4
      nicegui/static/copy_justpy_templates.sh
  76. 0 0
      nicegui/static/templates/__init__.py
  77. 0 120
      nicegui/static/templates/css/form.css
  78. 0 6
      nicegui/static/templates/favicon.html
  79. 0 68
      nicegui/static/templates/highcharts.html
  80. 0 36
      nicegui/static/templates/highcharts/avocado.js
  81. 0 258
      nicegui/static/templates/highcharts/dark-blue.js
  82. 0 260
      nicegui/static/templates/highcharts/dark-green.js
  83. 0 217
      nicegui/static/templates/highcharts/dark-unica.js
  84. 0 266
      nicegui/static/templates/highcharts/gray.js
  85. 0 77
      nicegui/static/templates/highcharts/grid-light.js
  86. 0 109
      nicegui/static/templates/highcharts/grid.js
  87. 0 207
      nicegui/static/templates/highcharts/high-contrast-dark.js
  88. 0 37
      nicegui/static/templates/highcharts/high-contrast-light.js
  89. 0 108
      nicegui/static/templates/highcharts/sand-signika.js
  90. 0 107
      nicegui/static/templates/highcharts/skies.js
  91. 0 141
      nicegui/static/templates/highcharts/slick.js
  92. 0 34
      nicegui/static/templates/highcharts/sunset.js
  93. 0 152
      nicegui/static/templates/js/aggrid.js
  94. 0 34
      nicegui/static/templates/js/altairjp.js
  95. 0 36
      nicegui/static/templates/js/bokehjp.js
  96. 0 356
      nicegui/static/templates/js/chartjp.js
  97. 0 48
      nicegui/static/templates/js/deckgl.js
  98. 0 90
      nicegui/static/templates/js/editorjp.js
  99. 0 177
      nicegui/static/templates/js/event_handler.js
  100. 0 337
      nicegui/static/templates/js/html_component.js

+ 5 - 1
nicegui.code-workspace

@@ -4,7 +4,11 @@
       "path": "."
     }
   ],
-  "settings": {},
+  "settings": {
+    "files.associations": {
+      "*.html": "jinja-html"
+    }
+  },
   "extensions": {
     "recommendations": [
       "ms-python.vscode-pylance",

+ 2 - 2
nicegui/__init__.py

@@ -1,2 +1,2 @@
-from nicegui import elements
-from nicegui.nicegui import app, ui
+from . import elements, globals, ui
+from .nicegui import app

+ 60 - 0
nicegui/client.py

@@ -0,0 +1,60 @@
+import asyncio
+import json
+import time
+from pathlib import Path
+from typing import Any, Dict, List, Optional
+
+from fastapi.responses import HTMLResponse
+
+from . import globals, ui, vue
+from .element import Element
+from .slot import Slot
+
+TEMPLATE = (Path(__file__).parent / 'templates' / 'index.html').read_text()
+
+
+class Client:
+
+    def __init__(self) -> None:
+        self.id = globals.next_client_id
+        globals.next_client_id += 1
+        globals.clients[self.id] = self
+
+        self.elements: Dict[str, Element] = {}
+        self.next_element_id: int = 0
+        self.slot_stack: List[Slot] = []
+        self.is_waiting_for_handshake: bool = False
+        self.environ: Optional[Dict[str, Any]] = None
+
+        globals.client_stack.append(self)
+        self.content = ui.column().classes('q-ma-md')
+        globals.client_stack.pop()
+
+    def __enter__(self):
+        globals.client_stack.append(self)
+        self.content.__enter__()
+        return self
+
+    def __exit__(self, *_):
+        self.content.__exit__()
+        globals.client_stack.pop()
+
+    def build_response(self) -> HTMLResponse:
+        vue_html, vue_styles, vue_scripts = vue.generate_vue_content()
+        elements = json.dumps({id: element.to_dict() for id, element in self.elements.items()})
+        return HTMLResponse(TEMPLATE
+                            .replace(r'{{ client_id }}', str(self.id))
+                            .replace(r'{{ elements | safe }}', elements)
+                            .replace(r'{{ vue_html | safe }}', vue_html)
+                            .replace(r'{{ vue_styles | safe }}', vue_styles)
+                            .replace(r'{{ vue_scripts | safe }}', vue_scripts)
+                            .replace(r'{{ js_imports | safe }}', vue.generate_js_imports()))
+
+    async def handshake(self, timeout: float = 3.0, check_interval: float = 0.1) -> None:
+        self.is_waiting_for_handshake = True
+        deadline = time.time() + timeout
+        while not self.environ:
+            if time.time() > deadline:
+                raise TimeoutError(f'No handshake after {timeout} seconds')
+            await asyncio.sleep(check_interval)
+        self.is_waiting_for_handshake = False

+ 138 - 0
nicegui/element.py

@@ -0,0 +1,138 @@
+import shlex
+from abc import ABC
+from typing import Callable, Dict, List, Optional
+
+from . import globals
+from .event import Event
+from .slot import Slot
+from .task_logger import create_task
+
+
+class Element(ABC):
+
+    def __init__(self, tag: str) -> None:
+        client = globals.client_stack[-1]
+        self.id = client.next_element_id
+        client.next_element_id += 1
+        self.tag = tag
+        self._classes: List[str] = []
+        self._style: Dict[str, str] = {}
+        self._props: Dict[str, str] = {}
+        self._events: List[Event] = []
+        self.content: str = ''
+        self.slots: Dict[str, Slot] = {}
+        self.default_slot = self.add_slot('default')
+
+        client.elements[self.id] = self
+        if client.slot_stack:
+            client.slot_stack[-1].children.append(self)
+
+    def add_slot(self, name: str) -> Slot:
+        self.slots[name] = Slot(self, name)
+        return self.slots[name]
+
+    def __enter__(self):
+        globals.client_stack[-1].slot_stack.append(self.default_slot)
+        return self
+
+    def __exit__(self, *_):
+        globals.client_stack[-1].slot_stack.pop()
+
+    def to_dict(self) -> Dict:
+        events: Dict[str, List[str]] = {}
+        for event in self._events:
+            events[event.type] = events.get(event.type, []) + event.args
+        return {
+            'id': self.id,
+            'tag': self.tag,
+            'class': self._classes,
+            'style': self._style,
+            'props': self._props,
+            'events': events,
+            'content': self.content,
+            'slots': {name: [child.id for child in slot.children] for name, slot in self.slots.items()},
+        }
+
+    def classes(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None):
+        '''HTML classes to modify the look of the element.
+        Every class in the `remove` parameter will be removed from the element.
+        Classes are separated with a blank space.
+        This can be helpful if the predefined classes by NiceGUI are not wanted in a particular styling.
+        '''
+        class_list = self._classes if replace is None else []
+        class_list = [c for c in class_list if c not in (remove or '').split()]
+        class_list += (add or '').split()
+        class_list += (replace or '').split()
+        new_classes = list(dict.fromkeys(class_list))  # NOTE: remove duplicates while preserving order
+        if self._classes != new_classes:
+            self._classes = new_classes
+            self.update()
+        return self
+
+    def style(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None):
+        '''CSS style sheet definitions to modify the look of the element.
+        Every style in the `remove` parameter will be removed from the element.
+        Styles are separated with a semicolon.
+        This can be helpful if the predefined style sheet definitions by NiceGUI are not wanted in a particular styling.
+        '''
+        def parse_style(text: Optional[str]) -> Dict[str, str]:
+            return dict((word.strip() for word in part.split(':')) for part in text.strip('; ').split(';')) if text else {}
+        style_dict = self._style if replace is None else {}
+        for key in parse_style(remove):
+            del style_dict[key]
+        style_dict.update(parse_style(add))
+        style_dict.update(parse_style(replace))
+        if self._style != style_dict:
+            self._style = style_dict
+            self.update()
+        return self
+
+    def props(self, add: Optional[str] = None, *, remove: Optional[str] = None):
+        '''Quasar props https://quasar.dev/vue-components/button#design to modify the look of the element.
+        Boolean props will automatically activated if they appear in the list of the `add` property.
+        Props are separated with a blank space. String values must be quoted.
+        Every prop passed to the `remove` parameter will be removed from the element.
+        This can be helpful if the predefined props by NiceGUI are not wanted in a particular styling.
+        '''
+        def parse_props(text: Optional[str]) -> Dict[str, str]:
+            if not text:
+                return {}
+            lexer = shlex.shlex(text, posix=True)
+            lexer.whitespace = ' '
+            lexer.wordchars += '=-.%'
+            return dict(word.split('=', 1) if '=' in word else (word, True) for word in lexer)
+        needs_update = False
+        for key in parse_props(remove):
+            if key in self._props:
+                needs_update = True
+                del self._props[key]
+        for key, value in parse_props(add).items():
+            if self._props.get(key) != value:
+                needs_update = True
+                self._props[key] = value
+        if needs_update:
+            self.update()
+        return self
+
+    def on(self, type: str, handler: Callable, args: List[str] = []):
+        self._events.append(Event(element_id=self.id, type=type, args=args, handler=handler))
+        return self
+
+    def handle_event(self, msg: Dict) -> None:
+        for event in self._events:
+            if event.type == msg['type']:
+                event.handler(msg)
+
+    def update(self) -> str:
+        if not globals.loop:
+            return
+        ids: List[int] = []
+
+        def collect_ids(id: str):
+            for slot in globals.client_stack[-1].elements[id].slots.values():
+                for child in slot.children:
+                    collect_ids(child.id)
+            ids.append(id)
+        collect_ids(self.id)
+        elements = {id: globals.client_stack[-1].elements[id].to_dict() for id in ids}
+        create_task(globals.sio.emit('update', {'elements': elements}, room=str(globals.client_stack[-1].id)))

+ 5 - 7
nicegui/elements/column.py

@@ -1,14 +1,12 @@
-import justpy as jp
+from ..element import Element
 
-from .group import Group
 
+class Column(Element):
 
-class Column(Group):
-
-    def __init__(self):
+    def __init__(self) -> None:
         '''Column Element
 
         Provides a container which arranges its child in a row.
         '''
-        view = jp.QDiv(classes='column items-start gap-4', delete_flag=False, temp=False)
-        super().__init__(view)
+        super().__init__('div')
+        self.classes('column items-start gap-4')

+ 13 - 9
nicegui/elements/label.py

@@ -1,24 +1,28 @@
-import justpy as jp
-
 from ..binding import BindableProperty, BindTextMixin
-from .element import Element
+from ..element import Element
 
 
 class Label(Element, BindTextMixin):
     text = BindableProperty()
 
-    def __init__(self, text: str = ''):
+    def __init__(self, text: str = '') -> None:
         """Label
 
         Displays some text.
 
         :param text: the content of the label
         """
-        view = jp.Div(text=text, temp=False)
-        super().__init__(view)
-
+        super().__init__('div')
         self.text = text
-        self.bind_text_to(self.view, 'text')
 
-    def set_text(self, text: str):
+    @property
+    def text(self) -> str:
+        return self.content
+
+    @text.setter
+    def text(self, value: str) -> None:
+        self.content = value
+        self.update()
+
+    def set_text(self, text: str) -> None:
         self.text = text

+ 0 - 0
nicegui/elements/badge.py → nicegui/elements/old/badge.py


+ 0 - 0
nicegui/elements/bool_element.py → nicegui/elements/old/bool_element.py


+ 0 - 0
nicegui/elements/button.py → nicegui/elements/old/button.py


+ 0 - 0
nicegui/elements/card.py → nicegui/elements/old/card.py


+ 0 - 0
nicegui/elements/chart.py → nicegui/elements/old/chart.py


+ 0 - 0
nicegui/elements/checkbox.py → nicegui/elements/old/checkbox.py


+ 0 - 0
nicegui/elements/choice_element.py → nicegui/elements/old/choice_element.py


+ 0 - 0
nicegui/elements/color_input.py → nicegui/elements/old/color_input.py


+ 0 - 0
nicegui/elements/color_picker.py → nicegui/elements/old/color_picker.py


+ 0 - 0
nicegui/elements/colors.js → nicegui/elements/old/colors.js


+ 0 - 0
nicegui/elements/colors.py → nicegui/elements/old/colors.py


+ 0 - 0
nicegui/elements/custom_view.py → nicegui/elements/old/custom_view.py


+ 0 - 0
nicegui/elements/dialog.py → nicegui/elements/old/dialog.py


+ 0 - 0
nicegui/elements/expansion.py → nicegui/elements/old/expansion.py


+ 0 - 0
nicegui/elements/float_element.py → nicegui/elements/old/float_element.py


+ 0 - 0
nicegui/elements/group.py → nicegui/elements/old/group.py


+ 0 - 0
nicegui/elements/html.py → nicegui/elements/old/html.py


+ 0 - 0
nicegui/elements/icon.py → nicegui/elements/old/icon.py


+ 0 - 0
nicegui/elements/image.py → nicegui/elements/old/image.py


+ 0 - 0
nicegui/elements/input.py → nicegui/elements/old/input.py


+ 0 - 0
nicegui/elements/interactive_image.js → nicegui/elements/old/interactive_image.js


+ 0 - 0
nicegui/elements/interactive_image.py → nicegui/elements/old/interactive_image.py


+ 0 - 0
nicegui/elements/joystick.js → nicegui/elements/old/joystick.js


+ 0 - 0
nicegui/elements/joystick.py → nicegui/elements/old/joystick.py


+ 0 - 0
nicegui/elements/keyboard.js → nicegui/elements/old/keyboard.js


+ 0 - 0
nicegui/elements/keyboard.py → nicegui/elements/old/keyboard.py


+ 0 - 0
nicegui/elements/line_plot.py → nicegui/elements/old/line_plot.py


+ 0 - 0
nicegui/elements/link.py → nicegui/elements/old/link.py


+ 0 - 0
nicegui/elements/log.js → nicegui/elements/old/log.js


+ 0 - 0
nicegui/elements/log.py → nicegui/elements/old/log.py


+ 0 - 0
nicegui/elements/markdown.py → nicegui/elements/old/markdown.py


+ 0 - 0
nicegui/elements/menu.py → nicegui/elements/old/menu.py


+ 0 - 0
nicegui/elements/menu_item.py → nicegui/elements/old/menu_item.py


+ 0 - 0
nicegui/elements/menu_separator.py → nicegui/elements/old/menu_separator.py


+ 0 - 0
nicegui/elements/number.py → nicegui/elements/old/number.py


+ 0 - 0
nicegui/elements/open.py → nicegui/elements/old/open.py


+ 0 - 0
nicegui/elements/plot.py → nicegui/elements/old/plot.py


+ 0 - 0
nicegui/elements/progress.py → nicegui/elements/old/progress.py


+ 0 - 0
nicegui/elements/radio.py → nicegui/elements/old/radio.py


+ 0 - 0
nicegui/elements/scene.js → nicegui/elements/old/scene.js


+ 0 - 0
nicegui/elements/scene.py → nicegui/elements/old/scene.py


+ 0 - 0
nicegui/elements/scene_object3d.py → nicegui/elements/old/scene_object3d.py


+ 0 - 0
nicegui/elements/scene_objects.py → nicegui/elements/old/scene_objects.py


+ 0 - 0
nicegui/elements/select.py → nicegui/elements/old/select.py


+ 0 - 0
nicegui/elements/slider.py → nicegui/elements/old/slider.py


+ 0 - 0
nicegui/elements/string_element.py → nicegui/elements/old/string_element.py


+ 0 - 0
nicegui/elements/switch.py → nicegui/elements/old/switch.py


+ 0 - 0
nicegui/elements/table.py → nicegui/elements/old/table.py


+ 0 - 0
nicegui/elements/toggle.py → nicegui/elements/old/toggle.py


+ 0 - 0
nicegui/elements/tree.py → nicegui/elements/old/tree.py


+ 0 - 0
nicegui/elements/upload.py → nicegui/elements/old/upload.py


+ 0 - 0
nicegui/elements/value_element.py → nicegui/elements/old/value_element.py


+ 5 - 7
nicegui/elements/row.py

@@ -1,14 +1,12 @@
-import justpy as jp
+from ..element import Element
 
-from .group import Group
 
+class Row(Element):
 
-class Row(Group):
-
-    def __init__(self):
+    def __init__(self) -> None:
         '''Row Element
 
         Provides a container which arranges its child in a row.
         '''
-        view = jp.QDiv(classes='row items-start gap-4', delete_flag=False, temp=False)
-        super().__init__(view)
+        super().__init__('div')
+        self.classes('row items-start gap-4')

+ 10 - 0
nicegui/event.py

@@ -0,0 +1,10 @@
+from dataclasses import dataclass
+from typing import Callable, List
+
+
+@dataclass
+class Event:
+    element_id: str
+    type: str
+    args: List[str]
+    handler: Callable

+ 9 - 36
nicegui/globals.py

@@ -1,45 +1,18 @@
-from __future__ import annotations
-
 import asyncio
 import logging
-from enum import Enum
-from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Union
-
-from starlette.applications import Starlette
-from uvicorn import Server
+from typing import TYPE_CHECKING, Dict, List, Optional
 
-from .config import Config
+from fastapi import FastAPI
+from socketio import AsyncServer
 
 if TYPE_CHECKING:
-    import justpy as jp
-
-    from .page_builder import PageBuilder
-
+    from .client import Client
 
-class State(Enum):
-    STOPPED = 0
-    STARTING = 1
-    STARTED = 2
-    STOPPING = 3
-
-
-app: Starlette
-config: Optional[Config] = None
-server: Optional[Server] = None
-state: State = State.STOPPED
+app: FastAPI
+sio: AsyncServer
 loop: Optional[asyncio.AbstractEventLoop] = None
-page_builders: Dict[str, 'PageBuilder'] = {}
-view_stacks: Dict[int, List['jp.HTMLBaseComponent']] = {}
-tasks: List[asyncio.tasks.Task] = []
 log: logging.Logger = logging.getLogger('nicegui')
-connect_handlers: List[Union[Callable, Awaitable]] = []
-disconnect_handlers: List[Union[Callable, Awaitable]] = []
-startup_handlers: List[Union[Callable, Awaitable]] = []
-shutdown_handlers: List[Union[Callable, Awaitable]] = []
-
 
-def find_route(function: Callable) -> str:
-    routes = [route for route, page_builder in page_builders.items() if page_builder.function == function]
-    if not routes:
-        raise ValueError(f'Invalid page function {function}')
-    return routes[0]
+client_stack: List['Client'] = []
+clients: Dict[int, 'Client'] = {}
+next_client_id: int = 0

+ 1 - 1
nicegui/helpers.py

@@ -5,7 +5,7 @@ import time
 from typing import Any
 
 
-def measure(*, reset: bool = False, ms: bool = False):
+def measure(*, reset: bool = False, ms: bool = False) -> None:
     global t
     if 't' in globals() and not reset:
         dt = time.time() - t

+ 35 - 51
nicegui/nicegui.py

@@ -1,66 +1,50 @@
-# isort:skip_file
 import asyncio
-from typing import Awaitable, Callable
+import urllib.parse
+from typing import Dict
 
-if True:  # NOTE: prevent formatter from mixing up these lines
-    import builtins
-    print_backup = builtins.print
-    builtins.print = lambda *args, **kwargs: kwargs.get('flush') and print_backup(*args, **kwargs)
-    from .ui import Ui  # NOTE: before justpy
-    import justpy as jp
-    builtins.print = print_backup
+from fastapi import FastAPI
+from fastapi.middleware.gzip import GZipMiddleware
+from fastapi_socketio import SocketManager
 
-from . import binding, globals
-from .page import create_favicon_routes, create_page_routes, init_auto_index_page
-from .task_logger import create_task
-from .routes import create_exclude_routes
-from .timer import Timer
+from . import globals, vue
+from .client import Client
 
-jp.app.router.on_startup.clear()  # NOTE: remove JustPy's original startup function
+globals.app = app = FastAPI(routes=vue.generate_js_routes())
+globals.sio = sio = SocketManager(app=app)._sio
 
+app.add_middleware(GZipMiddleware)
 
-@jp.app.on_event('startup')
-async def patched_justpy_startup():
-    jp.WebPage.loop = jp.asyncio.get_event_loop()
-    jp.JustPy.loop = jp.WebPage.loop
-    jp.JustPy.STATIC_DIRECTORY = jp.os.environ["STATIC_DIRECTORY"]
-    print(f'NiceGUI ready to go on {"https" if jp.SSL_KEYFILE else "http"}://{jp.HOST}:{jp.PORT}')
+Client().__enter__()
 
 
-@jp.app.on_event('startup')
-def startup():
-    globals.state = globals.State.STARTING
+@app.get('/')
+def index():
+    return globals.client_stack[-1].build_response()
+
+
+@app.on_event('startup')
+def on_startup() -> None:
     globals.loop = asyncio.get_running_loop()
-    init_auto_index_page()
-    create_page_routes()
-    create_favicon_routes()
-    create_exclude_routes()
-    globals.tasks.extend(create_task(t.coro, name=t.name) for t in Timer.prepared_coroutines)
-    Timer.prepared_coroutines.clear()
-    globals.tasks.extend(create_task(t, name='startup task')
-                         for t in globals.startup_handlers if isinstance(t, Awaitable))
-    [safe_invoke(t) for t in globals.startup_handlers if isinstance(t, Callable)]
-    jp.run_task(binding.loop())
-    globals.state = globals.State.STARTED
 
 
-@jp.app.on_event('shutdown')
-def shutdown():
-    globals.state = globals.State.STOPPING
-    [create_task(t, name='shutdown task') for t in globals.shutdown_handlers if isinstance(t, Awaitable)]
-    [safe_invoke(t) for t in globals.shutdown_handlers if isinstance(t, Callable)]
-    [t.cancel() for t in globals.tasks]
-    globals.state = globals.State.STOPPED
+@sio.on('connect')
+async def handle_connect(sid: str, _) -> None:
+    client = get_client(sid)
+    client.environ = sio.get_environ(sid)
+    sio.enter_room(sid, str(client.id))
 
 
-def safe_invoke(func: Callable):
-    try:
-        result = func()
-        if isinstance(result, Awaitable):
-            create_task(result)
-    except:
-        globals.log.exception(f'could not invoke {func}')
+@sio.on('event')
+def handle_event(sid: str, msg: Dict) -> None:
+    client = get_client(sid)
+    with client:
+        sender = client.elements.get(msg['id'])
+        if sender:
+            sender.handle_event(msg)
 
 
-app = globals.app = jp.app
-ui = Ui()
+def get_client(sid: str) -> Client:
+    query_bytes: bytearray = sio.get_environ(sid)['asgi.scope']['query_string']
+    query = urllib.parse.parse_qs(query_bytes.decode())
+    client_id = int(query['client_id'][0])
+    return globals.clients[client_id]

+ 10 - 0
nicegui/notify.py

@@ -0,0 +1,10 @@
+from . import globals
+from .task_logger import create_task
+
+
+def notify(message: str, *,
+           type: str = '',
+           color: str = '',
+           ) -> None:
+    options = {key: value for key, value in locals().items() if not key.startswith('_')}
+    create_task(globals.sio.emit('notify', options, room=str(globals.client_stack[-1].id)))

+ 0 - 0
nicegui/elements/element.py → nicegui/old/element.py


+ 45 - 0
nicegui/old/globals.py

@@ -0,0 +1,45 @@
+from __future__ import annotations
+
+import asyncio
+import logging
+from enum import Enum
+from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Union
+
+from starlette.applications import Starlette
+from uvicorn import Server
+
+from .config import Config
+
+if TYPE_CHECKING:
+    import justpy as jp
+
+    from .page_builder import PageBuilder
+
+
+class State(Enum):
+    STOPPED = 0
+    STARTING = 1
+    STARTED = 2
+    STOPPING = 3
+
+
+app: Starlette
+config: Optional[Config] = None
+server: Optional[Server] = None
+state: State = State.STOPPED
+loop: Optional[asyncio.AbstractEventLoop] = None
+page_builders: Dict[str, 'PageBuilder'] = {}
+view_stacks: Dict[int, List['jp.HTMLBaseComponent']] = {}
+tasks: List[asyncio.tasks.Task] = []
+log: logging.Logger = logging.getLogger('nicegui')
+connect_handlers: List[Union[Callable, Awaitable]] = []
+disconnect_handlers: List[Union[Callable, Awaitable]] = []
+startup_handlers: List[Union[Callable, Awaitable]] = []
+shutdown_handlers: List[Union[Callable, Awaitable]] = []
+
+
+def find_route(function: Callable) -> str:
+    routes = [route for route, page_builder in page_builders.items() if page_builder.function == function]
+    if not routes:
+        raise ValueError(f'Invalid page function {function}')
+    return routes[0]

+ 66 - 0
nicegui/old/nicegui.py

@@ -0,0 +1,66 @@
+# isort:skip_file
+import asyncio
+from typing import Awaitable, Callable
+
+if True:  # NOTE: prevent formatter from mixing up these lines
+    import builtins
+    print_backup = builtins.print
+    builtins.print = lambda *args, **kwargs: kwargs.get('flush') and print_backup(*args, **kwargs)
+    from .ui import Ui  # NOTE: before justpy
+    import justpy as jp
+    builtins.print = print_backup
+
+from . import binding, globals
+from .page import create_favicon_routes, create_page_routes, init_auto_index_page
+from .task_logger import create_task
+from .routes import create_exclude_routes
+from .timer import Timer
+
+jp.app.router.on_startup.clear()  # NOTE: remove JustPy's original startup function
+
+
+@jp.app.on_event('startup')
+async def patched_justpy_startup():
+    jp.WebPage.loop = jp.asyncio.get_event_loop()
+    jp.JustPy.loop = jp.WebPage.loop
+    jp.JustPy.STATIC_DIRECTORY = jp.os.environ["STATIC_DIRECTORY"]
+    print(f'NiceGUI ready to go on {"https" if jp.SSL_KEYFILE else "http"}://{jp.HOST}:{jp.PORT}')
+
+
+@jp.app.on_event('startup')
+def startup():
+    globals.state = globals.State.STARTING
+    globals.loop = asyncio.get_running_loop()
+    init_auto_index_page()
+    create_page_routes()
+    create_favicon_routes()
+    create_exclude_routes()
+    globals.tasks.extend(create_task(t.coro, name=t.name) for t in Timer.prepared_coroutines)
+    Timer.prepared_coroutines.clear()
+    globals.tasks.extend(create_task(t, name='startup task')
+                         for t in globals.startup_handlers if isinstance(t, Awaitable))
+    [safe_invoke(t) for t in globals.startup_handlers if isinstance(t, Callable)]
+    jp.run_task(binding.loop())
+    globals.state = globals.State.STARTED
+
+
+@jp.app.on_event('shutdown')
+def shutdown():
+    globals.state = globals.State.STOPPING
+    [create_task(t, name='shutdown task') for t in globals.shutdown_handlers if isinstance(t, Awaitable)]
+    [safe_invoke(t) for t in globals.shutdown_handlers if isinstance(t, Callable)]
+    [t.cancel() for t in globals.tasks]
+    globals.state = globals.State.STOPPED
+
+
+def safe_invoke(func: Callable):
+    try:
+        result = func()
+        if isinstance(result, Awaitable):
+            create_task(result)
+    except:
+        globals.log.exception(f'could not invoke {func}')
+
+
+app = globals.app = jp.app
+ui = Ui()

+ 0 - 0
nicegui/elements/notify.py → nicegui/old/notify.py


+ 332 - 0
nicegui/old/page.py

@@ -0,0 +1,332 @@
+from __future__ import annotations
+
+import asyncio
+import inspect
+import time
+import types
+import uuid
+from functools import wraps
+from typing import Callable, Dict, Generator, List, Optional
+
+import justpy as jp
+from addict import Dict as AdDict
+from pygments.formatters import HtmlFormatter
+from starlette.requests import Request
+from starlette.responses import FileResponse
+from starlette.routing import Route, compile_path
+from starlette.websockets import WebSocket
+
+from . import globals
+from .auto_context import Context, get_view_stack
+from .events import PageEvent
+from .helpers import is_coroutine
+from .page_builder import PageBuilder
+from .routes import add_route, convert_arguments
+
+
+class Page(jp.QuasarPage):
+
+    def __init__(self,
+                 title: Optional[str] = None,
+                 *,
+                 favicon: Optional[str] = None,
+                 dark: Optional[bool] = ...,
+                 classes: str = 'q-pa-md column items-start gap-4',
+                 css: str = HtmlFormatter().get_style_defs('.codehilite'),
+                 on_connect: Optional[Callable] = None,
+                 on_page_ready: Optional[Callable] = None,
+                 on_disconnect: Optional[Callable] = None,
+                 shared: bool = False,
+                 ) -> None:
+        super().__init__()
+
+        if globals.config:
+            self.title = title or globals.config.title
+            self.set_favicon(favicon or globals.config.favicon)
+            self.dark = dark if dark is not ... else globals.config.dark
+        else:
+            self.title = title
+            self.set_favicon(favicon)
+            self.dark = dark if dark is not ... else None
+        self.tailwind = True  # use Tailwind classes instead of Quasars
+        self.css = css
+        self.connect_handler = on_connect
+        self.page_ready_handler = on_page_ready
+        self.page_ready_generator: Optional[Generator[None, PageEvent, None]] = None
+        self.disconnect_handler = on_disconnect
+        self.shared = shared
+        self.delete_flag = not shared
+
+        self.waiting_javascript_commands: Dict[str, str] = {}
+        self.on('result_ready', self.handle_javascript_result)
+        self.on('page_ready', self.handle_page_ready)
+
+        self.layout = jp.QLayout(a=self, view='HHH LpR FFF', temp=False)
+        container = jp.QPageContainer(a=self.layout, temp=False)
+        self.view = jp.Div(a=container, classes=classes, temp=False)
+        self.view.add_page(self)
+
+    def set_favicon(self, favicon: Optional[str]) -> None:
+        if not favicon:
+            self.favicon = 'favicon.ico'
+        elif favicon.startswith('http://') or favicon.startswith('https://'):
+            self.favicon = favicon
+        else:
+            self.favicon = f'_favicon/{favicon}'
+
+    async def _route_function(self, request: Request) -> Page:
+        with Context(self.view):
+            for handler in globals.connect_handlers + ([self.connect_handler] if self.connect_handler else []):
+                arg_count = len(inspect.signature(handler).parameters)
+                is_coro = is_coroutine(handler)
+                if arg_count == 1:
+                    await handler(request) if is_coro else handler(request)
+                elif arg_count == 0:
+                    await handler() if is_coro else handler()
+                else:
+                    raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
+        return self
+
+    async def handle_page_ready(self, msg: AdDict) -> bool:
+        with Context(self.view) as context:
+            try:
+                if self.page_ready_generator is not None:
+                    if isinstance(self.page_ready_generator, types.AsyncGeneratorType):
+                        await context.watch_asyncs(self.page_ready_generator.asend(PageEvent(msg.websocket)))
+                    elif isinstance(self.page_ready_generator, types.GeneratorType):
+                        self.page_ready_generator.send(PageEvent(msg.websocket))
+            except (StopIteration, StopAsyncIteration):
+                pass  # after the page_ready_generator returns, it will raise StopIteration; it's part of the generator protocol and expected
+            except:
+                globals.log.exception('Failed to execute page-ready')
+            try:
+                if self.page_ready_handler:
+                    arg_count = len(inspect.signature(self.page_ready_handler).parameters)
+                    is_coro = is_coroutine(self.page_ready_handler)
+                    if arg_count == 1:
+                        result = self.page_ready_handler(msg.websocket)
+                    elif arg_count == 0:
+                        result = self.page_ready_handler()
+                    else:
+                        raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
+                    if is_coro:
+                        await context.watch_asyncs(result)
+            except:
+                globals.log.exception('Failed to execute page-ready')
+        return False
+
+    async def on_disconnect(self, websocket: Optional[WebSocket] = None) -> None:
+        with Context(self.view):
+            for handler in globals.disconnect_handlers + ([self.disconnect_handler] if self.disconnect_handler else[]):
+                arg_count = len(inspect.signature(handler).parameters)
+                is_coro = is_coroutine(handler)
+                if arg_count == 1:
+                    await handler(websocket) if is_coro else handler(websocket)
+                elif arg_count == 0:
+                    await handler() if is_coro else handler()
+                else:
+                    raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
+        await super().on_disconnect(websocket)
+
+    async def run_javascript_on_socket(self, code: str, websocket: WebSocket, *,
+                                       respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Optional[str]:
+        start_time = time.time()
+        request_id = str(uuid.uuid4())
+        await websocket.send_json({'type': 'run_javascript', 'data': code, 'request_id': request_id, 'send': respond})
+        if not respond:
+            return
+        while request_id not in self.waiting_javascript_commands:
+            if time.time() > start_time + timeout:
+                raise TimeoutError('JavaScript did not respond in time')
+            await asyncio.sleep(check_interval)
+        return self.waiting_javascript_commands.pop(request_id)
+
+    async def run_javascript(self, code: str, *,
+                             respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Dict[WebSocket, Optional[str]]:
+        if self.page_id not in jp.WebPage.sockets:
+            raise RuntimeError('Cannot run JavaScript, because page is not ready.')
+        sockets = list(jp.WebPage.sockets[self.page_id].values())
+        results = await asyncio.gather(
+            *[self.run_javascript_on_socket(code, socket, respond=respond, timeout=timeout, check_interval=check_interval)
+              for socket in sockets], return_exceptions=True)
+        return dict(zip(sockets, results))
+
+    def handle_javascript_result(self, msg: AdDict) -> bool:
+        self.waiting_javascript_commands[msg.request_id] = msg.result
+        return False
+
+
+def add_head_html(self, html: str) -> None:
+    find_parent_page().head_html += html
+
+
+def add_body_html(self, html: str) -> None:
+    find_parent_page().body_html += html
+
+
+async def run_javascript(self, code: str, *,
+                         respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Dict[WebSocket, Optional[str]]:
+    return await find_parent_page().run_javascript(code, respond=respond, timeout=timeout, check_interval=check_interval)
+
+
+class page:
+    def __init__(
+        self,
+        route: str,
+        title: Optional[str] = None,
+        *,
+        favicon: Optional[str] = None,
+        dark: Optional[bool] = ...,
+        classes: str = 'q-pa-md column items-start gap-4',
+        css: str = HtmlFormatter().get_style_defs('.codehilite'),
+        on_connect: Optional[Callable] = None,
+        on_page_ready: Optional[Callable] = None,
+        on_disconnect: Optional[Callable] = None,
+        shared: bool = False,
+    ):
+        """Page
+
+        Creates a new page at the given route.
+
+        :param route: route of the new page (path must start with '/')
+        :param title: optional page title
+        :param favicon: optional relative filepath to a favicon (default: `None`, NiceGUI icon will be used)
+        :param dark: whether to use Quasar's dark mode (defaults to `dark` argument of `run` command)
+        :param classes: tailwind classes for the container div (default: `'q-pa-md column items-start gap-4'`)
+        :param css: CSS definitions
+        :param on_connect: optional function or coroutine which is called for each new client connection
+        :param on_page_ready: optional function or coroutine which is called when the websocket is connected;  see `"Yielding for Page-Ready" <https://nicegui.io/reference#yielding_for_page-ready>`_ as an alternative.
+        :param on_disconnect: optional function or coroutine which is called when a client disconnects
+        :param shared: whether the page instance is shared between multiple clients (default: `False`)
+        """
+        self.route = route
+        self.title = title
+        self.favicon = favicon
+        self.dark = dark
+        self.classes = classes
+        self.css = css
+        self.on_connect = on_connect
+        self.on_page_ready = on_page_ready
+        self.on_disconnect = on_disconnect
+        self.shared = shared
+        self.page: Optional[Page] = None
+        *_, self.converters = compile_path(route)
+
+    def __call__(self, func: Callable, **kwargs) -> Callable:
+        @wraps(func)
+        async def decorated(request: Optional[Request] = None) -> Page:
+            self.page = Page(
+                title=self.title,
+                favicon=self.favicon,
+                dark=self.dark,
+                classes=self.classes,
+                css=self.css,
+                on_connect=self.on_connect,
+                on_page_ready=self.on_page_ready,
+                on_disconnect=self.on_disconnect,
+                shared=self.shared,
+            )
+            try:
+                with Context(self.page.view):
+                    if 'request' in inspect.signature(func).parameters:
+                        if self.shared:
+                            raise RuntimeError('Cannot use `request` argument in shared page')
+                    await self.connected(request)
+                    await self.before_content()
+                    args = {**kwargs, **convert_arguments(request, self.converters, func)}
+                    result = await func(**args) if is_coroutine(func) else func(**args)
+                    if isinstance(result, types.GeneratorType):
+                        if self.shared:
+                            raise RuntimeError('Yielding for page_ready is not supported on shared pages')
+                        next(result)
+                    if isinstance(result, types.AsyncGeneratorType):
+                        if self.shared:
+                            raise RuntimeError('Yielding for page_ready is not supported on shared pages')
+                        await result.__anext__()
+                    self.page.page_ready_generator = result
+                    await self.after_content()
+                return self.page
+            except Exception as e:
+                globals.log.exception(e)
+                return error(500, str(e))
+        builder = PageBuilder(decorated, self.shared, self.favicon)
+        if globals.state != globals.State.STOPPED:
+            builder.create_route(self.route)
+        globals.page_builders[self.route] = builder
+        return decorated
+
+    async def connected(self, request: Optional[Request]) -> None:
+        pass
+
+    async def before_content(self) -> None:
+        pass
+
+    async def after_content(self) -> None:
+        pass
+
+
+def find_parent_view() -> jp.HTMLBaseComponent:
+    view_stack = get_view_stack()
+    if not view_stack:
+        if globals.loop and globals.loop.is_running():
+            raise RuntimeError('cannot find parent view, view stack is empty')
+        page = Page(shared=True)
+        view_stack.append(page.view)
+        jp.Route('/', page._route_function)
+    return view_stack[-1]
+
+
+def find_parent_page() -> Page:
+    pages = list(find_parent_view().pages.values())
+    assert len(pages) == 1
+    return pages[0]
+
+
+def error(status_code: int, message: Optional[str] = None) -> Page:
+    title = globals.config.title if globals.config else f'Error {status_code}'
+    favicon = globals.config.favicon if globals.config else None
+    dark = globals.config.dark if globals.config else False
+    wp = Page(title=title, favicon=favicon, dark=dark)
+    div = jp.Div(a=wp.view, classes='w-full py-20 text-center')
+    jp.Div(a=div, classes='text-8xl py-5', text='☹',
+           style='font-family: "Arial Unicode MS", "Times New Roman", Times, serif;')
+    jp.Div(a=div, classes='text-6xl py-5', text=status_code)
+    if 400 <= status_code <= 499:
+        title = "This page doesn't exist"
+    elif 500 <= status_code <= 599:
+        title = 'Server error'
+    else:
+        title = 'Unknown error'
+    if message is not None:
+        title += ':'
+    jp.Div(a=div, classes='text-xl pt-5', text=title)
+    jp.Div(a=div, classes='text-lg pt-2 text-gray-500', text=message or '')
+    return wp
+
+
+def init_auto_index_page() -> None:
+    view_stack: List[jp.HTMLBaseComponent] = globals.view_stacks.get(0, [])
+    if not view_stack:
+        return  # there is no auto-index page on the view stack
+    page: Page = view_stack.pop().pages[0]
+    page.title = globals.config.title
+    page.set_favicon(globals.config.favicon)
+    page.dark = globals.config.dark
+    page.view.classes = globals.config.main_page_classes
+    assert len(view_stack) == 0
+
+
+def create_page_routes() -> None:
+    jp.Route("/{path:path}", lambda: error(404), last=True)
+    for route, page_builder in globals.page_builders.items():
+        page_builder.create_route(route)
+
+
+def create_favicon_routes() -> None:
+    for page_builder in globals.page_builders.values():
+        if page_builder.favicon:
+            add_route(None, Route(f'/static/_favicon/{page_builder.favicon}',
+                                  lambda _, filepath=page_builder.favicon: FileResponse(filepath)))
+    if globals.config.favicon:
+        add_route(None, Route(f'/static/_favicon/{globals.config.favicon}',
+                              lambda _: FileResponse(globals.config.favicon)))

+ 89 - 0
nicegui/old/run.py

@@ -0,0 +1,89 @@
+import inspect
+import logging
+import os
+import sys
+import webbrowser
+from typing import List, Optional
+
+import uvicorn
+from uvicorn.main import STARTUP_FAILURE
+from uvicorn.supervisors import ChangeReload, Multiprocess
+
+from . import globals
+from .config import Config
+
+os.environ['STATIC_DIRECTORY'] = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
+os.environ['TEMPLATES_DIRECTORY'] = os.path.join(os.environ['STATIC_DIRECTORY'], 'templates')
+
+
+def run(self, *,
+        host: str = os.environ.get('HOST', '0.0.0.0'),
+        port: int = int(os.environ.get('PORT', '8080')),
+        title: str = 'NiceGUI',
+        favicon: Optional[str] = None,
+        dark: Optional[bool] = False,
+        main_page_classes: str = 'q-pa-md column items-start gap-4',
+        binding_refresh_interval: float = 0.1,
+        show: bool = True,
+        reload: bool = True,
+        uvicorn_logging_level: str = 'warning',
+        uvicorn_reload_dirs: str = '.',
+        uvicorn_reload_includes: str = '*.py',
+        uvicorn_reload_excludes: str = '.*, .py[cod], .sw.*, ~*',
+        exclude: str = '',
+        ):
+    globals.config = Config(
+        host=host,
+        port=port,
+        title=title,
+        reload=reload,
+        favicon=favicon,
+        dark=dark,
+        main_page_classes=main_page_classes,
+        binding_refresh_interval=binding_refresh_interval,
+        excludes=[e.strip() for e in exclude.split(',')],
+    )
+    os.environ['HOST'] = globals.config.host
+    os.environ['PORT'] = str(globals.config.port)
+
+    if inspect.stack()[-2].filename.endswith('spawn.py'):
+        return
+
+    if show:
+        webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
+
+    def split_args(args: str) -> List[str]:
+        return args.split(',') if ',' in args else [args]
+
+    # NOTE: The following lines are basically a copy of `uvicorn.run`, but keep a reference to the `server`.
+
+    config = uvicorn.Config(
+        'nicegui:app' if reload else globals.app,
+        host=host,
+        port=port,
+        lifespan='on',
+        reload=reload,
+        reload_includes=split_args(uvicorn_reload_includes) if reload else None,
+        reload_excludes=split_args(uvicorn_reload_excludes) if reload else None,
+        reload_dirs=split_args(uvicorn_reload_dirs) if reload else None,
+        log_level=uvicorn_logging_level,
+    )
+    globals.server = uvicorn.Server(config=config)
+
+    if (reload or config.workers > 1) and not isinstance(config.app, str):
+        logging.warning('You must pass the application as an import string to enable "reload" or "workers".')
+        sys.exit(1)
+
+    if config.should_reload:
+        sock = config.bind_socket()
+        ChangeReload(config, target=globals.server.run, sockets=[sock]).run()
+    elif config.workers > 1:
+        sock = config.bind_socket()
+        Multiprocess(config, target=globals.server.run, sockets=[sock]).run()
+    else:
+        globals.server.run()
+    if config.uds:
+        os.remove(config.uds)  # pragma: py-win32
+
+    if not globals.server.started and not config.should_reload and config.workers == 1:
+        sys.exit(STARTUP_FAILURE)

+ 63 - 0
nicegui/old/ui.py

@@ -0,0 +1,63 @@
+# isort:skip_file
+import os
+
+
+class Ui:
+    from .run import run  # NOTE: before justpy
+
+    from .page import page, add_head_html, add_body_html, run_javascript
+    from .page_layout import Header as header
+    from .page_layout import Footer as footer
+    from .page_layout import LeftDrawer as left_drawer
+    from .page_layout import RightDrawer as right_drawer
+    from .page_layout import PageSticky as page_sticky
+    from .update import update
+
+    from .elements.badge import Badge as badge
+    from .elements.button import Button as button
+    from .elements.card import Card as card
+    from .elements.card import CardSection as card_section
+    from .elements.chart import Chart as chart
+    from .elements.checkbox import Checkbox as checkbox
+    from .elements.color_input import ColorInput as color_input
+    from .elements.color_picker import ColorPicker as color_picker
+    from .elements.colors import Colors as colors
+    from .elements.column import Column as column
+    from .elements.dialog import Dialog as dialog
+    from .elements.expansion import Expansion as expansion
+    from .elements.html import Html as html
+    from .elements.icon import Icon as icon
+    from .elements.image import Image as image
+    from .elements.input import Input as input
+    from .elements.interactive_image import InteractiveImage as interactive_image
+    from .elements.joystick import Joystick as joystick
+    from .elements.keyboard import Keyboard as keyboard
+    from .elements.label import Label as label
+    from .elements.link import Link as link, LinkTarget as link_target
+    from .elements.log import Log as log
+    from .elements.markdown import Markdown as markdown
+    from .elements.menu import Menu as menu
+    from .elements.menu_item import MenuItem as menu_item
+    from .elements.menu_separator import MenuSeparator as menu_separator
+    from .elements.notify import Notify as notify
+    from .elements.number import Number as number
+    from .elements.open import open, open_async
+    from .elements.progress import LinearProgress as linear_progress
+    from .elements.progress import CircularProgress as circular_progress
+    from .elements.radio import Radio as radio
+    from .elements.row import Row as row
+    from .elements.scene import Scene as scene
+    from .elements.select import Select as select
+    from .elements.slider import Slider as slider
+    from .elements.switch import Switch as switch
+    from .elements.table import Table as table
+    from .elements.toggle import Toggle as toggle
+    from .elements.tree import Tree as tree
+    from .elements.upload import Upload as upload
+    from .lifecycle import on_connect, on_disconnect, on_shutdown, on_startup, shutdown
+    from .routes import add_route, add_static_files, get
+    from .timer import Timer as timer
+
+    if os.environ.get('MATPLOTLIB', 'true').lower() == 'true':
+        from .elements.line_plot import LinePlot as line_plot
+        from .elements.plot import Plot as plot

+ 32 - 316
nicegui/page.py

@@ -1,332 +1,48 @@
-from __future__ import annotations
-
 import asyncio
 import inspect
 import time
-import types
-import uuid
-from functools import wraps
-from typing import Callable, Dict, Generator, List, Optional
+from typing import Callable
 
-import justpy as jp
-from addict import Dict as AdDict
-from pygments.formatters import HtmlFormatter
-from starlette.requests import Request
-from starlette.responses import FileResponse
-from starlette.routing import Route, compile_path
-from starlette.websockets import WebSocket
+from fastapi import Response
 
 from . import globals
-from .auto_context import Context, get_view_stack
-from .events import PageEvent
-from .helpers import is_coroutine
-from .page_builder import PageBuilder
-from .routes import add_route, convert_arguments
-
-
-class Page(jp.QuasarPage):
-
-    def __init__(self,
-                 title: Optional[str] = None,
-                 *,
-                 favicon: Optional[str] = None,
-                 dark: Optional[bool] = ...,
-                 classes: str = 'q-pa-md column items-start gap-4',
-                 css: str = HtmlFormatter().get_style_defs('.codehilite'),
-                 on_connect: Optional[Callable] = None,
-                 on_page_ready: Optional[Callable] = None,
-                 on_disconnect: Optional[Callable] = None,
-                 shared: bool = False,
-                 ) -> None:
-        super().__init__()
-
-        if globals.config:
-            self.title = title or globals.config.title
-            self.set_favicon(favicon or globals.config.favicon)
-            self.dark = dark if dark is not ... else globals.config.dark
-        else:
-            self.title = title
-            self.set_favicon(favicon)
-            self.dark = dark if dark is not ... else None
-        self.tailwind = True  # use Tailwind classes instead of Quasars
-        self.css = css
-        self.connect_handler = on_connect
-        self.page_ready_handler = on_page_ready
-        self.page_ready_generator: Optional[Generator[None, PageEvent, None]] = None
-        self.disconnect_handler = on_disconnect
-        self.shared = shared
-        self.delete_flag = not shared
-
-        self.waiting_javascript_commands: Dict[str, str] = {}
-        self.on('result_ready', self.handle_javascript_result)
-        self.on('page_ready', self.handle_page_ready)
-
-        self.layout = jp.QLayout(a=self, view='HHH LpR FFF', temp=False)
-        container = jp.QPageContainer(a=self.layout, temp=False)
-        self.view = jp.Div(a=container, classes=classes, temp=False)
-        self.view.add_page(self)
-
-    def set_favicon(self, favicon: Optional[str]) -> None:
-        if not favicon:
-            self.favicon = 'favicon.ico'
-        elif favicon.startswith('http://') or favicon.startswith('https://'):
-            self.favicon = favicon
-        else:
-            self.favicon = f'_favicon/{favicon}'
-
-    async def _route_function(self, request: Request) -> Page:
-        with Context(self.view):
-            for handler in globals.connect_handlers + ([self.connect_handler] if self.connect_handler else []):
-                arg_count = len(inspect.signature(handler).parameters)
-                is_coro = is_coroutine(handler)
-                if arg_count == 1:
-                    await handler(request) if is_coro else handler(request)
-                elif arg_count == 0:
-                    await handler() if is_coro else handler()
-                else:
-                    raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
-        return self
-
-    async def handle_page_ready(self, msg: AdDict) -> bool:
-        with Context(self.view) as context:
-            try:
-                if self.page_ready_generator is not None:
-                    if isinstance(self.page_ready_generator, types.AsyncGeneratorType):
-                        await context.watch_asyncs(self.page_ready_generator.asend(PageEvent(msg.websocket)))
-                    elif isinstance(self.page_ready_generator, types.GeneratorType):
-                        self.page_ready_generator.send(PageEvent(msg.websocket))
-            except (StopIteration, StopAsyncIteration):
-                pass  # after the page_ready_generator returns, it will raise StopIteration; it's part of the generator protocol and expected
-            except:
-                globals.log.exception('Failed to execute page-ready')
-            try:
-                if self.page_ready_handler:
-                    arg_count = len(inspect.signature(self.page_ready_handler).parameters)
-                    is_coro = is_coroutine(self.page_ready_handler)
-                    if arg_count == 1:
-                        result = self.page_ready_handler(msg.websocket)
-                    elif arg_count == 0:
-                        result = self.page_ready_handler()
-                    else:
-                        raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
-                    if is_coro:
-                        await context.watch_asyncs(result)
-            except:
-                globals.log.exception('Failed to execute page-ready')
-        return False
-
-    async def on_disconnect(self, websocket: Optional[WebSocket] = None) -> None:
-        with Context(self.view):
-            for handler in globals.disconnect_handlers + ([self.disconnect_handler] if self.disconnect_handler else[]):
-                arg_count = len(inspect.signature(handler).parameters)
-                is_coro = is_coroutine(handler)
-                if arg_count == 1:
-                    await handler(websocket) if is_coro else handler(websocket)
-                elif arg_count == 0:
-                    await handler() if is_coro else handler()
-                else:
-                    raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
-        await super().on_disconnect(websocket)
-
-    async def run_javascript_on_socket(self, code: str, websocket: WebSocket, *,
-                                       respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Optional[str]:
-        start_time = time.time()
-        request_id = str(uuid.uuid4())
-        await websocket.send_json({'type': 'run_javascript', 'data': code, 'request_id': request_id, 'send': respond})
-        if not respond:
-            return
-        while request_id not in self.waiting_javascript_commands:
-            if time.time() > start_time + timeout:
-                raise TimeoutError('JavaScript did not respond in time')
-            await asyncio.sleep(check_interval)
-        return self.waiting_javascript_commands.pop(request_id)
-
-    async def run_javascript(self, code: str, *,
-                             respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Dict[WebSocket, Optional[str]]:
-        if self.page_id not in jp.WebPage.sockets:
-            raise RuntimeError('Cannot run JavaScript, because page is not ready.')
-        sockets = list(jp.WebPage.sockets[self.page_id].values())
-        results = await asyncio.gather(
-            *[self.run_javascript_on_socket(code, socket, respond=respond, timeout=timeout, check_interval=check_interval)
-              for socket in sockets], return_exceptions=True)
-        return dict(zip(sockets, results))
-
-    def handle_javascript_result(self, msg: AdDict) -> bool:
-        self.waiting_javascript_commands[msg.request_id] = msg.result
-        return False
-
-
-def add_head_html(self, html: str) -> None:
-    find_parent_page().head_html += html
-
-
-def add_body_html(self, html: str) -> None:
-    find_parent_page().body_html += html
-
-
-async def run_javascript(self, code: str, *,
-                         respond: bool = True, timeout: float = 1.0, check_interval: float = 0.01) -> Dict[WebSocket, Optional[str]]:
-    return await find_parent_page().run_javascript(code, respond=respond, timeout=timeout, check_interval=check_interval)
+from .client import Client
+from .task_logger import create_task
 
 
 class page:
-    def __init__(
-        self,
-        route: str,
-        title: Optional[str] = None,
-        *,
-        favicon: Optional[str] = None,
-        dark: Optional[bool] = ...,
-        classes: str = 'q-pa-md column items-start gap-4',
-        css: str = HtmlFormatter().get_style_defs('.codehilite'),
-        on_connect: Optional[Callable] = None,
-        on_page_ready: Optional[Callable] = None,
-        on_disconnect: Optional[Callable] = None,
-        shared: bool = False,
-    ):
-        """Page
-
-        Creates a new page at the given route.
 
-        :param route: route of the new page (path must start with '/')
-        :param title: optional page title
-        :param favicon: optional relative filepath to a favicon (default: `None`, NiceGUI icon will be used)
-        :param dark: whether to use Quasar's dark mode (defaults to `dark` argument of `run` command)
-        :param classes: tailwind classes for the container div (default: `'q-pa-md column items-start gap-4'`)
-        :param css: CSS definitions
-        :param on_connect: optional function or coroutine which is called for each new client connection
-        :param on_page_ready: optional function or coroutine which is called when the websocket is connected;  see `"Yielding for Page-Ready" <https://nicegui.io/reference#yielding_for_page-ready>`_ as an alternative.
-        :param on_disconnect: optional function or coroutine which is called when a client disconnects
-        :param shared: whether the page instance is shared between multiple clients (default: `False`)
-        """
-        self.route = route
-        self.title = title
-        self.favicon = favicon
-        self.dark = dark
-        self.classes = classes
-        self.css = css
-        self.on_connect = on_connect
-        self.on_page_ready = on_page_ready
-        self.on_disconnect = on_disconnect
-        self.shared = shared
-        self.page: Optional[Page] = None
-        *_, self.converters = compile_path(route)
+    def __init__(self, path: str, response_timeout: float = 3.0) -> None:
+        self.path = path
+        self.response_timeout = response_timeout
+        # NOTE we need to remove existing routes for this path to make sure only the latest definition is used
+        globals.app.routes[:] = [r for r in globals.app.routes if r.path != path]
 
-    def __call__(self, func: Callable, **kwargs) -> Callable:
-        @wraps(func)
-        async def decorated(request: Optional[Request] = None) -> Page:
-            self.page = Page(
-                title=self.title,
-                favicon=self.favicon,
-                dark=self.dark,
-                classes=self.classes,
-                css=self.css,
-                on_connect=self.on_connect,
-                on_page_ready=self.on_page_ready,
-                on_disconnect=self.on_disconnect,
-                shared=self.shared,
-            )
+    def __call__(self, func: Callable) -> Callable:
+        async def decorated(*dec_args, **dec_kwargs) -> Response:
             try:
-                with Context(self.page.view):
-                    if 'request' in inspect.signature(func).parameters:
-                        if self.shared:
-                            raise RuntimeError('Cannot use `request` argument in shared page')
-                    await self.connected(request)
-                    await self.before_content()
-                    args = {**kwargs, **convert_arguments(request, self.converters, func)}
-                    result = await func(**args) if is_coroutine(func) else func(**args)
-                    if isinstance(result, types.GeneratorType):
-                        if self.shared:
-                            raise RuntimeError('Yielding for page_ready is not supported on shared pages')
-                        next(result)
-                    if isinstance(result, types.AsyncGeneratorType):
-                        if self.shared:
-                            raise RuntimeError('Yielding for page_ready is not supported on shared pages')
-                        await result.__anext__()
-                    self.page.page_ready_generator = result
-                    await self.after_content()
-                return self.page
+                with Client() as client:
+                    if any(p.name == 'client' for p in inspect.signature(func).parameters.values()):
+                        dec_kwargs['client'] = client
+                    result = func(*dec_args, **dec_kwargs)
+                if inspect.isawaitable(result):
+                    async def wait_for_result() -> Response:
+                        with client:
+                            await result
+                    task = create_task(wait_for_result())
+                    deadline = time.time() + self.response_timeout
+                    while task and not client.is_waiting_for_handshake and not task.done():
+                        if time.time() > deadline:
+                            raise TimeoutError(f'Response not ready after {self.response_timeout} seconds')
+                        await asyncio.sleep(0.1)
+                    result = task.result() if task.done() else None
+                if isinstance(result, Response):  # NOTE if setup returns a response, we don't need to render the page
+                    return result
+                return client.build_response()
             except Exception as e:
                 globals.log.exception(e)
-                return error(500, str(e))
-        builder = PageBuilder(decorated, self.shared, self.favicon)
-        if globals.state != globals.State.STOPPED:
-            builder.create_route(self.route)
-        globals.page_builders[self.route] = builder
-        return decorated
-
-    async def connected(self, request: Optional[Request]) -> None:
-        pass
-
-    async def before_content(self) -> None:
-        pass
-
-    async def after_content(self) -> None:
-        pass
-
-
-def find_parent_view() -> jp.HTMLBaseComponent:
-    view_stack = get_view_stack()
-    if not view_stack:
-        if globals.loop and globals.loop.is_running():
-            raise RuntimeError('cannot find parent view, view stack is empty')
-        page = Page(shared=True)
-        view_stack.append(page.view)
-        jp.Route('/', page._route_function)
-    return view_stack[-1]
-
-
-def find_parent_page() -> Page:
-    pages = list(find_parent_view().pages.values())
-    assert len(pages) == 1
-    return pages[0]
-
-
-def error(status_code: int, message: Optional[str] = None) -> Page:
-    title = globals.config.title if globals.config else f'Error {status_code}'
-    favicon = globals.config.favicon if globals.config else None
-    dark = globals.config.dark if globals.config else False
-    wp = Page(title=title, favicon=favicon, dark=dark)
-    div = jp.Div(a=wp.view, classes='w-full py-20 text-center')
-    jp.Div(a=div, classes='text-8xl py-5', text='☹',
-           style='font-family: "Arial Unicode MS", "Times New Roman", Times, serif;')
-    jp.Div(a=div, classes='text-6xl py-5', text=status_code)
-    if 400 <= status_code <= 499:
-        title = "This page doesn't exist"
-    elif 500 <= status_code <= 599:
-        title = 'Server error'
-    else:
-        title = 'Unknown error'
-    if message is not None:
-        title += ':'
-    jp.Div(a=div, classes='text-xl pt-5', text=title)
-    jp.Div(a=div, classes='text-lg pt-2 text-gray-500', text=message or '')
-    return wp
-
-
-def init_auto_index_page() -> None:
-    view_stack: List[jp.HTMLBaseComponent] = globals.view_stacks.get(0, [])
-    if not view_stack:
-        return  # there is no auto-index page on the view stack
-    page: Page = view_stack.pop().pages[0]
-    page.title = globals.config.title
-    page.set_favicon(globals.config.favicon)
-    page.dark = globals.config.dark
-    page.view.classes = globals.config.main_page_classes
-    assert len(view_stack) == 0
-
-
-def create_page_routes() -> None:
-    jp.Route("/{path:path}", lambda: error(404), last=True)
-    for route, page_builder in globals.page_builders.items():
-        page_builder.create_route(route)
 
+        parameters = [p for p in inspect.signature(func).parameters.values() if p.name != 'client']
+        decorated.__signature__ = inspect.Signature(parameters)
 
-def create_favicon_routes() -> None:
-    for page_builder in globals.page_builders.values():
-        if page_builder.favicon:
-            add_route(None, Route(f'/static/_favicon/{page_builder.favicon}',
-                                  lambda _, filepath=page_builder.favicon: FileResponse(filepath)))
-    if globals.config.favicon:
-        add_route(None, Route(f'/static/_favicon/{globals.config.favicon}',
-                              lambda _: FileResponse(globals.config.favicon)))
+        return globals.app.get(self.path)(decorated)

+ 3 - 77
nicegui/run.py

@@ -1,89 +1,15 @@
 import inspect
-import logging
-import os
-import sys
 import webbrowser
-from typing import List, Optional
 
 import uvicorn
-from uvicorn.main import STARTUP_FAILURE
-from uvicorn.supervisors import ChangeReload, Multiprocess
 
 from . import globals
-from .config import Config
 
-os.environ['STATIC_DIRECTORY'] = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
-os.environ['TEMPLATES_DIRECTORY'] = os.path.join(os.environ['STATIC_DIRECTORY'], 'templates')
-
-
-def run(self, *,
-        host: str = os.environ.get('HOST', '0.0.0.0'),
-        port: int = int(os.environ.get('PORT', '8080')),
-        title: str = 'NiceGUI',
-        favicon: Optional[str] = None,
-        dark: Optional[bool] = False,
-        main_page_classes: str = 'q-pa-md column items-start gap-4',
-        binding_refresh_interval: float = 0.1,
-        show: bool = True,
-        reload: bool = True,
-        uvicorn_logging_level: str = 'warning',
-        uvicorn_reload_dirs: str = '.',
-        uvicorn_reload_includes: str = '*.py',
-        uvicorn_reload_excludes: str = '.*, .py[cod], .sw.*, ~*',
-        exclude: str = '',
-        ):
-    globals.config = Config(
-        host=host,
-        port=port,
-        title=title,
-        reload=reload,
-        favicon=favicon,
-        dark=dark,
-        main_page_classes=main_page_classes,
-        binding_refresh_interval=binding_refresh_interval,
-        excludes=[e.strip() for e in exclude.split(',')],
-    )
-    os.environ['HOST'] = globals.config.host
-    os.environ['PORT'] = str(globals.config.port)
 
+def run(*, host: str = '0.0.0.0', port: int = 5000, reload: bool = True) -> None:
     if inspect.stack()[-2].filename.endswith('spawn.py'):
         return
 
-    if show:
-        webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
-
-    def split_args(args: str) -> List[str]:
-        return args.split(',') if ',' in args else [args]
-
-    # NOTE: The following lines are basically a copy of `uvicorn.run`, but keep a reference to the `server`.
-
-    config = uvicorn.Config(
-        'nicegui:app' if reload else globals.app,
-        host=host,
-        port=port,
-        lifespan='on',
-        reload=reload,
-        reload_includes=split_args(uvicorn_reload_includes) if reload else None,
-        reload_excludes=split_args(uvicorn_reload_excludes) if reload else None,
-        reload_dirs=split_args(uvicorn_reload_dirs) if reload else None,
-        log_level=uvicorn_logging_level,
-    )
-    globals.server = uvicorn.Server(config=config)
-
-    if (reload or config.workers > 1) and not isinstance(config.app, str):
-        logging.warning('You must pass the application as an import string to enable "reload" or "workers".')
-        sys.exit(1)
-
-    if config.should_reload:
-        sock = config.bind_socket()
-        ChangeReload(config, target=globals.server.run, sockets=[sock]).run()
-    elif config.workers > 1:
-        sock = config.bind_socket()
-        Multiprocess(config, target=globals.server.run, sockets=[sock]).run()
-    else:
-        globals.server.run()
-    if config.uds:
-        os.remove(config.uds)  # pragma: py-win32
+    webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
 
-    if not globals.server.started and not config.should_reload and config.workers == 1:
-        sys.exit(STARTUP_FAILURE)
+    uvicorn.run('nicegui:app' if reload else globals.app, host=host, port=port, reload=reload)

+ 21 - 0
nicegui/slot.py

@@ -0,0 +1,21 @@
+from typing import TYPE_CHECKING, List
+
+from . import globals
+
+if TYPE_CHECKING:
+    from .element import Element
+
+
+class Slot:
+
+    def __init__(self, parent: 'Element', name: str) -> None:
+        self.name = name
+        self.parent = parent
+        self.children: List['Element'] = []
+
+    def __enter__(self):
+        globals.client_stack[-1].slot_stack.append(self)
+        return self
+
+    def __exit__(self, *_):
+        globals.client_stack[-1].slot_stack.pop()

+ 0 - 4
nicegui/static/copy_justpy_templates.sh

@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-
-rm -r templates
-cp -r ../../../justpy/justpy/templates .

+ 0 - 0
nicegui/static/templates/__init__.py


+ 0 - 120
nicegui/static/templates/css/form.css

@@ -1,120 +0,0 @@
-{% raw %}
-
-/*  This file ads formatting for form elements in Tailwind https://nervous-knuth-fa9c3e.netlify.com/   additional form classes form-radio etc*/
-
-.form-checkbox {
-  -webkit-appearance: none;
-     -moz-appearance: none;
-          appearance: none;
-  display: inline-block;
-  height: 1em;
-  width: 1em;
-  vertical-align: middle;
-  border-width: 1px;
-  border-radius: 0.25rem;
-  background-color: #fff;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-}
-
-input[type=checkbox]:focus + .form-checkbox, input[type=checkbox].form-checkbox:focus {
-  outline: none;
-  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
-}
-
-input[type=checkbox]:focus:not(:checked) + .form-checkbox, input[type=checkbox].form-checkbox:focus:not(:checked) {
-  border-color: #63b3ed;
-}
-
-input[type=checkbox]:checked + .form-checkbox, input[type=checkbox].form-checkbox:checked {
-  background-color: currentColor;
-  border-color: currentColor;
-  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.293 4.293a1 1 0 0 1 0 1.414L7 12a1 1 0 0 1-1.414 0L3.293 9.707a1 1 0 0 1 1.414-1.414l1.586 1.586 5.586-5.586a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E");
-  background-size: cover;
-  background-position: center;
-  background-repeat: no-repeat;
-}
-
-.form-radio {
-  -webkit-appearance: none;
-     -moz-appearance: none;
-          appearance: none;
-  display: inline-block;
-  height: 1em;
-  width: 1em;
-  vertical-align: middle;
-  border-width: 1px;
-  border-radius: 9999px;
-  background-color: #fff;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-}
-
-input[type=radio]:focus + .form-radio, input[type=radio].form-radio:focus {
-  outline: none;
-  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
-}
-
-input[type=radio]:focus:not(:checked) + .form-radio, input[type=radio].form-radio:focus:not(:checked) {
-  border-color: #63b3ed;
-}
-
-input[type=radio]:checked + .form-radio, input[type=radio].form-radio:checked {
-  background-color: currentColor;
-  border-color: currentColor;
-  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='%23ffffff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='12' cy='12' r='5'/%3E%3C/svg%3E");
-  background-size: cover;
-  background-position: center;
-  background-repeat: no-repeat;
-}
-
-.form-input, .form-textarea, .form-multiselect {
-  -webkit-appearance: none;
-     -moz-appearance: none;
-          appearance: none;
-  background-color: #fff;
-  border-width: 1px;
-  border-radius: 0.25rem;
-  padding: 0.5rem 0.75rem;
-  line-height: 1.5;
-}
-
-.form-input:focus, .form-textarea:focus, .form-multiselect:focus {
-  outline: none;
-  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
-  border-color: #63b3ed;
-}
-
-.form-select {
-  background-color: #fff;
-  border-width: 1px;
-  border-radius: 0.25rem;
-  padding-top: 0.5rem;
-  padding-right: 2.5rem;
-  padding-bottom: 0.5rem;
-  padding-left: 0.75rem;
-  line-height: 1.5;
-  -webkit-appearance: none;
-     -moz-appearance: none;
-          appearance: none;
-  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23a0aec0' viewBox='0 0 24 24' %3E%3Cpath d='M15.3 9.3a1 1 0 0 1 1.4 1.4l-4 4a1 1 0 0 1-1.4 0l-4-4a1 1 0 0 1 1.4-1.4l3.3 3.29 3.3-3.3z'/%3E%3C/svg%3E");
-  background-position: right 0.5rem center;
-  background-repeat: no-repeat;
-  background-size: 1.5em 1.5em;
-}
-
-.form-select::-ms-expand {
-  display: none;
-}
-
-.form-select:focus {
-  outline: none;
-  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
-  border-color: #63b3ed;
-}
-
-{% endraw %}

File diff suppressed because it is too large
+ 0 - 6
nicegui/static/templates/favicon.html


+ 0 - 68
nicegui/static/templates/highcharts.html

@@ -1,68 +0,0 @@
-<style>
-    {#needed for exporting menu#}
-    hr {
-        display: block;
-        margin-before: 0.5em;
-        margin-after: 0.5em;
-        margin-start: auto;
-        margin-end: auto;
-        overflow: hidden;
-        border-style: inset;
-        border-width: 1px;
-    }
-</style>
-{% if not options.no_internet %}
-    <script src="https://code.highcharts.com/stock/highstock.js"></script>
-    <script src="https://code.highcharts.com/modules/variable-pie.js"></script>
-    <script src="https://code.highcharts.com/stock/modules/histogram-bellcurve.js"></script>
-    <script src="https://code.highcharts.com/modules/streamgraph.js"></script>
-    {#    <script src="https://code.highcharts.com/stock/modules/series-label.js"></script>#}
-    <script src="https://code.highcharts.com/modules/annotations.js"></script>
-    <script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
-    <script src=https://code.highcharts.com/modules/offline-exporting.js></script>
-    <script src="https://code.highcharts.com/stock/modules/export-data.js"></script>
-    <script src="https://code.highcharts.com/highcharts-more.js"></script>
-    <script src="https://code.highcharts.com/modules/data.js"></script>
-    <script src="https://code.highcharts.com/modules/dumbbell.js"></script>
-    <script src="https://code.highcharts.com/modules/lollipop.js"></script>
-    <script src="https://code.highcharts.com/modules/sankey.js"></script>
-    <script src="https://code.highcharts.com/modules/dependency-wheel.js"></script>
-    <script src="https://code.highcharts.com/modules/item-series.js"></script>
-    <script src="https://code.highcharts.com/modules/organization.js"></script>
-    <script src="https://code.highcharts.com/modules/timeline.js"></script>
-    <script src="https://code.highcharts.com/modules/heatmap.js"></script>
-    <script src="https://code.highcharts.com/modules/tilemap.js"></script>
-    <script src="https://code.highcharts.com/modules/drilldown.js"></script>
-    <script src="https://code.highcharts.com/modules/coloraxis.js"></script>
-    <script src="https://code.highcharts.com/highcharts-3d.js"></script>
-    <script src="https://code.highcharts.com/modules/cylinder.js"></script>
-    <script src="https://code.highcharts.com/modules/funnel3d.js"></script>
-    <script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
-    <script src="https://code.highcharts.com/modules/venn.js"></script>
-    <script src="https://code.highcharts.com/modules/accessibility.js"></script>
-    <script src="https://code.highcharts.com/modules/treemap.js"></script>
-    <script src="https://code.highcharts.com/modules/xrange.js"></script>
-
-    <script src="http://code.highcharts.com/maps/modules/map.js"></script>
-
-    {#Must be last#}
-    <script src="https://code.highcharts.com/stock/modules/boost.js"></script>
-{% else %}
-    <script src="templates/local/highcharts.js"></script>
-{% endif %}
-
-
-<script>
-    Highcharts.setOptions({
-        lang: {
-            thousandsSep: ','
-        }
-    });
-    {% if page_options.highcharts_theme %}
-        {% set theme_file = 'highcharts/' + page_options.highcharts_theme + '.js' %}
-        {% include theme_file %}
-    {% endif %}
-
-
-</script>
-

+ 0 - 36
nicegui/static/templates/highcharts/avocado.js

@@ -1,36 +0,0 @@
-/**
- * (c) 2010-2017 Highsoft AS
- *
- * License: www.highcharts.com/license
- *
- * Accessible high-contrast theme for Highcharts. Considers colorblindness and
- * monochrome rendering.
- * @author Øystein Moseng
- */
-
-//'use strict';
-
-Highcharts.theme = {
-    colors: ['#F3E796', '#95C471', '#35729E', '#251735'],
-
-    colorAxis: {
-        maxColor: '#05426E',
-        minColor: '#F3E796'
-    },
-
-    plotOptions: {
-        map: {
-            nullColor: '#fcfefe'
-        }
-    },
-
-    navigator: {
-        maskFill: 'rgba(170, 205, 170, 0.5)',
-        series: {
-            color: '#95C471',
-            lineColor: '#35729E'
-        }
-    }
-};
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 258
nicegui/static/templates/highcharts/dark-blue.js

@@ -1,258 +0,0 @@
-/**
- * (c) 2010-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * Dark blue theme for Highcharts JS
- * @author Torstein Honsi
- */
-
-Highcharts.theme = {
-    colors: ['#DDDF0D', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee',
-        '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-    chart: {
-        backgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
-            stops: [
-                [0, 'rgb(48, 48, 96)'],
-                [1, 'rgb(0, 0, 0)']
-            ]
-        },
-        borderColor: '#000000',
-        borderWidth: 2,
-        className: 'dark-container',
-        plotBackgroundColor: 'rgba(255, 255, 255, .1)',
-        plotBorderColor: '#CCCCCC',
-        plotBorderWidth: 1
-    },
-    title: {
-        style: {
-            color: '#C0C0C0',
-            font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
-        }
-    },
-    subtitle: {
-        style: {
-            color: '#666666',
-            font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
-        }
-    },
-    xAxis: {
-        gridLineColor: '#333333',
-        gridLineWidth: 1,
-        labels: {
-            style: {
-                color: '#A0A0A0'
-            }
-        },
-        lineColor: '#A0A0A0',
-        tickColor: '#A0A0A0',
-        title: {
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold',
-                fontSize: '12px',
-                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-
-            }
-        }
-    },
-    yAxis: {
-        gridLineColor: '#333333',
-        labels: {
-            style: {
-                color: '#A0A0A0'
-            }
-        },
-        lineColor: '#A0A0A0',
-        minorTickInterval: null,
-        tickColor: '#A0A0A0',
-        tickWidth: 1,
-        title: {
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold',
-                fontSize: '12px',
-                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-            }
-        }
-    },
-    tooltip: {
-        backgroundColor: 'rgba(0, 0, 0, 0.75)',
-        style: {
-            color: '#F0F0F0'
-        }
-    },
-    toolbar: {
-        itemStyle: {
-            color: 'silver'
-        }
-    },
-    plotOptions: {
-        line: {
-            dataLabels: {
-                color: '#CCC'
-            },
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        spline: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        scatter: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        candlestick: {
-            lineColor: 'white'
-        }
-    },
-    legend: {
-        itemStyle: {
-            font: '9pt Trebuchet MS, Verdana, sans-serif',
-            color: '#A0A0A0'
-        },
-        itemHoverStyle: {
-            color: '#FFF'
-        },
-        itemHiddenStyle: {
-            color: '#444'
-        }
-    },
-    credits: {
-        style: {
-            color: '#666'
-        }
-    },
-    labels: {
-        style: {
-            color: '#CCC'
-        }
-    },
-
-    navigation: {
-        buttonOptions: {
-            symbolStroke: '#DDDDDD',
-            hoverSymbolStroke: '#FFFFFF',
-            theme: {
-                fill: {
-                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                    stops: [
-                        [0.4, '#606060'],
-                        [0.6, '#333333']
-                    ]
-                },
-                stroke: '#000000'
-            }
-        }
-    },
-
-    // scroll charts
-    rangeSelector: {
-        buttonTheme: {
-            fill: {
-                linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                stops: [
-                    [0.4, '#888'],
-                    [0.6, '#555']
-                ]
-            },
-            stroke: '#000000',
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold'
-            },
-            states: {
-                hover: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.4, '#BBB'],
-                            [0.6, '#888']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'white'
-                    }
-                },
-                select: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.1, '#000'],
-                            [0.3, '#333']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'yellow'
-                    }
-                }
-            }
-        },
-        inputStyle: {
-            backgroundColor: '#333',
-            color: 'silver'
-        },
-        labelStyle: {
-            color: 'silver'
-        }
-    },
-
-    navigator: {
-        handles: {
-            backgroundColor: '#666',
-            borderColor: '#AAA'
-        },
-        outlineColor: '#CCC',
-        maskFill: 'rgba(16, 16, 16, 0.5)',
-        series: {
-            color: '#7798BF',
-            lineColor: '#A6C7ED'
-        }
-    },
-
-    scrollbar: {
-        barBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                    [0.4, '#888'],
-                    [0.6, '#555']
-            ]
-        },
-        barBorderColor: '#CCC',
-        buttonArrowColor: '#CCC',
-        buttonBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                    [0.4, '#888'],
-                    [0.6, '#555']
-            ]
-        },
-        buttonBorderColor: '#CCC',
-        rifleColor: '#FFF',
-        trackBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0, '#000'],
-                [1, '#333']
-            ]
-        },
-        trackBorderColor: '#666'
-    },
-
-    // special colors for some of the
-    legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
-    background2: 'rgb(35, 35, 70)',
-    dataLabelsColor: '#444',
-    textColor: '#C0C0C0',
-    maskColor: 'rgba(255,255,255,0.3)'
-};
-
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 260
nicegui/static/templates/highcharts/dark-green.js

@@ -1,260 +0,0 @@
-/**
- * (c) 2010-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * Dark blue theme for Highcharts JS
- * @author Torstein Honsi
- */
-
-
-Highcharts.theme = {
-    colors: ['#DDDF0D', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee',
-        '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-    chart: {
-        backgroundColor: {
-            linearGradient: [0, 0, 250, 500],
-            stops: [
-                [0, 'rgb(48, 96, 48)'],
-                [1, 'rgb(0, 0, 0)']
-            ]
-        },
-        borderColor: '#000000',
-        borderWidth: 2,
-        className: 'dark-container',
-        plotBackgroundColor: 'rgba(255, 255, 255, .1)',
-        plotBorderColor: '#CCCCCC',
-        plotBorderWidth: 1
-    },
-    title: {
-        style: {
-            color: '#C0C0C0',
-            font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
-        }
-    },
-    subtitle: {
-        style: {
-            color: '#666666',
-            font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
-        }
-    },
-    xAxis: {
-        gridLineColor: '#333333',
-        gridLineWidth: 1,
-        labels: {
-            style: {
-                color: '#A0A0A0'
-            }
-        },
-        lineColor: '#A0A0A0',
-        tickColor: '#A0A0A0',
-        title: {
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold',
-                fontSize: '12px',
-                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-
-            }
-        }
-    },
-    yAxis: {
-        gridLineColor: '#333333',
-        labels: {
-            style: {
-                color: '#A0A0A0'
-            }
-        },
-        lineColor: '#A0A0A0',
-        minorTickInterval: null,
-        tickColor: '#A0A0A0',
-        tickWidth: 1,
-        title: {
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold',
-                fontSize: '12px',
-                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-            }
-        }
-    },
-    tooltip: {
-        backgroundColor: 'rgba(0, 0, 0, 0.75)',
-        style: {
-            color: '#F0F0F0'
-        }
-    },
-    toolbar: {
-        itemStyle: {
-            color: 'silver'
-        }
-    },
-    plotOptions: {
-        line: {
-            dataLabels: {
-                color: '#CCC'
-            },
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        spline: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        scatter: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        candlestick: {
-            lineColor: 'white'
-        }
-    },
-    legend: {
-        itemStyle: {
-            font: '9pt Trebuchet MS, Verdana, sans-serif',
-            color: '#A0A0A0'
-        },
-        itemHoverStyle: {
-            color: '#FFF'
-        },
-        itemHiddenStyle: {
-            color: '#444'
-        }
-    },
-    credits: {
-        style: {
-            color: '#666'
-        }
-    },
-    labels: {
-        style: {
-            color: '#CCC'
-        }
-    },
-
-
-    navigation: {
-        buttonOptions: {
-            symbolStroke: '#DDDDDD',
-            hoverSymbolStroke: '#FFFFFF',
-            theme: {
-                fill: {
-                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                    stops: [
-                        [0.4, '#606060'],
-                        [0.6, '#333333']
-                    ]
-                },
-                stroke: '#000000'
-            }
-        }
-    },
-
-    // scroll charts
-    rangeSelector: {
-        buttonTheme: {
-            fill: {
-                linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                stops: [
-                    [0.4, '#888'],
-                    [0.6, '#555']
-                ]
-            },
-            stroke: '#000000',
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold'
-            },
-            states: {
-                hover: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.4, '#BBB'],
-                            [0.6, '#888']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'white'
-                    }
-                },
-                select: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.1, '#000'],
-                            [0.3, '#333']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'yellow'
-                    }
-                }
-            }
-        },
-        inputStyle: {
-            backgroundColor: '#333',
-            color: 'silver'
-        },
-        labelStyle: {
-            color: 'silver'
-        }
-    },
-
-    navigator: {
-        handles: {
-            backgroundColor: '#666',
-            borderColor: '#AAA'
-        },
-        outlineColor: '#CCC',
-        maskFill: 'rgba(16, 16, 16, 0.5)',
-        series: {
-            color: '#7798BF',
-            lineColor: '#A6C7ED'
-        }
-    },
-
-    scrollbar: {
-        barBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0.4, '#888'],
-                [0.6, '#555']
-            ]
-        },
-        barBorderColor: '#CCC',
-        buttonArrowColor: '#CCC',
-        buttonBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0.4, '#888'],
-                [0.6, '#555']
-            ]
-        },
-        buttonBorderColor: '#CCC',
-        rifleColor: '#FFF',
-        trackBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0, '#000'],
-                [1, '#333']
-            ]
-        },
-        trackBorderColor: '#666'
-    },
-
-    // special colors for some of the
-    legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
-    background2: 'rgb(35, 35, 70)',
-    dataLabelsColor: '#444',
-    textColor: '#C0C0C0',
-    maskColor: 'rgba(255,255,255,0.3)'
-};
-
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 217
nicegui/static/templates/highcharts/dark-unica.js

@@ -1,217 +0,0 @@
-/**
- * (c) 2010-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * Dark theme for Highcharts JS
- * @author Torstein Honsi
- */
-
-
-Highcharts.createElement('link', {
-    href: 'https://fonts.googleapis.com/css?family=Unica+One',
-    rel: 'stylesheet',
-    type: 'text/css'
-}, null, document.getElementsByTagName('head')[0]);
-
-Highcharts.theme = {
-    colors: ['#2b908f', '#90ee7e', '#f45b5b', '#7798BF', '#aaeeee', '#ff0066',
-        '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-    chart: {
-        backgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
-            stops: [
-                [0, '#2a2a2b'],
-                [1, '#3e3e40']
-            ]
-        },
-        style: {
-            fontFamily: '\'Unica One\', sans-serif'
-        },
-        plotBorderColor: '#606063'
-    },
-    title: {
-        style: {
-            color: '#E0E0E3',
-            textTransform: 'uppercase',
-            fontSize: '20px'
-        }
-    },
-    subtitle: {
-        style: {
-            color: '#E0E0E3',
-            textTransform: 'uppercase'
-        }
-    },
-    xAxis: {
-        gridLineColor: '#707073',
-        labels: {
-            style: {
-                color: '#E0E0E3'
-            }
-        },
-        lineColor: '#707073',
-        minorGridLineColor: '#505053',
-        tickColor: '#707073',
-        title: {
-            style: {
-                color: '#A0A0A3'
-
-            }
-        }
-    },
-    yAxis: {
-        gridLineColor: '#707073',
-        labels: {
-            style: {
-                color: '#E0E0E3'
-            }
-        },
-        lineColor: '#707073',
-        minorGridLineColor: '#505053',
-        tickColor: '#707073',
-        tickWidth: 1,
-        title: {
-            style: {
-                color: '#A0A0A3'
-            }
-        }
-    },
-    tooltip: {
-        backgroundColor: 'rgba(0, 0, 0, 0.85)',
-        style: {
-            color: '#F0F0F0'
-        }
-    },
-    plotOptions: {
-        series: {
-            dataLabels: {
-                color: '#B0B0B3'
-            },
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        boxplot: {
-            fillColor: '#505053'
-        },
-        candlestick: {
-            lineColor: 'white'
-        },
-        errorbar: {
-            color: 'white'
-        }
-    },
-    legend: {
-        itemStyle: {
-            color: '#E0E0E3'
-        },
-        itemHoverStyle: {
-            color: '#FFF'
-        },
-        itemHiddenStyle: {
-            color: '#606063'
-        }
-    },
-    credits: {
-        style: {
-            color: '#666'
-        }
-    },
-    labels: {
-        style: {
-            color: '#707073'
-        }
-    },
-
-    drilldown: {
-        activeAxisLabelStyle: {
-            color: '#F0F0F3'
-        },
-        activeDataLabelStyle: {
-            color: '#F0F0F3'
-        }
-    },
-
-    navigation: {
-        buttonOptions: {
-            symbolStroke: '#DDDDDD',
-            theme: {
-                fill: '#505053'
-            }
-        }
-    },
-
-    // scroll charts
-    rangeSelector: {
-        buttonTheme: {
-            fill: '#505053',
-            stroke: '#000000',
-            style: {
-                color: '#CCC'
-            },
-            states: {
-                hover: {
-                    fill: '#707073',
-                    stroke: '#000000',
-                    style: {
-                        color: 'white'
-                    }
-                },
-                select: {
-                    fill: '#000003',
-                    stroke: '#000000',
-                    style: {
-                        color: 'white'
-                    }
-                }
-            }
-        },
-        inputBoxBorderColor: '#505053',
-        inputStyle: {
-            backgroundColor: '#333',
-            color: 'silver'
-        },
-        labelStyle: {
-            color: 'silver'
-        }
-    },
-
-    navigator: {
-        handles: {
-            backgroundColor: '#666',
-            borderColor: '#AAA'
-        },
-        outlineColor: '#CCC',
-        maskFill: 'rgba(255,255,255,0.1)',
-        series: {
-            color: '#7798BF',
-            lineColor: '#A6C7ED'
-        },
-        xAxis: {
-            gridLineColor: '#505053'
-        }
-    },
-
-    scrollbar: {
-        barBackgroundColor: '#808083',
-        barBorderColor: '#808083',
-        buttonArrowColor: '#CCC',
-        buttonBackgroundColor: '#606063',
-        buttonBorderColor: '#606063',
-        rifleColor: '#FFF',
-        trackBackgroundColor: '#404043',
-        trackBorderColor: '#404043'
-    },
-
-    // special colors for some of the
-    legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
-    background2: '#505053',
-    dataLabelsColor: '#B0B0B3',
-    textColor: '#C0C0C0',
-    contrastTextColor: '#F0F0F3',
-    maskColor: 'rgba(255,255,255,0.3)'
-};
-
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 266
nicegui/static/templates/highcharts/gray.js

@@ -1,266 +0,0 @@
-/**
- * (c) 2010-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * Gray theme for Highcharts JS
- * @author Torstein Honsi
- */
-
-
-Highcharts.theme = {
-    colors: ['#DDDF0D', '#7798BF', '#55BF3B', '#DF5353', '#aaeeee',
-        '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-    chart: {
-        backgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0, 'rgb(96, 96, 96)'],
-                [1, 'rgb(16, 16, 16)']
-            ]
-        },
-        borderWidth: 0,
-        borderRadius: 0,
-        plotBackgroundColor: null,
-        plotShadow: false,
-        plotBorderWidth: 0
-    },
-    title: {
-        style: {
-            color: '#FFF',
-            font: '16px Lucida Grande, Lucida Sans Unicode,' +
-                ' Verdana, Arial, Helvetica, sans-serif'
-        }
-    },
-    subtitle: {
-        style: {
-            color: '#DDD',
-            font: '12px Lucida Grande, Lucida Sans Unicode,' +
-                ' Verdana, Arial, Helvetica, sans-serif'
-        }
-    },
-    xAxis: {
-        gridLineWidth: 0,
-        lineColor: '#999',
-        tickColor: '#999',
-        labels: {
-            style: {
-                color: '#999',
-                fontWeight: 'bold'
-            }
-        },
-        title: {
-            style: {
-                color: '#AAA',
-                font: 'bold 12px Lucida Grande, Lucida Sans Unicode,' +
-                ' Verdana, Arial, Helvetica, sans-serif'
-            }
-        }
-    },
-    yAxis: {
-        alternateGridColor: null,
-        minorTickInterval: null,
-        gridLineColor: 'rgba(255, 255, 255, .1)',
-        minorGridLineColor: 'rgba(255,255,255,0.07)',
-        lineWidth: 0,
-        tickWidth: 0,
-        labels: {
-            style: {
-                color: '#999',
-                fontWeight: 'bold'
-            }
-        },
-        title: {
-            style: {
-                color: '#AAA',
-                font: 'bold 12px Lucida Grande, Lucida Sans Unicode,' +
-                ' Verdana, Arial, Helvetica, sans-serif'
-            }
-        }
-    },
-    legend: {
-        itemStyle: {
-            color: '#CCC'
-        },
-        itemHoverStyle: {
-            color: '#FFF'
-        },
-        itemHiddenStyle: {
-            color: '#333'
-        }
-    },
-    labels: {
-        style: {
-            color: '#CCC'
-        }
-    },
-    tooltip: {
-        backgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0, 'rgba(96, 96, 96, .8)'],
-                [1, 'rgba(16, 16, 16, .8)']
-            ]
-        },
-        borderWidth: 0,
-        style: {
-            color: '#FFF'
-        }
-    },
-
-
-    plotOptions: {
-        series: {
-            nullColor: '#444444'
-        },
-        line: {
-            dataLabels: {
-                color: '#CCC'
-            },
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        spline: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        scatter: {
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        candlestick: {
-            lineColor: 'white'
-        }
-    },
-
-    toolbar: {
-        itemStyle: {
-            color: '#CCC'
-        }
-    },
-
-    navigation: {
-        buttonOptions: {
-            symbolStroke: '#DDDDDD',
-            hoverSymbolStroke: '#FFFFFF',
-            theme: {
-                fill: {
-                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                    stops: [
-                        [0.4, '#606060'],
-                        [0.6, '#333333']
-                    ]
-                },
-                stroke: '#000000'
-            }
-        }
-    },
-
-    // scroll charts
-    rangeSelector: {
-        buttonTheme: {
-            fill: {
-                linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                stops: [
-                    [0.4, '#888'],
-                    [0.6, '#555']
-                ]
-            },
-            stroke: '#000000',
-            style: {
-                color: '#CCC',
-                fontWeight: 'bold'
-            },
-            states: {
-                hover: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.4, '#BBB'],
-                            [0.6, '#888']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'white'
-                    }
-                },
-                select: {
-                    fill: {
-                        linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-                        stops: [
-                            [0.1, '#000'],
-                            [0.3, '#333']
-                        ]
-                    },
-                    stroke: '#000000',
-                    style: {
-                        color: 'yellow'
-                    }
-                }
-            }
-        },
-        inputStyle: {
-            backgroundColor: '#333',
-            color: 'silver'
-        },
-        labelStyle: {
-            color: 'silver'
-        }
-    },
-
-    navigator: {
-        handles: {
-            backgroundColor: '#666',
-            borderColor: '#AAA'
-        },
-        outlineColor: '#CCC',
-        maskFill: 'rgba(16, 16, 16, 0.5)',
-        series: {
-            color: '#7798BF',
-            lineColor: '#A6C7ED'
-        }
-    },
-
-    scrollbar: {
-        barBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0.4, '#888'],
-                [0.6, '#555']
-            ]
-        },
-        barBorderColor: '#CCC',
-        buttonArrowColor: '#CCC',
-        buttonBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0.4, '#888'],
-                [0.6, '#555']
-            ]
-        },
-        buttonBorderColor: '#CCC',
-        rifleColor: '#FFF',
-        trackBackgroundColor: {
-            linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
-            stops: [
-                [0, '#000'],
-                [1, '#333']
-            ]
-        },
-        trackBorderColor: '#666'
-    },
-
-    // special colors for some of the demo examples
-    legendBackgroundColor: 'rgba(48, 48, 48, 0.8)',
-    background2: 'rgb(70, 70, 70)',
-    dataLabelsColor: '#444',
-    textColor: '#E0E0E0',
-    maskColor: 'rgba(255,255,255,0.3)'
-};
-
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 77
nicegui/static/templates/highcharts/grid-light.js

@@ -1,77 +0,0 @@
-/**
- * @license Highcharts JS v6.1.2 (2018-08-31)
- *
- * (c) 2009-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-		Highcharts.createElement('link', {
-		    href: 'https://fonts.googleapis.com/css?family=Dosis:400,600',
-		    rel: 'stylesheet',
-		    type: 'text/css'
-		}, null, document.getElementsByTagName('head')[0]);
-
-		Highcharts.theme = {
-		    colors: ['#7cb5ec', '#f7a35c', '#90ee7e', '#7798BF', '#aaeeee', '#ff0066',
-		        '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-		    chart: {
-		        backgroundColor: null,
-		        style: {
-		            fontFamily: 'Dosis, sans-serif'
-		        }
-		    },
-		    title: {
-		        style: {
-		            fontSize: '16px',
-		            fontWeight: 'bold',
-		            textTransform: 'uppercase'
-		        }
-		    },
-		    tooltip: {
-		        borderWidth: 0,
-		        backgroundColor: 'rgba(219,219,216,0.8)',
-		        shadow: false
-		    },
-		    legend: {
-		        itemStyle: {
-		            fontWeight: 'bold',
-		            fontSize: '13px'
-		        }
-		    },
-		    xAxis: {
-		        gridLineWidth: 1,
-		        labels: {
-		            style: {
-		                fontSize: '12px'
-		            }
-		        }
-		    },
-		    yAxis: {
-		        minorTickInterval: 'auto',
-		        title: {
-		            style: {
-		                textTransform: 'uppercase'
-		            }
-		        },
-		        labels: {
-		            style: {
-		                fontSize: '12px'
-		            }
-		        }
-		    },
-		    plotOptions: {
-		        candlestick: {
-		            lineColor: '#404048'
-		        }
-		    },
-
-
-		    // General
-		    background2: '#F0F0EA'
-
-		};
-
-		// Apply the theme
-		Highcharts.setOptions(Highcharts.theme);
-

+ 0 - 109
nicegui/static/templates/highcharts/grid.js

@@ -1,109 +0,0 @@
-/**
- * @license Highcharts JS v6.1.2 (2018-08-31)
- *
- * (c) 2009-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-
-		Highcharts.theme = {
-		    colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572',
-		        '#FF9655', '#FFF263', '#6AF9C4'],
-		    chart: {
-		        backgroundColor: {
-		            linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
-		            stops: [
-		                [0, 'rgb(255, 255, 255)'],
-		                [1, 'rgb(240, 240, 255)']
-		            ]
-		        },
-		        borderWidth: 2,
-		        plotBackgroundColor: 'rgba(255, 255, 255, .9)',
-		        plotShadow: true,
-		        plotBorderWidth: 1
-		    },
-		    title: {
-		        style: {
-		            color: '#000',
-		            font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
-		        }
-		    },
-		    subtitle: {
-		        style: {
-		            color: '#666666',
-		            font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
-		        }
-		    },
-		    xAxis: {
-		        gridLineWidth: 1,
-		        lineColor: '#000',
-		        tickColor: '#000',
-		        labels: {
-		            style: {
-		                color: '#000',
-		                font: '11px Trebuchet MS, Verdana, sans-serif'
-		            }
-		        },
-		        title: {
-		            style: {
-		                color: '#333',
-		                fontWeight: 'bold',
-		                fontSize: '12px',
-		                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-
-		            }
-		        }
-		    },
-		    yAxis: {
-		        minorTickInterval: 'auto',
-		        lineColor: '#000',
-		        lineWidth: 1,
-		        tickWidth: 1,
-		        tickColor: '#000',
-		        labels: {
-		            style: {
-		                color: '#000',
-		                font: '11px Trebuchet MS, Verdana, sans-serif'
-		            }
-		        },
-		        title: {
-		            style: {
-		                color: '#333',
-		                fontWeight: 'bold',
-		                fontSize: '12px',
-		                fontFamily: 'Trebuchet MS, Verdana, sans-serif'
-		            }
-		        }
-		    },
-		    legend: {
-		        itemStyle: {
-		            font: '9pt Trebuchet MS, Verdana, sans-serif',
-		            color: 'black'
-
-		        },
-		        itemHoverStyle: {
-		            color: '#039'
-		        },
-		        itemHiddenStyle: {
-		            color: 'gray'
-		        }
-		    },
-		    labels: {
-		        style: {
-		            color: '#99b'
-		        }
-		    },
-
-		    navigation: {
-		        buttonOptions: {
-		            theme: {
-		                stroke: '#CCCCCC'
-		            }
-		        }
-		    }
-		};
-
-		// Apply the theme
-		Highcharts.setOptions(Highcharts.theme);
-

+ 0 - 207
nicegui/static/templates/highcharts/high-contrast-dark.js

@@ -1,207 +0,0 @@
-/* *
- *
- *  (c) 2010-2019 Highsoft AS
- *
- *  Author: Øystein Moseng
- *
- *  License: www.highcharts.com/license
- *
- *  Accessible high-contrast dark theme for Highcharts. Specifically tailored
- *  towards 3:1 contrast against black/off-black backgrounds. Neighboring
- *  colors are tested for color blindness.
- *
- *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
-var textBright = '#F0F0F3';
-Highcharts.theme = {
-    colors: [
-        '#a6f0ff',
-        '#70d49e',
-        '#e898a5',
-        '#007faa',
-        '#f9db72',
-        '#f45b5b',
-        '#1e824c',
-        '#e7934c',
-        '#dadfe1',
-        '#a0618b'
-    ],
-    chart: {
-        backgroundColor: '#1f1f20',
-        plotBorderColor: '#606063'
-    },
-    title: {
-        style: {
-            color: textBright
-        }
-    },
-    subtitle: {
-        style: {
-            color: textBright
-        }
-    },
-    xAxis: {
-        gridLineColor: '#707073',
-        labels: {
-            style: {
-                color: textBright
-            }
-        },
-        lineColor: '#707073',
-        minorGridLineColor: '#505053',
-        tickColor: '#707073',
-        title: {
-            style: {
-                color: textBright
-            }
-        }
-    },
-    yAxis: {
-        gridLineColor: '#707073',
-        labels: {
-            style: {
-                color: textBright
-            }
-        },
-        lineColor: '#707073',
-        minorGridLineColor: '#505053',
-        tickColor: '#707073',
-        title: {
-            style: {
-                color: textBright
-            }
-        }
-    },
-    tooltip: {
-        backgroundColor: 'rgba(0, 0, 0, 0.85)',
-        style: {
-            color: textBright
-        }
-    },
-    plotOptions: {
-        series: {
-            dataLabels: {
-                color: textBright
-            },
-            marker: {
-                lineColor: '#333'
-            }
-        },
-        boxplot: {
-            fillColor: '#505053'
-        },
-        candlestick: {
-            lineColor: 'white'
-        },
-        errorbar: {
-            color: 'white'
-        },
-        map: {
-            nullColor: '#353535'
-        }
-    },
-    legend: {
-        backgroundColor: 'transparent',
-        itemStyle: {
-            color: textBright
-        },
-        itemHoverStyle: {
-            color: '#FFF'
-        },
-        itemHiddenStyle: {
-            color: '#606063'
-        },
-        title: {
-            style: {
-                color: '#D0D0D0'
-            }
-        }
-    },
-    credits: {
-        style: {
-            color: textBright
-        }
-    },
-    labels: {
-        style: {
-            color: '#707073'
-        }
-    },
-    drilldown: {
-        activeAxisLabelStyle: {
-            color: textBright
-        },
-        activeDataLabelStyle: {
-            color: textBright
-        }
-    },
-    navigation: {
-        buttonOptions: {
-            symbolStroke: '#DDDDDD',
-            theme: {
-                fill: '#505053'
-            }
-        }
-    },
-    rangeSelector: {
-        buttonTheme: {
-            fill: '#505053',
-            stroke: '#000000',
-            style: {
-                color: '#eee'
-            },
-            states: {
-                hover: {
-                    fill: '#707073',
-                    stroke: '#000000',
-                    style: {
-                        color: textBright
-                    }
-                },
-                select: {
-                    fill: '#303030',
-                    stroke: '#101010',
-                    style: {
-                        color: textBright
-                    }
-                }
-            }
-        },
-        inputBoxBorderColor: '#505053',
-        inputStyle: {
-            backgroundColor: '#333',
-            color: textBright
-        },
-        labelStyle: {
-            color: textBright
-        }
-    },
-    navigator: {
-        handles: {
-            backgroundColor: '#666',
-            borderColor: '#AAA'
-        },
-        outlineColor: '#CCC',
-        maskFill: 'rgba(180,180,255,0.2)',
-        series: {
-            color: '#7798BF',
-            lineColor: '#A6C7ED'
-        },
-        xAxis: {
-            gridLineColor: '#505053'
-        }
-    },
-    scrollbar: {
-        barBackgroundColor: '#808083',
-        barBorderColor: '#808083',
-        buttonArrowColor: '#CCC',
-        buttonBackgroundColor: '#606063',
-        buttonBorderColor: '#606063',
-        rifleColor: '#FFF',
-        trackBackgroundColor: '#404043',
-        trackBorderColor: '#404043'
-    }
-};
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 37
nicegui/static/templates/highcharts/high-contrast-light.js

@@ -1,37 +0,0 @@
-/* *
- *
- *  (c) 2010-2019 Highsoft AS
- *
- *  Author: Øystein Moseng
- *
- *  License: www.highcharts.com/license
- *
- *  Accessible high-contrast theme for Highcharts. Specifically tailored
- *  towards 3:1 contrast against white/off-white backgrounds. Neighboring
- *  colors are tested for color blindness.
- *
- *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
-Highcharts.theme = {
-    colors: [
-        '#5f98cf',
-        '#434348',
-        '#49a65e',
-        '#f45b5b',
-        '#708090',
-        '#b68c51',
-        '#397550',
-        '#c0493d',
-        '#4f4a7a',
-        '#b381b3'
-    ],
-    navigator: {
-        series: {
-            color: '#5f98cf',
-            lineColor: '#5f98cf'
-        }
-    }
-};
-// Apply the theme
-Highcharts.setOptions(Highcharts.theme);

+ 0 - 108
nicegui/static/templates/highcharts/sand-signika.js

@@ -1,108 +0,0 @@
-/**
- * @license Highcharts JS v6.1.2 (2018-08-31)
- *
- * (c) 2009-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-		Highcharts.createElement('link', {
-		    href: 'https://fonts.googleapis.com/css?family=Signika:400,700',
-		    rel: 'stylesheet',
-		    type: 'text/css'
-		}, null, document.getElementsByTagName('head')[0]);
-
-		// Add the background image to the container
-		Highcharts.wrap(Highcharts.Chart.prototype, 'getContainer', function (proceed) {
-		    proceed.call(this);
-		    this.container.style.background =
-		        'url(https://www.highcharts.com/samples/graphics/sand.png)';
-		});
-
-
-		Highcharts.theme = {
-		    colors: ['#f45b5b', '#8085e9', '#8d4654', '#7798BF', '#aaeeee',
-		        '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],
-		    chart: {
-		        backgroundColor: null,
-		        style: {
-		            fontFamily: 'Signika, serif'
-		        }
-		    },
-		    title: {
-		        style: {
-		            color: 'black',
-		            fontSize: '16px',
-		            fontWeight: 'bold'
-		        }
-		    },
-		    subtitle: {
-		        style: {
-		            color: 'black'
-		        }
-		    },
-		    tooltip: {
-		        borderWidth: 0
-		    },
-		    legend: {
-		        itemStyle: {
-		            fontWeight: 'bold',
-		            fontSize: '13px'
-		        }
-		    },
-		    xAxis: {
-		        labels: {
-		            style: {
-		                color: '#6e6e70'
-		            }
-		        }
-		    },
-		    yAxis: {
-		        labels: {
-		            style: {
-		                color: '#6e6e70'
-		            }
-		        }
-		    },
-		    plotOptions: {
-		        series: {
-		            shadow: true
-		        },
-		        candlestick: {
-		            lineColor: '#404048'
-		        },
-		        map: {
-		            shadow: false
-		        }
-		    },
-
-		    // Highstock specific
-		    navigator: {
-		        xAxis: {
-		            gridLineColor: '#D0D0D8'
-		        }
-		    },
-		    rangeSelector: {
-		        buttonTheme: {
-		            fill: 'white',
-		            stroke: '#C0C0C8',
-		            'stroke-width': 1,
-		            states: {
-		                select: {
-		                    fill: '#D0D0D8'
-		                }
-		            }
-		        }
-		    },
-		    scrollbar: {
-		        trackBorderColor: '#C0C0C8'
-		    },
-
-		    // General
-		    background2: '#E0E0E8'
-
-		};
-
-		// Apply the theme
-		Highcharts.setOptions(Highcharts.theme);
-

+ 0 - 107
nicegui/static/templates/highcharts/skies.js

@@ -1,107 +0,0 @@
-/**
- * @license Highcharts JS v6.1.2 (2018-08-31)
- *
- * (c) 2009-2017 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-		/**
-		 * (c) 2010-2017 Torstein Honsi
-		 *
-		 * License: www.highcharts.com/license
-		 *
-		 * Skies theme for Highcharts JS
-		 * @author Torstein Honsi
-		 */
-
-		Highcharts.theme = {
-		    colors: ['#514F78', '#42A07B', '#9B5E4A', '#72727F', '#1F949A',
-		        '#82914E', '#86777F', '#42A07B'],
-		    chart: {
-		        className: 'skies',
-		        borderWidth: 0,
-		        plotShadow: true,
-		        plotBackgroundImage: 'https://www.highcharts.com/demo/gfx/skies.jpg',
-		        plotBackgroundColor: {
-		            linearGradient: [0, 0, 250, 500],
-		            stops: [
-		                [0, 'rgba(255, 255, 255, 1)'],
-		                [1, 'rgba(255, 255, 255, 0)']
-		            ]
-		        },
-		        plotBorderWidth: 1
-		    },
-		    title: {
-		        style: {
-		            color: '#3E576F',
-		            font: '16px Lucida Grande, Lucida Sans Unicode,' +
-		                ' Verdana, Arial, Helvetica, sans-serif'
-		        }
-		    },
-		    subtitle: {
-		        style: {
-		            color: '#6D869F',
-		            font: '12px Lucida Grande, Lucida Sans Unicode,' +
-		                ' Verdana, Arial, Helvetica, sans-serif'
-		        }
-		    },
-		    xAxis: {
-		        gridLineWidth: 0,
-		        lineColor: '#C0D0E0',
-		        tickColor: '#C0D0E0',
-		        labels: {
-		            style: {
-		                color: '#666',
-		                fontWeight: 'bold'
-		            }
-		        },
-		        title: {
-		            style: {
-		                color: '#666',
-		                font: '12px Lucida Grande, Lucida Sans Unicode,' +
-		                ' Verdana, Arial, Helvetica, sans-serif'
-		            }
-		        }
-		    },
-		    yAxis: {
-		        alternateGridColor: 'rgba(255, 255, 255, .5)',
-		        lineColor: '#C0D0E0',
-		        tickColor: '#C0D0E0',
-		        tickWidth: 1,
-		        labels: {
-		            style: {
-		                color: '#666',
-		                fontWeight: 'bold'
-		            }
-		        },
-		        title: {
-		            style: {
-		                color: '#666',
-		                font: '12px Lucida Grande, Lucida Sans Unicode,' +
-		                ' Verdana, Arial, Helvetica, sans-serif'
-		            }
-		        }
-		    },
-		    legend: {
-		        itemStyle: {
-		            font: '9pt Trebuchet MS, Verdana, sans-serif',
-		            color: '#3E576F'
-		        },
-		        itemHoverStyle: {
-		            color: 'black'
-		        },
-		        itemHiddenStyle: {
-		            color: 'silver'
-		        }
-		    },
-		    labels: {
-		        style: {
-		            color: '#3E576F'
-		        }
-		    }
-		};
-
-		// Apply the theme
-		Highcharts.setOptions(Highcharts.theme);
-

+ 0 - 141
nicegui/static/templates/highcharts/slick.js

@@ -1,141 +0,0 @@
-(function() {
-    var a, b, c, d, e, f, g;
-    a = jQuery, e = "highcharts-themes", g = {}, b = {
-        base: ["#dd7722", "#2288cc", "#dd3322", "#22aa99", "#bb4488", "#ddaa00", "#6655cc", "#99aa00"],
-        pastel: ["#E6645C", "#55A9DC", "#886DB3", "#6CC080"],
-        steel: ["#484D59", "#aaaaaa", "#4295F3"],
-        future: ["#E6645C", "#55A9DC", "#886DB3", "#6CC080"]
-    }, c = {
-        base: {
-            enabled: !0,
-            lineWidth: 1,
-            radius: 2,
-            fillColor: "#FFFFFF",
-            lineColor: null,
-            symbol: "circle",
-            states: {
-                hover: {
-                    enabled: !1,
-                    radius: 1,
-                    lineWidth: 5
-                }
-            }
-        },
-        pastel: {
-            enabled: !0,
-            lineWidth: 3,
-            radius: 5,
-            fillColor: null,
-            lineColor: "#FFFFFF",
-            symbol: "circle",
-            states: {
-                hover: {
-                    lineWidth: 5,
-                    radius: 7
-                }
-            }
-        },
-        steel: {
-            enabled: !0,
-            lineWidth: 2,
-            radius: 5,
-            fillColor: "#FFFFFF",
-            lineColor: null,
-            symbol: "circle",
-            states: {
-                hover: {
-                    lineWidth: 3,
-                    radius: 6
-                }
-            }
-        },
-        future: {
-            enabled: !0,
-            lineWidth: 8,
-            radius: 5,
-            fillColor: null,
-            lineColor: "rgba(0, 0, 0, 0.15)",
-            symbol: "circle",
-            states: {
-                hover: {
-                    lineWidth: 0,
-                    radius: 10
-                }
-            }
-        }
-    }, g.pastel = {
-        colors: b.pastel,
-        plotOptions: {
-            line: {
-                lineWidth: 3,
-                marker: c.pastel
-            },
-            bar: {
-                pointWidth: 1
-            },
-            column: {
-                pointWidth: 1
-            },
-            scatter: {
-                marker: c.pastel
-            }
-        }
-    }, g.steel = {
-        colors: b.steel,
-        plotOptions: {
-            line: {
-                marker: c.steel
-            },
-            bar: {
-                pointWidth: 1
-            },
-            column: {
-                pointWidth: 1
-            },
-            scatter: {
-                marker: c.steel
-            }
-        }
-    }, g.future = {
-        colors: b.future,
-        plotOptions: {
-            line: {
-                marker: c.future
-            },
-            bar: {
-                pointWidth: 1
-            },
-            column: {
-                pointWidth: 1
-            },
-            scatter: {
-                marker: c.future
-            }
-        }
-    }, g._defaults = {
-        chart: {
-            style: {
-                fontFamily: "Helvetica",
-                fontWeight: "normal"
-            }
-        },
-        xAxis: {
-            lineColor: "#ccc"
-        },
-        yAxis: {
-            gridLineColor: "#e0e0e0"
-        },
-        credits: !1,
-        legend: {
-            borderRadius: 0,
-            borderWidth: 0,
-            align: "center",
-            x: 15
-        }
-    };
-    for (d in g) f = g[d], "_defaults" !== d && a.extend(!0, f, g._defaults);
-    a.fn[e] = Highcharts.themes = g, Highcharts.setTheme = function(a) {
-        var b;
-        return (b = null != Highcharts[a]) ? Highcharts.setOptions(b) : console.warn("Found no such theme.")
-    }
-}).call(this);

+ 0 - 34
nicegui/static/templates/highcharts/sunset.js

@@ -1,34 +0,0 @@
-/**
- * @license Highcharts JS v6.1.2 (2018-08-31)
- *
- * (c) 2009-2017 Highsoft AS
- *
- * License: www.highcharts.com/license
- */
-
-
-		Highcharts.theme = {
-		    colors: ['#FDD089', '#FF7F79', '#A0446E', '#251535'],
-
-		    colorAxis: {
-		        maxColor: '#60042E',
-		        minColor: '#FDD089'
-		    },
-
-		    plotOptions: {
-		        map: {
-		            nullColor: '#fefefc'
-		        }
-		    },
-
-		    navigator: {
-		        series: {
-		            color: '#FF7F79',
-		            lineColor: '#A0446E'
-		        }
-		    }
-		};
-
-		// Apply the theme
-		Highcharts.setOptions(Highcharts.theme);
-

+ 0 - 152
nicegui/static/templates/js/aggrid.js

@@ -1,152 +0,0 @@
-// {* raw *}
-
-var cached_grid_def = {};
-
-Vue.component('grid', {
-    template:
-        `<div  v-bind:id="jp_props.id" :class="jp_props.classes"  :style="jp_props.style"  ></div>`,
-    methods: {
-        evaluate_formatters(def) {
-            if (Array.isArray(def)) {
-                for (const element of def) {
-                    this.evaluate_formatters(element);
-                }
-            } else if (typeof def == "object" && def !== null) {
-                for (const [key, value] of Object.entries(def)) {
-                    if (key.toLowerCase().includes('formatter')) {
-                        eval('def[key] = ' + def[key]);
-                    }
-                    this.evaluate_formatters(value);
-                }
-            }
-        },
-        grid_change() {
-            var j = JSON.stringify(this.$props.jp_props.def);
-            var grid_def = JSON.parse(j);  // Deep copy the grid definition
-            for (let i = 0; i < this.$props.jp_props.html_columns.length; i++) {
-                if (grid_def.columnDefs[this.$props.jp_props.html_columns[i]].cellRenderer === undefined)
-                grid_def.columnDefs[this.$props.jp_props.html_columns[i]].cellRenderer = function (params) {
-                    return params.value ? params.value : '';
-                };
-            }
-            cached_grid_def[this.$props.jp_props.id] = j;
-            grid_def.onGridReady = grid_ready;
-            grid_def.popupParent = document.querySelector('body');
-            this.evaluate_formatters(grid_def);
-            for (const field of this.$props.jp_props.evaluate) {
-                eval('grid_def[field] = ' + grid_def[field]);
-            }
-            // Code for CheckboxRenderer https://blog.ag-grid.com/binding-boolean-values-to-checkboxes-in-ag-grid/
-            function CheckboxRenderer() {
-            }
-
-            CheckboxRenderer.prototype.init = function (params) {
-                this.params = params;
-
-                this.eGui = document.createElement('input');
-                this.eGui.type = 'checkbox';
-                this.eGui.checked = params.value;
-
-                this.checkedHandler = this.checkedHandler.bind(this);
-                this.eGui.addEventListener('click', this.checkedHandler);
-            };
-
-            CheckboxRenderer.prototype.checkedHandler = function (e) {
-                let checked = e.target.checked;
-                let colId = this.params.column.colId;
-                this.params.node.setDataValue(colId, checked);
-            };
-
-            CheckboxRenderer.prototype.getGui = function (params) {
-                return this.eGui;
-            };
-
-            CheckboxRenderer.prototype.destroy = function (params) {
-                this.eGui.removeEventListener('click', this.checkedHandler);
-            };
-
-            grid_def.components = {
-                checkboxRenderer: CheckboxRenderer
-            };
-
-
-            new agGrid.Grid(document.getElementById(this.$props.jp_props.id.toString()), grid_def);  // the api calls are added to grid_def
-            cached_grid_def['g' + this.$props.jp_props.id] = grid_def;
-            var auto_size = this.$props.jp_props.auto_size;
-
-
-            function grid_ready(event) {
-                if (auto_size) {
-                    var allColumnIds = [];
-                    grid_def.columnApi.getAllColumns().forEach(function (column) {
-                        allColumnIds.push(column.colId);
-                    });
-                    grid_def.columnApi.autoSizeColumns(allColumnIds);
-                }
-            }
-
-            grid_def.api.addGlobalListener(global_listener);
-            var events = this.$props.jp_props.events;
-            var props = this.$props;
-
-            function global_listener(event_name, event_obj) {
-                if (events.includes(event_name)) {
-                    var event_fields = ['data', 'rowIndex', 'type', 'value']; // for cellClicked and rowClicked
-                    var e = {
-                        'event_type': event_name,
-                        'grid': 'ag-grid',
-                        'id': props.jp_props.id,
-                        'class_name': props.jp_props.class_name,
-                        'html_tag': props.jp_props.html_tag,
-                        'vue_type': props.jp_props.vue_type,
-                        'page_id': page_id,
-                        'websocket_id': websocket_id
-                    };
-                    var more_properties = ['value', 'oldValue', 'newValue', 'context', 'rowIndex', 'data', 'toIndex',
-                        'firstRow', 'lastRow', 'clientWidth', 'clientHeight', 'started', 'finished', 'direction', 'top',
-                        'left', 'animate', 'keepRenderedRows', 'newData', 'newPage', 'source', 'visible', 'pinned',
-                        'filterInstance', 'rowPinned', 'forceBrowserFocus'];
-                    for (let i = 0; i < more_properties.length; i++) {
-                        let property = more_properties[i];
-                        if (!(typeof event_obj[property] === "undefined")) {
-                            e[property] = event_obj[property];
-                        }
-                    }
-                    if (!(typeof event_obj.column === "undefined")) {
-                        e.colId = event_obj.column.colId;
-                    }
-                    if (!(typeof event_obj.node === "undefined")) {
-                        let node_properties = ['selected', 'rowHeight'];
-                        for (let i = 0; i < node_properties.length; i++) {
-                            let property = node_properties[i];
-                            if (!(typeof event_obj.node[property] === "undefined")) {
-                                e[property] = event_obj.node[property];
-                            }
-                        }
-                        e.selected = event_obj.node.selected;
-                    }
-
-                    if (['sortChanged', 'filterChanged', 'columnMoved', 'rowDragEnd'].includes(event_name)) {
-                        e.data = grid_def.api.getDataAsCsv();
-                    }
-                    send_to_server(e, 'event');
-                }
-            }
-        }
-    },
-    mounted() {
-        this.grid_change();
-    },
-    updated() {
-        if (JSON.stringify(this.$props.jp_props.def) != cached_grid_def[this.$props.jp_props.id]) {
-            grid_to_destroy = cached_grid_def['g' + this.$props.jp_props.id];
-            grid_to_destroy.api.destroy();
-            this.grid_change(); // Explore option to check difference and update with api instead of destroying and creating new grid
-        }
-    },
-    props: {
-        jp_props: Object
-    }
-});
-
-// {* endraw *}

+ 0 - 34
nicegui/static/templates/js/altairjp.js

@@ -1,34 +0,0 @@
-// {* raw *}
-
-// Uses https://github.com/vega/vega-embed
-
-Vue.component('altairjp', {
-    template:
-        `<div  v-bind:id="jp_props.id" :class="jp_props.classes"  :style="jp_props.style"  >
-<div v-bind:id="'altair' + jp_props.id" :class="jp_props.classes"  :style="jp_props.style" ></div>
-</div>`,
-    data: function () {
-        return {
-            vega_source: {}
-        }
-    },
-    methods: {
-        chart_create() {
-            this.vega_source = this.$props.jp_props.vega_source;
-            el = document.getElementById('altair' + this.$props.jp_props.id.toString());
-            vegaEmbed(el, JSON.parse(this.$props.jp_props.vega_source), this.$props.jp_props.options).then(function (result) {
-            }).catch(console.error);
-        }
-    },
-    mounted() {
-        this.chart_create();
-    },
-    updated() {
-        if (this.vega_source != this.$props.jp_props.vega_source) this.chart_create();
-    },
-    props: {
-        jp_props: Object
-    }
-});
-
-// {* endraw *}

+ 0 - 36
nicegui/static/templates/js/bokehjp.js

@@ -1,36 +0,0 @@
-// {* raw *}
-
-// https://docs.bokeh.org/en/latest/docs/user_guide/embed.html
-
-Vue.component('bokehjp', {
-    template:
-        `<div  v-bind:id="jp_props.id" :class="jp_props.classes"  :style="jp_props.style">
-<div v-bind:id="'bokeh' + jp_props.id"></div>
-</div>`,
-    data: function () {
-        return {
-            chart: null
-        }
-    },
-    methods: {
-        chart_create() {
-            this.chart = this.$props.jp_props.chart;
-            const chart_obj = JSON.parse(this.$props.jp_props.chart);
-            Bokeh.embed.embed_item(chart_obj, 'bokeh' + this.$props.jp_props.id.toString());
-        }
-    },
-    mounted() {
-        this.chart_create();
-    },
-    updated() {
-        if (this.chart != this.$props.jp_props.chart) {
-            document.getElementById('bokeh' + this.$props.jp_props.id.toString()).innerHTML = "";
-            this.chart_create();
-       }
-    },
-    props: {
-        jp_props: Object
-    }
-});
-
-// {* endraw *}

+ 0 - 356
nicegui/static/templates/js/chartjp.js

@@ -1,356 +0,0 @@
-//{% raw %}
-
-
-var cached_graph_def = {};
-var tooltip_timeout = null;
-// var tooltip_timeout_period = 100;
-Vue.component('chart', {
-
-    template:
-        `<div v-bind:id="jp_props.id" :class="jp_props.classes"  :style="jp_props.style" ></div>`,
-    methods: {
-        evaluate_formatters(def) {
-            if (Array.isArray(def)) {
-                for (const element of def) {
-                    this.evaluate_formatters(element);
-                }
-            } else if (typeof def == "object" && typeof def == "object") {
-                for (const [key, value] of Object.entries(def)) {
-                    if (key.toLowerCase().includes('formatter')) {
-                        eval('def[key] = ' + def[value]);
-                    }
-                    this.evaluate_formatters(value);
-                }
-            }
-        },
-        graph_change() {
-            cached_graph_def[this.$props.jp_props.id] = JSON.stringify(this.$props.jp_props.def);
-            var container = this.$props.jp_props.id.toString();
-            // Evaluate all properties that include 'formatter'
-            this.evaluate_formatters(this.$props.jp_props.def);
-            if (this.$props.jp_props.stock) {
-                var c = Highcharts.stockChart(container, this.$props.jp_props.def);
-            } else {
-                var c = Highcharts.chart(container, this.$props.jp_props.def);
-            }
-            var id = this.$props.jp_props.id;
-            var tooltip_timeout_period = this.$props.jp_props.tooltip_debounce;
-            var props = this.$props.jp_props;
-            cached_graph_def['chart' + container] = c;
-            var update_dict = {};
-            if (this.$props.jp_props.events.indexOf('tooltip') >= 0) {
-                var point_array = [];
-                update_dict.tooltip = {
-                    useHTML: true,
-                    shape: 'callout',
-                    positioner: function (boxWidth, boxHeight, point) {
-                        var yf = props.tooltip_y;  // 40 is default
-                        var xf = props.tooltip_x;  // 40 is default
-                        if (props.tooltip_fixed) return {
-                            x: xf,
-                            y: yf
-                        };
-                        return {
-                            x: point.plotX + c.plotLeft + xf,
-                            y: point.plotY + c.plotTop - yf
-                        };
-                    },
-                    formatter: function (tooltip) {
-                        if (this.point != null) {
-                            // Tooltip not shared or split
-                            var e = {
-                                event_type: 'tooltip',
-                                id: id,
-                                x: this.point.x,
-                                y: this.point.y,
-                                z: this.point.z,
-                                category: this.key,
-                                color: this.point.color,
-                                percentage: this.point.percentage,
-                                total: this.point.total,
-                                point_index: this.point.index,
-                                series_name: this.series.name,
-                                series_index: this.series.index,
-                                page_id: page_id,
-                                websocket_id: websocket_id
-                            };
-
-                        } else {
-                            // Tooltip shared or split
-                            for (let i = 0; i < this.points.length; i++) {
-                                let point = {};
-                                point.x = this.points[i].point.x; // Just .x instead of point.x returns the category
-                                point.y = this.points[i].y;
-                                point.z = this.points[i].z;
-                                point.category = this.points[i].key;
-                                point.color = this.points[i].color;
-                                point.percentage = this.points[i].percentage;
-                                point.total = this.points[i].total;
-                                point.point_index = this.points[i].index;
-                                point.series_name = this.points[i].series.name;
-                                point.series_index = this.points[i].series.index;
-                                point_array.push(point);
-                            }
-                            var e = {
-                                event_type: 'tooltip',
-                                x: this.x,
-                                id: id,
-                                points: point_array,
-                                page_id: page_id,
-                                websocket_id: websocket_id
-                            };
-                        }
-
-                        if (use_websockets) {
-                            // Wait tooltip_timeout_period before sending tooltip information to server.
-                            // This allows new tooltip event delete old one if it arrives less than 100ms
-                            // after the previous one. Basically, a debouncing of the tooltip event
-                            clearTimeout(tooltip_timeout);
-                            tooltip_timeout = setTimeout(function () {
-                                    //socket.send(JSON.stringify({'type': 'event', 'event_data': e}));
-                                    send_to_server(e, 'event');
-                                }
-                                , tooltip_timeout_period);
-                        }
-                        point_array = [];
-                        if (tooltip.split) {
-                            var return_array = [];
-                            for (var i = 0; i < tooltip.chart.series.length + 1; i++) {
-                                return_array.push('Loading...');
-                            }
-                            return return_array;
-                        } else return 'Loading...';
-                    },
-                }
-            }
-            update_dict.plotOptions = {
-                series: {
-                    cursor: 'pointer',
-                    events: {},
-                    point: {
-                        events: {}
-                    }
-                }
-            };
-            if (this.$props.jp_props.events.indexOf('point_click') >= 0) {
-                update_dict.plotOptions.series.point.events.click = function (e) {
-                    var p = {
-                        event_type: 'point_click',
-                        id: id,
-                        x: e.point.x,
-                        y: e.point.y,
-                        z: e.point.z,
-                        category: e.point.category,
-                        color: e.point.color,
-                        percentage: e.point.percentage,
-                        total: e.point.total,
-                        point_index: e.point.index,
-                        type: e.type,
-                        series_name: e.point.series.name,
-                        series_index: e.point.series.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-            }
-
-            if (this.$props.jp_props.events.indexOf('point_select') >= 0) {
-                update_dict.plotOptions.series.point.events.select = function (e) {
-                    var p = {
-                        event_type: 'point_select',
-                        id: id,
-                        x: e.target.x,
-                        y: e.target.y,
-                        z: e.target.z,
-                        accumulate: e.accumulate,
-                        category: e.target.category,
-                        color: e.target.color,
-                        percentage: e.target.percentage,
-                        total: e.target.total,
-                        point_index: e.target.index,
-                        type: e.type,
-                        series_name: e.target.series.name,
-                        series_index: e.target.series.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    var selectedPoints = this.series.chart.getSelectedPoints();
-                    var selected_points = [];
-                    for (let i = 0; i < selectedPoints.length; i++) {
-                        let point = selectedPoints[i];
-                        selected_points.push({
-                            x: point.x,
-                            y: point.y,
-                            z: point.z,
-                            category: point.category,
-                            color: point.color,
-                            percentage: point.percentage,
-                            total: point.total,
-                            point_index: point.index,
-                            series_name: point.series.name,
-                            series_index: point.series.index
-                        })
-                    }
-                    p.selected_points = selected_points;
-                    send_to_server(p, 'event');
-                }
-            }
-
-            if (this.$props.jp_props.events.indexOf('point_unselect') >= 0) {
-                update_dict.plotOptions.series.point.events.unselect = function (e) {
-                    var p = {
-                        event_type: 'point_unselect',
-                        id: id,
-                        x: e.target.x,
-                        y: e.target.y,
-                        z: e.target.z,
-                        accumulate: e.accumulate,
-                        category: e.target.category,
-                        color: e.target.color,
-                        percentage: e.target.percentage,
-                        total: e.target.total,
-                        point_index: e.target.index,
-                        type: e.type,
-                        series_name: e.target.series.name,
-                        series_index: e.target.series.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    var selectedPoints = this.series.chart.getSelectedPoints();
-                    var selected_points = [];
-                    for (let i = 0; i < selectedPoints.length; i++) {
-                        let point = selectedPoints[i];
-                        selected_points.push({
-                            x: point.x,
-                            y: point.y,
-                            z: point.z,
-                            category: point.category,
-                            color: point.color,
-                            percentage: point.percentage,
-                            total: point.total,
-                            point_index: point.index,
-                            series_name: point.series.name,
-                            series_index: point.series.index
-                        })
-                    }
-                    p.selected_points = selected_points;
-                    send_to_server(p, 'event');
-                }
-            }
-
-            if (this.$props.jp_props.events.indexOf('series_hide') >= 0) {
-                update_dict.plotOptions.series.events.hide = function (e) {
-                    var p = {
-                        event_type: 'series_hide',
-                        id: id,
-                        color: e.target.color,
-                        type: e.type,
-                        series_name: e.target.name,
-                        series_index: e.target.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-            }
-
-            if (this.$props.jp_props.events.indexOf('series_show') >= 0) {
-                update_dict.plotOptions.series.events.show = function (e) {
-                    var p = {
-                        event_type: 'series_show',
-                        id: id,
-                        color: e.target.color,
-                        type: e.type,
-                        series_name: e.target.name,
-                        series_index: e.target.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-
-            }
-            if (this.$props.jp_props.events.indexOf('series_click') >= 0) {
-                update_dict.plotOptions.series.events.click = function (e) {
-                    var p = {
-                        event_type: 'series_click',
-                        id: id,
-                        type: e.type,
-                        x: e.point.x,
-                        y: e.point.y,
-                        z: e.point.z,
-                        category: e.point.category,
-                        color: e.point.color,
-                        percentage: e.point.percentage,
-                        total: e.point.total,
-                        point_index: e.point.index,
-                        series_name: e.point.series.name,
-                        series_index: e.point.series.index,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-            }
-
-            if (this.$props.jp_props.events.indexOf('zoom_x') >= 0) {
-                update_dict.xAxis = {
-                    events: {}
-                };
-                update_dict.xAxis.events.setExtremes = function (e) {
-                    var p = {
-                        event_type: 'zoom_x',
-                        id: id,
-                        type: e.type,
-                        min: e.min,
-                        max: e.max,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-            }
-            if (this.$props.jp_props.events.indexOf('zoom_y') >= 0) {
-                update_dict.yAxis = {
-                    events: {}
-                };
-                update_dict.yAxis.events.setExtremes = function (e) {
-                    var p = {
-                        event_type: 'zoom_y',
-                        id: id,
-                        type: e.type,
-                        min: e.min,
-                        max: e.max,
-                        page_id: page_id,
-                        websocket_id: websocket_id
-                    };
-                    send_to_server(p, 'event');
-                }
-            }
-
-            c.update(update_dict);
-        }
-    },
-    mounted() {
-        this.graph_change();
-    },
-    updated() {
-        const container = this.$props.jp_props.id.toString();
-        const chart = cached_graph_def['chart' + container];
-        if (!this.$props.jp_props.use_cache || (JSON.stringify(this.$props.jp_props.def) != cached_graph_def[this.$props.jp_props.id])) {
-            cached_graph_def[this.$props.jp_props.id] = JSON.stringify(this.$props.jp_props.def);
-            if (this.$props.jp_props.update_create) {
-                this.graph_change();
-            } else {
-                chart.update(this.$props.jp_props.def, true, true, this.$props.jp_props.update_animation);
-            }
-        }
-    },
-    props: {
-        jp_props: Object
-    }
-});
-
-//   {% endraw %}
-

+ 0 - 48
nicegui/static/templates/js/deckgl.js

@@ -1,48 +0,0 @@
-// {* raw *}
-
-// Work in progress. Does not work well for all decks
-// Use the iframejp component instead for now
-
-var cached_deckgl_def = {};
-
-Vue.component('deckgl', {
-    template:
-        `<div  v-bind:id="jp_props.id" :class="jp_props.classes"  :style="jp_props.style"  ></div>`,
-    data: function () {
-        return {
-            deck_def: {},
-            deckInstance: null
-        }
-    },
-    methods: {
-        deck_create() {
-            const tooltip = true;
-            const customLibraries = null;
-            this.deck_def = this.$props.jp_props.deck;
-            jsonInput = JSON.parse(this.deck_def);
-            this.$nextTick(function () {
-                this.deckInstance = createDeck({
-                    mapboxApiKey: this.$props.jp_props.mapbox_key,
-                    container: document.getElementById(this.$props.jp_props.id.toString()),
-                    jsonInput,
-                    tooltip,
-                    customLibraries
-                });
-            });
-        }
-    },
-    mounted() {
-        this.deck_create();
-    },
-    updated() {
-        updateDeck('', this.deckInstance);
-        updateDeck(this.$props.jp_props.deck, this.deckInstance);
-        this.deckInstance.redraw(true);
-        this.deck_def = this.$props.jp_props.deck;
-    },
-    props: {
-        jp_props: Object
-    }
-});
-
-// {* endraw *}

+ 0 - 90
nicegui/static/templates/js/editorjp.js

@@ -1,90 +0,0 @@
-// {% raw %}
-
-// https://github.com/sparksuite/simplemde-markdown-editor
-// Component for markup editor
-Vue.component('editorjp', {
-
-    render: function (h) {
-        var comps = [this.jp_props.text];
-
-        var vnode = h(this.jp_props.html_tag,
-            {
-                class: this.jp_props.classes,  // class always shows up in rendering even when there is no class
-                style: this.jp_props.style,
-                attrs: this.jp_props.attrs,
-                on: {
-                    change: this.eventFunction,
-                },
-                directives: [],
-                ref: 'r' + this.jp_props.id
-
-            },
-            comps);
-        return vnode;
-    },
-    methods: {
-        eventFunction: (function (event) {
-            eventHandler(this.$props, event);
-        })
-    },
-    mounted() {
-        var simplemde = new SimpleMDE({element: (this.$refs['r' + this.$props.jp_props.id])});
-        this.$props.simplemde = simplemde;
-        this.$props.updated = false;
-        var p = this.$props;
-        p.updated = true;
-        if (this.$props.jp_props.value) {
-            simplemde.value(this.$props.jp_props.value);
-        } else {
-            simplemde.value(this.$props.jp_props.text);
-        }
-        p.cached_value = simplemde.value();
-        p.change_timeout = '';
-
-        // if (props.jp_props.debounce) {
-        // clearTimeout(props.timeout);
-        // props.timeout = setTimeout(function () {
-        //         send_to_server(e, props.jp_props.debug);
-        //     }
-        //     , props.jp_props.debounce);
-    // } else {
-    //     send_to_server(e, props.jp_props.debug);
-    // }
-
-        simplemde.codemirror.on("change", function (event) {
-            clearTimeout(p.change_timeout);
-            p.change_timeout = setTimeout(function () {
-
-                p.updated = !p.updated;
-                if (p.updated) {
-                    return;
-                }
-                event.type = 'change';
-                event.target = {};
-                event.target.id = p.jp_props.id;
-                event.target.value = simplemde.value();
-                event.currentTarget = {};
-                event.currentTarget.id = p.jp_props.id;
-                event.form_data = false;
-                eventHandler(p, event, false, simplemde.codemirror.getCursor());
-            }, 200);
-        });
-
-
-    },
-    updated() {
-        if (this.$props.jp_props.input_type) {
-            if (this.$props.cached_value != this.$props.jp_props.value) {
-                var cursor_position = this.$props.simplemde.codemirror.getCursor();
-                this.$props.simplemde.value(this.$props.jp_props.value);
-                this.$props.simplemde.codemirror.setCursor(cursor_position);
-                this.$props.cached_value = this.$props.jp_props.value;
-            }
-        }
-    },
-    props: {
-        jp_props: Object,
-    }
-});
-
-// {% endraw %}

+ 0 - 177
nicegui/static/templates/js/event_handler.js

@@ -1,177 +0,0 @@
-// {% raw %}
-
-var files_chosen = {};
-
-function eventHandler(props, event, form_data, aux) {
-
-    if (props.jp_props.debug) {
-        console.log('-------------------------');
-        console.log('In eventHandler: ' + event.type + '  ' + props.jp_props.vue_type + '  ' + props.jp_props.class_name);
-        console.log(event);
-        console.log(props.jp_props);
-        console.log('-------------------------');
-    }
-    if (!websocket_ready && use_websockets) {
-        setTimeout(function(){ eventHandler(props, event, form_data, aux); }, 100);
-        return;
-    }
-    let event_type = event.type;
-    if (event_type == 'input' && (props.jp_props.vue_type == 'quasar_component') && (props.jp_props.disable_input_event)) {
-        comp_dict[props.jp_props.id].value = event.target.value;
-        return;
-    }
-    if (event_type == 'focusin' && (props.jp_props.vue_type == 'quasar_component')) {
-        event_type = 'focus';
-        event.target.value = comp_dict[props.jp_props.id].value;
-    }
-    if (event_type == 'focusout' && (props.jp_props.vue_type == 'quasar_component')) {
-        event_type = 'blur';
-        event.target.value = comp_dict[props.jp_props.id].value;
-    }
-    e = {
-        'event_type': event_type,
-        'id': props.jp_props.id,
-        'class_name': props.jp_props.class_name,
-        'html_tag': props.jp_props.html_tag,
-        'vue_type': props.jp_props.vue_type,
-        'event_target': event.target.id,
-        'input_type': props.jp_props.input_type,
-        'checked': event.target.checked,
-        'data': event.data,
-        'value': event.target.value,
-        'page_id': page_id,
-        'websocket_id': websocket_id
-    };
-    if (props.jp_props.additional_properties) {
-        for (let i = 0; i < props.jp_props.additional_properties.length; i++) {
-            e[props.jp_props.additional_properties[i]] = event[props.jp_props.additional_properties[i]];
-        }
-    }
-    if ((event instanceof Event) && (event.target.type == 'file')) {
-
-        files_chosen[event.target.id] = event.target.files;
-        var files = [];
-        for (let i = 0; i < event.target.files.length; i++) {
-            const fi = event.target.files[i];
-            files.push({name: fi.name, size: fi.size, type: fi.type, lastModified: fi.lastModified});
-        }
-        e['files'] = files;
-    }
-    if (form_data) {
-        e['form_data'] = form_data;
-    } else {
-        if (event.currentTarget)
-            e['event_current_target'] = event.currentTarget.id;
-    }
-    if (aux) e['aux'] = aux;
-    if (event instanceof KeyboardEvent) {
-        // https://developer.mozilla.org/en-US/docs/Web/Events/keydown   keyup, keypress
-        e['key_data'] = {
-            altKey: event.altKey,
-            ctrlKey: event.ctrlKey,
-            shiftKey: event.shiftKey,
-            metaKey: event.metaKey,
-            code: event.code,
-            key: event.key,
-            location: event.location,
-            repeat: event.repeat,
-            locale: event.locale
-        }
-    }
-
-    let modifiers = props.jp_props.event_modifiers[event.type];
-
-    if (modifiers && modifiers.debounce) {
-        let callNow = modifiers.debounce.immediate && !modifiers.debounce.timeout;
-        clearTimeout(modifiers.debounce.timeout);
-        let set_e = e;
-        modifiers.debounce.timeout = setTimeout(function () {
-                modifiers.debounce.timeout = undefined;
-                if (!callNow) send_to_server(set_e, 'event', props.jp_props.debug);
-            }
-            , modifiers.debounce.value);
-        if (callNow) send_to_server(set_e, 'event', props.jp_props.debug);
-
-    } else if (modifiers && modifiers.throttle) {
-        if (!modifiers.throttle.timeout) {
-            let set_e = e;
-            modifiers.throttle.timeout = setTimeout(function () {
-                    send_to_server(set_e, 'event', props.jp_props.debug);
-                    modifiers.throttle.timeout = undefined;
-                }
-                , modifiers.throttle.value);
-        }
-    } else if (props.jp_props.debounce && (event.type == 'input')) {
-        clearTimeout(props.timeout);
-        let set_e = e;
-        props.timeout = setTimeout(function () {
-                send_to_server(set_e, 'event', props.jp_props.debug);
-            }
-            , props.jp_props.debounce);
-    } else {
-        send_to_server(e, 'event', props.jp_props.debug);
-    }
-
-    // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
-    if (props.jp_props.scroll && (event.type == 'click')) {
-        event.preventDefault();
-        c = document.getElementById(props.jp_props.scroll_to);
-
-        c.scrollIntoView({
-            behavior: props.jp_props.scroll_option,    // Default is 'smooth'
-            block: props.jp_props.block_option,
-            inline: props.jp_props.inline_option,
-        });
-
-    }
-}
-
-function send_to_server(e, event_type, debug_flag) {
-    if (debug_flag) {
-        console.log('Sending message to server:');
-        console.log({'type': event_type, 'event_data': e});
-    }
-    if (use_websockets) {
-        if (web_socket_closed) {
-            window.location.reload();
-            return;
-        }
-        if (websocket_ready) {
-            socket.send(JSON.stringify({'type': event_type, 'event_data': e}));
-        } else {
-            setTimeout(function () {
-                socket.send(JSON.stringify({'type': event_type, 'event_data': e}));
-            }, 1000);
-        }
-    } else {
-
-        d = JSON.stringify({'type': 'event', 'event_data': e});
-        $.ajax({
-            type: "POST",
-            url: "/zzz_justpy_ajax",
-            data: JSON.stringify({'type': event_type, 'event_data': e}),
-            success: function (msg) {
-                if (msg.page_options.redirect) {
-                    location.href = msg.page_options.redirect;
-                }
-                if (msg.page_options.open) {
-                    window.open(msg.page_options.open, '_blank');
-                }
-                if (msg.page_options.display_url !== null)
-                    window.history.pushState("", "", msg.page_options.display_url);
-                document.title = msg.page_options.title;
-                if (msg.page_options.favicon) {
-                    var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
-                    link.type = 'image/x-icon';
-                    link.rel = 'shortcut icon';
-                    link.href = '{{ options.static_name + '/' }}' + msg.page_options.favicon;
-                    document.getElementsByTagName('head')[0].appendChild(link);
-                }
-                if (msg) app1.justpyComponents = msg.data;
-            },
-            dataType: 'json'
-        });
-    }
-}
-
-// {% endraw %}

+ 0 - 337
nicegui/static/templates/js/html_component.js

@@ -1,337 +0,0 @@
-// {% raw %}
-
-
-Vue.component('html_component', {
-
-    render: function (h) {
-        if (this.jp_props.hasOwnProperty('text')) {
-            var comps = [this.jp_props.text];
-        } else comps = [];
-
-        for (var i = 0; i < this.jp_props.object_props.length; i++) {
-            if (this.jp_props.object_props[i].show) {
-                comps.push(h(this.jp_props.object_props[i].vue_type, {
-                    props: {
-                        jp_props: this.jp_props.object_props[i]
-                    }
-                }))
-            }
-        }
-
-        description_object = {
-            style: this.jp_props.style,
-            attrs: this.jp_props.attrs,
-            domProps: {
-                // innerHTML: this.jp_props.inner_html
-            },
-            on: {
-                // click: this.eventFunction,
-            },
-            directives: [],
-            slot: this.jp_props.slot,
-            ref: 'r' + this.jp_props.id
-        };
-
-        if (this.jp_props.classes) {
-            description_object['class'] = this.jp_props.classes;
-        }
-
-        var event_description = {};
-        for (i = 0; i < this.jp_props.events.length; i++) {
-            if (!this.jp_props.events[i].includes('__'))
-                event_description[this.jp_props.events[i]] = this.eventFunction
-        }
-        description_object['on'] = event_description;
-
-
-        if (this.jp_props.inner_html) {
-            description_object['domProps'] = {innerHTML: this.jp_props.inner_html};
-        }
-
-        return h(this.jp_props.html_tag, description_object, comps);
-
-    },
-    data: function () {
-        return {
-            previous_display: 'none'
-        }
-    },
-    methods: {
-
-        eventFunction: (function (event) {
-            if (!this.$props.jp_props.event_propagation) {
-                event.stopPropagation();
-            }
-            if (event.type == 'dragstart') {
-                if (this.$props.jp_props.drag_options) {
-                    this.$refs['r' + this.$props.jp_props.id].className = this.$props.jp_props.drag_options['drag_classes']
-                }
-            }
-            if (event.type == 'dragover') {
-                event.preventDefault();
-                return
-            }
-            if (event.type == 'drop') {
-
-            }
-            if (event.type == 'submit') {
-                var form_reference = this.$el;
-                var props = this.$props;
-                event.preventDefault();    //stop form from being submitted in the normal way
-                event.stopPropagation();
-                var form_elements_list = [];
-                var form_elements = form_reference.elements;
-                var reader = new FileReader();
-                var file_readers = [];
-                var reader_ready = [];
-                var file_content = [];
-                var file_element_position = null;
-
-                for (var i = 0; i < form_elements.length; i++) {
-                    var attributes = form_elements[i].attributes;
-                    var attr_dict = {};
-                    attr_dict['html_tag'] = form_elements[i].tagName.toLowerCase();
-                    for (var j = 0; j < attributes.length; j++) {
-                        var attr = attributes[j];
-                        attr_dict[attr.name] = attr.value;
-                        if (attr.name == 'type') {
-                            var input_type = attr.value;
-                        }
-                    }
-                    attr_dict['value'] = form_elements[i].value;
-                    attr_dict['checked'] = form_elements[i].checked;
-                    attr_dict['id'] = form_elements[i].id;
-
-                    if ((attr_dict['html_tag'] == 'input') && (input_type == 'file') && (files_chosen[attr_dict['id']])) {
-                        file_element_position = i;
-                        reader_ready = [];
-                        attr_dict['files'] = [];
-                        const file_list = files_chosen[attr_dict['id']];
-                        const num_files = file_list.length;
-                        for (let j = 0; j < num_files; j++) {
-                            reader_ready.push(false);
-                            file_content.push('pending');
-                            file_readers.push(new FileReader());
-                            attr_dict['files'].push({
-                                file_content: 'pending',
-                                name: file_list[j].name,
-                                size: file_list[j].size,
-                                type: file_list[j].type,
-                                lastModified: file_list[j].lastModified
-                            });
-                        }
-                        for (let j = 0; j < num_files; j++) {
-                            file_readers[j].onload = function (e) {
-                                file_content[j] = e.target.result.substring(e.target.result.indexOf(",") + 1);
-                                reader_ready[j] = true;
-                            };
-                            file_readers[j].readAsDataURL(file_list[j]);
-                        }
-                    }
-
-                    form_elements_list.push(attr_dict);
-                }
-
-                function check_readers() {
-                    if (reader_ready.every(function (x) {
-                        return x
-                    })) {
-                        const file_element = form_elements_list[file_element_position];
-
-                        for (let i = 0; i < file_element.files.length; i++) {
-                            file_element.files[i].file_content = file_content[i];
-                        }
-                        eventHandler(props, event, form_elements_list);
-                        return;
-                    } else {
-
-                    }
-                    setTimeout(check_readers, 300);
-                }
-
-                if (file_element_position === null) {
-                    eventHandler(props, event, form_elements_list);
-                } else {
-                    check_readers();
-                }
-
-            } else {
-                eventHandler(this.$props, event, false);
-            }
-        }),
-        animateFunction: (function () {
-            var animation = this.$props.jp_props.animation;
-            var element = this.$el;
-            element.classList.add('animated', animation);
-            element.classList.remove('hidden');
-            var event_func = function () {
-                element.classList.remove('animated', animation);
-                if (animation.includes('Out')) {
-                    element.classList.add('hidden');
-                } else {
-                    // element.classList.remove('hidden');
-                }
-                element.removeEventListener('animationend', event_func);
-            };
-            element.addEventListener('animationend', event_func);
-        }),
-        transitionFunction: (function () {
-            let el = this.$refs['r' + this.$props.jp_props.id];
-            const props = this.$props.jp_props;
-            if (el.$el) el = el.$el;
-            const class_list = props.classes.trim().replace(/\s\s+/g, ' ').split(' ');
-            // Transition change from hidden to not hidden
-            if (props.transition.enter && this.previous_display == 'none' && (!class_list.includes('hidden'))) {
-
-                let enter_list = props.transition.enter.trim().replace(/\s\s+/g, ' ').split(' ');
-                let enter_start_list = props.transition.enter_start.trim().replace(/\s\s+/g, ' ').split(' ');
-                let enter_end_list = props.transition.enter_end.trim().replace(/\s\s+/g, ' ').split(' ');
-                el.classList.add(...enter_start_list);
-
-                setTimeout(function () {
-                    el.classList.remove(...enter_start_list);
-                    el.classList.add(...enter_list);
-                    el.classList.add(...enter_end_list);
-                    let event_func = function () {
-                        el.removeEventListener('transitionend', event_func);
-                        el.classList.remove(...enter_list);
-                        el.classList.remove(...enter_end_list);
-                    };
-                    el.addEventListener('transitionend', event_func);
-                }, 3);
-            }
-            // Transition change from not hidden to hidden
-            else if (props.transition.leave && this.previous_display != 'none' && (class_list.includes('hidden'))) {
-                let leave_list = props.transition.leave.trim().replace(/\s\s+/g, ' ').split(' ');
-                let leave_start_list = props.transition.leave_start.trim().replace(/\s\s+/g, ' ').split(' ');
-                let leave_end_list = props.transition.leave_end.trim().replace(/\s\s+/g, ' ').split(' ');
-                el.classList.add(...leave_start_list);
-                el.classList.remove('hidden');
-
-                setTimeout(function () {
-                    el.classList.remove(...leave_start_list);
-                    el.classList.add(...leave_list);
-                    el.classList.add(...leave_end_list);
-                    let event_func = function () {
-                        el.removeEventListener('transitionend', event_func);
-                        el.classList.remove(...leave_list);
-                        el.classList.remove(...leave_end_list);
-                        el.classList.add('hidden');
-
-                    };
-                    el.addEventListener('transitionend', event_func);
-                }, 3);
-
-            }
-        }),
-        transitionLoadFunction: (function () {
-            let el = this.$refs['r' + this.$props.jp_props.id];
-            const props = this.$props.jp_props;
-            if (el.$el) el = el.$el;
-            const class_list = props.classes.trim().replace(/\s\s+/g, ' ').split(' ');
-
-
-                let load_list = props.transition.load.trim().replace(/\s\s+/g, ' ').split(' ');
-                let load_start_list = props.transition.load_start.trim().replace(/\s\s+/g, ' ').split(' ');
-                let load_end_list = props.transition.load_end.trim().replace(/\s\s+/g, ' ').split(' ');
-                el.classList.add(...load_start_list);
-
-                setTimeout(function () {
-                    el.classList.remove(...load_start_list);
-                    el.classList.add(...load_list);
-                    el.classList.add(...load_end_list);
-                    let event_func = function () {
-                        el.removeEventListener('transitionend', event_func);
-                        el.classList.remove(...load_end_list);
-                        el.classList.remove(...load_list);
-                    };
-                    el.addEventListener('transitionend', event_func);
-                }, 3)
-
-        })
-    },
-    mounted() {
-        const el = this.$refs['r' + this.$props.jp_props.id];
-        const props = this.$props.jp_props;
-         if (Boolean(props.attrs.srcdoc)) {
-             this.$props.jp_props.attrs.srcdoc = decodeURIComponent(this.$props.jp_props.attrs.srcdoc);
-         }
-
-        if (props.animation) this.animateFunction();
-        if (props.id && props.transition && props.transition.load) this.transitionLoadFunction();
-
-        for (let i = 0; i < props.events.length; i++) {
-            let split_event = props.events[i].split('__');
-            if (split_event[1] == 'out')
-                document.addEventListener(split_event[0], function (event) {
-                    if (el.contains(event.target)) return;
-                    if (el.offsetWidth < 1 && el.offsetHeight < 1) return;
-                    e = {
-                        'event_type': 'click__out',
-                        'id': props.id,
-                        'class_name': props.class_name,
-                        'html_tag': props.html_tag,
-                        'vue_type': props.vue_type,
-                        'page_id': page_id,
-                        'websocket_id': websocket_id
-                    };
-                    send_to_server(e, 'event', props.debug);
-                });
-        }
-
-        if (props.input_type && (props.input_type != 'file')) {
-            el.value = props.value;
-        }
-
-        if (props.set_focus) {
-            this.$nextTick(() => el.focus())
-        }
-
-
-    },
-    beforeUpdate() {
-        if (this.$props.jp_props.id && this.$props.jp_props.transition) {
-            let el = this.$refs['r' + this.$props.jp_props.id];
-            if (el.$el) el = el.$el;
-            this.previous_display = getComputedStyle(el, null).display;
-        }
-    },
-    updated() {
-        const el = this.$refs['r' + this.$props.jp_props.id];
-        const props = this.$props.jp_props;
-        if (Boolean(props.attrs.srcdoc)) {
-             this.$props.jp_props.attrs.srcdoc = decodeURIComponent(this.$props.jp_props.attrs.srcdoc);
-         }
-
-        if (props.animation) this.animateFunction();
-        if (this.$props.jp_props.id && props.transition) this.transitionFunction();
-
-        if (props.input_type && (props.input_type != 'file')) {
-
-            el.value = props.value;    //make sure that the input value is the correct one received from server
-
-            if (props.input_type == 'radio') {
-                if (props.checked) {
-                    el.checked = true;  // This un-checks other radio buttons in group also
-                } else {
-                    el.checked = false;
-                }
-            }
-
-            if (props.input_type == 'checkbox') {
-                el.checked = props.checked;
-            }
-        }
-
-        if (props.set_focus) {
-            this.$nextTick(() => el.focus())
-        }
-
-    },
-    props: {
-        jp_props: Object,
-
-    }
-});
-
-// {% endraw %}

Some files were not shown because too many files changed in this diff