Merge "Wait for UI plugins to load"
This commit is contained in:
@@ -1353,10 +1353,13 @@ driven plugins:
|
|||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
----
|
----
|
||||||
|
|
||||||
It is important that the module name that is provided to the
|
The name that is provided to the `GwtPlugin` must match the GWT
|
||||||
`GwtPlugin` matches the GWT module contained in the plugin. The name
|
module name compiled into the plugin. The name of the GWT module
|
||||||
of the GWT module can be explicitly set in the GWT module file by
|
can be explicitly set in the GWT module XML file by specifying
|
||||||
specifying the `rename-to` attribute on the module.
|
the `rename-to` attribute on the module. It is important that the
|
||||||
|
module name be unique across all plugins installed on the server,
|
||||||
|
as the module name determines the JavaScript namespace used by the
|
||||||
|
compiled plugin code.
|
||||||
|
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
@@ -1364,14 +1367,14 @@ specifying the `rename-to` attribute on the module.
|
|||||||
----
|
----
|
||||||
|
|
||||||
The actual GWT code must be implemented in a class that extends
|
The actual GWT code must be implemented in a class that extends
|
||||||
`com.google.gerrit.plugin.client.Plugin`:
|
`com.google.gerrit.plugin.client.PluginEntryPoint`:
|
||||||
|
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
public class HelloPlugin extends Plugin {
|
public class HelloPlugin extends PluginEntryPoint {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onModuleLoad() {
|
public void onPluginLoad() {
|
||||||
// Create the dialog box
|
// Create the dialog box
|
||||||
final DialogBox dialogBox = new DialogBox();
|
final DialogBox dialogBox = new DialogBox();
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.google.gerrit.client.account.AccountCapabilities;
|
|||||||
import com.google.gerrit.client.account.AccountInfo;
|
import com.google.gerrit.client.account.AccountInfo;
|
||||||
import com.google.gerrit.client.admin.ProjectScreen;
|
import com.google.gerrit.client.admin.ProjectScreen;
|
||||||
import com.google.gerrit.client.api.ApiGlue;
|
import com.google.gerrit.client.api.ApiGlue;
|
||||||
|
import com.google.gerrit.client.api.PluginLoader;
|
||||||
import com.google.gerrit.client.changes.ChangeConstants;
|
import com.google.gerrit.client.changes.ChangeConstants;
|
||||||
import com.google.gerrit.client.changes.ChangeListScreen;
|
import com.google.gerrit.client.changes.ChangeListScreen;
|
||||||
import com.google.gerrit.client.config.ConfigServerApi;
|
import com.google.gerrit.client.config.ConfigServerApi;
|
||||||
@@ -49,12 +50,8 @@ import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
|
|||||||
import com.google.gerrit.reviewdb.client.AuthType;
|
import com.google.gerrit.reviewdb.client.AuthType;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gwt.aria.client.Roles;
|
import com.google.gwt.aria.client.Roles;
|
||||||
import com.google.gwt.core.client.Callback;
|
|
||||||
import com.google.gwt.core.client.CodeDownloadException;
|
|
||||||
import com.google.gwt.core.client.EntryPoint;
|
import com.google.gwt.core.client.EntryPoint;
|
||||||
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.ScriptInjector;
|
|
||||||
import com.google.gwt.dom.client.AnchorElement;
|
import com.google.gwt.dom.client.AnchorElement;
|
||||||
import com.google.gwt.dom.client.Document;
|
import com.google.gwt.dom.client.Document;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
@@ -84,12 +81,9 @@ import com.google.gwt.user.client.ui.RootPanel;
|
|||||||
import com.google.gwtexpui.clippy.client.CopyableLabel;
|
import com.google.gwtexpui.clippy.client.CopyableLabel;
|
||||||
import com.google.gwtexpui.user.client.UserAgent;
|
import com.google.gwtexpui.user.client.UserAgent;
|
||||||
import com.google.gwtexpui.user.client.ViewSite;
|
import com.google.gwtexpui.user.client.ViewSite;
|
||||||
import com.google.gwtjsonrpc.client.CallbackHandle;
|
|
||||||
import com.google.gwtjsonrpc.client.JsonDefTarget;
|
import com.google.gwtjsonrpc.client.JsonDefTarget;
|
||||||
import com.google.gwtjsonrpc.client.JsonUtil;
|
import com.google.gwtjsonrpc.client.JsonUtil;
|
||||||
import com.google.gwtjsonrpc.client.XsrfManager;
|
import com.google.gwtjsonrpc.client.XsrfManager;
|
||||||
import com.google.gwtjsonrpc.client.impl.ResultDeserializer;
|
|
||||||
import com.google.gwtjsonrpc.common.AsyncCallback;
|
|
||||||
import com.google.gwtorm.client.KeyUtil;
|
import com.google.gwtorm.client.KeyUtil;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -571,7 +565,7 @@ public class Gerrit implements EntryPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveDefaultTheme();
|
saveDefaultTheme();
|
||||||
loadPlugins(hpd, token);
|
PluginLoader.load(hpd.plugins, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveDefaultTheme() {
|
private void saveDefaultTheme() {
|
||||||
@@ -580,53 +574,6 @@ public class Gerrit implements EntryPoint {
|
|||||||
Document.get().getElementById("gerrit_footer"));
|
Document.get().getElementById("gerrit_footer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadPlugins(HostPageData hpd, final String token) {
|
|
||||||
if (hpd.plugins != null && !hpd.plugins.isEmpty()) {
|
|
||||||
for (final String url : hpd.plugins) {
|
|
||||||
ScriptInjector.fromUrl(url)
|
|
||||||
.setWindow(ScriptInjector.TOP_WINDOW)
|
|
||||||
.setCallback(new Callback<Void, Exception>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Void result) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception reason) {
|
|
||||||
ErrorDialog d;
|
|
||||||
if (reason instanceof CodeDownloadException) {
|
|
||||||
d = new ErrorDialog(M.cannotDownloadPlugin(url));
|
|
||||||
} else {
|
|
||||||
d = new ErrorDialog(M.pluginFailed(url));
|
|
||||||
}
|
|
||||||
d.center();
|
|
||||||
}
|
|
||||||
}).inject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CallbackHandle<Void> cb = new CallbackHandle<Void>(
|
|
||||||
new ResultDeserializer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void fromResult(JavaScriptObject responseObject) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new AsyncCallback<Void>() {
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable caught) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Void result) {
|
|
||||||
display(token);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cb.install();
|
|
||||||
ScriptInjector.fromString(cb.getFunctionName() + "();")
|
|
||||||
.setWindow(ScriptInjector.TOP_WINDOW)
|
|
||||||
.inject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void refreshMenuBar() {
|
public static void refreshMenuBar() {
|
||||||
menuLeft.clear();
|
menuLeft.clear();
|
||||||
menuRight.clear();
|
menuRight.clear();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public interface GerritConstants extends Constants {
|
|||||||
String menuSignIn();
|
String menuSignIn();
|
||||||
String menuRegister();
|
String menuRegister();
|
||||||
String reportBug();
|
String reportBug();
|
||||||
|
String loadingPlugins();
|
||||||
|
|
||||||
String signInDialogTitle();
|
String signInDialogTitle();
|
||||||
String signInDialogClose();
|
String signInDialogClose();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
menuSignIn = Sign In
|
menuSignIn = Sign In
|
||||||
menuRegister = Register
|
menuRegister = Register
|
||||||
reportBug = Report Bug
|
reportBug = Report Bug
|
||||||
|
loadingPlugins = Loading plugins ...
|
||||||
|
|
||||||
signInDialogTitle = Code Review - Sign In
|
signInDialogTitle = Code Review - Sign In
|
||||||
signInDialogClose = Close
|
signInDialogClose = Close
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ public interface GerritCss extends CssResource {
|
|||||||
String errorDialogGlass();
|
String errorDialogGlass();
|
||||||
String errorDialogText();
|
String errorDialogText();
|
||||||
String errorDialogTitle();
|
String errorDialogTitle();
|
||||||
|
String loadingPluginsDialog();
|
||||||
String fileColumnHeader();
|
String fileColumnHeader();
|
||||||
String fileCommentBorder();
|
String fileCommentBorder();
|
||||||
String fileLine();
|
String fileLine();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ branchCreationNotAllowedUnderRefnamePrefix = Branch creation is not allowed unde
|
|||||||
branchAlreadyExists = A branch with the name {0} already exists.
|
branchAlreadyExists = A branch with the name {0} already exists.
|
||||||
branchCreationConflict = Cannot create branch {0} since it conflicts with branch {1}.
|
branchCreationConflict = Cannot create branch {0} since it conflicts with branch {1}.
|
||||||
|
|
||||||
pluginFailed = Plugin JavaScript {0} failed to load
|
pluginFailed = Plugin "{0}" failed to load
|
||||||
cannotDownloadPlugin = Cannot download JavaScript plugin from: {0}.
|
cannotDownloadPlugin = Cannot load plugin from {0}
|
||||||
|
|
||||||
parentUpdateFailed = Setting parent project failed: {0}
|
parentUpdateFailed = Setting parent project failed: {0}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
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;
|
||||||
@@ -24,29 +26,36 @@ public class ApiGlue {
|
|||||||
private static String pluginName;
|
private static String pluginName;
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
init0();
|
init0(GWT.getHostPageBaseURL(), NativeString.TYPE);
|
||||||
ActionContext.init();
|
ActionContext.init();
|
||||||
|
Plugin.init();
|
||||||
addHistoryHook();
|
addHistoryHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void init0() /*-{
|
private static native void init0(String serverUrl, JavaScriptObject JsonString) /*-{
|
||||||
var serverUrl = @com.google.gwt.core.client.GWT::getHostPageBaseURL()();
|
$wnd.Gerrit = {
|
||||||
var Plugin = function (name){this.name = name};
|
JsonString: JsonString,
|
||||||
var Gerrit = {
|
events: {},
|
||||||
|
plugins: {},
|
||||||
|
change_actions: {},
|
||||||
|
revision_actions: {},
|
||||||
|
project_actions: {},
|
||||||
|
|
||||||
getPluginName: @com.google.gerrit.client.api.ApiGlue::getPluginName(),
|
getPluginName: @com.google.gerrit.client.api.ApiGlue::getPluginName(),
|
||||||
install: function (f) {
|
install: function (f) {
|
||||||
var p = new Plugin(this.getPluginName());
|
var p = this._getPluginByUrl(@com.google.gerrit.client.api.PluginName::getCallerUrl()());
|
||||||
@com.google.gerrit.client.api.ApiGlue::install(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gerrit/client/api/JsUiPlugin;)(f,p);
|
@com.google.gerrit.client.api.ApiGlue::install(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gerrit/client/api/Plugin;)(f,p);
|
||||||
|
},
|
||||||
|
installGwt: function(u){return this._getPluginByUrl(u)},
|
||||||
|
_getPluginByUrl: function(u) {
|
||||||
|
return u.indexOf(serverUrl) == 0
|
||||||
|
? this.plugins[u.substring(serverUrl.length)]
|
||||||
|
: this.plugins[u]
|
||||||
},
|
},
|
||||||
|
|
||||||
go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
|
go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
|
||||||
refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
|
refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
|
||||||
|
|
||||||
events: {},
|
|
||||||
change_actions: {},
|
|
||||||
revision_actions: {},
|
|
||||||
project_actions: {},
|
|
||||||
|
|
||||||
on: function (e,f){(this.events[e] || (this.events[e]=[])).push(f)},
|
on: function (e,f){(this.events[e] || (this.events[e]=[])).push(f)},
|
||||||
onAction: function (t,n,c){this._onAction(this.getPluginName(),t,n,c)},
|
onAction: function (t,n,c){this._onAction(this.getPluginName(),t,n,c)},
|
||||||
_onAction: function (p,t,n,c) {
|
_onAction: function (p,t,n,c) {
|
||||||
@@ -81,34 +90,7 @@ public class ApiGlue {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
||||||
JsonString: @com.google.gerrit.client.rpc.NativeString::TYPE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Plugin.prototype = {
|
|
||||||
getPluginName: function(){return this.name},
|
|
||||||
go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
|
|
||||||
refresh: Gerrit.refresh,
|
|
||||||
onAction: function(t,n,c) {Gerrit._onAction(this.name,t,n,c)},
|
|
||||||
|
|
||||||
url: function (d) {
|
|
||||||
var u = serverUrl + 'plugins/' + this.name + '/';
|
|
||||||
if (d && d.length > 0) u += d.charAt(0)=='/' ? d.substring(1) : d;
|
|
||||||
return u;
|
|
||||||
},
|
|
||||||
|
|
||||||
_api: function(d) {
|
|
||||||
var u = 'plugins/' + this.name + '/';
|
|
||||||
if (d && d.length > 0) u += d.charAt(0)=='/' ? d.substring(1) : d;
|
|
||||||
return @com.google.gerrit.client.rpc.RestApi::new(Ljava/lang/String;)(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)},
|
|
||||||
post: function(u,i,b){@com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
|
|
||||||
put: function(u,i,b){@com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
|
|
||||||
'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
|
||||||
};
|
|
||||||
|
|
||||||
$wnd.Gerrit = Gerrit;
|
|
||||||
}-*/;
|
}-*/;
|
||||||
|
|
||||||
/** Install deprecated {@code gerrit_addHistoryHook()} function. */
|
/** Install deprecated {@code gerrit_addHistoryHook()} function. */
|
||||||
@@ -119,17 +101,25 @@ public class ApiGlue {
|
|||||||
};
|
};
|
||||||
}-*/;
|
}-*/;
|
||||||
|
|
||||||
private static void install(JavaScriptObject cb, JsUiPlugin p) {
|
private static void install(JavaScriptObject cb, Plugin p) throws Exception {
|
||||||
try {
|
try {
|
||||||
pluginName = p.name();
|
pluginName = p.name();
|
||||||
invoke(cb, p);
|
invoke(cb, p);
|
||||||
|
p._initialized();
|
||||||
|
} catch (Exception e) {
|
||||||
|
p.failure(e);
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
pluginName = null;
|
pluginName = null;
|
||||||
|
PluginLoader.loaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String getPluginName() {
|
private static final String getPluginName() {
|
||||||
return pluginName != null ? pluginName : PluginName.get();
|
if (pluginName != null) {
|
||||||
|
return pluginName;
|
||||||
|
}
|
||||||
|
return PluginName.fromUrl(PluginName.getCallerUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final void go(String urlOrToken) {
|
private static final void go(String urlOrToken) {
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// 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.gwt.core.client.JavaScriptObject;
|
|
||||||
|
|
||||||
class JsUiPlugin extends JavaScriptObject {
|
|
||||||
final native String name() /*-{ return this.name }-*/;
|
|
||||||
|
|
||||||
protected JsUiPlugin() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// 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.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
|
final class Plugin extends JavaScriptObject {
|
||||||
|
private static final JavaScriptObject TYPE = createType();
|
||||||
|
|
||||||
|
static Plugin create(String url) {
|
||||||
|
int s = "plugins/".length();
|
||||||
|
int e = url.indexOf('/', s);
|
||||||
|
String name = url.substring(s, e);
|
||||||
|
return create(TYPE, url, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
final native String url() /*-{ return this._scriptUrl }-*/;
|
||||||
|
final native String name() /*-{ return this.name }-*/;
|
||||||
|
|
||||||
|
final native boolean loaded() /*-{ return this._success || this._failure != null }-*/;
|
||||||
|
final native Exception failure() /*-{ return this._failure }-*/;
|
||||||
|
final native void failure(Exception e) /*-{ this._failure = e }-*/;
|
||||||
|
final native boolean success() /*-{ return this._success || false }-*/;
|
||||||
|
final native void _initialized() /*-{ this._success = true }-*/;
|
||||||
|
|
||||||
|
private static native Plugin create(JavaScriptObject T, String u, String n)
|
||||||
|
/*-{ return new T(u,n) }-*/;
|
||||||
|
|
||||||
|
private static native JavaScriptObject createType() /*-{
|
||||||
|
function Plugin(u, n) {
|
||||||
|
this._scriptUrl = u;
|
||||||
|
this.name = n;
|
||||||
|
}
|
||||||
|
return Plugin;
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
static native void init() /*-{
|
||||||
|
var G = $wnd.Gerrit;
|
||||||
|
@com.google.gerrit.client.api.Plugin::TYPE.prototype = {
|
||||||
|
getPluginName: function(){return this.name},
|
||||||
|
go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
|
||||||
|
refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
|
||||||
|
on: G.on,
|
||||||
|
onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
|
||||||
|
|
||||||
|
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)},
|
||||||
|
post: function(u,i,b){@com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
|
||||||
|
put: function(u,i,b){@com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
|
||||||
|
'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
|
||||||
|
|
||||||
|
_loadedGwt: function(){@com.google.gerrit.client.api.PluginLoader::loaded()()},
|
||||||
|
_api: function(u){return @com.google.gerrit.client.rpc.RestApi::new(Ljava/lang/String;)(this._url(u))},
|
||||||
|
_url: function (d) {
|
||||||
|
var u = 'plugins/' + this.name + '/';
|
||||||
|
if (d && d.length > 0)
|
||||||
|
return u + (d.charAt(0)=='/' ? d.substring(1) : d);
|
||||||
|
return u;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
protected Plugin() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
// 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.ErrorDialog;
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gwt.core.client.Callback;
|
||||||
|
import com.google.gwt.core.client.CodeDownloadException;
|
||||||
|
import com.google.gwt.core.client.ScriptInjector;
|
||||||
|
import com.google.gwt.user.client.Timer;
|
||||||
|
import com.google.gwt.user.client.Window;
|
||||||
|
import com.google.gwt.user.client.ui.DialogBox;
|
||||||
|
import com.google.gwtexpui.progress.client.ProgressBar;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Loads JavaScript plugins with a progress meter visible. */
|
||||||
|
public class PluginLoader extends DialogBox {
|
||||||
|
private static final int MAX_LOAD_TIME_MILLIS = 5000;
|
||||||
|
private static PluginLoader self;
|
||||||
|
|
||||||
|
public static void load(List<String> plugins, final String token) {
|
||||||
|
if (plugins == null || plugins.isEmpty()) {
|
||||||
|
Gerrit.display(token);
|
||||||
|
} else {
|
||||||
|
self = new PluginLoader(token);
|
||||||
|
self.load(plugins);
|
||||||
|
self.startTimers();
|
||||||
|
self.center();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loaded() {
|
||||||
|
self.loadedOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String token;
|
||||||
|
private ProgressBar progress;
|
||||||
|
private Timer show;
|
||||||
|
private Timer update;
|
||||||
|
private Timer timeout;
|
||||||
|
private boolean visible;
|
||||||
|
|
||||||
|
private PluginLoader(String tokenToDisplay) {
|
||||||
|
super(/* auto hide */false, /* modal */true);
|
||||||
|
token = tokenToDisplay;
|
||||||
|
progress = new ProgressBar(Gerrit.C.loadingPlugins());
|
||||||
|
|
||||||
|
setStyleName(Gerrit.RESOURCES.css().errorDialog());
|
||||||
|
addStyleName(Gerrit.RESOURCES.css().loadingPluginsDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(List<String> pluginUrls) {
|
||||||
|
for (String url : pluginUrls) {
|
||||||
|
Plugin plugin = Plugin.create(url);
|
||||||
|
plugins().put(url, plugin);
|
||||||
|
ScriptInjector.fromUrl(url)
|
||||||
|
.setWindow(ScriptInjector.TOP_WINDOW)
|
||||||
|
.setCallback(new LoadCallback(plugin))
|
||||||
|
.inject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTimers() {
|
||||||
|
show = new Timer() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
setText(Window.getTitle());
|
||||||
|
setWidget(progress);
|
||||||
|
setGlassEnabled(true);
|
||||||
|
getGlassElement().addClassName(Gerrit.RESOURCES.css().errorDialogGlass());
|
||||||
|
hide(true);
|
||||||
|
center();
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
show.schedule(500);
|
||||||
|
|
||||||
|
update = new Timer() {
|
||||||
|
private int cycle;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
progress.setValue(100 * ++cycle * 250 / MAX_LOAD_TIME_MILLIS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
update.scheduleRepeating(250);
|
||||||
|
|
||||||
|
timeout = new Timer() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timeout.schedule(MAX_LOAD_TIME_MILLIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadedOne() {
|
||||||
|
boolean done = true;
|
||||||
|
for (Plugin plugin : Natives.asList(plugins().values())) {
|
||||||
|
done &= plugin.loaded();
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finish() {
|
||||||
|
show.cancel();
|
||||||
|
update.cancel();
|
||||||
|
timeout.cancel();
|
||||||
|
self = null;
|
||||||
|
|
||||||
|
if (!hadFailures()) {
|
||||||
|
if (visible) {
|
||||||
|
progress.setValue(100);
|
||||||
|
new Timer() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
hide(true);
|
||||||
|
}
|
||||||
|
}.schedule(250);
|
||||||
|
} else {
|
||||||
|
hide(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gerrit.display(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hadFailures() {
|
||||||
|
boolean failed = false;
|
||||||
|
for (Plugin plugin : Natives.asList(plugins().values())) {
|
||||||
|
if (!plugin.success()) {
|
||||||
|
failed = true;
|
||||||
|
|
||||||
|
Exception e = plugin.failure();
|
||||||
|
String msg;
|
||||||
|
if (e != null && e instanceof CodeDownloadException) {
|
||||||
|
msg = Gerrit.M.cannotDownloadPlugin(plugin.url());
|
||||||
|
} else {
|
||||||
|
msg = Gerrit.M.pluginFailed(plugin.name());
|
||||||
|
}
|
||||||
|
hide(true);
|
||||||
|
new ErrorDialog(msg).center();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native NativeMap<Plugin> plugins()
|
||||||
|
/*-{ return $wnd.Gerrit.plugins }-*/;
|
||||||
|
|
||||||
|
private class LoadCallback implements Callback<Void, Exception> {
|
||||||
|
private final Plugin plugin;
|
||||||
|
|
||||||
|
LoadCallback(Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Void result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception reason) {
|
||||||
|
plugin.failure(reason);
|
||||||
|
loadedOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,14 +31,29 @@ import com.google.gwt.core.client.impl.StackTraceCreator;
|
|||||||
class PluginName {
|
class PluginName {
|
||||||
private static final String UNKNOWN = "<unknown>";
|
private static final String UNKNOWN = "<unknown>";
|
||||||
|
|
||||||
static String get() {
|
private static String baseUrl() {
|
||||||
return GWT.<PluginName> create(PluginName.class).guessName();
|
return GWT.getHostPageBaseURL() + "plugins/";
|
||||||
}
|
}
|
||||||
|
|
||||||
String guessName() {
|
static String getCallerUrl() {
|
||||||
|
return GWT.<PluginName> create(PluginName.class).findCallerUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String fromUrl(String url) {
|
||||||
|
String baseUrl = baseUrl();
|
||||||
|
if (url != null && url.startsWith(baseUrl)) {
|
||||||
|
int s = url.indexOf('/', baseUrl.length());
|
||||||
|
if (s > 0) {
|
||||||
|
return url.substring(baseUrl.length(), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
String findCallerUrl() {
|
||||||
JavaScriptException err = makeException();
|
JavaScriptException err = makeException();
|
||||||
if (hasStack(err)) {
|
if (hasStack(err)) {
|
||||||
return PluginNameMoz.guessName(err);
|
return PluginNameMoz.getUrl(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
String baseUrl = baseUrl();
|
String baseUrl = baseUrl();
|
||||||
@@ -46,19 +61,12 @@ class PluginName {
|
|||||||
for (int i = trace.length - 1; i >= 0; i--) {
|
for (int i = trace.length - 1; i >= 0; i--) {
|
||||||
String u = trace[i].getFileName();
|
String u = trace[i].getFileName();
|
||||||
if (u != null && u.startsWith(baseUrl)) {
|
if (u != null && u.startsWith(baseUrl)) {
|
||||||
int s = u.indexOf('/', baseUrl.length());
|
return u;
|
||||||
if (s > 0) {
|
|
||||||
return u.substring(baseUrl.length(), s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String baseUrl() {
|
|
||||||
return GWT.getHostPageBaseURL() + "plugins/";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StackTraceElement[] getTrace(JavaScriptException err) {
|
private static StackTraceElement[] getTrace(JavaScriptException err) {
|
||||||
StackTraceCreator.fillInStackTrace(err);
|
StackTraceCreator.fillInStackTrace(err);
|
||||||
return err.getStackTrace();
|
return err.getStackTrace();
|
||||||
@@ -72,21 +80,22 @@ class PluginName {
|
|||||||
|
|
||||||
/** Extracts URL from the stack frame. */
|
/** Extracts URL from the stack frame. */
|
||||||
static class PluginNameMoz extends PluginName {
|
static class PluginNameMoz extends PluginName {
|
||||||
String guessName() {
|
String findCallerUrl() {
|
||||||
return guessName(makeException());
|
return getUrl(makeException());
|
||||||
}
|
}
|
||||||
|
|
||||||
static String guessName(JavaScriptException e) {
|
private static String getUrl(JavaScriptException e) {
|
||||||
String baseUrl = baseUrl();
|
String baseUrl = baseUrl();
|
||||||
JsArrayString stack = getStack(e);
|
JsArrayString stack = getStack(e);
|
||||||
for (int i = stack.length() - 1; i >= 0; i--) {
|
for (int i = stack.length() - 1; i >= 0; i--) {
|
||||||
String frame = stack.get(i);
|
String frame = stack.get(i);
|
||||||
int at = frame.indexOf(baseUrl);
|
int at = frame.indexOf(baseUrl);
|
||||||
if (at >= 0) {
|
if (at >= 0) {
|
||||||
int s = frame.indexOf('/', at + baseUrl.length());
|
int end = frame.indexOf(':', at + baseUrl.length());
|
||||||
if (s > 0) {
|
if (end < 0) {
|
||||||
return frame.substring(at + baseUrl.length(), s);
|
end = frame.length();
|
||||||
}
|
}
|
||||||
|
return frame.substring(at, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
|
|||||||
@@ -431,6 +431,11 @@ a:hover {
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-family: verdana;
|
font-family: verdana;
|
||||||
}
|
}
|
||||||
|
.loadingPluginsDialog {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Screen **/
|
/** Screen **/
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
package ${package}.client;
|
package ${package}.client;
|
||||||
|
|
||||||
import com.google.gerrit.plugin.client.Plugin;
|
import com.google.gerrit.plugin.client.PluginEntryPoint;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
import com.google.gwt.event.dom.client.ClickHandler;
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
@@ -27,10 +27,10 @@ import ${package}.HelloMenu;
|
|||||||
/**
|
/**
|
||||||
* HelloWorld Plugin.
|
* HelloWorld Plugin.
|
||||||
*/
|
*/
|
||||||
public class HelloPlugin extends Plugin {
|
public class HelloPlugin extends PluginEntryPoint {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onModuleLoad() {
|
public void onPluginLoad() {
|
||||||
// Create the dialog box
|
// Create the dialog box
|
||||||
final DialogBox dialogBox = new DialogBox();
|
final DialogBox dialogBox = new DialogBox();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2012 The Android Open Source Project
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -14,21 +14,46 @@
|
|||||||
|
|
||||||
package com.google.gerrit.plugin.client;
|
package com.google.gerrit.plugin.client;
|
||||||
|
|
||||||
import com.google.gwt.core.client.EntryPoint;
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for writing Gerrit Web UI plugins
|
* Wrapper around the plugin instance exposed by Gerrit.
|
||||||
*
|
*
|
||||||
* Writing a plugin:
|
* Listeners for events generated by the main UI must be registered
|
||||||
* <ol>
|
* through this instance.
|
||||||
* <li>Declare subtype of Plugin</li>
|
|
||||||
* <li>Bind WebUiPlugin to GwtPlugin implementation in Gerrit-Module</li>
|
|
||||||
* </ol>
|
|
||||||
*/
|
*/
|
||||||
public abstract class Plugin implements EntryPoint {
|
public final class Plugin extends JavaScriptObject {
|
||||||
public native static void go(String t)
|
private static final Plugin self = install(
|
||||||
/*-{ $wnd.Gerrit.go(t) }-*/;
|
GWT.getModuleBaseURL() + GWT.getModuleName() + ".nocache.js");
|
||||||
|
|
||||||
public native static void refresh()
|
/** Obtain the plugin instance wrapper. */
|
||||||
/*-{ $wnd.Gerrit.refresh() }-*/;
|
public static Plugin get() {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Installed name of the plugin. */
|
||||||
|
public final String getName() {
|
||||||
|
return getPluginName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Installed name of the plugin. */
|
||||||
|
public final native String getPluginName()
|
||||||
|
/*-{ return this.getPluginName() }-*/;
|
||||||
|
|
||||||
|
/** Navigate the UI to the screen identified by the token. */
|
||||||
|
public final native void go(String token)
|
||||||
|
/*-{ return this.go(token) }-*/;
|
||||||
|
|
||||||
|
/** Refresh the current UI. */
|
||||||
|
public final native void refresh()
|
||||||
|
/*-{ return this.refresh() }-*/;
|
||||||
|
|
||||||
|
protected Plugin() {
|
||||||
|
}
|
||||||
|
|
||||||
|
native void _initialized() /*-{ this._success = true }-*/;
|
||||||
|
native void _loaded() /*-{ this._loadedGwt() }-*/;
|
||||||
|
private static native final Plugin install(String u)
|
||||||
|
/*-{ return $wnd.Gerrit.installGwt(u) }-*/;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (C) 2012 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;
|
||||||
|
|
||||||
|
import com.google.gwt.core.client.EntryPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for writing Gerrit Web UI plugins
|
||||||
|
*
|
||||||
|
* Writing a plugin:
|
||||||
|
* <ol>
|
||||||
|
* <li>Declare subtype of Plugin</li>
|
||||||
|
* <li>Bind WebUiPlugin to GwtPlugin implementation in Gerrit-Module</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
public abstract class PluginEntryPoint implements EntryPoint {
|
||||||
|
/**
|
||||||
|
* The plugin entry point method, called automatically by loading
|
||||||
|
* a module that declares an implementing class as an entry point.
|
||||||
|
*/
|
||||||
|
public abstract void onPluginLoad();
|
||||||
|
|
||||||
|
public final void onModuleLoad() {
|
||||||
|
Plugin self = Plugin.get();
|
||||||
|
try {
|
||||||
|
onPluginLoad();
|
||||||
|
self._initialized();
|
||||||
|
} finally {
|
||||||
|
self._loaded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Submodule plugins/cookbook-plugin updated: 701846c29e...9160d607f4
Reference in New Issue
Block a user