ソースを参照

Use a virtual dom to render the login form

JC Brand 7 年 前
コミット
be7f8ab4c4
5 ファイル変更155 行追加11 行削除
  1. 121 0
      package-lock.json
  2. 2 0
      package.json
  3. 2 0
      src/config.js
  4. 22 6
      src/converse-controlbox.js
  5. 8 5
      src/converse-register.js

+ 121 - 0
package-lock.json

@@ -1203,6 +1203,12 @@
         "repeat-element": "1.1.2"
       }
     },
+    "browser-split": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz",
+      "integrity": "sha1-ewl1dPjj6tYG+0Zk5krf3aKYGpM=",
+      "dev": true
+    },
     "browserslist": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz",
@@ -1258,6 +1264,12 @@
         }
       }
     },
+    "camelize": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
+      "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=",
+      "dev": true
+    },
     "caniuse-lite": {
       "version": "1.0.30000718",
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000718.tgz",
@@ -1920,6 +1932,12 @@
         }
       }
     },
+    "dom-walk": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
+      "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=",
+      "dev": true
+    },
     "domelementtype": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
@@ -2047,6 +2065,17 @@
       "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
       "dev": true
     },
+    "error": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/error/-/error-4.4.0.tgz",
+      "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=",
+      "dev": true,
+      "requires": {
+        "camelize": "1.0.0",
+        "string-template": "0.2.1",
+        "xtend": "4.0.1"
+      }
+    },
     "error-ex": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
@@ -2260,6 +2289,15 @@
       "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
       "dev": true
     },
+    "ev-store": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/ev-store/-/ev-store-7.0.0.tgz",
+      "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=",
+      "dev": true,
+      "requires": {
+        "individual": "3.0.0"
+      }
+    },
     "event-emitter": {
       "version": "0.3.5",
       "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@@ -3567,6 +3605,16 @@
         "is-glob": "2.0.1"
       }
     },
+    "global": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
+      "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
+      "dev": true,
+      "requires": {
+        "min-document": "2.19.0",
+        "process": "0.5.2"
+      }
+    },
     "globals": {
       "version": "9.18.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
@@ -4126,6 +4174,12 @@
         "repeating": "2.0.1"
       }
     },
+    "individual": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz",
+      "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=",
+      "dev": true
+    },
     "infinity-agent": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz",
@@ -4323,6 +4377,12 @@
       "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
       "dev": true
     },
+    "is-object": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
+      "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
+      "dev": true
+    },
     "is-path-cwd": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
@@ -4875,6 +4935,15 @@
         "mime-db": "1.29.0"
       }
     },
+    "min-document": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
+      "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
+      "dev": true,
+      "requires": {
+        "dom-walk": "0.1.1"
+      }
+    },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -4988,6 +5057,12 @@
         "inherits": "2.0.3"
       }
     },
+    "next-tick": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
+      "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=",
+      "dev": true
+    },
     "node-emoji": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz",
@@ -7907,6 +7982,12 @@
       "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=",
       "dev": true
     },
+    "process": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
+      "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
+      "dev": true
+    },
     "process-nextick-args": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
@@ -9014,6 +9095,12 @@
         "strip-ansi": "3.0.1"
       }
     },
+    "string-template": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
+      "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=",
+      "dev": true
+    },
     "string-width": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -9527,6 +9614,12 @@
       "integrity": "sha1-R84j7Y1Ord+p1LjvAHG2zxB418g=",
       "dev": true
     },
+    "vdom-parser": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/vdom-parser/-/vdom-parser-1.4.1.tgz",
+      "integrity": "sha1-tmFo/Su+yBl0++X9Lk5nd9/Bc+0=",
+      "dev": true
+    },
     "verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -9546,6 +9639,22 @@
         }
       }
     },
+    "virtual-dom": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/virtual-dom/-/virtual-dom-2.1.1.tgz",
+      "integrity": "sha1-gO2i1IG57eDASRGM78tKBfIdE3U=",
+      "dev": true,
+      "requires": {
+        "browser-split": "0.0.1",
+        "error": "4.4.0",
+        "ev-store": "7.0.0",
+        "global": "4.3.2",
+        "is-object": "1.0.1",
+        "next-tick": "0.2.2",
+        "x-is-array": "0.1.0",
+        "x-is-string": "0.1.0"
+      }
+    },
     "wait-until-promise": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wait-until-promise/-/wait-until-promise-1.0.0.tgz",
@@ -9642,6 +9751,18 @@
         "slide": "1.1.6"
       }
     },
