Plugin popup() api
Changes to JS API:
- popups have backdrop and is centered
- plugin.popup() takes a string custom element name
- plugin.popup() returns an API for closing and reopening the popup
- plugin.deprecated.popup() takes Element (similar to GWT Plugin JS API)
Recommended usage:
``` js
Gerrit.install(function(plugin) {
const popup = plugin.popup('my-plugin-popup-simple');;
// ... work
popup.close();
// ... more work
popup.open();
});
```
``` html
<dom-module id="my-plugin-popup-simple">
<template>
<div>popup popup popup popup popup </div>
</template>
<script>
Polymer({is: 'my-plugin-popup-simple'});
</script>
</dom-module>
```
Change-Id: Icb3f83d35f3c60915f12b77bc8a7d548d50d5695
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index defbe8a..406a4a7 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -46,6 +46,7 @@
<link rel="import" href="./core/gr-reporting/gr-reporting.html">
<link rel="import" href="./core/gr-router/gr-router.html">
<link rel="import" href="./diff/gr-diff-view/gr-diff-view.html">
+<link rel="import" href="./plugins/gr-endpoint-decorator/gr-endpoint-decorator.html">
<link rel="import" href="./plugins/gr-external-style/gr-external-style.html">
<link rel="import" href="./plugins/gr-plugin-host/gr-plugin-host.html">
<link rel="import" href="./settings/gr-cla-view/gr-cla-view.html">
@@ -201,6 +202,7 @@
on-close="_handleRegistrationDialogClose">
</gr-registration-dialog>
</gr-overlay>
+ <gr-endpoint-decorator name="plugin-overlay"></gr-endpoint-decorator>
<gr-error-manager id="errorManager"></gr-error-manager>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-reporting id="reporting"></gr-reporting>
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html
new file mode 100644
index 0000000..3ccb3fd
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html
@@ -0,0 +1,28 @@
+<!--
+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-overlay/gr-overlay.html">
+
+<dom-module id="gr-plugin-popup">
+ <template>
+ <style include="shared-styles"></style>
+ <gr-overlay id="overlay" with-backdrop>
+ <content></content>
+ </gr-overlay>
+ </template>
+ <script src="gr-plugin-popup.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
new file mode 100644
index 0000000..8286eae
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
@@ -0,0 +1,28 @@
+// 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(window) {
+ 'use strict';
+ Polymer({
+ is: 'gr-plugin-popup',
+ get opened() {
+ return this.$.overlay.opened;
+ },
+ open() {
+ return this.$.overlay.open();
+ },
+ close() {
+ this.$.overlay.close();
+ },
+ });
+})(window);
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
new file mode 100644
index 0000000..2dbf96d
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
@@ -0,0 +1,67 @@
+<!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-plugin-popup</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="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-plugin-popup.html"/>
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+ <template>
+ <gr-plugin-popup></gr-plugin-popup>
+ </template>
+</test-fixture>
+
+<script>
+ suite('gr-plugin-popup tests', () => {
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ element = fixture('basic');
+ stub('gr-overlay', {
+ open: sandbox.stub().returns(Promise.resolve()),
+ close: sandbox.stub(),
+ });
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ test('exists', () => {
+ assert.isOk(element);
+ });
+
+ test('open uses open() from gr-overlay', () => {
+ return element.open().then(() => {
+ assert.isTrue(element.$.overlay.open.called);
+ });
+ });
+
+ test('close uses close() from gr-overlay', () => {
+ element.close();
+ assert.isTrue(element.$.overlay.close.called);
+ });
+ });
+</script>
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html
new file mode 100644
index 0000000..6bf37de
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html
@@ -0,0 +1,23 @@
+<!--
+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">
+<link rel="import" href="gr-plugin-popup.html">
+
+<dom-module id="gr-popup-interface">
+ <script src="gr-popup-interface.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
new file mode 100644
index 0000000..e62e882
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
@@ -0,0 +1,71 @@
+// 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(window) {
+ 'use strict';
+
+ /**
+ * Plugin popup API.
+ * Provides method for opening and closing popups from plugin.
+ * opt_moduleName is a name of custom element that will be automatically
+ * inserted on popup opening.
+ * @param {!Object} plugin
+ * @param {opt_moduleName=} string
+ */
+ function GrPopupInterface(plugin, opt_moduleName) {
+ this.plugin = plugin;
+ this._openingPromise = null;
+ this._popup = null;
+ this._moduleName = opt_moduleName || null;
+ }
+
+ GrPopupInterface.prototype._getElement = function() {
+ return Polymer.dom(this._popup);
+ };
+
+ /**
+ * Opens the popup, inserts it into DOM over current UI.
+ * Creates the popup if not previously created. Creates popup content element,
+ * if it was provided with constructor.
+ * @returns {!Promise<!Object>}
+ */
+ GrPopupInterface.prototype.open = function() {
+ if (!this._openingPromise) {
+ this._openingPromise =
+ this.plugin.hook('plugin-overlay').getLastAttached()
+ .then(hookEl => {
+ const popup = document.createElement('gr-plugin-popup');
+ if (this._moduleName) {
+ const el = Polymer.dom(popup).appendChild(
+ document.createElement(this._moduleName));
+ el.plugin = this.plugin;
+ }
+ this._popup = Polymer.dom(hookEl).appendChild(popup);
+ Polymer.dom.flush();
+ return this._popup.open().then(() => this);
+ });
+ }
+ return this._openingPromise;
+ };
+
+ /**
+ * Hides the popup.
+ */
+ GrPopupInterface.prototype.close = function() {
+ if (!this._popup) { return; }
+ this._popup.close();
+ this._openingPromise = null;
+ };
+
+ window.GrPopupInterface = GrPopupInterface;
+})(window);
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
new file mode 100644
index 0000000..7d9dd28
--- /dev/null
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
@@ -0,0 +1,112 @@
+<!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-popup-interface</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="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-popup-interface.html"/>
+
+<script>void(0);</script>
+
+<test-fixture id="container">
+ <template>
+ <div></div>
+ </template>
+</test-fixture>
+
+<dom-module id="gr-user-test-popup">
+ <template>
+ <div id="barfoo">some test module</div>
+ </template>
+ <script>Polymer({is: 'gr-user-test-popup'});</script>
+</dom-module>
+
+<script>
+ suite('gr-popup-interface tests', () => {
+ let container;
+ let instance;
+ let plugin;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ Gerrit.install(p => { plugin = p; }, '0.1',
+ 'http://test.com/plugins/testplugin/static/test.js');
+ container = fixture('container');
+ sandbox.stub(plugin, 'hook').returns({
+ getLastAttached() {
+ return Promise.resolve(container);
+ },
+ });
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ suite('manual', () => {
+ setup(() => {
+ instance = new GrPopupInterface(plugin);
+ });
+
+ test('open', () => {
+ return instance.open().then(api => {
+ assert.strictEqual(api, instance);
+ const manual = document.createElement('div');
+ manual.id = 'foobar';
+ manual.innerHTML = 'manual content';
+ api._getElement().appendChild(manual);
+ flushAsynchronousOperations();
+ assert.equal(
+ container.querySelector('#foobar').textContent, 'manual content');
+ });
+ });
+
+ test('close', () => {
+ return instance.open().then(api => {
+ assert.isTrue(api._getElement().node.opened);
+ api.close();
+ assert.isFalse(api._getElement().node.opened);
+ });
+ });
+ });
+
+ suite('components', () => {
+ setup(() => {
+ instance = new GrPopupInterface(plugin, 'gr-user-test-popup');
+ });
+
+ test('open', () => {
+ return instance.open().then(api => {
+ assert.isNotNull(
+ Polymer.dom(container).querySelector('gr-user-test-popup'));
+ });
+ });
+
+ test('close', () => {
+ return instance.open().then(api => {
+ assert.isTrue(api._getElement().node.opened);
+ api.close();
+ assert.isFalse(api._getElement().node.opened);
+ });
+ });
+ });
+ });
+</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
index f6e2b64..53f889f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
@@ -19,6 +19,7 @@
<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
<link rel="import" href="../../plugins/gr-attribute-helper/gr-attribute-helper.html">
<link rel="import" href="../../plugins/gr-dom-hooks/gr-dom-hooks.html">
+<link rel="import" href="../../plugins/gr-popup-interface/gr-popup-interface.html">
<link rel="import" href="../../plugins/gr-theme-api/gr-theme-api.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index ca0f372..7c9033e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -338,5 +338,35 @@
'http://test.com/r/plugins/testplugin/static/test.js');
});
});
+
+ suite('popup', () => {
+ test('popup(element) is deprecated', () => {
+ assert.throws(() => {
+ plugin.popup(document.createElement('div'));
+ });
+ });
+
+ test('popup(moduleName) creates popup with component', () => {
+ const openStub = sandbox.stub();
+ sandbox.stub(window, 'GrPopupInterface').returns({
+ open: openStub,
+ });
+ plugin.popup('some-name');
+ assert.isTrue(openStub.calledOnce);
+ assert.isTrue(GrPopupInterface.calledWith(plugin, 'some-name'));
+ });
+
+ test('deprecated.popup(element) creates popup with element', () => {
+ const el = document.createElement('div');
+ el.textContent = 'some text here';
+ const openStub = sandbox.stub(GrPopupInterface.prototype, 'open');
+ openStub.returns(Promise.resolve({
+ _getElement() {
+ return document.createElement('div');
+ }}));
+ plugin.deprecated.popup(el);
+ assert.isTrue(openStub.calledOnce);
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index 6c3db84..f1d607c 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -76,6 +76,10 @@
return;
}
this._name = pathname.split('/')[2];
+
+ this.deprecated = {
+ popup: deprecatedAPI.popup.bind(this),
+ };
}
Plugin._sharedAPIElement = document.createElement('gr-js-api-interface');
@@ -176,6 +180,24 @@
return new GrAttributeHelper(element);
};
+ Plugin.prototype.popup = function(moduleName) {
+ if (typeof moduleName !== 'string') {
+ throw new Error('deprecated, use deprecated.popup');
+ }
+ const api = new GrPopupInterface(this, moduleName);
+ return api.open();
+ };
+
+ const deprecatedAPI = {};
+ deprecatedAPI.popup = function(el) {
+ console.warn('plugin.deprecated.popup() is deprecated!');
+ if (!el) {
+ throw new Error('Popup contents not found');
+ }
+ const api = new GrPopupInterface(this);
+ api.open().then(api => api._getElement().appendChild(el));
+ };
+
const Gerrit = window.Gerrit || {};
// Number of plugins to initialize, -1 means 'not yet known'.