Allow plugins to add entire screens to Gerrit
Add an extension screen which contains a hook that can be used by GWT and JS plugins to integrate complete screens into the Gerrit UI. Change-Id: I48a92ea49c4384db034177b04b2e7f0bea6a87b2
This commit is contained in:

committed by
David Ostrovsky

parent
e9c62bb780
commit
d5c844f43e
@@ -1498,6 +1498,48 @@ In order to be able to do REST calls the GWT module must inherit
|
|||||||
<inherits name="com.google.gwt.json.JSON"/>
|
<inherits name="com.google.gwt.json.JSON"/>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
== Add Screen
|
||||||
|
A GWT plugin can add a menu item that opens a screen that is
|
||||||
|
implemented by the plugin. This way plugin screens can be fully
|
||||||
|
integrated into the Gerrit UI.
|
||||||
|
|
||||||
|
Example menu item:
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
public class MyMenu implements TopMenu {
|
||||||
|
private final List<MenuEntry> menuEntries;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public MyMenu(@PluginName String name) {
|
||||||
|
menuEntries = Lists.newArrayList();
|
||||||
|
menuEntries.add(new MenuEntry("My Menu", Collections.singletonList(
|
||||||
|
new MenuItem("My Screen", "#/x/" + name + "/my-screen", ""))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MenuEntry> getEntries() {
|
||||||
|
return menuEntries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Example screen:
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
public class MyPlugin extends PluginEntryPoint {
|
||||||
|
@Override
|
||||||
|
public void onPluginLoad() {
|
||||||
|
Plugin.get().screen("my-screen", new Screen.EntryPoint() {
|
||||||
|
@Override
|
||||||
|
public void onLoad(Screen screen) {
|
||||||
|
screen.add(new InlineLabel("My Screen");
|
||||||
|
screen.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
[[http]]
|
[[http]]
|
||||||
== HTTP Servlets
|
== HTTP Servlets
|
||||||
|
|
||||||
|
@@ -139,8 +139,8 @@ Gerrit.on(event, callback);
|
|||||||
|
|
||||||
Supported events:
|
Supported events:
|
||||||
|
|
||||||
* `history`: Invoked when the view is changed to a new page within the
|
* `history`: Invoked when the view is changed to a new screen within
|
||||||
Gerrit web application. The token after "#" is passed as the
|
the Gerrit web application. The token after "#" is passed as the
|
||||||
argument to the callback function, for example "/c/42/" while
|
argument to the callback function, for example "/c/42/" while
|
||||||
showing change 42.
|
showing change 42.
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ on a button associated with a server side `UiAction`.
|
|||||||
.Signature
|
.Signature
|
||||||
[source,javascript]
|
[source,javascript]
|
||||||
----
|
----
|
||||||
Gerrit.onAction(type, view_name, callback);
|
self.onAction(type, view_name, callback);
|
||||||
----
|
----
|
||||||
|
|
||||||
* type: `'change'`, `'revision'` or `'project'`, indicating which type
|
* type: `'change'`, `'revision'` or `'project'`, indicating which type
|
||||||
@@ -177,6 +177,27 @@ Gerrit.onAction(type, view_name, callback);
|
|||||||
* callback: JavaScript function to invoke when the user clicks. The
|
* callback: JavaScript function to invoke when the user clicks. The
|
||||||
function will be passed a link:#ActionContext[action context].
|
function will be passed a link:#ActionContext[action context].
|
||||||
|
|
||||||
|
[[self_screen]]
|
||||||
|
=== self.screen()
|
||||||
|
Register a JavaScript callback to be invoked when the user navigates
|
||||||
|
to an extension screen provided by the plugin. Extension screens are
|
||||||
|
usually linked from the link:dev-plugins.html#top-menu-extensions[top menu].
|
||||||
|
The callback can populate the DOM with the screen's contents.
|
||||||
|
|
||||||
|
.Signature
|
||||||
|
[source,javascript]
|
||||||
|
----
|
||||||
|
self.screen(pattern, callback);
|
||||||
|
----
|
||||||
|
|
||||||
|
* pattern: URL token pattern to identify the screen. Argument can be
|
||||||
|
either a string (`'index'`) or a RegExp object (`/list\/(.*)/`).
|
||||||
|
If a RegExp is used the matching groups will be available inside of
|
||||||
|
the context as `token_match`.
|
||||||
|
|
||||||
|
* callback: JavaScript function to invoke when the user navigates to
|
||||||
|
the screen. The function will be passed a link:#ScreenContext[screen context].
|
||||||
|
|
||||||
[[self_url]]
|
[[self_url]]
|
||||||
=== self.url()
|
=== self.url()
|
||||||
Returns a URL within the plugin's URL space. If invoked with no
|
Returns a URL within the plugin's URL space. If invoked with no
|
||||||
@@ -282,7 +303,7 @@ context.get(function (result) {
|
|||||||
|
|
||||||
[[context_go]]
|
[[context_go]]
|
||||||
=== context.go()
|
=== context.go()
|
||||||
Go to a page. Shorthand for link:#Gerrit_go[`Gerrit.go()`].
|
Go to a screen. Shorthand for link:#Gerrit_go[`Gerrit.go()`].
|
||||||
|
|
||||||
[[context_hide]]
|
[[context_hide]]
|
||||||
=== context.hide()
|
=== context.hide()
|
||||||
@@ -402,7 +423,7 @@ loaded the change.
|
|||||||
When the action is invoked on a specific project,
|
When the action is invoked on a specific project,
|
||||||
the name of the project.
|
the name of the project.
|
||||||
|
|
||||||
== Action Context HTML Helpers
|
=== HTML Helpers
|
||||||
The link:#ActionContext[action context] includes some HTML helper
|
The link:#ActionContext[action context] includes some HTML helper
|
||||||
functions to make working with DOM based widgets less painful.
|
functions to make working with DOM based widgets less painful.
|
||||||
|
|
||||||
@@ -446,6 +467,80 @@ functions to make working with DOM based widgets less painful.
|
|||||||
|
|
||||||
* `msg(label)`: a new label.
|
* `msg(label)`: a new label.
|
||||||
|
|
||||||
|
|
||||||
|
[[ScreenContext]]
|
||||||
|
== Screen Context
|
||||||
|
A new screen context is passed to the `screen` callback function
|
||||||
|
each time the user navigates to a matching URL.
|
||||||
|
|
||||||
|
[[screen_body]]
|
||||||
|
=== screen.body
|
||||||
|
Empty HTML `<div>` node the plugin should add its content to. The
|
||||||
|
node is already attached to the document, but is invisible. Plugins
|
||||||
|
must call `screen.show()` to display the DOM node. Deferred display
|
||||||
|
allows an implementor to partially populate the DOM, make remote HTTP
|
||||||
|
requests, finish populating when the callbacks arrive, and only then
|
||||||
|
make the view visible to the user.
|
||||||
|
|
||||||
|
[[screen_token]]
|
||||||
|
=== screen.token
|
||||||
|
URL token fragment that activated this screen. The value is identical
|
||||||
|
to `screen.token_match[0]`. If the URL is `/#/x/hello/list` the token
|
||||||
|
will be `"list"`.
|
||||||
|
|
||||||
|
[[screen_token_match]]
|
||||||
|
=== screen.token_match
|
||||||
|
Array of matching subgroups from the pattern specified to `screen()`.
|
||||||
|
This is identical to the result of RegExp.exec. Index 0 contains the
|
||||||
|
entire matching expression; index 1 the first matching group, etc.
|
||||||
|
|
||||||
|
[[screen_onUnload]]
|
||||||
|
=== screen.onUnload()
|
||||||
|
Configures an optional callback to be invoked just before the screen
|
||||||
|
is deleted from the browser DOM. Plugins can use this callback to
|
||||||
|
remove event listeners from DOM nodes, preventing memory leaks.
|
||||||
|
|
||||||
|
.Signature
|
||||||
|
[source,javascript]
|
||||||
|
----
|
||||||
|
screen.onUnload(callback)
|
||||||
|
----
|
||||||
|
|
||||||
|
* callback: JavaScript function to be invoked just before the
|
||||||
|
`screen.body` DOM element is removed from the browser DOM.
|
||||||
|
This event happens when the user navigates to another screen.
|
||||||
|
|
||||||
|
[[screen.setTitle]]
|
||||||
|
=== screen.setTitle()
|
||||||
|
Sets the heading text to be displayed when the screen is visible.
|
||||||
|
This is presented in a large bold font below the menus, but above the
|
||||||
|
content in `screen.body`. Setting the title also sets the window
|
||||||
|
title to the same string, if it has not already been set.
|
||||||
|
|
||||||
|
.Signature
|
||||||
|
[source,javascript]
|
||||||
|
----
|
||||||
|
screen.setPageTitle(titleText)
|
||||||
|
----
|
||||||
|
|
||||||
|
[[screen.setWindowTitle]]
|
||||||
|
=== screen.setWindowTitle()
|
||||||
|
Sets the text to be displayed in the browser's title bar when the
|
||||||
|
screen is visible. Plugins should always prefer this method over
|
||||||
|
trying to set `window.title` directly. The window title defaults to
|
||||||
|
the title given to `setTitle`.
|
||||||
|
|
||||||
|
.Signature
|
||||||
|
[source,javascript]
|
||||||
|
----
|
||||||
|
screen.setWindowTitle(titleText)
|
||||||
|
----
|
||||||
|
|
||||||
|
[[screen_show]]
|
||||||
|
=== screen.show()
|
||||||
|
Destroy the currently visible screen and display the plugin's screen.
|
||||||
|
This method must be called after adding content to `screen.body`.
|
||||||
|
|
||||||
[[Gerrit]]
|
[[Gerrit]]
|
||||||
== Gerrit
|
== Gerrit
|
||||||
|
|
||||||
@@ -518,7 +613,7 @@ encouraged to use `self.getPluginName()` whenever possible.
|
|||||||
|
|
||||||
[[Gerrit_go]]
|
[[Gerrit_go]]
|
||||||
=== Gerrit.go()
|
=== Gerrit.go()
|
||||||
Updates the web UI to display the view identified by the supplied
|
Updates the web UI to display the screen identified by the supplied
|
||||||
URL token. The URL token is the text after `#` in the browser URL.
|
URL token. The URL token is the text after `#` in the browser URL.
|
||||||
|
|
||||||
[source,javascript]
|
[source,javascript]
|
||||||
@@ -621,6 +716,27 @@ Gerrit.onAction(type, view_name, callback);
|
|||||||
* callback: JavaScript function to invoke when the user clicks. The
|
* callback: JavaScript function to invoke when the user clicks. The
|
||||||
function will be passed a link:#ActionContext[ActionContext].
|
function will be passed a link:#ActionContext[ActionContext].
|
||||||
|
|
||||||
|
[[Gerrit_screen]]
|
||||||
|
=== Gerrit.screen()
|
||||||
|
Register a JavaScript callback to be invoked when the user navigates
|
||||||
|
to an extension screen provided by the plugin. Extension screens are
|
||||||
|
usually linked from the link:dev-plugins.html#top-menu-extensions[top menu].
|
||||||
|
The callback can populate the DOM with the screen's contents.
|
||||||
|
|
||||||
|
.Signature
|
||||||
|
[source,javascript]
|
||||||
|
----
|
||||||
|
Gerrit.screen(pattern, callback);
|
||||||
|
----
|
||||||
|
|
||||||
|
* pattern: URL token pattern to identify the screen. Argument can be
|
||||||
|
either a string (`'index'`) or a RegExp object (`/list\/(.*)/`).
|
||||||
|
If a RegExp is used the matching groups will be available inside of
|
||||||
|
the context as `token_match`.
|
||||||
|
|
||||||
|
* callback: JavaScript function to invoke when the user navigates to
|
||||||
|
the screen. The function will be passed link:#ScreenContext[screen context].
|
||||||
|
|
||||||
[[Gerrit_refresh]]
|
[[Gerrit_refresh]]
|
||||||
=== Gerrit.refresh()
|
=== Gerrit.refresh()
|
||||||
Redisplays the current web UI view, refreshing all information.
|
Redisplays the current web UI view, refreshing all information.
|
||||||
|
@@ -60,6 +60,7 @@ import com.google.gerrit.client.admin.ProjectDashboardsScreen;
|
|||||||
import com.google.gerrit.client.admin.ProjectInfoScreen;
|
import com.google.gerrit.client.admin.ProjectInfoScreen;
|
||||||
import com.google.gerrit.client.admin.ProjectListScreen;
|
import com.google.gerrit.client.admin.ProjectListScreen;
|
||||||
import com.google.gerrit.client.admin.ProjectScreen;
|
import com.google.gerrit.client.admin.ProjectScreen;
|
||||||
|
import com.google.gerrit.client.api.ExtensionScreen;
|
||||||
import com.google.gerrit.client.change.ChangeScreen2;
|
import com.google.gerrit.client.change.ChangeScreen2;
|
||||||
import com.google.gerrit.client.changes.AccountDashboardScreen;
|
import com.google.gerrit.client.changes.AccountDashboardScreen;
|
||||||
import com.google.gerrit.client.changes.ChangeScreen;
|
import com.google.gerrit.client.changes.ChangeScreen;
|
||||||
@@ -226,6 +227,9 @@ public class Dispatcher {
|
|||||||
} else if (matchPrefix("/c/", token)) {
|
} else if (matchPrefix("/c/", token)) {
|
||||||
change(token);
|
change(token);
|
||||||
|
|
||||||
|
} else if (matchPrefix("/x/", token)) {
|
||||||
|
extension(token);
|
||||||
|
|
||||||
} else if (matchExact(MINE, token)) {
|
} else if (matchExact(MINE, token)) {
|
||||||
Gerrit.display(token, mine(token));
|
Gerrit.display(token, mine(token));
|
||||||
|
|
||||||
@@ -564,6 +568,15 @@ public class Dispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void extension(final String token) {
|
||||||
|
ExtensionScreen view = new ExtensionScreen(skip(token));
|
||||||
|
if (view.isFound()) {
|
||||||
|
Gerrit.display(token, view);
|
||||||
|
} else {
|
||||||
|
Gerrit.display(token, new NotFoundScreen());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isChangeScreen2() {
|
private static boolean isChangeScreen2() {
|
||||||
if (!Gerrit.getConfig().getNewFeatures()) {
|
if (!Gerrit.getConfig().getNewFeatures()) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -505,12 +505,9 @@ public class Gerrit implements EntryPoint {
|
|||||||
body = new ViewSite<Screen>() {
|
body = new ViewSite<Screen>() {
|
||||||
@Override
|
@Override
|
||||||
protected void onShowView(Screen view) {
|
protected void onShowView(Screen view) {
|
||||||
lastViewToken = History.getToken();
|
|
||||||
String token = view.getToken();
|
String token = view.getToken();
|
||||||
if (!token.equals(lastViewToken)) {
|
History.newItem(token, false);
|
||||||
History.newItem(token, false);
|
dispatchHistoryHooks(token);
|
||||||
dispatchHistoryHooks(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view instanceof ChangeListScreen) {
|
if (view instanceof ChangeListScreen) {
|
||||||
lastChangeListToken = token;
|
lastChangeListToken = token;
|
||||||
@@ -518,6 +515,7 @@ public class Gerrit implements EntryPoint {
|
|||||||
|
|
||||||
super.onShowView(view);
|
super.onShowView(view);
|
||||||
view.onShowView();
|
view.onShowView();
|
||||||
|
lastViewToken = token;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gBody.add(body);
|
gBody.add(body);
|
||||||
|
@@ -15,8 +15,6 @@
|
|||||||
package com.google.gerrit.client.api;
|
package com.google.gerrit.client.api;
|
||||||
|
|
||||||
import com.google.gerrit.client.Gerrit;
|
import com.google.gerrit.client.Gerrit;
|
||||||
import com.google.gerrit.client.rpc.NativeString;
|
|
||||||
import com.google.gwt.core.client.GWT;
|
|
||||||
import com.google.gwt.core.client.JavaScriptObject;
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
import com.google.gwt.core.client.JsArray;
|
import com.google.gwt.core.client.JsArray;
|
||||||
import com.google.gwt.user.client.History;
|
import com.google.gwt.user.client.History;
|
||||||
@@ -26,17 +24,20 @@ public class ApiGlue {
|
|||||||
private static String pluginName;
|
private static String pluginName;
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
init0(GWT.getHostPageBaseURL(), NativeString.TYPE);
|
init0();
|
||||||
ActionContext.init();
|
ActionContext.init();
|
||||||
Plugin.init();
|
Plugin.init();
|
||||||
addHistoryHook();
|
addHistoryHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void init0(String serverUrl, JavaScriptObject JsonString) /*-{
|
private static native void init0() /*-{
|
||||||
|
var serverUrl = @com.google.gwt.core.client.GWT::getHostPageBaseURL()();
|
||||||
|
var ScreenDefinition = @com.google.gerrit.client.api.ExtensionScreen.Definition::TYPE;
|
||||||
$wnd.Gerrit = {
|
$wnd.Gerrit = {
|
||||||
JsonString: JsonString,
|
JsonString: @com.google.gerrit.client.rpc.NativeString::TYPE,
|
||||||
events: {},
|
events: {},
|
||||||
plugins: {},
|
plugins: {},
|
||||||
|
screens: {},
|
||||||
change_actions: {},
|
change_actions: {},
|
||||||
revision_actions: {},
|
revision_actions: {},
|
||||||
project_actions: {},
|
project_actions: {},
|
||||||
@@ -63,6 +64,12 @@ public class ApiGlue {
|
|||||||
if ('change' == t) this.change_actions[i]=c;
|
if ('change' == t) this.change_actions[i]=c;
|
||||||
else if ('revision' == t) this.revision_actions[i]=c;
|
else if ('revision' == t) this.revision_actions[i]=c;
|
||||||
else if ('project' == t) this.project_actions[i]=c;
|
else if ('project' == t) this.project_actions[i]=c;
|
||||||
|
else if ('screen' == t) _screen(p,t,c);
|
||||||
|
},
|
||||||
|
screen: function(r,c){this._screen(this.getPluginName(),r,c)},
|
||||||
|
_screen: function(p,r,c){
|
||||||
|
var s = new ScreenDefinition(r,c);
|
||||||
|
(this.screens[p] || (this.screens[p]=[])).push(s);
|
||||||
},
|
},
|
||||||
|
|
||||||
url: function (d) {
|
url: function (d) {
|
||||||
|
@@ -0,0 +1,139 @@
|
|||||||
|
// Copyright (C) 2013 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.
|
||||||
|
|
||||||
|
package com.google.gerrit.client.api;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.client.ui.Screen;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
import com.google.gwt.core.client.JsArray;
|
||||||
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
|
||||||
|
/** Screen contributed by a plugin. */
|
||||||
|
public class ExtensionScreen extends Screen {
|
||||||
|
private Context ctx;
|
||||||
|
|
||||||
|
public ExtensionScreen(String token) {
|
||||||
|
String name;
|
||||||
|
String rest;
|
||||||
|
int s = token.indexOf('/');
|
||||||
|
if (0 < s) {
|
||||||
|
name = token.substring(0, s);
|
||||||
|
rest = token.substring(s + 1);
|
||||||
|
} else {
|
||||||
|
name = token;
|
||||||
|
rest = "";
|
||||||
|
}
|
||||||
|
ctx = create(name, rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context create(String name, String rest) {
|
||||||
|
for (Definition def : Natives.asList(Definition.get(name))) {
|
||||||
|
JsArrayString m = def.match(rest);
|
||||||
|
if (m != null) {
|
||||||
|
return Context.create(def, this, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFound() {
|
||||||
|
return ctx != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoad() {
|
||||||
|
super.onLoad();
|
||||||
|
setHeaderVisible(false);
|
||||||
|
ctx.onLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onUnload() {
|
||||||
|
super.onUnload();
|
||||||
|
for (JavaScriptObject u : Natives.asList(ctx.unload())) {
|
||||||
|
ApiGlue.invoke(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Definition extends JavaScriptObject {
|
||||||
|
static final JavaScriptObject TYPE = init();
|
||||||
|
private static native JavaScriptObject init() /*-{
|
||||||
|
function ScreenDefinition(r, c) {
|
||||||
|
this.pattern = r;
|
||||||
|
this.onLoad = c;
|
||||||
|
};
|
||||||
|
return ScreenDefinition;
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
static native JsArray<Definition> get(String n)
|
||||||
|
/*-{ return $wnd.Gerrit.screens[n] || [] }-*/;
|
||||||
|
|
||||||
|
final native JsArrayString match(String t)
|
||||||
|
/*-{
|
||||||
|
var p = this.pattern;
|
||||||
|
if (p instanceof $wnd.RegExp) {
|
||||||
|
var m = p.exec(t);
|
||||||
|
return m && m[0] == t ? m : null;
|
||||||
|
}
|
||||||
|
return p == t ? [t] : null;
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
protected Definition() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Context extends JavaScriptObject {
|
||||||
|
static final Context create(
|
||||||
|
Definition def,
|
||||||
|
ExtensionScreen view,
|
||||||
|
JsArrayString match) {
|
||||||
|
return create(TYPE, def, view, view.getBody().getElement(), match);
|
||||||
|
}
|
||||||
|
|
||||||
|
final native void onLoad() /*-{ this._d.onLoad(this) }-*/;
|
||||||
|
final native JsArray<JavaScriptObject> unload() /*-{ return this._u }-*/;
|
||||||
|
|
||||||
|
private static final native Context create(
|
||||||
|
JavaScriptObject T,
|
||||||
|
Definition d,
|
||||||
|
ExtensionScreen s,
|
||||||
|
Element e,
|
||||||
|
JsArrayString m)
|
||||||
|
/*-{ return new T(d,s,e,m) }-*/;
|
||||||
|
|
||||||
|
private static final JavaScriptObject TYPE = init();
|
||||||
|
private static final native JavaScriptObject init() /*-{
|
||||||
|
var T = function(d,s,e,m) {
|
||||||
|
this._d = d;
|
||||||
|
this._s = s;
|
||||||
|
this._u = [];
|
||||||
|
this.body = e;
|
||||||
|
this.token = m[0];
|
||||||
|
this.token_match = m;
|
||||||
|
};
|
||||||
|
T.prototype = {
|
||||||
|
setTitle: function(t){this._s.@com.google.gerrit.client.ui.Screen::setPageTitle(Ljava/lang/String;)(t)},
|
||||||
|
setWindowTitle: function(t){this._s.@com.google.gerrit.client.ui.Screen::setWindowTitle(Ljava/lang/String;)(t)},
|
||||||
|
show: function(){$entry(this._s.@com.google.gwtexpui.user.client.View::display()())},
|
||||||
|
onUnload: function(f){this._u.push(f)},
|
||||||
|
};
|
||||||
|
return T;
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
protected Context() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -54,6 +54,7 @@ final class Plugin extends JavaScriptObject {
|
|||||||
refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
|
refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
|
||||||
on: function(e,f){G.on(e,f)},
|
on: function(e,f){G.on(e,f)},
|
||||||
onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
|
onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
|
||||||
|
screen: function(p,c){G._screen(this.name,p,c)},
|
||||||
|
|
||||||
url: function (u){return G.url(this._url(u))},
|
url: function (u){return G.url(this._url(u))},
|
||||||
get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
||||||
|
@@ -137,6 +137,10 @@ public abstract class Screen extends View {
|
|||||||
body.add(w);
|
body.add(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected FlowPanel getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
protected void setTheme(final ThemeInfo t) {
|
protected void setTheme(final ThemeInfo t) {
|
||||||
theme = t;
|
theme = t;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<module>
|
<module>
|
||||||
|
<inherits name="com.google.gwt.json.JSON"/>
|
||||||
|
|
||||||
<define-linker name="gerrit_plugin" class="com.google.gerrit.plugin.linker.GerritPluginLinker"/>
|
<define-linker name="gerrit_plugin" class="com.google.gerrit.plugin.linker.GerritPluginLinker"/>
|
||||||
<add-linker name="gerrit_plugin"/>
|
<add-linker name="gerrit_plugin"/>
|
||||||
<generate-with class="com.google.gerrit.plugin.rebind.PluginGenerator">
|
<generate-with class="com.google.gerrit.plugin.rebind.PluginGenerator">
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.plugin.client;
|
package com.google.gerrit.plugin.client;
|
||||||
|
|
||||||
|
import com.google.gerrit.plugin.client.screen.Screen;
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
import com.google.gwt.core.client.JavaScriptObject;
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
@@ -49,6 +50,35 @@ public final class Plugin extends JavaScriptObject {
|
|||||||
public final native void refresh()
|
public final native void refresh()
|
||||||
/*-{ return this.refresh() }-*/;
|
/*-{ return this.refresh() }-*/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a screen displayed at {@code /#/x/plugin/token}.
|
||||||
|
*
|
||||||
|
* @param token literal anchor token appearing after the plugin name. For
|
||||||
|
* regular expression matching use {@code screenRegex()} .
|
||||||
|
* @param entry callback function invoked to create the screen widgets.
|
||||||
|
*/
|
||||||
|
public final void screen(String token, Screen.EntryPoint entry) {
|
||||||
|
screen(token, wrap(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final native void screen(String t, JavaScriptObject e)
|
||||||
|
/*-{ this.screen(t, e) }-*/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a screen displayed at {@code /#/x/plugin/regex}.
|
||||||
|
*
|
||||||
|
* @param regex JavaScript {@code RegExp} expression to match the anchor token
|
||||||
|
* after the plugin name. Matching groups are exposed through the
|
||||||
|
* {@code Screen} object passed into the {@code Screen.EntryPoint}.
|
||||||
|
* @param entry callback function invoked to create the screen widgets.
|
||||||
|
*/
|
||||||
|
public final void screenRegex(String regex, Screen.EntryPoint entry) {
|
||||||
|
screenRegex(regex, wrap(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final native void screenRegex(String p, JavaScriptObject e)
|
||||||
|
/*-{ this.screen(new $wnd.RegExp(p), e) }-*/;
|
||||||
|
|
||||||
protected Plugin() {
|
protected Plugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,4 +86,11 @@ public final class Plugin extends JavaScriptObject {
|
|||||||
native void _loaded() /*-{ this._loadedGwt() }-*/;
|
native void _loaded() /*-{ this._loadedGwt() }-*/;
|
||||||
private static native final Plugin install(String u)
|
private static native final Plugin install(String u)
|
||||||
/*-{ return $wnd.Gerrit.installGwt(u) }-*/;
|
/*-{ return $wnd.Gerrit.installGwt(u) }-*/;
|
||||||
|
|
||||||
|
private static final native JavaScriptObject wrap(Screen.EntryPoint b) /*-{
|
||||||
|
return $entry(function(c){
|
||||||
|
b.@com.google.gerrit.plugin.client.screen.Screen.EntryPoint::onLoad(Lcom/google/gerrit/plugin/client/screen/Screen;)(
|
||||||
|
@com.google.gerrit.plugin.client.screen.Screen::new(Lcom/google/gerrit/plugin/client/screen/Screen$Context;)(c));
|
||||||
|
});
|
||||||
|
}-*/;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (C) 2013 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.
|
||||||
|
|
||||||
|
package com.google.gerrit.plugin.client.screen;
|
||||||
|
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.user.client.ui.SimplePanel;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen contributed by this plugin.
|
||||||
|
*
|
||||||
|
* Screens should be registered early at module load:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @Override
|
||||||
|
* public void onModuleLoad() {
|
||||||
|
* Plugin.get().screen("hi", new Screen.EntryPoint() {
|
||||||
|
* @Override
|
||||||
|
* public void onLoad(Screen screen) {
|
||||||
|
* screen.setPageTitle("Hi");
|
||||||
|
* screen.show(new Label("World"));
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final class Screen extends SimplePanel {
|
||||||
|
/** Initializes a screen for display. */
|
||||||
|
public interface EntryPoint {
|
||||||
|
/**
|
||||||
|
* Invoked when the screen has been created, but not yet displayed.
|
||||||
|
* <p>
|
||||||
|
* The implementation should create a single widget to define the content of
|
||||||
|
* this screen and added it to the passed screen instance. When the screen
|
||||||
|
* is ready to be displayed, call {@link Screen#show()}.
|
||||||
|
* <p>
|
||||||
|
* To use multiple widgets, compose them in panels such as {@code FlowPanel}
|
||||||
|
* and add only the top level widget to the screen.
|
||||||
|
* <p>
|
||||||
|
* The screen is already attached to the browser DOM in an invisible area.
|
||||||
|
* Any widgets added to the screen will immediately receive {@code onLoad()}.
|
||||||
|
* GWT will fire {@code onUnload()} when the screen is removed from the UI,
|
||||||
|
* generally caused by the user navigating to another screen.
|
||||||
|
*
|
||||||
|
* @param screen panel that will contain the screen widget.
|
||||||
|
*/
|
||||||
|
public void onLoad(Screen screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Context extends JavaScriptObject {
|
||||||
|
final native Element body() /*-{ return this.body }-*/;
|
||||||
|
final native JsArrayString token_match() /*-{ return this.token_match }-*/;
|
||||||
|
final native void show() /*-{ this.show() }-*/;
|
||||||
|
final native void setTitle(String t) /*-{ this.setTitle(t) }-*/;
|
||||||
|
final native void setWindowTitle(String t) /*-{ this.setWindowTitle(t) }-*/;
|
||||||
|
final native void detach(Screen s) /*-{
|
||||||
|
this.onUnload($entry(function(){
|
||||||
|
s.@com.google.gwt.user.client.ui.Widget::onDetach()();
|
||||||
|
}));
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
protected Context() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Context ctx;
|
||||||
|
|
||||||
|
Screen(Context ctx) {
|
||||||
|
super(ctx.body());
|
||||||
|
this.ctx = ctx;
|
||||||
|
onAttach();
|
||||||
|
ctx.detach(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the token suffix after {@code "/#/x/plugin-name/"}. */
|
||||||
|
public final String getToken() {
|
||||||
|
return getToken(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param group groups range from 1 to {@code getTokenGroups() - 1}. Token
|
||||||
|
* group 0 is the entire token, see {@link #getToken()}.
|
||||||
|
* @return the token from the regex match group.
|
||||||
|
*/
|
||||||
|
public final String getToken(int group) {
|
||||||
|
return ctx.token_match().get(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return total number of token groups. */
|
||||||
|
public final int getTokenGroups() {
|
||||||
|
return ctx.token_match().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the page title text; appears above the widget.
|
||||||
|
*
|
||||||
|
* @param titleText text to display above the widget.
|
||||||
|
*/
|
||||||
|
public final void setPageTitle(String titleText) {
|
||||||
|
ctx.setTitle(titleText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window title text; appears in the browser window title bar.
|
||||||
|
*
|
||||||
|
* @param titleText text to display in the window title bar.
|
||||||
|
*/
|
||||||
|
public final void setWindowTitle(String titleText) {
|
||||||
|
ctx.setWindowTitle(titleText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the widget and immediately show the screen.
|
||||||
|
*
|
||||||
|
* @param w child containing the content.
|
||||||
|
*/
|
||||||
|
public final void show(Widget w) {
|
||||||
|
setWidget(w);
|
||||||
|
ctx.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Show this screen in the web interface. */
|
||||||
|
public final void show() {
|
||||||
|
ctx.show();
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,6 @@ GWT_COMPILER_OPTS = [
|
|||||||
'-optimize', '9',
|
'-optimize', '9',
|
||||||
'-XdisableClassMetadata',
|
'-XdisableClassMetadata',
|
||||||
'-XdisableCastChecking',
|
'-XdisableCastChecking',
|
||||||
'-XenableClosureCompiler',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
GWT_PLUGIN_DEPS = [
|
GWT_PLUGIN_DEPS = [
|
||||||
|
Reference in New Issue
Block a user