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>