Compatibility fix for Polymer 2

Polymer 2 uses shadow dom. Before the fix all styles were loaded as a
document-level styles. To load styles inside correct element this fix
logically separates plugin in 2 parts: gr-editor and codemirror-element.
The codemirror-element is a wrapper for codemirror and it incapsulates all
styles and scripts inside the element. gr-editor connects codemirror-element
with gerrit - it dynamically loads codemirror-element, set correct
options and adds event listeners.
Also, codemirror doesn't work with shadydom correctly. Because of it,
there 2 versions of codemirror-element - one is for shadowdom and antoher one
is for shadydom.

Bug: Issue 11143
Change-Id: I304cc73df1ea9a5c59fe295fe50c817ed266ffc2
diff --git a/BUILD b/BUILD
index feed56a..8d41cee 100644
--- a/BUILD
+++ b/BUILD
@@ -26,9 +26,25 @@
 )
 
 bundle_assets(
-    name = "codemirror-assets",
-    srcs = ["gr-editor/codemirror-assets.html"],
-    app = "gr-editor/codemirror-assets.html",
+    name = "codemirror-element-shadowdom",
+    srcs = [
+        "gr-editor/codemirror-element.css",
+        "gr-editor/codemirror-element.js",
+        "gr-editor/codemirror-element-shadowdom.html",
+    ],
+    app = "gr-editor/codemirror-element-shadowdom.html",
+    split = False,
+    deps = ["//lib/js:codemirror-minified"],
+)
+
+bundle_assets(
+    name = "codemirror-element-shadydom",
+    srcs = [
+        "gr-editor/codemirror-element.css",
+        "gr-editor/codemirror-element.js",
+        "gr-editor/codemirror-element-shadydom.html",
+    ],
+    app = "gr-editor/codemirror-element-shadydom.html",
     split = False,
     deps = ["//lib/js:codemirror-minified"],
 )
@@ -40,5 +56,8 @@
         "gr-editor/*.js",
     ]),
     app = "plugin.html",
-    assets = [":codemirror-assets"],
+    assets = [
+        ":codemirror-element-shadowdom",
+        ":codemirror-element-shadydom",
+    ],
 )
diff --git a/gr-editor/codemirror-assets.html b/gr-editor/codemirror-element-shadowdom.html
similarity index 68%
copy from gr-editor/codemirror-assets.html
copy to gr-editor/codemirror-element-shadowdom.html
index bf73d6f..cd0f2e6 100644
--- a/gr-editor/codemirror-assets.html
+++ b/gr-editor/codemirror-element-shadowdom.html
@@ -16,26 +16,34 @@
 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="codemirror-element">
+  <template>
+    <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">
+
+    <link rel="stylesheet" type="css" href="./codemirror-element.css" />
+    <div id="wrapper"></div>
+  </template>
+  <script src="./codemirror-element.js"></script>
+</dom-module>
 
 <script src="../bower_components/codemirror-minified/lib/codemirror.js"></script>
 <script src="../bower_components/codemirror-minified/addon/display/rulers.js"></script>
diff --git a/gr-editor/codemirror-assets.html b/gr-editor/codemirror-element-shadydom.html
similarity index 94%
rename from gr-editor/codemirror-assets.html
rename to gr-editor/codemirror-element-shadydom.html
index bf73d6f..c159ea6 100644
--- a/gr-editor/codemirror-assets.html
+++ b/gr-editor/codemirror-element-shadydom.html
@@ -16,6 +16,11 @@
 limitations under the License.
 -->
 
+<!--
+Codemirror doesn't work correctly with shadydom. For shadydom all codemirror's styles
+must be at the document level.
+-->
+
 <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">
@@ -37,6 +42,14 @@
 <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="codemirror-element">
+  <template>
+    <link rel="stylesheet" type="css" href="./codemirror-element.css" />
+    <div id="wrapper"></div>
+  </template>
+  <script src="./codemirror-element.js"></script>
+</dom-module>
+
 <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>
