page.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import inspect
  2. import justpy as jp
  3. from typing import Awaitable, Callable, Optional, Union
  4. from pygments.formatters import HtmlFormatter
  5. from starlette.requests import Request
  6. from ..globals import config, page_stack, view_stack
  7. class Page(jp.QuasarPage):
  8. def __init__(self,
  9. route: str,
  10. title: Optional[str] = None,
  11. favicon: Optional[str] = None,
  12. dark: Optional[bool] = ...,
  13. classes: str = 'q-ma-md column items-start',
  14. css: str = HtmlFormatter().get_style_defs('.codehilite'),
  15. on_connect: Optional[Union[Awaitable, Callable]] = None,
  16. ):
  17. """Page
  18. Creates a new page at the given path.
  19. :param route: route of the new page (path must start with '/')
  20. :param title: optional page title
  21. :param favicon: optional favicon
  22. :param dark: whether to use Quasar's dark mode (defaults to `dark` argument of `run` command)
  23. :param classes: tailwind classes for the container div (default: `'q-ma-md column items-start'`)
  24. :param css: CSS definitions
  25. :param on_connect: optional function or coroutine which is called for each new client connection
  26. """
  27. super().__init__()
  28. self.delete_flag = False
  29. self.title = title or config.title
  30. self.favicon = favicon or config.favicon
  31. self.dark = dark if dark is not ... else config.dark
  32. self.tailwind = True # use Tailwind classes instead of Quasars
  33. self.css = css
  34. self.on_connect = on_connect or config.on_connect
  35. self.head_html += '''
  36. <script>
  37. confirm = () => { setTimeout(location.reload.bind(location), 100); return false; };
  38. </script>
  39. ''' # avoid confirmation dialog for reload
  40. self.view = jp.Div(a=self, classes=classes, style='row-gap: 1em', temp=False)
  41. self.view.add_page(self)
  42. self.route = route
  43. jp.Route(route, self._route_function)
  44. async def _route_function(self, request: Request):
  45. if self.on_connect:
  46. arg_count = len(inspect.signature(self.on_connect).parameters)
  47. is_coro = inspect.iscoroutinefunction(self.on_connect)
  48. if arg_count == 1:
  49. await self.on_connect(request) if is_coro else self.on_connect(request)
  50. elif arg_count == 0:
  51. await self.on_connect() if is_coro else self.on_connect()
  52. else:
  53. raise ValueError(f'invalid number of arguments (0 or 1 allowed, got {arg_count})')
  54. return self
  55. def __enter__(self):
  56. page_stack.append(self)
  57. view_stack.append(self.view)
  58. return self
  59. def __exit__(self, *_):
  60. page_stack.pop()
  61. view_stack.pop()