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>