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'}]},
             {'id': 'letters', 'children': [{'id': 'A'}, {'id': 'B'}]},
         ], label_key='id', on_select=lambda e: ui.notify(e.value))
         ], label_key='id', on_select=lambda e: ui.notify(e.value))
 
 
-    # @example(ui.log)
+    @example(ui.log, skip=False)
     def log_example():
     def log_example():
         from datetime import datetime
         from datetime import datetime
 
 

+ 5 - 1
nicegui/element.py

@@ -1,6 +1,6 @@
 import shlex
 import shlex
 from abc import ABC
 from abc import ABC
-from typing import Callable, Dict, List, Optional
+from typing import Any, Callable, Dict, List, Optional
 
 
 from . import globals
 from . import globals
 from .elements.mixins.visibility import Visibility
 from .elements.mixins.visibility import Visibility
@@ -145,3 +145,7 @@ class Element(ABC, Visibility):
         collect_ids(self.id)
         collect_ids(self.id)
         elements = {id: self.client.elements[id].to_dict() for id in ids}
         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)))
         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 element = elements[id];
         const props = {
         const props = {
           id: element.id,
           id: element.id,
+          ref: 'r' + element.id,
           class: element.class.join(' ') || undefined,
           class: element.class.join(' ') || undefined,
           style: Object.entries(element.style).reduce((str, [p, val]) => `${str}${p}:${val};`, '') || undefined,
           style: Object.entries(element.style).reduce((str, [p, val]) => `${str}${p}:${val};`, '') || undefined,
           ...element.props,
           ...element.props,
@@ -63,6 +64,7 @@
           window.socket.on("update", (msg) => {
           window.socket.on("update", (msg) => {
             Object.entries(msg.elements).forEach(([id, element]) => this.elements[element.id] = element);
             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("notify", (msg) => Quasar.Notify.create(msg));
           window.socket.on("disconnect", () => window.location.reload());
           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.label import Label as label
 from .elements.link import Link as link
 from .elements.link import Link as link
 from .elements.link import LinkTarget as link_target
 from .elements.link import LinkTarget as link_target
+from .elements.log import Log as log
 from .elements.markdown import Markdown as markdown
 from .elements.markdown import Markdown as markdown
 from .elements.menu import Menu as menu
 from .elements.menu import Menu as menu
 from .elements.menu import MenuItem as menu_item
 from .elements.menu import MenuItem as menu_item