diff --git a/gr-editor/codemirror-element.css b/gr-editor/codemirror-element.css
new file mode 100644
index 0000000..06c5cda
--- /dev/null
+++ b/gr-editor/codemirror-element.css
@@ -0,0 +1,29 @@
+#wrapper {
+  height: 100%;
+  z-index: 0;
+}
+.CodeMirror {
+  font-family: 'Roboto Mono', Menlo, 'Lucida Console', Monaco, monospace;
+  height: auto;
+  /* CodeMirror has a default z-index of 4. Set to 0 to avoid collisions with fixed header. */
+  z-index: 0;
+}
+.CodeMirror-linenumbers {
+  background-color: #fafafa;
+}
+.CodeMirror-linenumber {
+  color: #757575;
+}
+.CodeMirror-ruler {
+  border-left: 1px solid #ddd;
+}
+.cm-tab:before {
+  color: #757575;
+  content: "\2192";
+  position: absolute;
+}
+.cm-trailingspace {
+  background-color: #ef9a9a;
+  border: 1px solid #f44336;
+  border-radius: 3px;
+}
diff --git a/gr-editor/codemirror-element.js b/gr-editor/codemirror-element.js
new file mode 100644
index 0000000..65182d8
--- /dev/null
+++ b/gr-editor/codemirror-element.js
@@ -0,0 +1,65 @@
+// 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.
+(function() {
+  Polymer({
+    is: 'codemirror-element',
+    /**
+     * Fired when the content of the editor changes.
+     *
+     * @event content-change
+     */
+
+    ready() {
+      this.scopeSubtree(this.$.wrapper, true);
+    },
+
+    attached() {
+      this._initialize();
+    },
+
+    setParams(params) {
+      this._params = params;
+      this._initialize();
+    },
+
+    _initialize() {
+      // setParams(params) can be called before or after attach().
+      // Codemirror must be initialized only after both functions were called
+      if(!this._params || !this.isAttached) {
+        return;
+      }
+      // attached() can be called multiple times.
+      // Initialization must be done only once
+      if(this.initialized) {
+        return;
+      }
+      this.initialized = true;
+      this.scopeSubtree(this.$.wrapper, true);
+      this._nativeMirror = window.CodeMirror(this.$.wrapper, this._params);
+      this.async(() => {
+        this._nativeMirror.refresh();
+        this._nativeMirror.focus();
+      }, 1);
+      this._addEventListeners();
+    },
+
+    _addEventListeners() {
+      this._nativeMirror.on('change', e => {
+        this.dispatchEvent(new CustomEvent('content-change',
+            {detail: {value: e.getValue()}}));
+      });
+    },
+
+  });
+})();
diff --git a/gr-editor/gr-editor.html b/gr-editor/gr-editor.html
index b7b2cc9..74d01a8 100644
--- a/gr-editor/gr-editor.html
+++ b/gr-editor/gr-editor.html
@@ -16,38 +16,7 @@
 
 <dom-module id="gr-editor">
   <template>
-    <style>
-      #wrapper {
-        height: 100%;
-        z-index: 0;
-      }
-      .CodeMirror {
-        font-family: 'Roboto Mono', Menlo, 'Lucida Console', Monaco, monospace;
-        height: auto;
-        /* CodeMirror has a default z-index of 4. Set to 0 to avoid collisions with fixed header. */
-        z-index: 0;
-      }
-      .CodeMirror-linenumbers {
-        background-color: #fafafa;
-      }
-      .CodeMirror-linenumber {
-        color: #757575;
-      }
-      .CodeMirror-ruler {
-        border-left: 1px solid #ddd;
-      }
-      .cm-tab:before {
-        color: #757575;
-        content: "\2192";
-        position: absolute;
-      }
-      .cm-trailingspace {
-        background-color: #ef9a9a;
-        border: 1px solid #f44336;
-        border-radius: 3px;
-      }
-    </style>
-    <div id="wrapper"></div>
+    <codemirror-element id="codemirror"></codemirror-element>
   </template>
   <script src="gr-editor.js"></script>
 </dom-module>
diff --git a/gr-editor/gr-editor.js b/gr-editor/gr-editor.js
index ad88d9e..ee2f455 100644
--- a/gr-editor/gr-editor.js
+++ b/gr-editor/gr-editor.js
@@ -41,33 +41,32 @@
     },
 
     _initializeMirror() {
-      this.scopeSubtree(this.$.wrapper, true);
       return new Promise((resolve, reject) => {
         this._importCodeMirror().then(() => {
           const params = this.getCodeMirrorParams(this.fileType,
               this.fileContent, this.prefs);
-          this.mirror = window.CodeMirror(this.$.wrapper, params);
-          this.async(() => {
-            this.mirror.refresh();
-            this.mirror.focus();
-          }, 1);
-          this.addEventListeners();
+          this.mirror = this.$.codemirror;
+          this.mirror.setParams(params);
+          this._addEventListeners();
           resolve();
         });
       });
     },
 
     _importCodeMirror() {
-      const url = this.plugin.url('/static/codemirror-assets.html');
+      const codemirrorElementFile = Polymer.Settings.useShadow
+          ? '/static/codemirror-element-shadowdom.html'
+          : '/static/codemirror-element-shadydom.html';
+      const url = this.plugin.url(codemirrorElementFile);
       return new Promise((resolve, reject) => {
         (this.importHref || Polymer.importHref)(url, resolve, reject);
       });
     },
 
-    addEventListeners() {
-      this.mirror.on('change', e => {
+    _addEventListeners() {
+      this.mirror.addEventListener('content-change', e => {
         this.dispatchEvent(new CustomEvent('content-change',
-            {detail: {value: e.getValue()}, bubbles: true}));
+            {detail: {value: e.detail.value}, bubbles: true, composed: true}));
       });
     },
 
diff --git a/gr-editor/gr-editor_test.html b/gr-editor/gr-editor_test.html
index 8af7c69..474aa60 100644
--- a/gr-editor/gr-editor_test.html
+++ b/gr-editor/gr-editor_test.html
@@ -51,7 +51,7 @@
       attached() {},
       _importCodeMirror() {
         return new Promise((resolve, reject) => {
-          this.importHref('./codemirror-assets.html', resolve, reject);
+          this.importHref('./codemirror-element-shadowdom.html', resolve, reject);
         });
       },
     });
@@ -67,8 +67,8 @@
 
     element._initializeMirror().then(() => {
       assert.ok(element.mirror);
-      assert.equal(element.mirror.getValue(), element.fileContent);
+      assert.equal(element.mirror._nativeMirror.getValue(), element.fileContent);
     });
   });
 });
-</script>
\ No newline at end of file
+</script>