ソースを参照

add set_auto_scroll_bottom feature

wangweimin 5 年 前
コミット
66ac0b4055
5 ファイル変更56 行追加41 行削除
  1. 0 9
      pywebio/html/index.html
  2. 49 29
      pywebio/html/js/form.js
  3. 1 1
      pywebio/input_ctrl.py
  4. 2 2
      pywebio/interact.py
  5. 4 0
      pywebio/output.py

+ 0 - 9
pywebio/html/index.html

@@ -78,22 +78,13 @@
         // console.log('<<<', JSON.parse(d));
         old_send.apply(this, arguments);
     };
-
     ws.onopen = function () {
         // ws.send("Hello, world");
     };
-    var viewer = $('.viewer');
-    var body = $('body');
     ws.onmessage = function (evt) {
         var msg = JSON.parse(evt.data);
         console.log('>>>', msg);
         ctrl.handle_message(msg);
-        // viewer.scrollTop(md_body[0].scrollHeight);  // 输出区自动滚动
-        viewer.stop().animate({scrollTop:viewer[0].scrollHeight}, 700);
-        setTimeout(function () {
-            // body.scrollTop(body[0].scrollHeight);  // 整个页面自动滚动
-            body.stop().animate({scrollTop:body[0].scrollHeight}, 700);
-        }, WebIO.FormShowDuration+10);
     };
     ws.onclose = function () {
         document.title = 'Closed';

+ 49 - 29
pywebio/html/js/form.js

@@ -109,34 +109,52 @@
         };
     }
 
+    var AutoScrollBottom = true;  // 是否有新内容时自动滚动到底部
+
+    OutputController.prototype.accept_command = ['output', 'output_ctl'];
+
     function OutputController(ws_client, container_elem) {
         this.ws_client = ws_client;
         this.container_elem = $(container_elem);
         this.md_parser = new Mditor.Parser();
 
-        this.handle_message = function (msg) {
-            if (msg.command === 'output') {
-                if (msg.spec.type === 'text')
-                    this.container_elem.append(this.md_parser.parse(msg.spec.content));  // 直接更改innerHtml会导致事件绑定失效
-                else if (msg.spec.type === 'buttons')
-                    this.handle_buttons(msg);
-                else if (msg.spec.type === 'file')
-                    this.handle_file(msg);
-                else
-                    console.warn('Unknown output type:%s', msg.spec.type);
-            } else if (msg.command === 'output_ctl'){
-                if(msg.spec.title)
-                    $('#title').text(msg.spec.title);  // 直接使用#title不规范 todo
-                if(msg.spec.output_fixed_height!==undefined)
-                    if(msg.spec.output_fixed_height)
-                        $('.container').removeClass('no-fix-height');  // todo 不规范
-                    else
-                        $('.container').addClass('no-fix-height');  // todo 不规范
-            }
-        }
+        this.container_parent = this.container_elem.parent();
+        this.body = $('html,body');
     }
 
-    OutputController.prototype.accept_command = ['output', 'output_ctl'];
+    OutputController.prototype.scroll_bottom = function () {
+        this.container_parent.stop().animate({scrollTop: this.container_parent[0].scrollHeight}, 700);
+        var that = this;
+        setTimeout(function () {
+            // body.scrollTop(body[0].scrollHeight);  // 整个页面自动滚动
+            that.body.stop().animate({scrollTop: that.body[0].scrollHeight}, 700);
+        }, ShowDuration + 10);
+    };
+
+    OutputController.prototype.handle_message = function (msg) {
+        if (msg.command === 'output') {
+            if (msg.spec.type === 'text')
+                this.container_elem.append(this.md_parser.parse(msg.spec.content));  // 直接更改innerHtml会导致事件绑定失效
+            else if (msg.spec.type === 'buttons')
+                this.handle_buttons(msg);
+            else if (msg.spec.type === 'file')
+                this.handle_file(msg);
+            else
+                console.warn('Unknown output type:%s', msg.spec.type);
+        } else if (msg.command === 'output_ctl') {
+            if (msg.spec.title)
+                $('#title').text(msg.spec.title);  // 直接使用#title不规范 todo
+            if (msg.spec.output_fixed_height !== undefined)
+                if (msg.spec.output_fixed_height)
+                    $('.container').removeClass('no-fix-height');  // todo 不规范
+                else
+                    $('.container').addClass('no-fix-height');  // todo 不规范
+            if (msg.spec.auto_scroll_bottom !== undefined)
+                AutoScrollBottom = msg.spec.auto_scroll_bottom;
+        }
+        if (AutoScrollBottom)
+            this.scroll_bottom();
+    };
 
     OutputController.prototype.handle_file = function (msg) {
         const html = `<div class="form-group"><button type="button" class="btn btn-link">${msg.spec.name}</button></div>`;
@@ -147,6 +165,7 @@
             saveAs(blob, msg.spec.name, {}, false);
         });
     };
