Quellcode durchsuchen

lock scope height after clear scope in `use_scope(clear=True)``

wangweimin vor 2 Jahren
Ursprung
Commit
8a58af0407
3 geänderte Dateien mit 21 neuen und 6 gelöschten Zeilen
  1. 2 0
      docs/spec.rst
  2. 4 3
      pywebio/output.py
  3. 15 3
      webiojs/src/handlers/output.ts

+ 2 - 0
docs/spec.rst

@@ -367,7 +367,9 @@ The ``spec`` fields of ``output_ctl`` commands:
         - null: Do nothing
         - `'remove'`: Remove the old scope first and then create a new one
         - `'clear'`: Just clear the contents of the old scope, but don’t create a new scope
+        - `'blank'`: Clear the contents of the old scope and keep the height, don’t create a new scope
 
+* loose: css selector of the scope, set the scope not to keep the height (i.e., revoke the effect of ``set_scope(if_exist='blank')``)
 * clear: css selector of the scope need to clear
 * clear_before
 * clear_after

+ 4 - 3
pywebio/output.py

@@ -1765,8 +1765,8 @@ def use_scope(name=None, clear=False, **kwargs):
 
     def before_enter():
         if create_scope:
-            if_exist = 'clear' if clear else None
-            set_scope(name, if_exist=if_exist, **scope_params)
+            if_exist = 'blank' if clear else None
+            set_scope(name, if_exist=if_exist, **scope_params)  # lock the height of the scope and clear its content
 
     return use_scope_(name=name, before_enter=before_enter)
 
@@ -1787,7 +1787,8 @@ class use_scope_:
         If this method returns True, it means that the context manager can handle the exception,
         so that the with statement terminates the propagation of the exception
         """
-        get_current_session().pop_scope()
+        scope = get_current_session().pop_scope()
+        send_msg('output_ctl', dict(loose=scope2dom(scope)))  # revoke lock the height of the scope
         return False  # Propagate Exception
 
     def __call__(self, func):

+ 15 - 3
webiojs/src/handlers/output.ts

@@ -10,7 +10,7 @@ const DISPLAY_NONE_TAGS = ['script', 'style'];
 let after_show_callbacks: (() => void) [] = [];
 
 // register a callback to execute after the current output widget showing
-export function AfterCurrentOutputWidgetShow(callback: () => void){
+export function AfterCurrentOutputWidgetShow(callback: () => void) {
     after_show_callbacks.push(callback);
 }
 
@@ -86,7 +86,7 @@ export class OutputHandler implements CommandHandler {
 
             // to avoid widget width exceeding page width
             // show horizon scroll bar when content too wide
-            if(elem.width() > this.container_elem.width())
+            if (elem.width() > this.container_elem.width())
                 elem.wrap($(document.createElement('div')).css('overflow', 'auto'));
 
             if (this.is_elem_visible(elem) && container_elem.length == 1) {  // 输出内容为可见标签且输出目的scope唯一
@@ -127,11 +127,20 @@ export class OutputHandler implements CommandHandler {
                 else if (spec.if_exist == 'clear') {
                     old.empty();
                     return;
+                } else if (spec.if_exist == 'blank') { // Clear the contents of the old scope and keep the height
+                    let scope_css: any = {'min-height': old.height()};
+                    let prev = old.prev(), next = old.next();
+                    if (prev.length)
+                        scope_css['margin-top'] = old[0].getBoundingClientRect().top - prev[0].getBoundingClientRect().bottom;
+                    if (next.length)
+                        scope_css['margin-bottom'] = next[0].getBoundingClientRect().top - old[0].getBoundingClientRect().bottom;
+                    old.css(scope_css);
+                    old.empty();
+                    return;
                 } else {
                     return;
                 }
             }
-
             let html = `<div id="${spec.set_scope}"></div>`;
             if (spec.position === 0)
                 container_elem.prepend(html);
@@ -144,6 +153,9 @@ export class OutputHandler implements CommandHandler {
                     $(`${spec.container} > *`).eq(spec.position).insertAfter(html);
             }
         }
+        if (msg.spec.loose !== undefined) { // revoke the effect of ``set_scope(if_exist='blank')``
+            $(msg.spec.loose).css({'min-height': '', 'margin-top': '', 'margin-bottom': ''});
+        }
         if (msg.spec.clear !== undefined) {
             $(msg.spec.clear).empty();
         }