Browse Source

update ui.log

Falko Schindler 2 years ago
parent
commit
52a19a921a

+ 1 - 1
api_docs_and_examples.py

@@ -384,7 +384,7 @@ To overlay an SVG, make the `viewBox` exactly the size of the image and provide
             {'id': 'letters', 'children': [{'id': 'A'}, {'id': 'B'}]},
         ], label_key='id', on_select=lambda e: ui.notify(e.value))
 
-    # @example(ui.log)
+    @example(ui.log, skip=False)
     def log_example():
         from datetime import datetime
 

+ 5 - 1
nicegui/element.py

@@ -1,6 +1,6 @@
 import shlex
 from abc import ABC
-from typing import Callable, Dict, List, Optional
+from typing import Any, Callable, Dict, List, Optional
 
 from . import globals
 from .elements.mixins.visibility import Visibility
@@ -145,3 +145,7 @@ class Element(ABC, Visibility):
         collect_ids(self.id)
         elements = {id: self.client.elements[id].to_dict() for id in ids}
         create_task(globals.sio.emit('update', {'elements': elements}, room=str(self.client.id)))
+
+    def run_method(self, name: str, *args: Any) -> None:
+        data = {'id': self.id, 'name': name, 'args': args}
+        create_task(globals.sio.emit('run_method', data, room=str(self.client.id)))

+ 26 - 0
nicegui/elements/log.js

@@ -0,0 +1,26 @@
+export default {
+  template: "<textarea disabled></textarea>",
+  data() {
+    return {
+      num_lines: 0,
+    };
+  },
+  methods: {
+    push(line) {
+      const decoded = decodeURIComponent(line);
+      const textarea = this.$el;
+      textarea.innerHTML += (this.num_lines ? "\n" : "") + decoded;
+      textarea.scrollTop = textarea.scrollHeight;
+      this.num_lines += decoded.split("\n").length;
+      while (this.max_lines && this.num_lines > this.max_lines) {
+        const index = textarea.innerHTML.indexOf("\n");
+        if (index == -1) break;
+        textarea.innerHTML = textarea.innerHTML.slice(index + 1);
+        this.num_lines -= 1;
+      }
+    },
+  },
+  props: {
+    max_lines: Number,
+  },
+};

+ 22 - 0
nicegui/elements/log.py

@@ -0,0 +1,22 @@
+from ..element import Element
+from ..vue import register_component
+
+register_component('log', __file__, 'log.js')
+
+
+class Log(Element):
+
+    def __init__(self, max_lines: int = None) -> None:
+        """Log view
+
+        Create a log view that allows to add new lines without re-transmitting the whole history to the client.
+
+        :param max_lines: maximum number of lines before dropping oldest ones (default: `None`)
+        """
+        super().__init__('log')
+        self._props['max_lines'] = max_lines
+        self.classes('border whitespace-pre font-mono')
+        self.style('opacity: 1 !important; cursor: text !important')
+
+    def push(self, line: str) -> None:
+        self.run_method('push', line)

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

@@ -1,42 +0,0 @@
-var num_lines = 0;
-
-Vue.component("log", {
-  template: `<textarea v-bind:id="jp_props.id" :class="jp_props.classes" :style="jp_props.style" disabled></textarea>`,
-  mounted() {
-    comp_dict[this.$props.jp_props.id] = this;
-
-    const sendConnectEvent = () => {
-      if (websocket_id === "") return;
-      const event = {
-        event_type: "onConnect",
-        vue_type: this.$props.jp_props.vue_type,
-        id: this.$props.jp_props.id,
-        page_id: page_id,
-        websocket_id: websocket_id,
-      };
-      send_to_server(event, "event");
-      clearInterval(connectInterval);
-    };
-    const connectInterval = setInterval(sendConnectEvent, 100);
-  },
-  methods: {
-    push(line) {
-      const decoded = decodeURIComponent(line);
-      const textarea = document.getElementById(this.$props.jp_props.id);
-      textarea.innerHTML += (num_lines ? "\n" : "") + decoded;
-      textarea.scrollTop = textarea.scrollHeight;
-      num_lines += decoded.split("\n").length;
-
-      const max_lines = this.$props.jp_props.options.max_lines;
-      while (max_lines != null && num_lines > max_lines) {
-        const index = textarea.innerHTML.indexOf("\n");
-        if (index == -1) break;
-        textarea.innerHTML = textarea.innerHTML.slice(index + 1);
-        num_lines -= 1;
-      }
-    },
-  },
-  props: {
-    jp_props: Object,
-  },
-});

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

@@ -1,58 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import traceback
-import urllib
-from collections import deque
-from typing import Deque
-
-from justpy.htmlcomponents import WebPage
-
-from ..routes import add_dependencies
-from ..task_logger import create_task
-from .custom_view import CustomView
-from .element import Element
-
-add_dependencies(__file__)
-
-
-class LogView(CustomView):
-
-    def __init__(self, lines: Deque[str], max_lines: int):
-        super().__init__('log', max_lines=max_lines)
-        self.lines = lines
-        self.allowed_events = ['onConnect']
-        self.initialize(onConnect=self.handle_connect)
-
-    def handle_connect(self, msg):
-        try:
-            if self.lines:
-                content = '\n'.join(self.lines)
-                command = f'push("{urllib.parse.quote(content)}")'
-                create_task(self.run_method(command, msg.websocket), name=str(command))
-        except:
-            traceback.print_exc()
-
-
-class Log(Element):
-
-    def __init__(self, max_lines: int = None):
-        """Log view
-
-        Create a log view that allows to add new lines without re-transmitting the whole history to the client.
-
-        :param max_lines: maximum number of lines before dropping oldest ones (default: `None`)
-        """
-        self.lines = deque(maxlen=max_lines)
-        super().__init__(LogView(lines=self.lines, max_lines=max_lines))
-        self.classes('border whitespace-pre font-mono').style('opacity: 1 !important; cursor: text !important')
-
-    async def push_async(self, line: str):
-        self.lines.append(line)
-        await asyncio.gather(*[
-            self.view.run_method(f'push("{urllib.parse.quote(line)}")', socket)
-            for socket in WebPage.sockets.get(self.page.page_id, {}).values()
-        ])
-
-    def push(self, line: str):
-        create_task(self.push_async(line), name=f'log.push line {line}')

+ 2 - 0
nicegui/templates/index.html

@@ -24,6 +24,7 @@
         const element = elements[id];
         const props = {
           id: element.id,
+          ref: 'r' + element.id,
           class: element.class.join(' ') || undefined,
           style: Object.entries(element.style).reduce((str, [p, val]) => `${str}${p}:${val};`, '') || undefined,
           ...element.props,
@@ -63,6 +64,7 @@
           window.socket.on("update", (msg) => {
             Object.entries(msg.elements).forEach(([id, element]) => this.elements[element.id] = element);
           });
+          window.socket.on("run_method", (msg) => this.$refs['r' + msg.id][msg.name](...msg.args));
           window.socket.on("notify", (msg) => Quasar.Notify.create(msg));
           window.socket.on("disconnect", () => window.location.reload());
         },

+ 1 - 0
nicegui/ui.py

@@ -15,6 +15,7 @@ from .elements.joystick import Joystick as joystick
 from .elements.label import Label as label
 from .elements.link import Link as link
 from .elements.link import 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 import MenuItem as menu_item