summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js')
-rw-r--r--polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js310
1 files changed, 282 insertions, 28 deletions
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 b3ae649151..ac4129f430 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
@@ -14,36 +14,103 @@
(function(window) {
'use strict';
- var warnNotSupported = function(opt_name) {
+ const warnNotSupported = function(opt_name) {
console.warn('Plugin API method ' + (opt_name || '') + ' is not supported');
};
- var stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
- var GWT_PLUGIN_STUB = {};
- stubbedMethods.forEach(function(name) {
+ /**
+ * Hash of loaded and installed plugins, name to Plugin object.
+ */
+ const plugins = {};
+
+ const stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
+ const GWT_PLUGIN_STUB = {};
+ for (const name of stubbedMethods) {
GWT_PLUGIN_STUB[name] = warnNotSupported.bind(null, name);
- });
+ }
+
+ let _restAPI;
+ const getRestAPI = () => {
+ if (!_restAPI) {
+ _restAPI = document.createElement('gr-rest-api-interface');
+ }
+ return _restAPI;
+ };
+
+ // TODO (viktard): deprecate in favor of GrPluginRestApi.
+ function send(method, url, opt_callback, opt_payload) {
+ return getRestAPI().send(method, url, opt_payload).then(response => {
+ if (response.status < 200 || response.status >= 300) {
+ return response.text().then(text => {
+ if (text) {
+ return Promise.reject(text);
+ } else {
+ return Promise.reject(response.status);
+ }
+ });
+ } else {
+ return getRestAPI().getResponseObject(response);
+ }
+ }).then(response => {
+ if (opt_callback) {
+ opt_callback(response);
+ }
+ return response;
+ });
+ }
+
+ const API_VERSION = '0.1';
- var API_VERSION = '0.1';
+ /**
+ * Plugin-provided custom components can affect content in extension
+ * points using one of following methods:
+ * - DECORATE: custom component is set with `content` attribute and may
+ * decorate (e.g. style) DOM element.
+ * - REPLACE: contents of extension point are replaced with the custom
+ * component.
+ * - STYLE: custom component is a shared styles module that is inserted
+ * into the extension point.
+ */
+ const EndpointType = {
+ DECORATE: 'decorate',
+ REPLACE: 'replace',
+ STYLE: 'style',
+ };
// GWT JSNI uses $wnd to refer to window.
// http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
window.$wnd = window;
+ function getPluginNameFromUrl(url) {
+ const base = Gerrit.BaseUrlBehavior.getBaseUrl();
+ const pathname = url.pathname.replace(base, '');
+ // Site theme is server from predefined path.
+ if (pathname === '/static/gerrit-theme.html') {
+ return 'gerrit-theme';
+ } else if (!pathname.startsWith('/plugins')) {
+ console.warn('Plugin not being loaded from /plugins base path:',
+ url.href, '— Unable to determine name.');
+ return;
+ }
+ return pathname.split('/')[2];
+ }
+
function Plugin(opt_url) {
+ this._domHooks = new GrDomHooksManager(this);
+
if (!opt_url) {
console.warn('Plugin not being loaded from /plugins base path.',
'Unable to determine name.');
return;
}
+ this.deprecated = {
+ install: deprecatedAPI.install.bind(this),
+ popup: deprecatedAPI.popup.bind(this),
+ onAction: deprecatedAPI.onAction.bind(this),
+ };
this._url = new URL(opt_url);
- if (this._url.pathname.indexOf('/plugins') !== 0) {
- console.warn('Plugin not being loaded from /plugins base path:',
- this._url.href, '— Unable to determine name.');
- return;
- }
- this._name = this._url.pathname.split('/')[2];
+ this._name = getPluginNameFromUrl(this._url);
}
Plugin._sharedAPIElement = document.createElement('gr-js-api-interface');
@@ -54,6 +121,30 @@
return this._name;
};
+ Plugin.prototype.registerStyleModule = function(endpointName, moduleName) {
+ Gerrit._endpoints.registerModule(
+ this, endpointName, EndpointType.STYLE, moduleName);
+ };
+
+ Plugin.prototype.registerCustomComponent = function(
+ endpointName, opt_moduleName, opt_options) {
+ const type = opt_options && opt_options.replace ?
+ EndpointType.REPLACE : EndpointType.DECORATE;
+ const hook = this._domHooks.getDomHook(endpointName, opt_moduleName);
+ const moduleName = opt_moduleName || hook.getModuleName();
+ Gerrit._endpoints.registerModule(
+ this, endpointName, type, moduleName, hook);
+ return hook.getPublicAPI();
+ };
+
+ /**
+ * Returns instance of DOM hook API for endpoint. Creates a placeholder
+ * element for the first call.
+ */
+ Plugin.prototype.hook = function(endpointName, opt_options) {
+ return this.registerCustomComponent(endpointName, undefined, opt_options);
+ };
+
Plugin.prototype.getServerInfo = function() {
return document.createElement('gr-rest-api-interface').getConfig();
};
@@ -63,37 +154,154 @@
};
Plugin.prototype.url = function(opt_path) {
- return this._url.origin + '/plugins/' + this._name + (opt_path || '/');
+ const base = Gerrit.BaseUrlBehavior.getBaseUrl();
+ return this._url.origin + base + '/plugins/' +
+ this._name + (opt_path || '/');
+ };
+
+ Plugin.prototype._send = function(method, url, opt_callback, opt_payload) {
+ return send(method, this.url(url), opt_callback, opt_payload);
+ };
+
+ Plugin.prototype.get = function(url, opt_callback) {
+ console.warn('.get() is deprecated! Use .restApi().get()');
+ return this._send('GET', url, opt_callback);
+ };
+
+ Plugin.prototype.post = function(url, payload, opt_callback) {
+ console.warn('.post() is deprecated! Use .restApi().post()');
+ return this._send('POST', url, opt_callback, payload);
+ };
+
+ Plugin.prototype.put = function(url, payload, opt_callback) {
+ console.warn('.put() is deprecated! Use .restApi().put()');
+ return this._send('PUT', url, opt_callback, payload);
+ };
+
+ Plugin.prototype.delete = function(url, opt_callback) {
+ return Gerrit.delete(this.url(url), opt_callback);
};
Plugin.prototype.changeActions = function() {
- return new GrChangeActionsInterface(Plugin._sharedAPIElement.getElement(
- Plugin._sharedAPIElement.Element.CHANGE_ACTIONS));
+ return new GrChangeActionsInterface(this,
+ Plugin._sharedAPIElement.getElement(
+ Plugin._sharedAPIElement.Element.CHANGE_ACTIONS));
};
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));
};
- var Gerrit = window.Gerrit || {};
+ Plugin.prototype.changeView = function() {
+ return new GrChangeViewApi(this);
+ };
+
+ Plugin.prototype.theme = function() {
+ return new GrThemeApi(this);
+ };
+
+ Plugin.prototype.project = function() {
+ return new GrProjectApi(this);
+ };
+
+ /**
+ * To make REST requests for plugin-provided endpoints, use
+ * @example
+ * const pluginRestApi = plugin.restApi(plugin.url());
+ *
+ * @param {string} Base url for subsequent .get(), .post() etc requests.
+ */
+ Plugin.prototype.restApi = function(opt_prefix) {
+ return new GrPluginRestApi(opt_prefix);
+ };
+
+ Plugin.prototype.attributeHelper = function(element) {
+ return new GrAttributeHelper(element);
+ };
+
+ Plugin.prototype.eventHelper = function(element) {
+ return new GrEventHelper(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 = {
+ install() {
+ console.log('Installing deprecated APIs is deprecated!');
+ for (const method in this.deprecated) {
+ if (method === 'install') continue;
+ this[method] = this.deprecated[method];
+ }
+ },
+
+ popup(el) {
+ console.warn('plugin.deprecated.popup() is deprecated, ' +
+ 'use plugin.popup() insted!');
+ if (!el) {
+ throw new Error('Popup contents not found');
+ }
+ const api = new GrPopupInterface(this);
+ api.open().then(api => api._getElement().appendChild(el));
+ return api;
+ },
+
+ onAction(type, action, callback) {
+ console.warn('plugin.deprecated.onAction() is deprecated,' +
+ ' use plugin.changeActions() instead!');
+ if (type !== 'change' && type !== 'revision') {
+ console.warn(`${type} actions are not supported.`);
+ return;
+ }
+ this.on('showchange', (change, revision) => {
+ const details = this.changeActions().getActionDetails(action);
+ this.changeActions().addTapListener(details.__key, () => {
+ callback(new GrPluginActionContext(this, details, change, revision));
+ });
+ });
+ },
+
+ };
+
+ const Gerrit = window.Gerrit || {};
+
+ // Provide reset plugins function to clear installed plugins between tests.
+ const app = document.querySelector('#app');
+ if (!app) {
+ // No gr-app found (running tests)
+ Gerrit._resetPlugins = () => {
+ for (const k of Object.keys(plugins)) {
+ delete plugins[k];
+ }
+ };
+ }
// Number of plugins to initialize, -1 means 'not yet known'.
Gerrit._pluginsPending = -1;
+ Gerrit._endpoints = new GrPluginEndpoints();
+
Gerrit.getPluginName = function() {
console.warn('Gerrit.getPluginName is not supported in PolyGerrit.',
- 'Please use self.getPluginName() instead.');
+ 'Please use plugin.getPluginName() instead.');
};
Gerrit.css = function(rulesStr) {
if (!Gerrit._customStyleSheet) {
- var styleEl = document.createElement('style');
+ const styleEl = document.createElement('style');
document.head.appendChild(styleEl);
Gerrit._customStyleSheet = styleEl.sheet;
}
- var name = '__pg_js_api_class_' + Gerrit._customStyleSheet.cssRules.length;
+ const name = '__pg_js_api_class_' +
+ Gerrit._customStyleSheet.cssRules.length;
Gerrit._customStyleSheet.insertRule('.' + name + '{' + rulesStr + '}', 0);
return name;
};
@@ -106,22 +314,68 @@
return;
}
- // TODO(andybons): Polyfill currentScript for IE10/11 (edge supports it).
- var src = opt_src || (document.currentScript && document.currentScript.src);
- var plugin = new Plugin(src);
+ const src = opt_src || (document.currentScript &&
+ (document.currentScript.src || document.currentScript.baseURI));
+ const name = getPluginNameFromUrl(new URL(src));
+ const existingPlugin = plugins[name];
+ const plugin = existingPlugin || new Plugin(src);
try {
callback(plugin);
+ plugins[name] = plugin;
} catch (e) {
- console.warn(plugin.getPluginName() + ' install failed: ' +
- e.name + ': ' + e.message);
+ console.warn(`${name} install failed: ${e.name}: ${e.message}`);
+ }
+ // Don't double count plugins that may have an html and js install.
+ // TODO(beckysiegel) remove name check once name issue is resolved.
+ // If there isn't a name, it's due to an issue with the polyfill for
+ // html imports in Safari/Firefox. In this case, other plugin related
+ // features may still be broken, but still make sure to call.
+ // _pluginInstalled.
+ if (!name || !existingPlugin) {
+ Gerrit._pluginInstalled();
}
- Gerrit._pluginInstalled();
};
Gerrit.getLoggedIn = function() {
+ console.warn('Gerrit.getLoggedIn() is deprecated! ' +
+ 'Use plugin.restApi().getLoggedIn()');
return document.createElement('gr-rest-api-interface').getLoggedIn();
};
+ Gerrit.get = function(url, callback) {
+ console.warn('.get() is deprecated! Use plugin.restApi().get()');
+ send('GET', url, callback);
+ };
+
+ Gerrit.post = function(url, payload, callback) {
+ console.warn('.post() is deprecated! Use plugin.restApi().post()');
+ send('POST', url, callback, payload);
+ };
+
+ Gerrit.put = function(url, payload, callback) {
+ console.warn('.put() is deprecated! Use plugin.restApi().put()');
+ send('PUT', url, callback, payload);
+ };
+
+ Gerrit.delete = function(url, opt_callback) {
+ console.warn('.delete() is deprecated! Use plugin.restApi().delete()');
+ return getRestAPI().send('DELETE', url).then(response => {
+ if (response.status !== 204) {
+ return response.text().then(text => {
+ if (text) {
+ return Promise.reject(text);
+ } else {
+ return Promise.reject(response.status);
+ }
+ });
+ }
+ if (opt_callback) {
+ opt_callback(response);
+ }
+ return response;
+ });
+ };
+
/**
* Polyfill GWT API dependencies to avoid runtime exceptions when loading
* GWT-compiled plugins.
@@ -140,7 +394,7 @@
if (Gerrit._arePluginsLoaded()) {
Gerrit._allPluginsPromise = Promise.resolve();
} else {
- Gerrit._allPluginsPromise = new Promise(function(resolve) {
+ Gerrit._allPluginsPromise = new Promise(resolve => {
Gerrit._resolveAllPluginsLoaded = resolve;
});
}