Dynamically load CodeMirror themes
Most users run with the default theme, which does not require any additional CSS. The total set of themes costs 7.3 KiB of download when added into the default CSS file. Split the themes into their own files and only load the theme when it is required by the browser. Change-Id: I48f274347e1ca94895c0756fa17479661c78fd57
This commit is contained in:
parent
3a52cede92
commit
a2346d1f0a
@ -20,6 +20,7 @@ public enum Theme {
|
||||
ECLIPSE,
|
||||
ELEGANT,
|
||||
NEAT,
|
||||
|
||||
// Dark themes
|
||||
MIDNIGHT,
|
||||
NIGHT,
|
||||
|
@ -56,6 +56,7 @@ import com.google.gwt.user.client.ui.ToggleButton;
|
||||
|
||||
import net.codemirror.mode.ModeInfo;
|
||||
import net.codemirror.mode.ModeInjector;
|
||||
import net.codemirror.theme.ThemeLoader;
|
||||
|
||||
/** Displays current diff preferences. */
|
||||
class PreferencesBox extends Composite {
|
||||
@ -386,18 +387,30 @@ class PreferencesBox extends Composite {
|
||||
|
||||
@UiHandler("theme")
|
||||
void onTheme(@SuppressWarnings("unused") ChangeEvent e) {
|
||||
prefs.theme(Theme.valueOf(theme.getValue(theme.getSelectedIndex())));
|
||||
view.setThemeStyles(prefs.theme().isDark());
|
||||
view.operation(new Runnable() {
|
||||
final Theme newTheme = getSelectedTheme();
|
||||
prefs.theme(newTheme);
|
||||
ThemeLoader.loadTheme(newTheme, new GerritCallback<Void>() {
|
||||
@Override
|
||||
public void run() {
|
||||
String t = prefs.theme().name().toLowerCase();
|
||||
view.getCmFromSide(DisplaySide.A).setOption("theme", t);
|
||||
view.getCmFromSide(DisplaySide.B).setOption("theme", t);
|
||||
public void onSuccess(Void result) {
|
||||
view.operation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (getSelectedTheme() == newTheme && isAttached()) {
|
||||
String t = newTheme.name().toLowerCase();
|
||||
view.getCmFromSide(DisplaySide.A).setOption("theme", t);
|
||||
view.getCmFromSide(DisplaySide.B).setOption("theme", t);
|
||||
view.setThemeStyles(newTheme.isDark());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Theme getSelectedTheme() {
|
||||
return Theme.valueOf(theme.getValue(theme.getSelectedIndex()));
|
||||
}
|
||||
|
||||
@UiHandler("apply")
|
||||
void onApply(@SuppressWarnings("unused") ClickEvent e) {
|
||||
close();
|
||||
@ -493,26 +506,8 @@ class PreferencesBox extends Composite {
|
||||
}
|
||||
|
||||
private void initTheme() {
|
||||
theme.addItem(
|
||||
Theme.DEFAULT.name().toLowerCase(),
|
||||
Theme.DEFAULT.name());
|
||||
theme.addItem(
|
||||
Theme.ECLIPSE.name().toLowerCase(),
|
||||
Theme.ECLIPSE.name());
|
||||
theme.addItem(
|
||||
Theme.ELEGANT.name().toLowerCase(),
|
||||
Theme.ELEGANT.name());
|
||||
theme.addItem(
|
||||
Theme.NEAT.name().toLowerCase(),
|
||||
Theme.NEAT.name());
|
||||
theme.addItem(
|
||||
Theme.MIDNIGHT.name().toLowerCase(),
|
||||
Theme.MIDNIGHT.name());
|
||||
theme.addItem(
|
||||
Theme.NIGHT.name().toLowerCase(),
|
||||
Theme.NIGHT.name());
|
||||
theme.addItem(
|
||||
Theme.TWILIGHT.name().toLowerCase(),
|
||||
Theme.TWILIGHT.name());
|
||||
for (Theme t : Theme.values()) {
|
||||
theme.addItem(t.name().toLowerCase(), t.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ import net.codemirror.lib.KeyMap;
|
||||
import net.codemirror.lib.Pos;
|
||||
import net.codemirror.mode.ModeInfo;
|
||||
import net.codemirror.mode.ModeInjector;
|
||||
import net.codemirror.theme.ThemeLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -175,7 +176,10 @@ public class SideBySide2 extends Screen {
|
||||
|
||||
CallbackGroup cmGroup = new CallbackGroup();
|
||||
CodeMirror.initLibrary(cmGroup.add(CallbackGroup.<Void> emptyCallback()));
|
||||
|
||||
final CallbackGroup group = new CallbackGroup();
|
||||
final AsyncCallback<Void> themeCallback =
|
||||
group.add(CallbackGroup.<Void> emptyCallback());
|
||||
final AsyncCallback<Void> modeInjectorCb =
|
||||
group.add(CallbackGroup.<Void> emptyCallback());
|
||||
|
||||
@ -189,6 +193,9 @@ public class SideBySide2 extends Screen {
|
||||
public void onSuccess(DiffInfo diffInfo) {
|
||||
diff = diffInfo;
|
||||
fileSize = bucketFileSize(diffInfo);
|
||||
|
||||
// Load theme after CM library to ensure theme can override CSS.
|
||||
ThemeLoader.loadTheme(prefs.theme(), themeCallback);
|
||||
if (prefs.syntaxHighlighting()) {
|
||||
if (fileSize.compareTo(FileSize.SMALL) > 0) {
|
||||
modeInjectorCb.onSuccess(null);
|
||||
|
@ -20,4 +20,5 @@
|
||||
<source path='lib'/>
|
||||
<source path='keymap'/>
|
||||
<source path='mode'/>
|
||||
<source path='theme'/>
|
||||
</module>
|
||||
|
83
gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java
vendored
Normal file
83
gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (C) 2014 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 net.codemirror.theme;
|
||||
|
||||
import com.google.gerrit.extensions.common.Theme;
|
||||
import com.google.gwt.dom.client.StyleInjector;
|
||||
import com.google.gwt.resources.client.ExternalTextResource;
|
||||
import com.google.gwt.resources.client.ResourceCallback;
|
||||
import com.google.gwt.resources.client.ResourceException;
|
||||
import com.google.gwt.resources.client.TextResource;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/** Dynamically loads a known CodeMirror theme's CSS */
|
||||
public class ThemeLoader {
|
||||
private static final ExternalTextResource[] THEMES = {
|
||||
Themes.I.eclipse(),
|
||||
Themes.I.elegant(),
|
||||
Themes.I.midnight(),
|
||||
Themes.I.neat(),
|
||||
Themes.I.night(),
|
||||
Themes.I.twilight(),
|
||||
};
|
||||
|
||||
private static final EnumSet<Theme> loaded = EnumSet.of(Theme.DEFAULT);
|
||||
|
||||
public static final void loadTheme(final Theme theme,
|
||||
final AsyncCallback<Void> cb) {
|
||||
if (loaded.contains(theme)) {
|
||||
cb.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ExternalTextResource resource = findTheme(theme);
|
||||
if (resource == null) {
|
||||
cb.onFailure(new Exception("unknown theme " + theme));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
resource.getText(new ResourceCallback<TextResource>() {
|
||||
@Override
|
||||
public void onSuccess(TextResource resource) {
|
||||
StyleInjector.inject(resource.getText());
|
||||
loaded.add(theme);
|
||||
cb.onSuccess(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ResourceException e) {
|
||||
cb.onFailure(e);
|
||||
}
|
||||
});
|
||||
} catch (ResourceException e) {
|
||||
cb.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final ExternalTextResource findTheme(Theme theme) {
|
||||
for (ExternalTextResource r : THEMES) {
|
||||
if (theme.name().toLowerCase().equals(r.getName())) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ThemeLoader() {
|
||||
}
|
||||
}
|
34
gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
vendored
Normal file
34
gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2014 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 net.codemirror.theme;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.ExternalTextResource;
|
||||
|
||||
public interface Themes extends ClientBundle {
|
||||
public static final Themes I = GWT.create(Themes.class);
|
||||
|
||||
@Source("eclipse.css") ExternalTextResource eclipse();
|
||||
@Source("elegant.css") ExternalTextResource elegant();
|
||||
@Source("midnight.css") ExternalTextResource midnight();
|
||||
@Source("neat.css") ExternalTextResource neat();
|
||||
@Source("night.css") ExternalTextResource night();
|
||||
@Source("twilight.css") ExternalTextResource twilight();
|
||||
|
||||
// When adding a resource, update:
|
||||
// - static initializer in ThemeLoader
|
||||
// - enum value in com.google.gerrit.extensions.common.Theme
|
||||
}
|
@ -19,18 +19,29 @@ CLOSURE_COMPILER_ARGS = [
|
||||
genrule(
|
||||
name = 'css',
|
||||
cmd = ';'.join([
|
||||
':>$OUT',
|
||||
"echo '/** @license' >>$OUT",
|
||||
"echo '/** @license' >$OUT",
|
||||
'unzip -p $(location :zip) %s/LICENSE >>$OUT' % TOP,
|
||||
"echo '*/' >>$OUT",
|
||||
] +
|
||||
['unzip -p $(location :zip) %s/%s >>$OUT' % (TOP, n)
|
||||
for n in CM_CSS + CM_THEMES]
|
||||
for n in CM_CSS]
|
||||
),
|
||||
deps = [':zip'],
|
||||
out = 'cm.css',
|
||||
)
|
||||
|
||||
for n in CM_THEMES:
|
||||
genrule(
|
||||
name = 'theme_%s' % n,
|
||||
cmd = ';'.join([
|
||||
"echo '/** @license' >$OUT",
|
||||
'unzip -p $(location :zip) %s/LICENSE >>$OUT' % TOP,
|
||||
"echo '*/' >>$OUT",
|
||||
'unzip -p $(location :zip) %s/theme/%s.css >>$OUT' % (TOP, n)
|
||||
]
|
||||
),
|
||||
out = 'theme_%s.css' % n,
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = 'cm-verbose',
|
||||
cmd = ';'.join([
|
||||
@ -42,7 +53,6 @@ genrule(
|
||||
['unzip -p $(location :zip) %s/addon/%s >>$OUT' % (TOP, n)
|
||||
for n in CM_ADDONS]
|
||||
),
|
||||
deps = [':zip'],
|
||||
out = 'cm-verbose.js',
|
||||
)
|
||||
|
||||
@ -62,7 +72,6 @@ for n in CM_MODES:
|
||||
"echo '*/' >>$OUT",
|
||||
'unzip -p $(location :zip) %s/mode/%s/%s.js >>$OUT' % (TOP, n, n),
|
||||
]),
|
||||
deps = [':zip'],
|
||||
out = 'mode_%s_src.js' %n,
|
||||
)
|
||||
js_minify(
|
||||
@ -86,18 +95,14 @@ genrule(
|
||||
name = 'jar',
|
||||
cmd = ';'.join([
|
||||
'cd $TMP',
|
||||
'mkdir -p net/codemirror/{lib,mode}',
|
||||
'mkdir -p net/codemirror/{lib,mode,theme}',
|
||||
'cp $(location :css) net/codemirror/lib',
|
||||
'cp $(location :js) net/codemirror/lib']
|
||||
+ ['cp $(location :mode_%s_js) net/codemirror/mode/%s.js' % (n, n)
|
||||
for n in CM_MODES]
|
||||
+ ['zip -qr $OUT net/codemirror/{lib,mode}']),
|
||||
deps = [
|
||||
':css',
|
||||
':js',
|
||||
':js_minifier',
|
||||
':zip',
|
||||
] + [':mode_%s_js' % n for n in CM_MODES],
|
||||
+ ['cp $(location :theme_%s) net/codemirror/theme/%s.css' % (n, n)
|
||||
for n in CM_THEMES]
|
||||
+ ['zip -qr $OUT net/codemirror/{lib,mode,theme}']),
|
||||
out = 'codemirror.jar',
|
||||
)
|
||||
|
||||
@ -107,7 +112,6 @@ genrule(
|
||||
' -o $OUT' +
|
||||
' -u ' + URL +
|
||||
' -v ' + SHA1,
|
||||
deps = ['//tools:download_file'],
|
||||
out = ZIP,
|
||||
)
|
||||
|
||||
|
@ -4,15 +4,6 @@ CM_CSS = [
|
||||
'addon/scroll/simplescrollbars.css',
|
||||
]
|
||||
|
||||
CM_THEMES = [
|
||||
'theme/eclipse.css',
|
||||
'theme/elegant.css',
|
||||
'theme/midnight.css',
|
||||
'theme/neat.css',
|
||||
'theme/night.css',
|
||||
'theme/twilight.css',
|
||||
]
|
||||
|
||||
CM_JS = [
|
||||
'lib/codemirror.js',
|
||||
'mode/meta.js',
|
||||
@ -30,6 +21,21 @@ CM_ADDONS = [
|
||||
'mode/simple.js',
|
||||
]
|
||||
|
||||
# Available themes must be enumerated here,
|
||||
# in gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/Theme.java,
|
||||
# in gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
|
||||
CM_THEMES = [
|
||||
'eclipse',
|
||||
'elegant',
|
||||
'midnight',
|
||||
'neat',
|
||||
'night',
|
||||
'twilight',
|
||||
]
|
||||
|
||||
# Available modes must be enumerated here,
|
||||
# in gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java,
|
||||
# and in CodeMirror's own mode/meta.js script.
|
||||
CM_MODES = [
|
||||
'clike',
|
||||
'clojure',
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 80373ef2e4c1978b8c9a68a12c05ec05c4063f8a
|
||||
Subproject commit 39ffdc20f021484c1ce1dca2ae9f00fa10a482f4
|
Loading…
Reference in New Issue
Block a user