Render per-project themes on the client side
Always include the relevant <style>/<div> tags in the host page, even if they are empty. Have Gerrit store the sitewide values, and swap them in and out when loading project-specific screens. Change-Id: Iab6d2c91bf636ef361e2031dd39904e0c7e9bf41
This commit is contained in:
@@ -21,4 +21,13 @@
|
||||
<when-property-is name="user.agent" value="ie8"/>
|
||||
</any>
|
||||
</replace-with>
|
||||
|
||||
<replace-with class="com.google.gerrit.client.Themer.ThemerIE">
|
||||
<when-type-is class="com.google.gerrit.client.Themer" />
|
||||
<any>
|
||||
<when-property-is name="user.agent" value="ie6"/>
|
||||
<when-property-is name="user.agent" value="ie8"/>
|
||||
<when-property-is name="user.agent" value="ie9"/>
|
||||
</any>
|
||||
</replace-with>
|
||||
</module>
|
||||
|
@@ -95,6 +95,7 @@ public class Gerrit implements EntryPoint {
|
||||
GWT.create(GerritResources.class);
|
||||
public static final SystemInfoService SYSTEM_SVC;
|
||||
public static final EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);
|
||||
public static Themer THEMER = GWT.create(Themer.class);
|
||||
|
||||
private static String myHost;
|
||||
private static GerritConfig myConfig;
|
||||
@@ -552,9 +553,17 @@ public class Gerrit implements EntryPoint {
|
||||
if (signInAnchor != null) {
|
||||
signInAnchor.setHref(loginRedirect(token));
|
||||
}
|
||||
|
||||
saveDefaultTheme();
|
||||
loadPlugins(hpd, token);
|
||||
}
|
||||
|
||||
private void saveDefaultTheme() {
|
||||
THEMER.init(Document.get().getElementById("gerrit_sitecss"),
|
||||
Document.get().getElementById("gerrit_header"),
|
||||
Document.get().getElementById("gerrit_footer"));
|
||||
}
|
||||
|
||||
private void loadPlugins(HostPageData hpd, final String token) {
|
||||
if (hpd.plugins != null) {
|
||||
for (final String url : hpd.plugins) {
|
||||
|
@@ -0,0 +1,80 @@
|
||||
// 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.server.git;
|
||||
|
||||
package com.google.gerrit.client;
|
||||
|
||||
import com.google.gerrit.client.projects.ThemeInfo;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.StyleElement;
|
||||
|
||||
public class Themer {
|
||||
public static class ThemerIE extends Themer {
|
||||
protected ThemerIE() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCssText(StyleElement el) {
|
||||
return el.getCssText();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCssText(StyleElement el, String css) {
|
||||
el.setCssText(css);
|
||||
}
|
||||
}
|
||||
|
||||
protected StyleElement cssElement;
|
||||
protected Element headerElement;
|
||||
protected Element footerElement;
|
||||
protected String cssText;
|
||||
protected String headerHtml;
|
||||
protected String footerHtml;
|
||||
|
||||
protected Themer() {
|
||||
}
|
||||
|
||||
public void set(ThemeInfo theme) {
|
||||
set(theme.css() != null ? theme.css() : cssText,
|
||||
theme.header() != null ? theme.header() : headerHtml,
|
||||
theme.footer() != null ? theme.footer() : footerHtml);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
set(cssText, headerHtml, footerHtml);
|
||||
}
|
||||
|
||||
void init(Element css, Element header, Element footer) {
|
||||
cssElement = StyleElement.as(css);
|
||||
headerElement = header;
|
||||
footerElement = footer;
|
||||
|
||||
cssText = getCssText(this.cssElement);
|
||||
headerHtml = header.getInnerHTML();
|
||||
footerHtml = footer.getInnerHTML();
|
||||
}
|
||||
|
||||
protected String getCssText(StyleElement el) {
|
||||
return el.getInnerHTML();
|
||||
}
|
||||
|
||||
protected void setCssText(StyleElement el, String css) {
|
||||
el.setInnerHTML(css);
|
||||
}
|
||||
|
||||
private void set(String css, String header, String footer) {
|
||||
setCssText(cssElement, css);
|
||||
headerElement.setInnerHTML(header);
|
||||
footerElement.setInnerHTML(footer);
|
||||
}
|
||||
}
|
@@ -275,6 +275,7 @@ public class ChangeScreen extends Screen
|
||||
@Override
|
||||
public void onSuccess(ConfigInfoCache.Entry result) {
|
||||
commentLinkProcessor = result.getCommentLinkProcessor();
|
||||
setTheme(result.getTheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -185,6 +185,7 @@ public class PublishCommentScreen extends AccountScreen implements
|
||||
@Override
|
||||
public void onSuccess(ConfigInfoCache.Entry result) {
|
||||
commentLinkProcessor = result.getCommentLinkProcessor();
|
||||
setTheme(result.getTheme());
|
||||
display(pubDetail);
|
||||
}
|
||||
|
||||
|
@@ -371,44 +371,39 @@ public abstract class PatchScreen extends Screen implements
|
||||
fileList.movePointerTo(patchKey);
|
||||
}
|
||||
|
||||
com.google.gwtjsonrpc.common.AsyncCallback<PatchScript> pscb =
|
||||
new ScreenLoadCallback<PatchScript>(this) {
|
||||
CallbackGroup cb = new CallbackGroup();
|
||||
ConfigInfoCache.get(patchSetDetail.getProject(),
|
||||
cb.add(new AsyncCallback<ConfigInfoCache.Entry>() {
|
||||
@Override
|
||||
protected void preDisplay(final PatchScript result) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
onResult(result, isFirst);
|
||||
}
|
||||
public void onSuccess(ConfigInfoCache.Entry result) {
|
||||
commentLinkProcessor = result.getCommentLinkProcessor();
|
||||
contentTable.setCommentLinkProcessor(commentLinkProcessor);
|
||||
setTheme(result.getTheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
settingsPanel.setEnabled(true);
|
||||
super.onFailure(caught);
|
||||
}
|
||||
public void onFailure(Throwable caught) {
|
||||
// Handled by ScreenLoadCallback.onFailure.
|
||||
}
|
||||
};
|
||||
if (commentLinkProcessor == null) {
|
||||
// Fetch config in parallel if we haven't previously.
|
||||
CallbackGroup cb = new CallbackGroup();
|
||||
ConfigInfoCache.get(patchSetDetail.getProject(),
|
||||
cb.add(new AsyncCallback<ConfigInfoCache.Entry>() {
|
||||
@Override
|
||||
public void onSuccess(ConfigInfoCache.Entry result) {
|
||||
commentLinkProcessor = result.getCommentLinkProcessor();
|
||||
contentTable.setCommentLinkProcessor(commentLinkProcessor);
|
||||
}
|
||||
}));
|
||||
PatchUtil.DETAIL_SVC.patchScript(patchKey, idSideA, idSideB,
|
||||
settingsPanel.getValue(), cb.addGwtjsonrpc(
|
||||
new ScreenLoadCallback<PatchScript>(this) {
|
||||
@Override
|
||||
protected void preDisplay(final PatchScript result) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
onResult(result, isFirst);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
// Handled by ScreenLoadCallback.onFailure.
|
||||
}
|
||||
}));
|
||||
pscb = cb.addGwtjsonrpc(pscb);
|
||||
}
|
||||
|
||||
PatchUtil.DETAIL_SVC.patchScript(patchKey, idSideA, idSideB, //
|
||||
settingsPanel.getValue(), pscb);
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
settingsPanel.setEnabled(true);
|
||||
super.onFailure(caught);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void onResult(final PatchScript script, final boolean isFirst) {
|
||||
|
@@ -64,6 +64,8 @@ public class ConfigInfo extends JavaScriptObject {
|
||||
return commentLinks;
|
||||
}
|
||||
|
||||
final native ThemeInfo theme() /*-{ return this.theme; }-*/;
|
||||
|
||||
protected ConfigInfo() {
|
||||
}
|
||||
|
||||
|
@@ -42,6 +42,10 @@ public class ConfigInfoCache {
|
||||
}
|
||||
return commentLinkProcessor;
|
||||
}
|
||||
|
||||
public ThemeInfo getTheme() {
|
||||
return info.theme();
|
||||
}
|
||||
}
|
||||
|
||||
public static void get(Project.NameKey name, AsyncCallback<Entry> cb) {
|
||||
|
@@ -0,0 +1,26 @@
|
||||
// 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.server.git;
|
||||
|
||||
package com.google.gerrit.client.projects;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
|
||||
public class ThemeInfo extends JavaScriptObject {
|
||||
public final native String css() /*-{ return this.css; }-*/;
|
||||
public final native String header() /*-{ return this.header; }-*/;
|
||||
public final native String footer() /*-{ return this.footer; }-*/;
|
||||
|
||||
protected ThemeInfo() {
|
||||
}
|
||||
}
|
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.client.ui;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.projects.ThemeInfo;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
|
||||
@@ -41,6 +42,9 @@ public abstract class Screen extends View {
|
||||
private String windowTitle;
|
||||
private Widget titleWidget;
|
||||
|
||||
private ThemeInfo theme;
|
||||
private boolean setTheme;
|
||||
|
||||
protected Screen() {
|
||||
initWidget(new FlowPanel());
|
||||
setStyleName(Gerrit.RESOURCES.css().screen());
|
||||
@@ -54,6 +58,14 @@ public abstract class Screen extends View {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnload() {
|
||||
super.onUnload();
|
||||
if (setTheme) {
|
||||
Gerrit.THEMER.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerKeys() {
|
||||
}
|
||||
|
||||
@@ -124,6 +136,10 @@ public abstract class Screen extends View {
|
||||
body.add(w);
|
||||
}
|
||||
|
||||
protected void setTheme(final ThemeInfo t) {
|
||||
theme = t;
|
||||
}
|
||||
|
||||
/** Get the history token for this screen. */
|
||||
public String getToken() {
|
||||
return token;
|
||||
@@ -167,5 +183,12 @@ public abstract class Screen extends View {
|
||||
Gerrit.EVENT_BUS.fireEvent(new ScreenLoadEvent(this));
|
||||
Gerrit.setQueryString(null);
|
||||
registerKeys();
|
||||
|
||||
if (theme != null) {
|
||||
Gerrit.THEMER.set(theme);
|
||||
setTheme = true;
|
||||
} else {
|
||||
Gerrit.THEMER.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -352,11 +352,9 @@ public class HostPageServlet extends HttpServlet {
|
||||
|
||||
String css = HtmlDomUtil.readFile(src.getParentFile(), src.getName());
|
||||
if (css == null) {
|
||||
banner.getParentNode().removeChild(banner);
|
||||
return info;
|
||||
}
|
||||
|
||||
banner.removeAttribute("id");
|
||||
banner.appendChild(hostDoc.createCDATASection("\n" + css + "\n"));
|
||||
return info;
|
||||
}
|
||||
@@ -375,7 +373,6 @@ public class HostPageServlet extends HttpServlet {
|
||||
|
||||
Document html = HtmlDomUtil.parseFile(src);
|
||||
if (html == null) {
|
||||
banner.getParentNode().removeChild(banner);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@
|
||||
})();
|
||||
</script>
|
||||
<script id="gerrit_hostpagedata"></script>
|
||||
<style id="gerrit_sitecss" type="text/css"></style>
|
||||
<style id="gerrit_sitecss" type="text/css"></style>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
|
Reference in New Issue
Block a user