Gerrit Code Review supports an API for JavaScript plugins to interact with the web UI and the server process.
Plugin loading and initialization
JavaScript is loaded using a standard <script src='…'>
HTML tag.
Plugins should protect the global namespace by defining their code
within an anonymous function passed to Gerrit.install()
. The plugin
will be passed an object describing its registration with Gerrit.
-
The plugin provides pluginname.js, and can be a standalone file or a static asset in a jar as a Web UI plugin.
-
pluginname.js contains a call to
Gerrit.install()
. There should only be a singleGerrit.install()
call per file. -
The Gerrit web app imports pluginname.js.
-
For standalone plugins, the entry point file is a
pluginname.js
file located ingerrit-site/plugins
folder, wherepluginname
is an alphanumeric plugin name.
Examples
Here’s a recommended starter myplugin.js
:
Gerrit.install(plugin => {
// Your code here.
});
Low-level DOM API concepts
Basically, the DOM is the API surface. Low-level API provides methods for decorating, replacing, and styling DOM elements exposed through a set of endpoints.
Gerrit provides a simple way for accessing the DOM via DOM hooks API. A DOM
hook is a custom element that is instantiated for the plugin endpoint. In the
decoration case, a hook is set with a content
attribute that points to the DOM
element.
-
Get the DOM hook API instance via
plugin.hook(endpointName)
-
Set up an
onAttached
callback -
Callback is called when the hook element is created and inserted into DOM
-
Use element.content to get UI element
Gerrit.install(plugin => {
const domHook = plugin.hook('reply-text');
domHook.onAttached(element => {
if (!element.content) { return; }
// element.content is a reply dialog text area.
});
});
Decorating DOM Elements
For each endpoint, Gerrit provides a list of DOM properties (such as attributes and events) that are supported in the long-term.
Gerrit.install(plugin => {
const domHook = plugin.hook('reply-text');
domHook.onAttached(element => {
if (!element.content) { return; }
element.content.style.border = '1px red dashed';
});
});
Replacing DOM Elements
An endpoint’s contents can be replaced by passing the replace attribute as an option.
Gerrit.install(plugin => {
const domHook = plugin.hook('header-title', {replace: true});
domHook.onAttached(element => {
element.appendChild(document.createElement('my-site-header'));
});
});
Styling DOM Elements
Gerrit only offers customized CSS styling by setting custom_properties (aka css variables).
See app-theme.ts for the list of available variables.
Just add code like this to your JavaScript plugin:
const styleEl = document.createElement('style');
styleEl.innerHTML = `
html {
--header-background-color: #c3d9ff;
}
html.darkTheme {
--header-background-color: #c3d9ff90;
}
`;
document.head.appendChild(styleEl);
High-level DOM API concepts
High level API is based on low-level DOM API and is essentially a standardized way for doing common tasks. It’s less flexible, but will be a bit more stable.
The common way to access high-level API is through plugin
instance passed
into setup callback parameter of Gerrit.install()
, also sometimes referred to
as self
.
Low-level DOM API
The low-level DOM API methods are the base of all UI customization.
attributeHelper
plugin.attributeHelper(element)
Alternative for Polymer data for plugins that don’t use Polymer. Can be used to bind element attribute changes to callbacks.
registerCustomComponent
plugin.registerCustomComponent(endpointName, opt_moduleName, opt_options)
See endpoints.
registerDynamicCustomComponent
plugin.registerDynamicCustomComponent(dynamicEndpointName, opt_moduleName,
opt_options)
See endpoints.
registerStyleModule
plugin.registerStyleModule(endpointName, moduleName)
This API is deprecated and will be removed either in version 3.6 or 3.7, see above for an alternative.
on
Register a JavaScript callback to be invoked when events occur within the web interface. Signature
self.on(event, callback);
Parameters
-
event: A supported event type. See below for description.
-
callback: JavaScript function to be invoked when event happens. Arguments may be passed to this function, depending on the event.
Supported events:
-
history
: Invoked when the view is changed to a new screen within the Gerrit web application. The token after "#" is passed as the argument to the callback function, for example "/c/42/" while showing change 42. -
showchange
: Invoked when a change is made visible. A ChangeInfo and RevisionInfo are passed as arguments. Gerrit provides a third parameter which is an object with amergeable
boolean. -
submitchange
: Invoked when the submit button is clicked on a change. A ChangeInfo and RevisionInfo are passed as arguments. Similar to a form submit validation, the function must return true to allow the operation to continue, or false to prevent it. The function may be called multiple times, for example, if submitting a change shows a confirmation dialog, this event may be called to validate that the check whether dialog can be shown, and called again when the submit is confirmed to check whether the actual submission action can proceed. -
comment
: Invoked when a DOM element that represents a comment is created. This DOM element is passed as argument. This DOM element contains nested elements that Gerrit uses to format the comment. The DOM structure may differ between comment types such as inline comments, file-level comments and summary comments, and it may change with new Gerrit versions. -
highlightjs-loaded
: Invoked when the highlight.js library has finished loading. The globalhljs
object (also now accessible viawindow.hljs
) is passed as an argument to the callback function. This event can be used to register a new language highlighter with the highlight.js library before syntax highlighting begins.
High-level API
Plugin instance provides access to a number of more specific APIs and methods to be used by plugin authors.
changeActions
self.changeActions()
Returns an instance of the ChangeActionsPluginApi.
changeActions.add()
Adds a new action to the change actions section. Returns the key of the newly added action.
changeActions.add(type, label)
-
type: The type of the action, either
change
orrevision
. -
label: The label to be used in UI for this action.
changeActions.remove()
Removes an action from the change actions section.
changeActions.remove(key)
-
key: The key of the action.
changeActions.addTapListener()
Adds a tap listener to an action that will be invoked when the action is tapped.
changeActions.addTapListener(key, callback)
-
key: The key of the action.
-
callback: JavaScript function to be invoked when action tapped.
changeActions.removeTapListener()
Removes an existing tap listener on an action.
changeActions.removeTapListener(key, callback)
-
key: The key of the action.
-
callback: JavaScript function to be removed.
changeActions.setLabel()
Sets the label for an action.
changeActions.setLabel(key, label)
-
key: The key of the action.
-
label: The label of the action.
changeActions.setTitle()
Sets the title for an action.
changeActions.setTitle(key, title)
-
key: The key of the action.
-
title: The title of the action.
changeActions.setIcon()
Sets an icon for an action.
changeActions.setIcon(key, icon)
-
key: The key of the action.
-
icon: The name of the icon.
changeActions.setEnabled()
Sets an action to enabled or disabled.
changeActions.setEnabled(key, enabled)
-
key: The key of the action.
-
enabled: The status of the action, true to enable.
changeActions.setActionHidden()
Sets an action to be hidden.
changeActions.setActionHidden(type, key, hidden)
-
type: The type of the action.
-
key: The key of the action.
-
hidden: True to hide the action, false to show the action.
changeActions.setActionOverflow()
Sets an action to show in overflow menu.
changeActions.setActionOverflow(type, key, overflow)
-
type: The type of the action.
-
key: The key of the action.
-
overflow: True to move the action to overflow menu, false to move the action out of the overflow menu.
getPluginName
plugin.getPluginName()
Returns the name this plugin was installed as by the server administrator. The plugin name is required to access REST API views installed by the plugin, or to access resources.
popup
plugin.popup(moduleName)
Creates a popup that contains the given web components. Can be controlled with
calling open()
and close()
on the return value.
restApi
plugin.restApi(opt_prefix)
-
(optional) URL prefix, for easy switching into plugin URL space, e.g.
changes/1/revisions/1/cookbook~say-hello
-
Instance of RestPluginApi.
screen
plugin.screen(screenName, opt_moduleName)
Registers a web component as a dedicated top-level page that the router understands and that has a URL (/x/pluginname/screenname) that can be navigated to. Extension screens are usually linked from the top menu.
-
string screenName
URL path fragment of the screen, e.g./x/pluginname/screenname
-
string opt_moduleName
(Optional) Web component to be instantiated for this screen.
-
Instance of HookApi.
url
plugin.url(opt_path)
Returns a URL within the plugin’s URL space. If invoked with no parameter the URL of the plugin is returned. If passed a string the argument is appended to the plugin URL.
A plugin’s URL is where this plugin is loaded, it doesn’t
necessary to be the same as the Gerrit host. Use window.location
if you need to access the Gerrit host info.
self.url(); // "https://gerrit-review.googlesource.com/plugins/demo/"
self.url('/static/icon.png'); // "https://gerrit-review.googlesource.com/plugins/demo/static/icon.png"