+    "x-is-array": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz",
+      "integrity": "sha1-3lIBcdR7P0FvVYfWKbidJrEtwp0=",
+      "dev": true
+    },
+    "x-is-string": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+      "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
+      "dev": true
+    },
     "xdg-basedir": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz",

+ 2 - 0
package.json

@@ -78,6 +78,8 @@
     "strophejs-plugin-vcard": "0.0.1",
     "text": "requirejs/text#2.0.15",
     "uglify-es": "^3.0.24",
+    "vdom-parser": "^1.4.1",
+    "virtual-dom": "^2.1.1",
     "wait-until-promise": "^1.0.0",
     "xss": "^0.3.3"
   },

+ 2 - 0
src/config.js

@@ -35,6 +35,8 @@ require.config({
         "lodash.noconflict":        "src/lodash.noconflict",
         "pluggable":                "node_modules/pluggable.js/dist/pluggable",
         "polyfill":                 "src/polyfill",
+        "virtual-dom":              "node_modules/virtual-dom/dist/virtual-dom",
+        "vdom-parser":              "node_modules/vdom-parser/dist",
         "sizzle":                   "node_modules/jquery/sizzle/dist/sizzle",
         "strophe":                  "node_modules/strophe.js/strophe",
         "strophe.disco":            "node_modules/strophejs-plugin-disco/strophe.disco",

+ 22 - 6
src/converse-controlbox.js

@@ -10,6 +10,8 @@
     define(["jquery.noconflict",
             "converse-core",
             "lodash.fp",
+            "virtual-dom",
+            "vdom-parser",
             "tpl!add_contact_dropdown",
             "tpl!add_contact_form",
             "tpl!converse_brand_heading",
@@ -32,6 +34,8 @@
             $,
             converse,
             fp,
+            vdom,
+            vdom_parser,
             tpl_add_contact_dropdown,
             tpl_add_contact_form,
             tpl_brand_heading,
@@ -423,7 +427,7 @@
                 },
 
                 render () {
-                    this.el.innerHTML = tpl_login_panel({
+                    const html = tpl_login_panel({
                         '__': __,
                         'ANONYMOUS': _converse.ANONYMOUS,
                         'EXTERNAL': _converse.EXTERNAL,
@@ -433,9 +437,15 @@
                         'authentication': _converse.authentication,
                         'label_anon_login': __('Click here to log in anonymously'),
                         'placeholder_username': (_converse.locked_domain || _converse.default_domain) && __('Username') || __('user@domain'),
-                    })
+                    });
+                    const form = this.el.querySelector('form');
+                    if (_.isNull(form)) {
+                        this.el.innerHTML = html;
+                    } else {
+                        const patches = vdom.diff(vdom_parser(form), vdom_parser(html));
+                        vdom.patch(form, patches);
+                    }
                     this.renderConnectionFeedback();
-                    this.$el.find('input#jid').focus();
                     return this;
                 },
 
@@ -453,9 +463,15 @@
                     }
                 },
 
-                showSpinner () {
+                showSpinner (only_submit_button=false) {
                     const form = this.el.querySelector('form');
-                    form.innerHTML = tpl_spinner();
+                    if (only_submit_button) {
+                        const button = form.querySelector('input[type=submit]');
+                        button.classList.add('hidden');
+                        button.insertAdjacentHTML('afterend', '<span class="spinner login-submit"/>');
+                    } else {
+                        form.innerHTML = tpl_spinner();
+                    }
                     return this;
                 },
 
@@ -497,7 +513,7 @@
                     } else if (_converse.default_domain && !_.includes(jid, '@')) {
                         jid = jid + '@' + _converse.default_domain;
                     }
-                    this.showSpinner().connect(jid, password);
+                    this.showSpinner(true).connect(jid, password);
                     return false;
                 },
 

+ 8 - 5
src/converse-register.js

@@ -64,12 +64,15 @@
 
                 render: function (cfg) {
                     const { _converse } = this.__super__;
+                    const form = this.el.querySelector('form');
                     this.__super__.render.apply(this, arguments);
-                    if (_converse.allow_registration) {
-                        this.el.insertAdjacentHTML(
-                            'beforeend',
-                            tpl_register_link({'__': _converse.__})
-                        );
+                    if (_.isNull(form)) {
+                        if (_converse.allow_registration) {
+                            this.el.insertAdjacentHTML(
+                                'beforeend',
+                                tpl_register_link({'__': _converse.__})
+                            );
+                        }
                     }
                     return this;
                 }