Merge remote-tracking branch 'server/master'

This commit is contained in:
Axel Uhl committed 2014-05-28 18:09:58 +02:00
commit 46d45f694c
7 files changed
+220 -92

No files matched your search

+2 -27
View File
@@ -82,35 +82,10 @@
</web-resource-collection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>eventmanager</role-name>
</auth-constraint>
</security-constraint>
<!-- Preparation of security constraints for the leaderboard and raceboard pages
<security-constraint>
<web-resource-collection>
<web-resource-name>Raceboard pages</web-resource-name>
<url-pattern>/RaceBoard.html</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>spectator</role-name>
<role-name>moderator</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Leaderboard pages</web-resource-name>
<url-pattern>/Leaderboard.html</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>spectator</role-name>
<role-name>moderator</role-name>
</auth-constraint>
</security-constraint>
-->
<security-constraint>
<web-resource-collection>
<web-resource-name>Leaderboard editing pages</web-resource-name>
@@ -118,7 +93,7 @@
</web-resource-collection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>moderator</role-name>
<role-name>eventmanager</role-name>
</auth-constraint>
</security-constraint>
@@ -15,10 +15,10 @@ import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.AbstractEntryPoint;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
@@ -35,6 +35,8 @@ import com.sap.sailing.gwt.ui.client.shared.panels.UserStatusPanel;
import com.sap.sailing.gwt.ui.masterdataimport.MasterDataImportPanel;
import com.sap.sailing.gwt.ui.shared.BetterDateTimeBox;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.UserDTO;
import com.sap.sailing.gwt.ui.usermanagement.UserRoles;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
@@ -46,7 +48,7 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
private final SailingServiceAsync sailingService = GWT.create(SailingService.class);
private final MediaServiceAsync mediaService = GWT.create(MediaService.class);
private final UserManagementServiceAsync userManagementService = GWT.create(UserManagementService.class);
@Override
protected void doOnModuleLoad() {
super.doOnModuleLoad();
@@ -55,6 +57,20 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.sailingServiceRemotePath);
registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
userManagementService.getUser(new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
reportError("Could not read user: " + caught.getMessage());
}
@Override
public void onSuccess(UserDTO result) {
createUI(result);
}
});
}
private void createUI(UserDTO user) {
BetterDateTimeBox.initialize();
RootLayoutPanel rootPanel = RootLayoutPanel.get();
@@ -63,7 +79,7 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
DockPanel topInformationPanel = new DockPanel();
topInformationPanel.setSize("100%", "95%");
UserStatusPanel userStatusPanel = new UserStatusPanel(userManagementService, this);
UserStatusPanel userStatusPanel = new UserStatusPanel(user);
userStatusPanel.ensureDebugId("UserStatus");
topInformationPanel.add(userStatusPanel, DockPanel.WEST);
topInformationPanel.add(persistentAlertLabel, DockPanel.CENTER);
@@ -79,64 +95,53 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
SailingEventManagementPanel sailingEventManagementPanel = new SailingEventManagementPanel(sailingService, this,
stringMessages);
sailingEventManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, sailingEventManagementPanel, stringMessages.events());
addToTabPanel(tabPanel, user, sailingEventManagementPanel, stringMessages.events(), AdminConsoleFeatures.MANAGE_EVENTS);
RegattaStructureManagementPanel eventStructureManagementPanel = new RegattaStructureManagementPanel(
sailingService, this, stringMessages, this);
eventStructureManagementPanel.ensureDebugId("RegattaStructureManagement");
eventStructureManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, eventStructureManagementPanel, stringMessages.regattas());
addToTabPanel(tabPanel, user, eventStructureManagementPanel, stringMessages.regattas(), AdminConsoleFeatures.MANAGE_REGATTAS);
regattaDisplayers.add(eventStructureManagementPanel);
TracTracEventManagementPanel tractracEventManagementPanel = new TracTracEventManagementPanel(sailingService,
this, this, stringMessages);
tractracEventManagementPanel.ensureDebugId("TracTracEventManagement");
tractracEventManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, tractracEventManagementPanel, stringMessages.tracTracEvents());
addToTabPanel(tabPanel, user, tractracEventManagementPanel, stringMessages.tracTracEvents(), AdminConsoleFeatures.MANAGE_TRACKED_RACES);
regattaDisplayers.add(tractracEventManagementPanel);
SwissTimingReplayConnectorPanel swissTimingReplayConnectorPanel = new SwissTimingReplayConnectorPanel(
sailingService, this, this, stringMessages);
swissTimingReplayConnectorPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, swissTimingReplayConnectorPanel, stringMessages.swissTimingArchiveConnector());
addToTabPanel(tabPanel, user, swissTimingReplayConnectorPanel, stringMessages.swissTimingArchiveConnector(), AdminConsoleFeatures.MANAGE_TRACKED_RACES);
regattaDisplayers.add(swissTimingReplayConnectorPanel);
SwissTimingEventManagementPanel swisstimingEventManagementPanel = new SwissTimingEventManagementPanel(
sailingService, this, this, stringMessages);
// swisstimingEventManagementPanel.ensureDebugId("SwissTimingEventManagement");
swisstimingEventManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, swisstimingEventManagementPanel, stringMessages.swissTimingEvents());
addToTabPanel(tabPanel, user, swisstimingEventManagementPanel, stringMessages.swissTimingEvents(), AdminConsoleFeatures.MANAGE_TRACKED_RACES);
regattaDisplayers.add(swisstimingEventManagementPanel);
final RaceLogTrackingEventManagementPanel raceLogTrackingEventManagementPanel = new RaceLogTrackingEventManagementPanel(
sailingService, this, this, this, stringMessages);
raceLogTrackingEventManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, raceLogTrackingEventManagementPanel, stringMessages.raceLogTracking());
addToTabPanel(tabPanel, user, raceLogTrackingEventManagementPanel, stringMessages.raceLogTracking(), AdminConsoleFeatures.MANAGE_RACELOG_TRACKING);
regattaDisplayers.add(raceLogTrackingEventManagementPanel);
IgtimiAccountsPanel igtimiAccountsPanel = new IgtimiAccountsPanel(sailingService, this, stringMessages);
igtimiAccountsPanel.ensureDebugId("IgtimiAccounts");
igtimiAccountsPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, igtimiAccountsPanel, stringMessages.igtimiAccounts());
addToTabPanel(tabPanel, user, igtimiAccountsPanel, stringMessages.igtimiAccounts(), AdminConsoleFeatures.MANAGE_IGTIMI_ACCOUNTS);
TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(sailingService, this,
this, stringMessages);
trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
trackedRacesManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, trackedRacesManagementPanel, stringMessages.trackedRaces());
addToTabPanel(tabPanel, user, trackedRacesManagementPanel, stringMessages.trackedRaces(), AdminConsoleFeatures.SHOW_TRACKED_RACES);
regattaDisplayers.add(trackedRacesManagementPanel);
final CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, stringMessages, this);
// trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement");
trackedRacesManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, competitorPanel, stringMessages.competitors());
addToTabPanel(tabPanel, user, competitorPanel, stringMessages.competitors(), AdminConsoleFeatures.MANAGE_ALL_COMPETITORS);
RaceCourseManagementPanel raceCourseManagementPanel = new RaceCourseManagementPanel(sailingService, this, this,
stringMessages);
// raceCourseManagementPanel.ensureDebugId("RaceCourseManagement");
raceCourseManagementPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, raceCourseManagementPanel, stringMessages.courseLayout());
addToTabPanel(tabPanel, user, raceCourseManagementPanel, stringMessages.courseLayout(), AdminConsoleFeatures.MANAGE_COURSE_LAYOUT);
regattaDisplayers.add(raceCourseManagementPanel);
final AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
@@ -144,39 +149,36 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
WindPanel windPanel = new WindPanel(sailingService, asyncActionsExecutor, this, this, stringMessages);
// windPanel.ensureDebugId("WindManagement");
regattaDisplayers.add(windPanel);
windPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, windPanel, stringMessages.wind());
addToTabPanel(tabPanel, user, windPanel, stringMessages.wind(), AdminConsoleFeatures.MANAGE_WIND);
final LeaderboardGroupConfigPanel leaderboardGroupConfigPanel = new LeaderboardGroupConfigPanel(sailingService,
this, this, stringMessages);
leaderboardGroupConfigPanel.ensureDebugId("LeaderboardGroupConfiguration");
leaderboardGroupConfigPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, leaderboardGroupConfigPanel, stringMessages.leaderboardGroupConfiguration());
addToTabPanel(tabPanel, user, leaderboardGroupConfigPanel, stringMessages.leaderboardGroupConfiguration(), AdminConsoleFeatures.MANAGE_LEADERBOARD_GROUPS);
regattaDisplayers.add(leaderboardGroupConfigPanel);
final LeaderboardConfigPanel leaderboardConfigPanel = new LeaderboardConfigPanel(sailingService, this, this,
stringMessages,
/* showRaceDetails */true);
stringMessages, /* showRaceDetails */true);
leaderboardConfigPanel.ensureDebugId("LeaderboardConfiguration");
leaderboardConfigPanel.setSize("90%", "90%");
addScrollableTab(tabPanel, leaderboardConfigPanel, stringMessages.leaderboardConfiguration());
addToTabPanel(tabPanel, user, leaderboardConfigPanel, stringMessages.leaderboardConfiguration(), AdminConsoleFeatures.MANAGE_LEADERBOARDS);
regattaDisplayers.add(leaderboardConfigPanel);
ResultImportUrlsManagementPanel resultImportUrlsManagementPanel = new ResultImportUrlsManagementPanel(sailingService, this, stringMessages);
addScrollableTab(tabPanel, resultImportUrlsManagementPanel, stringMessages.resultImportUrls());
addToTabPanel(tabPanel, user, resultImportUrlsManagementPanel, stringMessages.resultImportUrls(), AdminConsoleFeatures.MANAGE_RESULT_IMPORT_URLS);
RemoteSailingServerInstancesManagementPanel sailingServerInstancesManagementPanel = new RemoteSailingServerInstancesManagementPanel(sailingService, this, stringMessages);
addScrollableTab(tabPanel, sailingServerInstancesManagementPanel, stringMessages.sailingServers());
addToTabPanel(tabPanel, user, sailingServerInstancesManagementPanel, stringMessages.sailingServers(), AdminConsoleFeatures.MANAGE_SAILING_SERVER_INSTANCES);
ReplicationPanel replicationPanel = new ReplicationPanel(sailingService, this, stringMessages);
final ReplicationPanel replicationPanel = new ReplicationPanel(sailingService, this, stringMessages);
// replicationPanel.ensureDebugId("ReplicationManagement");
addScrollableTab(tabPanel, replicationPanel, stringMessages.replication());
addToTabPanel(tabPanel, user, replicationPanel, stringMessages.replication(), AdminConsoleFeatures.MANAGE_REPLICATION);
final MediaPanel mediaPanel = new MediaPanel(mediaService, this, stringMessages);
addScrollableTab(tabPanel, mediaPanel, stringMessages.mediaPanel());
addToTabPanel(tabPanel, user, mediaPanel, stringMessages.mediaPanel(), AdminConsoleFeatures.MANAGE_MEDIA);
final MasterDataImportPanel masterDataImportPanel = new MasterDataImportPanel(stringMessages, sailingService,
this, sailingEventManagementPanel, leaderboardGroupConfigPanel);
addScrollableTab(tabPanel, masterDataImportPanel, stringMessages.masterDataImportPanel());
addToTabPanel(tabPanel, user, masterDataImportPanel, stringMessages.masterDataImportPanel(), AdminConsoleFeatures.MANAGE_MASTERDATA_IMPORT);
/*final DeviceConfigurationPanel deviceConfigurationAdminPanel = new DeviceConfigurationPanel(sailingService,
stringMessages, this);
@@ -184,7 +186,7 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
final DeviceConfigurationPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(sailingService,
stringMessages, this);
addScrollableTab(tabPanel, deviceConfigurationUserPanel, stringMessages.deviceConfiguration());
addToTabPanel(tabPanel, user, deviceConfigurationUserPanel, stringMessages.deviceConfiguration(), AdminConsoleFeatures.MANAGE_DEVICE_CONFIGURATION);
tabPanel.selectTab(0);
tabPanel.addSelectionHandler(new SelectionHandler<Integer>() {
@@ -212,11 +214,31 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt
dockPanel.add(tabPanel);
}
private void addScrollableTab(TabLayoutPanel tabPanel, Widget widget, String tabTitle) {
ScrollPanel widgetScroller = new ScrollPanel();
widgetScroller.add(widget);
tabPanel.add(widgetScroller, tabTitle, false);
private void addToTabPanel(TabLayoutPanel tabPanel, UserDTO user, Panel panelToAdd, String tabTitle, AdminConsoleFeatures feature) {
if(user != null && isUserInRole(user, feature.getEnabledRoles())) {
ScrollPanel scrollPanel = new ScrollPanel();
scrollPanel.add(panelToAdd);
panelToAdd.setSize("90%", "90%");
tabPanel.add(scrollPanel, tabTitle, false);
}
}
private boolean isUserInRole(UserDTO user, UserRoles[] roles) {
boolean result = false;
for(UserRoles enabledRole: roles) {
if (user.roles.contains(enabledRole.name())) {
result = true;
break;
}
}
return result;
}
// private void addScrollableTab(TabLayoutPanel tabPanel, Widget widget, String tabTitle) {
// ScrollPanel widgetScroller = new ScrollPanel();
// widgetScroller.add(widget);
// tabPanel.add(widgetScroller, tabTitle, false);
// }
@Override
public void fillRegattas() {
@@ -0,0 +1,34 @@
package com.sap.sailing.gwt.ui.adminconsole;
import com.sap.sailing.gwt.ui.usermanagement.UserRoles;
public enum AdminConsoleFeatures {
MANAGE_EVENTS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_REGATTAS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_TRACKED_RACES (UserRoles.eventmanager, UserRoles.administrator),
SHOW_TRACKED_RACES (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_RACELOG_TRACKING (UserRoles.administrator),
MANAGE_ALL_COMPETITORS (UserRoles.administrator),
MANAGE_COURSE_LAYOUT (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_WIND (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_IGTIMI_ACCOUNTS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_LEADERBOARDS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_LEADERBOARD_GROUPS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_RESULT_IMPORT_URLS (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_MEDIA (UserRoles.eventmanager, UserRoles.administrator),
MANAGE_SAILING_SERVER_INSTANCES (UserRoles.administrator),
MANAGE_REPLICATION (UserRoles.administrator),
MANAGE_MASTERDATA_IMPORT (UserRoles.administrator),
MANAGE_DEVICE_CONFIGURATION (UserRoles.eventmanager, UserRoles.administrator);
private UserRoles[] enabledRoles;
AdminConsoleFeatures(UserRoles... enabledRoles) {
this.enabledRoles = enabledRoles;
}
public UserRoles[] getEnabledRoles() {
return enabledRoles;
}
}
@@ -1,17 +1,14 @@
package com.sap.sailing.gwt.ui.client.shared.panels;
import com.google.gwt.dom.client.Style;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.UserManagementServiceAsync;
import com.sap.sailing.gwt.ui.shared.UserDTO;
public class UserStatusPanel extends FlowPanel {
private UserDTO user;
private final UserDTO user;
private final Label userNameLabel;
@@ -19,27 +16,18 @@ public class UserStatusPanel extends FlowPanel {
private final Label userRolesText;
public UserStatusPanel(final UserManagementServiceAsync userManagementService, final ErrorReporter errorReporter) {
public UserStatusPanel(UserDTO user) {
super();
this.user = user;
userNameLabel = new Label("User:");
userNameText = new Label("");
userRolesText = new Label("");
user = null;
userManagementService.getUser(new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not read user: " + caught.getMessage());
}
@Override
public void onSuccess(UserDTO result) {
updateUser(result);
}
});
addFloatingWidget(userNameLabel);
addFloatingWidget(userNameText);
addFloatingWidget(userRolesText);
updateUser(user);
updateUser();
}
private void addFloatingWidget(Widget w) {
@@ -48,9 +36,7 @@ public class UserStatusPanel extends FlowPanel {
add(w);
}
private void updateUser(UserDTO newUser) {
this.user = newUser;
private void updateUser() {
if(user != null) {
userNameText.setText(user.principalName);
userRolesText.setText(user.roles.toString());
@@ -3,5 +3,6 @@ package com.sap.sailing.gwt.ui.usermanagement;
public enum UserRoles {
administrator,
spectator,
moderator
moderator,
eventmanager
}
@@ -12,13 +12,17 @@
# format, either plain text or OBF:.
#
axel: axel,spectator,moderator,administrator
simon: simon,spectator,moderator,administrator
frank: frank,spectator,moderator,administrator
jens: jens,spectator,moderator,administrator
lennart: lennart,spectator,moderator,administrator
marcus: marcus,spectator,moderator,administrator
marcus: marcus,spectator,moderator,eventmanager
milan: milan,spectator,moderator,administrator
nils: nils,spectator,moderator,administrator
stefan: stefan,spectator,moderator,administrator
riccardo: riccardo,spectator,moderator,administrator
christopher: christopher,spectator,moderator,administrator
armin: armin,spectator,moderator,administrator
jacob@sejlsport.dk: !hsf/sf67, eventmanager
m.welte@stg-academy.org: mwelte, eventmanager
e.anders@stg-academy.org: eanders, eventmanager
+106
View File
@@ -48,6 +48,112 @@ Instead, we decided to use a very simple, light-weight MVP (Model, View, Present
A micro framework in package com.sap.sse.gwt.client.mvp supports developers in the implementation of UI components. It offers an `AbstractEntryPoint` class that manages most of the configuration tasks and establishes the links between the activity manager, place history manager, activity mapper and the event bus. The `AbstractActivityProxy` helps in applying code splitting to activities. The `example` subpackage contains two sample components that demonstrate how to use the micro framework. There is also some Javadoc on the most important classes.
## Dealing with CSS Media Queries
GWT doesn't handle media queries in `CssResource` interfaces. To still cope, we agreed to use the following approach. Each CSS file that contains media queries of the form `@media ...` are copied so that for each media query in the original CSS file one additional copy is created. We then remove (or comment out) the contents of all CSS rule sets enclosed in any media queries from the original CSS file so that the declarations remain with an empty body. In each of the media query-specific copies we do the same, only for all rule sets that were not contained in the media query section. The `@media` enclosings are removed from or commented out in the original CSS file and all copies.
The Java resource file that describes the CSS file then has to declare a CSS resource for each of the copies and the original CSS file. The interface for the main resource that has to extend `CssResource` must be declared using the `@Shared` annotation. This ensures that the specializing media query-specific interfaces receive the same obfuscated class names as the main CSS resource. For each media query-specific copy, another interface that extends the main CSS's interface needs to be declared.
Example: Assume we have an original CSS document of the following form:
<pre>
.a {
width: 75px;
}
@media (min-width: 25em) {
.b {
height: 10px;
}
}
@media (min-width: 50em) {
.b {
height: 20px;
}
}
</pre>
Then the cleaned version of the original CSS looks like this:
<pre>
.a {
width: 75px;
}
/* @media (min-width: 25em) { */
.b {
}
/* } */
/* @media (min-width: 50em) { */
.b {
}
/* } */
</pre>
The copy for the first media query:
<pre>
.a {
}
/* @media (min-width: 25em) { */
.b {
height: 10px;
}
/* } */
/* @media (min-width: 50em) { */
.b {
}
/* } */
</pre>
and for the second media query:
<pre>
.a {
}
/* @media (min-width: 25em) { */
.b {
}
/* } */
/* @media (min-width: 50em) { */
.b {
height: 20px;
}
/* } */
</pre>
The Java resource interface then would look something like this:
<pre>
public interface MyResources extends ClientBundle {
public static final MyResources INSTANCE = GWT.create(MyResources.class);
@Source("path/to/main.css")
MainCss mainCss();
@Shared
public interface MainCss extends CssResource {
String a();
String b();
}
public interface Media1Css extends MainCss {
}
@Source("path/to/media1.css")
Media1Css media1Css();
public interface Media2Css extends MainCss {
}
@Source("path/to/media2.css")
Media2Css media2Css();
}
</pre>
The injection then has to happen in the component to which the CSS belongs which could be an entry point's `onModuleLoad()` method or a widget's / UiBinder's constructor. Example:
<pre>
MyResources.INSTANCE.mainCss().ensureInjected();
StyleInjector.injectAtEnd("@media (min-width: 25em) { "+MyResources.INSTANCE.media1().getText()+"}");
StyleInjector.injectAtEnd("@media (min-width: 50em) { "+MyResources.INSTANCE.media2().getText()+"}");
</pre>
## GWT Code Splitting
For the various areas of the site we don't always want to have to load a new page. Instead, we'd like to use the "places" pattern with a local history management. This goes together well with GWT Code Splitting (see http://www.gwtproject.org/doc/latest/DevGuideCodeSplitting.html#patterns) which allows an application to load its parts when they are needed. This speeds up the initial loading process and keeps bandwidth consumption low.