Merge "Expose reply dialog and label score value to plugins."
This commit is contained in:
		| @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| --> | ||||
|  | ||||
| <link rel="import" href="../../../bower_components/polymer/polymer.html"> | ||||
| <link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html"> | ||||
| <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html"> | ||||
| <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html"> | ||||
| <link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html"> | ||||
| <link rel="import" href="../../../bower_components/polymer/polymer.html"> | ||||
| <link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html"> | ||||
| <link rel="import" href="../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.html"> | ||||
| <link rel="import" href="../../shared/gr-account-chip/gr-account-chip.html"> | ||||
| <link rel="import" href="../../shared/gr-button/gr-button.html"> | ||||
| <link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html"> | ||||
| @@ -95,6 +96,9 @@ limitations under the License. | ||||
|         min-height: 6em; | ||||
|         position: relative; | ||||
|       } | ||||
|       .textareaContainer > * { | ||||
|         flex: 1; | ||||
|       } | ||||
|       iron-autogrow-textarea { | ||||
|         padding: 0; | ||||
|         font-family: var(--monospace-font-family); | ||||
| @@ -202,17 +206,19 @@ limitations under the License. | ||||
|         </gr-overlay> | ||||
|       </section> | ||||
|       <section class="textareaContainer"> | ||||
|         <iron-autogrow-textarea | ||||
|             id="textarea" | ||||
|             class="message" | ||||
|             autocomplete="on" | ||||
|             placeholder=[[_messagePlaceholder]] | ||||
|             disabled="{{disabled}}" | ||||
|             rows="4" | ||||
|             max-rows="15" | ||||
|             bind-value="{{draft}}" | ||||
|             on-bind-value-changed="_handleHeightChanged"> | ||||
|         </iron-autogrow-textarea> | ||||
|         <gr-endpoint-decorator name="reply-text"> | ||||
|           <iron-autogrow-textarea | ||||
|               id="textarea" | ||||
|               class="message" | ||||
|               autocomplete="on" | ||||
|               placeholder=[[_messagePlaceholder]] | ||||
|               disabled="{{disabled}}" | ||||
|               rows="4" | ||||
|               max-rows="15" | ||||
|               bind-value="{{draft}}" | ||||
|               on-bind-value-changed="_handleHeightChanged"> | ||||
|           </iron-autogrow-textarea> | ||||
|         </gr-endpoint-decorator> | ||||
|       </section> | ||||
|       <section class="previewContainer"> | ||||
|         <label> | ||||
|   | ||||
| @@ -198,14 +198,24 @@ | ||||
|  | ||||
|     setLabelValue(label, value) { | ||||
|       const selectorEl = | ||||
|           this.$.labelScores.$$('iron-selector[data-label="' + label + '"]'); | ||||
|           this.$.labelScores.$$(`iron-selector[data-label="${label}"]`); | ||||
|       // The selector may not be present if it’s not at the latest patch set. | ||||
|       if (!selectorEl) { return; } | ||||
|       const item = selectorEl.$$('gr-button[data-value="' + value + '"]'); | ||||
|       const item = selectorEl.$$(`gr-button[data-value="${value}"]`); | ||||
|       if (!item) { return; } | ||||
|       selectorEl.selectIndex(selectorEl.indexOf(item)); | ||||
|     }, | ||||
|  | ||||
|     getLabelValue(label) { | ||||
|       const selectorEl = | ||||
|           this.$.labelScores.$$(`iron-selector[data-label="${label}"]`); | ||||
|       // The selector may not be present if it’s not at the latest patch set. | ||||
|       if (!selectorEl) { return null; } | ||||
|       const item = selectorEl.querySelector('gr-button.iron-selected'); | ||||
|       if (!item) { return null; } | ||||
|       return item.getAttribute('data-value'); | ||||
|     }, | ||||
|  | ||||
|     _handleEscKey(e) { | ||||
|       this.cancel(); | ||||
|     }, | ||||
|   | ||||
| @@ -210,6 +210,26 @@ limitations under the License. | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
|     test('getlabelValue returns value', done => { | ||||
|       flush(() => { | ||||
|         MockInteractions.tap(element.$$('gr-label-scores').$$( | ||||
|             'iron-selector[data-label="Verified"] > ' + | ||||
|             'gr-button[data-value="-1"]')); | ||||
|         assert.equal('-1', element.getLabelValue('Verified')); | ||||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
|     test('getlabelValue when no score is selected', done => { | ||||
|       flush(() => { | ||||
|         MockInteractions.tap(element.$$('gr-label-scores').$$( | ||||
|             'iron-selector[data-label="Code-Review"] > ' + | ||||
|             'gr-button[data-value="-1"]')); | ||||
|         assert.isNull(element.getLabelValue('Verified')); | ||||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
|     test('setlabelValue', () => { | ||||
|       element._account = {_account_id: 1}; | ||||
|       flushAsynchronousOperations(); | ||||
|   | ||||
| @@ -0,0 +1,25 @@ | ||||
| <!-- | ||||
| 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="import" href="../../../bower_components/polymer/polymer.html"> | ||||
| <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html"> | ||||
|  | ||||
| <dom-module id="gr-endpoint-decorator"> | ||||
|   <template> | ||||
|     <content></content> | ||||
|   </template> | ||||
|   <script src="gr-endpoint-decorator.js"></script> | ||||
| </dom-module> | ||||
| @@ -0,0 +1,49 @@ | ||||
| // 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() { | ||||
|   'use strict'; | ||||
|  | ||||
|   Polymer({ | ||||
|     is: 'gr-endpoint-decorator', | ||||
|  | ||||
|     properties: { | ||||
|       name: String, | ||||
|     }, | ||||
|  | ||||
|     _import(url) { | ||||
|       return new Promise((resolve, reject) => { | ||||
|         this.importHref(url, resolve, reject); | ||||
|       }); | ||||
|     }, | ||||
|  | ||||
|     _initPluginDomHook(name, plugin) { | ||||
|       const el = document.createElement(name); | ||||
|       el.plugin = plugin; | ||||
|       el.content = this.getContentChildren()[0]; | ||||
|       return Polymer.dom(this.root).appendChild(el); | ||||
|     }, | ||||
|  | ||||
|     ready() { | ||||
|       Gerrit.awaitPluginsLoaded().then(() => Promise.all( | ||||
|           Gerrit._getPluginsForEndpoint(this.name).map( | ||||
|               pluginUrl => this._import(pluginUrl))) | ||||
|       ).then(() => { | ||||
|         const modulesData = Gerrit._getEndpointDetails(this.name); | ||||
|         for (const {moduleName, plugin} of modulesData) { | ||||
|           this._initPluginDomHook(moduleName, plugin); | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|   }); | ||||
| })(); | ||||
| @@ -0,0 +1,71 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- | ||||
| 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. | ||||
| --> | ||||
|  | ||||
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> | ||||
| <title>gr-endpoint-decorator</title> | ||||
|  | ||||
| <script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> | ||||
| <script src="../../../bower_components/web-component-tester/browser.js"></script> | ||||
|  | ||||
| <link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html"> | ||||
| <link rel="import" href="gr-endpoint-decorator.html"> | ||||
|  | ||||
| <test-fixture id="basic"> | ||||
|   <template> | ||||
|     <gr-endpoint-decorator name="foo"></gr-endpoint-decorator> | ||||
|   </template> | ||||
| </test-fixture> | ||||
|  | ||||
| <script> | ||||
|   suite('gr-endpoint-decorator', () => { | ||||
|     let sandbox; | ||||
|     let element; | ||||
|     let plugin; | ||||
|  | ||||
|     setup(done => { | ||||
|       sandbox = sinon.sandbox.create(); | ||||
|  | ||||
|       // NB: Order is important. | ||||
|       Gerrit.install(p => { | ||||
|         plugin = p; | ||||
|         plugin.registerCustomComponent('foo', 'some-module'); | ||||
|       }, '0.1', 'http://some/plugin/url.html'); | ||||
|  | ||||
|       sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve()); | ||||
|  | ||||
|       element = fixture('basic'); | ||||
|       sandbox.stub(element, '_initPluginDomHook'); | ||||
|       sandbox.stub(element, 'importHref', (url, resolve) => { resolve(); }); | ||||
|  | ||||
|       flush(done); | ||||
|     }); | ||||
|  | ||||
|     teardown(() => { | ||||
|       sandbox.restore(); | ||||
|     }); | ||||
|  | ||||
|     test('imports plugin-provided module', () => { | ||||
|       assert.isTrue( | ||||
|           element.importHref.calledWith(new URL('http://some/plugin/url.html'))); | ||||
|     }); | ||||
|  | ||||
|     test('inits plugin-provided dom hook', () => { | ||||
|       assert.isTrue( | ||||
|           element._initPluginDomHook.calledWith('some-module', plugin)); | ||||
|     }); | ||||
|   }); | ||||
| </script> | ||||
| @@ -34,24 +34,13 @@ | ||||
|     }, | ||||
|  | ||||
|     ready() { | ||||
|       Gerrit.awaitPluginsLoaded().then(() => { | ||||
|         const sharedStyles = Gerrit._styleModules[this.name]; | ||||
|         if (sharedStyles) { | ||||
|           const pluginUrls = []; | ||||
|           const moduleNames = []; | ||||
|           sharedStyles.reduce((result, item) => { | ||||
|             if (!result.pluginUrls.includes(item.pluginUrl)) { | ||||
|               result.pluginUrls.push(item.pluginUrl); | ||||
|             } | ||||
|             result.moduleNames.push(item.moduleName); | ||||
|             return result; | ||||
|           }, {pluginUrls, moduleNames}); | ||||
|           Promise.all(pluginUrls.map(this._import.bind(this))) | ||||
|               .then(() => { | ||||
|                 for (const name of moduleNames) { | ||||
|                   this._applyStyle(name); | ||||
|                 } | ||||
|               }); | ||||
|       Gerrit.awaitPluginsLoaded().then(() => Promise.all( | ||||
|           Gerrit._getPluginsForEndpoint(this.name).map( | ||||
|               pluginUrl => this._import(pluginUrl))) | ||||
|       ).then(() => { | ||||
|         const moduleNames = Gerrit._getModulesForEndoint(this.name); | ||||
|         for (const name of moduleNames) { | ||||
|           this._applyStyle(name); | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|   | ||||
| @@ -30,18 +30,26 @@ limitations under the License. | ||||
| </test-fixture> | ||||
|  | ||||
| <script> | ||||
|   suite('gr-change-metadata integration tests', () => { | ||||
|   suite('gr-external-style integration tests', () => { | ||||
|     let sandbox; | ||||
|     let element; | ||||
|  | ||||
|     setup(done => { | ||||
|       sandbox = sinon.sandbox.create(); | ||||
|  | ||||
|       // NB: Order is important. | ||||
|       let plugin; | ||||
|       Gerrit.install(p => { | ||||
|         plugin = p; | ||||
|         plugin.registerStyleModule('foo', 'some-module'); | ||||
|       }, '0.1', 'http://some/plugin/url.html'); | ||||
|  | ||||
|       sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve()); | ||||
|       Gerrit._styleModules = {foo: [{pluginUrl: 'bar', moduleName: 'baz'}]}; | ||||
|  | ||||
|       element = fixture('basic'); | ||||
|       sandbox.stub(element, '_applyStyle'); | ||||
|       sandbox.stub(element, 'importHref', (url, resolve) => { resolve(); }); | ||||
|  | ||||
|       flush(done); | ||||
|     }); | ||||
|  | ||||
| @@ -50,11 +58,12 @@ limitations under the License. | ||||
|     }); | ||||
|  | ||||
|     test('imports plugin-provided module', () => { | ||||
|       assert.isTrue(element.importHref.calledWith('bar')); | ||||
|       assert.isTrue(element.importHref.calledWith( | ||||
|           new URL('http://some/plugin/url.html'))); | ||||
|     }); | ||||
|  | ||||
|     test('applies plugin-provided styles', () => { | ||||
|       assert.isTrue(element._applyStyle.calledWith('baz')); | ||||
|       assert.isTrue(element._applyStyle.calledWith('some-module')); | ||||
|     }); | ||||
|   }); | ||||
| </script> | ||||
|   | ||||
| @@ -14,17 +14,44 @@ | ||||
| (function(window) { | ||||
|   'use strict'; | ||||
|  | ||||
|   function GrChangeReplyInterface(el) { | ||||
|     this._el = el; | ||||
|   /** | ||||
|    * Don't add new API methods to GrChangeReplyInterfaceOld. | ||||
|    * All new API should be added to GrChangeReplyInterface. | ||||
|    * @deprecated | ||||
|    */ | ||||
|   class GrChangeReplyInterfaceOld { | ||||
|     constructor(el) { | ||||
|       this._el = el; | ||||
|     } | ||||
|  | ||||
|     getLabelValue(label) { | ||||
|       return this._el.getLabelValue(label); | ||||
|     } | ||||
|  | ||||
|     setLabelValue(label, value) { | ||||
|       this._el.setLabelValue(label, value); | ||||
|     } | ||||
|  | ||||
|     send(opt_includeComments) { | ||||
|       return this._el.send(opt_includeComments); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   GrChangeReplyInterface.prototype.setLabelValue = function(label, value) { | ||||
|     this._el.setLabelValue(label, value); | ||||
|   }; | ||||
|   class GrChangeReplyInterface extends GrChangeReplyInterfaceOld { | ||||
|     constructor(plugin, el) { | ||||
|       super(el); | ||||
|       this.plugin = plugin; | ||||
|     } | ||||
|  | ||||
|   GrChangeReplyInterface.prototype.send = function(opt_includeComments) { | ||||
|     return this._el.send(opt_includeComments); | ||||
|   }; | ||||
|     addReplyTextChangedCallback(handler) { | ||||
|       this.plugin.getDomHook('reply-text').then(el => { | ||||
|         if (!el.content) { return; } | ||||
|         el.content.addEventListener('value-changed', e => { | ||||
|           handler(e.detail.value); | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   window.GrChangeReplyInterface = GrChangeReplyInterface; | ||||
| })(window); | ||||
|   | ||||
| @@ -22,9 +22,9 @@ limitations under the License. | ||||
| <script src="../../../bower_components/web-component-tester/browser.js"></script> | ||||
| <link rel="import" href="../../../test/common-test-setup.html"/> | ||||
| <!-- | ||||
|      This must refer to the element this interface is wrapping around. Otherwise | ||||
|      breaking changes to gr-reply-dialog won’t be noticed. | ||||
|    --> | ||||
| This must refer to the element this interface is wrapping around. Otherwise | ||||
| breaking changes to gr-reply-dialog won’t be noticed. | ||||
| --> | ||||
| <link rel="import" href="../../change/gr-reply-dialog/gr-reply-dialog.html"> | ||||
|  | ||||
| <script>void(0);</script> | ||||
| @@ -60,13 +60,17 @@ limitations under the License. | ||||
|     }); | ||||
|  | ||||
|     test('calls', () => { | ||||
|       const setLabelValueStub = sinon.stub(element, 'setLabelValue'); | ||||
|       changeReply.setLabelValue('My-Label', '+1337'); | ||||
|       assert(setLabelValueStub.calledWithExactly('My-Label', '+1337')); | ||||
|       sandbox.stub(element, 'getLabelValue').returns('+123'); | ||||
|       assert.equal(changeReply.getLabelValue('My-Label'), '+123'); | ||||
|  | ||||
|       const sendStub = sinon.stub(element, 'send'); | ||||
|       sandbox.stub(element, 'setLabelValue'); | ||||
|       changeReply.setLabelValue('My-Label', '+1337'); | ||||
|       assert.isTrue( | ||||
|           element.setLabelValue.calledWithExactly('My-Label', '+1337')); | ||||
|  | ||||
|       sandbox.stub(element, 'send'); | ||||
|       changeReply.send(false); | ||||
|       assert(sendStub.calledWithExactly(false)); | ||||
|       assert.isTrue(element.send.calledWithExactly(false)); | ||||
|     }); | ||||
|   }); | ||||
| </script> | ||||
|   | ||||
| @@ -34,6 +34,11 @@ | ||||
|  | ||||
|   const API_VERSION = '0.1'; | ||||
|  | ||||
|   const EndpointType = { | ||||
|     STYLE: 'style', | ||||
|     DOM_DECORATION: 'dom', | ||||
|   }; | ||||
|  | ||||
|   // GWT JSNI uses $wnd to refer to window. | ||||
|   // http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html | ||||
|   window.$wnd = window; | ||||
| @@ -52,6 +57,8 @@ | ||||
|       return; | ||||
|     } | ||||
|     this._name = this._url.pathname.split('/')[2]; | ||||
|     this._generatedHookNames = []; | ||||
|     this._hooks = []; | ||||
|   } | ||||
|  | ||||
|   Plugin._sharedAPIElement = document.createElement('gr-js-api-interface'); | ||||
| @@ -62,14 +69,27 @@ | ||||
|     return this._name; | ||||
|   }; | ||||
|  | ||||
|   Plugin.prototype.registerStyleModule = function(stylingEndpointName, | ||||
|       moduleName) { | ||||
|     if (!Gerrit._styleModules[stylingEndpointName]) { | ||||
|       Gerrit._styleModules[stylingEndpointName] = []; | ||||
|   Plugin.prototype.registerStyleModule = function(endpointName, moduleName) { | ||||
|     this._registerEndpointModule( | ||||
|         endpointName, EndpointType.STYLE, moduleName); | ||||
|   }; | ||||
|  | ||||
|   Plugin.prototype.registerCustomComponent = | ||||
|       function(endpointName, moduleName) { | ||||
|         this._registerEndpointModule( | ||||
|             endpointName, EndpointType.DOM_DECORATION, moduleName); | ||||
|       }; | ||||
|  | ||||
|   Plugin.prototype._registerEndpointModule = function(endpoint, type, module) { | ||||
|     const endpoints = Gerrit._endpoints; | ||||
|     if (!endpoints[endpoint]) { | ||||
|       endpoints[endpoint] = []; | ||||
|     } | ||||
|     Gerrit._styleModules[stylingEndpointName].push({ | ||||
|     endpoints[endpoint].push({ | ||||
|       moduleName: module, | ||||
|       plugin: this, | ||||
|       pluginUrl: this._url, | ||||
|       moduleName, | ||||
|       type, | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| @@ -105,8 +125,37 @@ | ||||
|   }; | ||||
|  | ||||
|   Plugin.prototype.changeReply = function() { | ||||
|     return new GrChangeReplyInterface(Plugin._sharedAPIElement.getElement( | ||||
|         Plugin._sharedAPIElement.Element.REPLY_DIALOG)); | ||||
|     return new GrChangeReplyInterface(this, | ||||
|       Plugin._sharedAPIElement.getElement( | ||||
|           Plugin._sharedAPIElement.Element.REPLY_DIALOG)); | ||||
|   }; | ||||
|  | ||||
|   Plugin.prototype._getGeneratedHookName = function(endpointName) { | ||||
|     if (!this._generatedHookNames[endpointName]) { | ||||
|       this._generatedHookNames[endpointName] = this.getPluginName() + | ||||
|         '-autogenerated-' + endpointName; | ||||
|     } | ||||
|     return this._generatedHookNames[endpointName]; | ||||
|   }; | ||||
|  | ||||
|   Plugin.prototype.getDomHook = function(endpointName) { | ||||
|     const hookName = this._getGeneratedHookName(endpointName); | ||||
|     if (!this._hooks[hookName]) { | ||||
|       this._hooks[hookName] = new Promise((resolve, reject) => { | ||||
|         Polymer({ | ||||
|           is: hookName, | ||||
|           properties: { | ||||
|             plugin: Object, | ||||
|             content: Object, | ||||
|           }, | ||||
|           attached() { | ||||
|             resolve(this); | ||||
|           }, | ||||
|         }); | ||||
|         this.registerCustomComponent(endpointName, hookName); | ||||
|       }); | ||||
|     } | ||||
|     return this._hooks[hookName]; | ||||
|   }; | ||||
|  | ||||
|   const Gerrit = window.Gerrit || {}; | ||||
| @@ -114,8 +163,8 @@ | ||||
|   // Number of plugins to initialize, -1 means 'not yet known'. | ||||
|   Gerrit._pluginsPending = -1; | ||||
|  | ||||
|   // Hash of style modules to be applied, insertion point to shared style name. | ||||
|   Gerrit._styleModules = {}; | ||||
|   // Hash of custom components to be instantiated for extension endpoints. | ||||
|   Gerrit._endpoints = {}; | ||||
|  | ||||
|   Gerrit.getPluginName = function() { | ||||
|     console.warn('Gerrit.getPluginName is not supported in PolyGerrit.', | ||||
| @@ -204,5 +253,67 @@ | ||||
|     return Gerrit._pluginsPending === 0; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Get detailed information about modules registered with an extension | ||||
|    * endpoint. | ||||
|    * @param {string} name Endpoint name. | ||||
|    * @param {?{ | ||||
|    *   type: (string|undefined), | ||||
|    *   moduleName: (string|undefined) | ||||
|    * }} opt_options | ||||
|    * @return {{ | ||||
|    *   moduleName: string, | ||||
|    *   plugin: Plugin, | ||||
|    *   pluginUrl: String, | ||||
|    *   type: EndpointType, | ||||
|    * }} | ||||
|    */ | ||||
|   Gerrit._getEndpointDetails = function(name, opt_options) { | ||||
|     const type = opt_options && opt_options.type; | ||||
|     const moduleName = opt_options && opt_options.moduleName; | ||||
|     if (!Gerrit._endpoints[name]) { | ||||
|       return []; | ||||
|     } | ||||
|     return Gerrit._endpoints[name] | ||||
|         .filter(item => (!type || item.type === type) && | ||||
|                     (!moduleName || moduleName == item.moduleName)); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Get detailed module names for instantiating at the endpoint | ||||
|    * @param {string} name Endpoint name. | ||||
|    * @param {?{ | ||||
|    *   type: (string|undefined), | ||||
|    *   moduleName: (string|undefined) | ||||
|    * }} opt_options | ||||
|    * @return {!Array<string>} | ||||
|    */ | ||||
|   Gerrit._getModulesForEndoint = function(name, opt_options) { | ||||
|     const modulesData = Gerrit._getEndpointDetails(name, opt_options); | ||||
|     if (!modulesData.length) { | ||||
|       return []; | ||||
|     } | ||||
|     return modulesData.map(m => m.moduleName); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Get .html plugin URLs with element and module definitions. | ||||
|    * @param {string} name Endpoint name. | ||||
|    * @param {?{ | ||||
|    *   type: (string|undefined), | ||||
|    *   moduleName: (string|undefined) | ||||
|    * }} opt_options | ||||
|    * @return {!Array<!URL>} | ||||
|    */ | ||||
|   Gerrit._getPluginsForEndpoint = function(name, opt_options) { | ||||
|     const modulesData = | ||||
|           Gerrit._getEndpointDetails(name, opt_options).filter( | ||||
|               data => data.pluginUrl.pathname.indexOf('.html') !== -1); | ||||
|     if (!modulesData.length) { | ||||
|       return []; | ||||
|     } | ||||
|     return Array.from(new Set(modulesData.map(m => m.pluginUrl))); | ||||
|   }; | ||||
|  | ||||
|   window.Gerrit = Gerrit; | ||||
| })(window); | ||||
|   | ||||
							
								
								
									
										16
									
								
								polygerrit-ui/app/samples/lgtm-plugin.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								polygerrit-ui/app/samples/lgtm-plugin.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <dom-module id="lgtm-plugin"> | ||||
|   <script> | ||||
|     Gerrit.install(plugin => { | ||||
|       const replyApi = plugin.changeReply(); | ||||
|       replyApi.addReplyTextChangedCallback(text => { | ||||
|         const label = 'Code-Review'; | ||||
|         const labelValue = replyApi.getLabelValue(label); | ||||
|         if (labelValue && | ||||
|             labelValue === ' 0' && | ||||
|             text.indexOf('LGTM') === 0) { | ||||
|           replyApi.setLabelValue(label, '+1'); | ||||
|         } | ||||
|       }); | ||||
|     }); | ||||
|   </script> | ||||
| </dom-module> | ||||
		Reference in New Issue
	
	Block a user
	 Viktar Donich
					Viktar Donich