+
     OutputController.prototype.handle_buttons = function (msg) {
         const btns_tpl = `<div class="form-group">{{#buttons}}
                              <button value="{{value}}" onclick="WebIO.DisplayAreaButtonOnClick(this, '{{callback_id}}')" class="btn btn-primary {{#small}}btn-sm{{/small}}">{{label}}</button> 
@@ -157,8 +176,8 @@
     };
 
     // 显示区按钮点击回调函数
-    function DisplayAreaButtonOnClick(this_ele,callback_id) {
-        if(WSClient===undefined)
+    function DisplayAreaButtonOnClick(this_ele, callback_id) {
+        if (WSClient === undefined)
             return console.error("can't invoke DisplayAreaButtonOnClick when WebIOController is not instantiated");
 
         var val = $(this_ele).val();
@@ -187,8 +206,8 @@
             if (ctrl === old_ctrl || old_ctrl === undefined) {
                 console.log('开:%s', ctrl.spec.label);
                 return ctrl.element.show(ShowDuration, function () {
-                    // 有时候autofocus属性不生效,手动激活一下
-                    $('[autofocus]').focus();
+                    if(AutoScrollBottom)
+                        $('[auto_focus]').focus();
                 });
             }
             this.form_ctrls.move_to_top(coro_id);
@@ -198,8 +217,8 @@
                 // 需要在回调中重新获取当前前置表单元素,因为100ms内可能有变化
                 var t = that.form_ctrls.get_top();
                 if (t) t[t.length - 1].element.show(ShowDuration, function () {
-                    // 有时候autofocus属性不生效,手动激活一下
-                    $('[autofocus]').focus();
+                    if(AutoScrollBottom)
+                        $('[auto_focus]').focus();
                 });
             });
         };
@@ -262,7 +281,8 @@
                         deleted.element.remove();
                         var t = that.form_ctrls.get_top();
                         if (t) t[t.length - 1].element.show(ShowDuration, function () {
-                            $('[autofocus]').focus();
+                            if(AutoScrollBottom)
+                                $('[auto_focus]').focus();
                         });
                     });
                 } else {
@@ -757,6 +777,7 @@
     };
 
     var WSClient;
+
     function WebIOController(ws_client, output_container_elem, input_container_elem) {
         WSClient = ws_client;
         this.output_ctrl = new OutputController(ws_client, output_container_elem);
@@ -777,7 +798,6 @@
     return {
         'WebIOController': WebIOController,
         'DisplayAreaButtonOnClick': DisplayAreaButtonOnClick,
-        'FormShowDuration': ShowDuration
     }
 
 })));

+ 1 - 1
pywebio/input_ctrl.py

@@ -34,7 +34,7 @@ async def single_input(item_spec, valid_func, preprocess_func):
     # todo 是否可以原地修改spec
     item_spec['label'] = ''
 
-    item_spec.setdefault('autofocus', True)  # 如果没有设置autofocus参数,则开启参数  todo CHECKBOX, RADIO 特殊处理
+    item_spec.setdefault('auto_focus', True)  # 如果没有设置autofocus参数,则开启参数  todo CHECKBOX, RADIO 特殊处理
 
     spec = dict(label=label, inputs=[item_spec])
 

+ 2 - 2
pywebio/interact.py

@@ -212,11 +212,11 @@ def input_group(label, inputs, valid_func=None):
         spec_inputs.append(input_kwargs['item_spec'])
 
     # def add_autofocus(spec_inputs):
-    if all('autofocus' not in i for i in spec_inputs):  # 每一个输入项都没有设置autofocus参数
+    if all('auto_focus' not in i for i in spec_inputs):  # 每一个输入项都没有设置autofocus参数
         for i in spec_inputs:
             text_inputs = {TEXT, NUMBER, PASSWORD, SELECT}  # todo update
             if i.get('type') in text_inputs:
-                i['autofocus'] = True
+                i['auto_focus'] = True
                 break
 
     spec = dict(label=label, inputs=spec_inputs)

+ 4 - 0
pywebio/output.py

@@ -17,6 +17,10 @@ def set_output_fixed_height(enabled=True):
     send_msg('output_ctl', dict(output_fixed_height=enabled))
 
 
+def set_auto_scroll_bottom(enabled=True):
+    send_msg('output_ctl', dict(auto_scroll_bottom=enabled))
+
+
 def text_print(text, *, ws=None):
     if text is None:
         text = ''