Browse Source

New `ui.log` implementation (#2686)

* re-implement ui.log

* update tests

* improve sizing

* add dynamic auto-scroll

* cleanup
Falko Schindler 1 năm trước cách đây
mục cha
commit
4a67bc95ce
4 tập tin đã thay đổi với 19 bổ sung92 xóa
  1. 0 42
      nicegui/elements/log.js
  2. 8 19
      nicegui/elements/log.py
  3. 11 5
      nicegui/static/nicegui.css
  4. 0 26
      tests/test_log.py

+ 0 - 42
nicegui/elements/log.js

@@ -1,42 +0,0 @@
-export default {
-  template: "<textarea disabled></textarea>",
-  data() {
-    return {
-      num_lines: 0,
-      total_count: 0,
-    };
-  },
-  mounted() {
-    const text = decodeURIComponent(this.lines);
-    this.$el.innerHTML = text;
-    this.num_lines = text ? text.split("\n").length : 0;
-    this.total_count = this.num_lines;
-    this.$el.scrollTop = this.$el.scrollHeight;
-  },
-  methods: {
-    push(line, total_count) {
-      if (total_count <= this.total_count) return;
-      this.total_count = total_count;
-      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;
-      }
-    },
-    clear() {
-      const textarea = this.$el;
-      textarea.innerHTML = "";
-      this.num_lines = 0;
-    },
-  },
-  props: {
-    max_lines: Number,
-    lines: String,
-  },
-};

+ 8 - 19
nicegui/elements/log.py

@@ -1,11 +1,10 @@
-import urllib.parse
-from collections import deque
 from typing import Any, Optional
 
 from ..element import Element
+from .label import Label
 
 
-class Log(Element, component='log.js'):
+class Log(Element):
 
     def __init__(self, max_lines: Optional[int] = None) -> None:
         """Log View
@@ -15,26 +14,16 @@ class Log(Element, component='log.js'):
         :param max_lines: maximum number of lines before dropping oldest ones (default: `None`)
         """
         super().__init__()
-        self._props['max_lines'] = max_lines
-        self._props['lines'] = ''
+        self.max_lines = max_lines
         self._classes.append('nicegui-log')
-        self.lines: deque[str] = deque(maxlen=max_lines)
-        self.total_count: int = 0
 
     def push(self, line: Any) -> None:
         """Add a new line to the log.
 
         :param line: the line to add (can contain line breaks)
         """
-        new_lines = [urllib.parse.quote(line) for line in str(line).splitlines()]
-        self.lines.extend(new_lines)
-        self._props['lines'] = '\n'.join(self.lines)
-        self.total_count += len(new_lines)
-        self.run_method('push', urllib.parse.quote(str(line)), self.total_count)
-
-    def clear(self) -> None:
-        """Clear the log."""
-        super().clear()
-        self._props['lines'] = ''
-        self.lines.clear()
-        self.run_method('clear')
+        for text in str(line).splitlines():
+            with self:
+                Label(text)
+        while self.max_lines is not None and len(self.default_slot.children) > self.max_lines:
+            self.remove(0)

+ 11 - 5
nicegui/static/nicegui.css

@@ -213,17 +213,23 @@
 .nicegui-aggrid,
 .nicegui-echart,
 .nicegui-leaflet,
+.nicegui-log,
 .nicegui-scroll-area {
   width: 100%;
   height: 16rem;
 }
 .nicegui-log {
-  padding: 0.25rem;
-  border-width: 1px;
-  white-space: pre;
+  padding: 0.5rem;
+  scroll-padding-bottom: 0.5rem;
+  scroll-snap-type: y proximity;
+  overflow-y: scroll;
+  outline: 1px solid rgba(127, 159, 191, 0.15);
   font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
-  opacity: 1 !important;
-  cursor: text !important;
+  white-space: pre;
+  background-color: rgba(127, 159, 191, 0.05);
+}
+.nicegui-log > :last-child {
+  scroll-snap-align: end;
 }
 h6.q-timeline__title {
   font-size: 1.25rem;

+ 0 - 26
tests/test_log.py

@@ -53,29 +53,3 @@ def test_special_characters(screen: Screen):
     screen.should_contain('50%')
     screen.click('push')
     screen.should_contain('100%')
-
-
-def test_line_duplication_bug_906(screen: Screen):
-    ui.button('Log', on_click=lambda: ui.log().push('Hi!'))
-
-    screen.open('/')
-    screen.click('Log')
-    screen.should_contain('Hi!')
-    screen.should_not_contain('Hi!\nHi!')
-
-
-def test_another_duplication_bug_1173(screen: Screen):
-    log1 = ui.log()
-
-    def test():
-        log1.push('A')
-        log2 = ui.log()
-        log2.push('C')
-        log2.push('D')
-    ui.button('test', on_click=test)
-
-    screen.open('/')
-    screen.click('test')
-    screen.should_contain('A')
-    screen.should_contain('C\nD')
-    screen.should_not_contain('C\nD\nC\nD')