Bladeren bron

refine(frontend): add `after_add_to_dom`、`after_show` life-circle callback to FormController and InputItem

wangweimin 4 jaren geleden
bovenliggende
commit
7c5b181ba4

+ 21 - 0
webiojs/src/handlers/input.ts

@@ -41,6 +41,10 @@ export class InputHandler implements CommandHandler {
             body_scroll_to(this.container_elem, 'bottom', () => {
                 $('[auto_focus="true"]').focus();
             });
+
+        let old_ctrls = this.form_ctrls.get_top();
+        if(old_ctrls)
+            old_ctrls[old_ctrls.length - 1].after_show();
     };
 
     // hide old_ctrls显示的表单,激活 task_id 对应的表单
@@ -82,6 +86,7 @@ export class InputHandler implements CommandHandler {
             let ctrl = new FormController(this.session, msg.task_id, msg.spec);
             target_ctrls.push(ctrl);
             this.container_elem.append(ctrl.create_element());
+            ctrl.after_add_to_dom();
             this._activate_form(msg.task_id, old_ctrl);
         } else if (msg.command in make_set(['update_input'])) {
             // 更新表单
@@ -130,6 +135,7 @@ class FormController {
     private spec: any;
     // name -> input_controller
     private name2input: { [i: string]: InputItem } = {};
+    private show_count: number = 0;
 
     public static register_inputitem(cls: typeof InputItem) {
         for (let type of cls.accept_input_types) {
@@ -258,6 +264,21 @@ class FormController {
 
         this.name2input[spec.target_name].update_input(spec);
     };
+
+    // 在表单加入DOM树后,触发输入项的on_add_to_dom回调
+    after_add_to_dom() {
+        for (let name in this.name2input) {
+            this.name2input[name].after_add_to_dom();
+        }
+    }
+
+    // 在表单被显示后,触发输入项的after_show回调
+    after_show() {
+        for (let name in this.name2input) {
+            this.name2input[name].after_show(this.show_count === 0);
+        }
+        this.show_count += 1;
+    }
 }
 
 for (let item of all_input_items)

+ 10 - 0
webiojs/src/models/input/base.ts

@@ -27,6 +27,16 @@ export class InputItem {
         throw new Error("Not implement!");
     }
 
+    //在表单加入DOM树后触发
+    after_add_to_dom(): any {
+
+    }
+
+    //在表单被显示后触发
+    after_show(first_show:boolean): any {
+
+    }
+
     protected send_value_listener(input_item: this, event: { type: string }) {
         // let this_elem = $(this);
         input_item.session.send_message({

+ 4 - 2
webiojs/src/models/input/file.ts

@@ -58,8 +58,6 @@ export class File extends InputItem {
             };
             fr.readAsDataURL(file);
         });
-        //  todo 通过回调的方式调用init
-        setTimeout(bsCustomFileInput.init, state.ShowDuration + 100);
 
         return this.element;
     }
@@ -72,6 +70,10 @@ export class File extends InputItem {
     get_value(): any {
         return this.data_url_value;
     }
+
+    after_add_to_dom(): any {
+        bsCustomFileInput.init();
+    }
 }
 
 

+ 20 - 18
webiojs/src/models/input/textarea.ts

@@ -18,6 +18,15 @@ export class Textarea extends InputItem {
     static accept_input_types: string[] = ["textarea"];
 
     private code_mirror: any = null;
+    private code_mirror_config: { [name: string]: any } = {
+        'theme': 'base16-light',
+        'mode': 'python',
+        'lineNumbers': true,  // 显示行数
+        'indentUnit': 4,  //缩进单位为4
+        'styleActiveLine': true,  // 当前行背景高亮
+        'matchBrackets': true,  //括号匹配
+        'lineWrapping': true,  //自动换行
+    };
 
     constructor(session: Session, task_id: string, spec: any) {
         super(session, task_id, spec);
@@ -45,26 +54,11 @@ export class Textarea extends InputItem {
         if (spec.code) {
             CodeMirror.modeURL = appConfig.codeMirrorModeURL;
 
-            let config: { [name: string]: any } = {
-                'theme': 'base16-light',
-                'mode': 'python',
-                'lineNumbers': true,  // 显示行数
-                'indentUnit': 4,  //缩进单位为4
-                'styleActiveLine': true,  // 当前行背景高亮
-                'matchBrackets': true,  //括号匹配
-                'lineWrapping': true,  //自动换行
-            };
             for (let k in that.spec.code)
-                config[k] = that.spec.code[k];
-
-            if (config.theme && config.theme !== 'base16-light')
-                Textarea.load_codemirror_theme(config.theme);
+                this.code_mirror_config[k] = that.spec.code[k];
 
-            setTimeout(function () {  // 需要等待当前表单被添加到文档树中后,再初始化CodeMirror,否则CodeMirror样式会发生错误
-                that.code_mirror = CodeMirror.fromTextArea(that.element.find('textarea')[0], config);
-                CodeMirror.autoLoadMode(that.code_mirror, config.mode);
-                that.code_mirror.setSize(null, 20 * that.spec.rows);
-            }, 100);
+            if (this.code_mirror_config.theme && this.code_mirror_config.theme !== 'base16-light')
+                Textarea.load_codemirror_theme(this.code_mirror_config.theme);
         }
 
         return this.element;
@@ -80,6 +74,14 @@ export class Textarea extends InputItem {
         return this.element.find('textarea').val();
     };
 
+    after_show(first_show: boolean): any {
+        if (first_show && this.spec.code) {
+            this.code_mirror = CodeMirror.fromTextArea(this.element.find('textarea')[0], this.code_mirror_config);
+            CodeMirror.autoLoadMode(this.code_mirror, this.code_mirror_config.mode);
+            this.code_mirror.setSize(null, 20 * this.spec.rows);
+        }
+    };
+
     static load_codemirror_theme(theme: string, url_tpl = appConfig.codeMirrorThemeURL) {
         let cssId = 'codemirror_theme_' + theme;  // you could encode the css path itself to generate id..
         if (!document.getElementById(cssId)) {