Lazy load codemirror assets

Requires a relatively significant refactor of the attached function.

Uses promises instead of callbacks for loading to tests and later code
more legible and straightforward.

Bug: Issue 8764
Change-Id: I081564ff75c383bf042f77820e017ef04c8c313c
diff --git a/BUILD b/BUILD
index 614df41..306479a 100644
--- a/BUILD
+++ b/BUILD
@@ -1,5 +1,5 @@
 load("//tools/bzl:genrule2.bzl", "genrule2")
-load("//tools/bzl:js.bzl", "polygerrit_plugin")
+load("//tools/bzl:js.bzl", "polygerrit_plugin", "vulcanize")
 load("//tools/bzl:plugin.bzl", "gerrit_plugin")
 
 gerrit_plugin(
@@ -15,11 +15,13 @@
 
 genrule2(
     name = "cm-static",
-    srcs = [":cm"],
+    srcs = [":cm", ":cm-dep"],
     outs = ["cm-static.jar"],
     cmd = " && ".join([
         "mkdir $$TMP/static",
         "cp -rp $(locations :cm) $$TMP/static",
+        "cp -rp $(locations :cm-dep) $$TMP/static",
+        "mv $$TMP/static/cm-dep.html $$TMP/static/codemirror-assets.html",
         "cd $$TMP",
         "zip -Drq $$ROOT/$@ -g .",
     ]),
@@ -31,3 +33,11 @@
     app = "plugin.html",
     deps = ["//lib/js:codemirror-minified"],
 )
+
+vulcanize(
+    name = "cm-dep",
+    srcs = glob(['gr-editor/codemirror-assets.html']),
+    app = "gr-editor/codemirror-assets.html",
+    deps = ["//lib/js:codemirror-minified"],
+    split = False,
+)
diff --git a/gr-editor/codemirror-assets.html b/gr-editor/codemirror-assets.html
new file mode 100644
index 0000000..fbe4fcb
--- /dev/null
+++ b/gr-editor/codemirror-assets.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/lib/codemirror.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/ambiance.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/ambiance-mobile.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/blackboard.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/cobalt.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/eclipse.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/elegant.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/erlang-dark.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/lesser-dark.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/midnight.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/monokai.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/neat.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/night.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/rubyblue.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/solarized.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/twilight.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/vibrant-ink.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/xq-dark.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/xq-light.css">
+<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/addon/fold/foldgutter.css">
+
+<script src="../bower_components/codemirror-minified/lib/codemirror.js"></script>
+<script src="../bower_components/codemirror-minified/addon/display/rulers.js"></script>
+<script src="../bower_components/codemirror-minified/addon/edit/closebrackets.js"></script>
+<script src="../bower_components/codemirror-minified/addon/edit/closetag.js"></script>
+<script src="../bower_components/codemirror-minified/addon/edit/matchbrackets.js"></script>
+<script src="../bower_components/codemirror-minified/addon/edit/matchtags.js"></script>
+<script src="../bower_components/codemirror-minified/addon/edit/trailingspace.js"></script>
+<script src="../bower_components/codemirror-minified/addon/mode/simple.js"></script>
+<script src="../bower_components/codemirror-minified/addon/mode/multiplex.js"></script>
+<script src="../bower_components/codemirror-minified/mode/meta.js"></script>
+<script src="../bower_components/codemirror-minified/mode/clike/clike.js"></script>
+<script src="../bower_components/codemirror-minified/mode/clojure/clojure.js"></script>
+<script src="../bower_components/codemirror-minified/mode/css/css.js"></script>
+<script src="../bower_components/codemirror-minified/mode/dart/dart.js"></script>
+<script src="../bower_components/codemirror-minified/mode/dockerfile/dockerfile.js"></script>
+<script src="../bower_components/codemirror-minified/mode/erlang/erlang.js"></script>
+<script src="../bower_components/codemirror-minified/mode/go/go.js"></script>
+<script src="../bower_components/codemirror-minified/mode/haskell/haskell.js"></script>
+<script src="../bower_components/codemirror-minified/mode/htmlembedded/htmlembedded.js"></script>
+<script src="../bower_components/codemirror-minified/mode/htmlmixed/htmlmixed.js"></script>
+<script src="../bower_components/codemirror-minified/mode/javascript/javascript.js"></script>
+<script src="../bower_components/codemirror-minified/mode/markdown/markdown.js"></script>
+<script src="../bower_components/codemirror-minified/mode/php/php.js"></script>
+<script src="../bower_components/codemirror-minified/mode/puppet/puppet.js"></script>
+<script src="../bower_components/codemirror-minified/mode/python/python.js"></script>
+<script src="../bower_components/codemirror-minified/mode/ruby/ruby.js"></script>
+<script src="../bower_components/codemirror-minified/mode/sass/sass.js"></script>
+<script src="../bower_components/codemirror-minified/mode/shell/shell.js"></script>
+<script src="../bower_components/codemirror-minified/mode/soy/soy.js"></script>
+<script src="../bower_components/codemirror-minified/mode/sql/sql.js"></script>
+<script src="../bower_components/codemirror-minified/mode/velocity/velocity.js"></script>
+<script src="../bower_components/codemirror-minified/mode/xml/xml.js"></script>
+<script src="../bower_components/codemirror-minified/mode/yaml/yaml.js"></script>
\ No newline at end of file
diff --git a/gr-editor/gr-editor-styles.html b/gr-editor/gr-editor-styles.html
deleted file mode 100644
index de8078e..0000000
--- a/gr-editor/gr-editor-styles.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/lib/codemirror.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/ambiance.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/ambiance-mobile.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/blackboard.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/cobalt.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/eclipse.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/elegant.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/erlang-dark.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/lesser-dark.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/midnight.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/monokai.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/neat.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/night.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/rubyblue.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/solarized.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/twilight.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/vibrant-ink.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/xq-dark.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/theme/xq-light.css">
-<link rel="stylesheet" type="css" href="../bower_components/codemirror-minified/addon/fold/foldgutter.css">
-
-<dom-module id="gr-editor-styles">
-  <template>
-    <style></style>
-  </template>
-</dom-module>
diff --git a/gr-editor/gr-editor.html b/gr-editor/gr-editor.html
index fd8673e..b7b2cc9 100644
--- a/gr-editor/gr-editor.html
+++ b/gr-editor/gr-editor.html
@@ -14,45 +14,9 @@
 limitations under the License.
 -->
 
-<link rel="import" href="gr-editor-styles.html">
-
-<script src="../bower_components/codemirror-minified/lib/codemirror.js"></script>
-<script src="../bower_components/codemirror-minified/addon/display/rulers.js"></script>
-<script src="../bower_components/codemirror-minified/addon/edit/closebrackets.js"></script>
-<script src="../bower_components/codemirror-minified/addon/edit/closetag.js"></script>
-<script src="../bower_components/codemirror-minified/addon/edit/matchbrackets.js"></script>
-<script src="../bower_components/codemirror-minified/addon/edit/matchtags.js"></script>
-<script src="../bower_components/codemirror-minified/addon/edit/trailingspace.js"></script>
-<script src="../bower_components/codemirror-minified/addon/mode/simple.js"></script>
-<script src="../bower_components/codemirror-minified/addon/mode/multiplex.js"></script>
-<script src="../bower_components/codemirror-minified/mode/meta.js"></script>
-<script src="../bower_components/codemirror-minified/mode/clike/clike.js"></script>
-<script src="../bower_components/codemirror-minified/mode/clojure/clojure.js"></script>
-<script src="../bower_components/codemirror-minified/mode/css/css.js"></script>
-<script src="../bower_components/codemirror-minified/mode/dart/dart.js"></script>
-<script src="../bower_components/codemirror-minified/mode/dockerfile/dockerfile.js"></script>
-<script src="../bower_components/codemirror-minified/mode/erlang/erlang.js"></script>
-<script src="../bower_components/codemirror-minified/mode/go/go.js"></script>
-<script src="../bower_components/codemirror-minified/mode/haskell/haskell.js"></script>
-<script src="../bower_components/codemirror-minified/mode/htmlembedded/htmlembedded.js"></script>
-<script src="../bower_components/codemirror-minified/mode/htmlmixed/htmlmixed.js"></script>
-<script src="../bower_components/codemirror-minified/mode/javascript/javascript.js"></script>
-<script src="../bower_components/codemirror-minified/mode/markdown/markdown.js"></script>
-<script src="../bower_components/codemirror-minified/mode/php/php.js"></script>
-<script src="../bower_components/codemirror-minified/mode/puppet/puppet.js"></script>
-<script src="../bower_components/codemirror-minified/mode/python/python.js"></script>
-<script src="../bower_components/codemirror-minified/mode/ruby/ruby.js"></script>
-<script src="../bower_components/codemirror-minified/mode/sass/sass.js"></script>
-<script src="../bower_components/codemirror-minified/mode/shell/shell.js"></script>
-<script src="../bower_components/codemirror-minified/mode/soy/soy.js"></script>
-<script src="../bower_components/codemirror-minified/mode/sql/sql.js"></script>
-<script src="../bower_components/codemirror-minified/mode/velocity/velocity.js"></script>
-<script src="../bower_components/codemirror-minified/mode/xml/xml.js"></script>
-<script src="../bower_components/codemirror-minified/mode/yaml/yaml.js"></script>
-
 <dom-module id="gr-editor">
   <template>
-    <style include="gr-editor-styles">
+    <style>
       #wrapper {
         height: 100%;
         z-index: 0;
diff --git a/gr-editor/gr-editor.js b/gr-editor/gr-editor.js
index bb9233e..388b92f 100644
--- a/gr-editor/gr-editor.js
+++ b/gr-editor/gr-editor.js
@@ -33,18 +33,35 @@
       fileType: String,
       mirror: Object,
       prefs: Object,
+      plugin: Object,
     },
 
     attached() {
+      this._initializeMirror();
+    },
+
+    _initializeMirror() {
       this.scopeSubtree(this.$.wrapper, true);
-      const params =
-          this.getCodeMirrorParams(this.fileType, this.fileContent, this.prefs);
-      this.mirror = CodeMirror(this.$.wrapper, params);
-      this.async(() => {
-        this.mirror.refresh();
-        this.mirror.focus();
-      }, 1);
-      this.addEventListeners();
+      return new Promise((resolve, reject) => {
+        this._importCodeMirror().then(() => {
+          const params = this.getCodeMirrorParams(this.fileType,
+              this.fileContent, this.prefs);
+          this.mirror = CodeMirror(this.$.wrapper, params);
+          this.async(() => {
+            this.mirror.refresh();
+            this.mirror.focus();
+          }, 1);
+          this.addEventListeners();
+          resolve();
+        });
+      });
+    },
+
+    _importCodeMirror() {
+      const url = this.plugin.url('static/codemirror-assets.html');
+      return new Promise((resolve, reject) => {
+        this.importHref(url, resolve, reject);
+      });
     },
 
     addEventListeners() {
diff --git a/gr-editor/gr-editor_test.html b/gr-editor/gr-editor_test.html
index 2d68df6..8af7c69 100644
--- a/gr-editor/gr-editor_test.html
+++ b/gr-editor/gr-editor_test.html
@@ -47,27 +47,28 @@
     sandbox = sinon.sandbox.create();
 
     stub('gr-editor', {
-      // Stub ready because it exists before attached in the Polymer lifecycle,
-      // and the editor plugin initializes in the attached callback.
-      ready() {
-        this.fileType = 'text/x-php';
-        this.fileContent = '<?php echo test; ?>';
-        this.prefs = {};
+      // Stub attached to allow for parameterization within tests.
+      attached() {},
+      _importCodeMirror() {
+        return new Promise((resolve, reject) => {
+          this.importHref('./codemirror-assets.html', resolve, reject);
+        });
       },
-    })
-
+    });
     element = fixture('basic');
   });
 
-  teardown(() => {
-    sandbox.restore();
-  });
+  teardown(() => { sandbox.restore(); });
 
   test('renders', () => {
-    flushAsynchronousOperations();
+    element.fileType = 'text/x-php';
+    element.fileContent = '<?php echo test; ?>';
+    element.prefs = {};
 
-    assert.ok(element.mirror);
-    assert.equal(element.mirror.getValue(), element.fileContent);
+    element._initializeMirror().then(() => {
+      assert.ok(element.mirror);
+      assert.equal(element.mirror.getValue(), element.fileContent);
+    });
   });
 });
 </script>
\ No newline at end of file