Merge branch 'ubilabs--rcapp--master' into ubilabs--rcapp--develop

This commit is contained in:
Peter Siegmund committed 2016-03-09 12:18:52 +01:00
commit f80561637c
301 files changed
+4662 -2066

No files matched your search

+3 -1
View File
@@ -36,8 +36,10 @@ start_servers() {
echo "Starting Java server \"$conf\"" >>/var/log/sailing.out
su - sailing -c "cd $SERVERS_DIR/$conf && ./start" 2>>/var/log/sailing.err >>/var/log/sailing.out
server_name="`echo $SERVER_NAME | tr [A-Z] [a-z]`"
echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map internal IP $INSTANCE_INTERNAL_IP4 to plain server running $SERVER_PORT..." >>/var/log/sailing.out
echo "Use Plain-SSL ${INSTANCE_INTERNAL_IP4} 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
echo "Appending macro invocation to $APACHE_CONFIG_DIR/001-events.conf to map ${server_name}.sapsailing.com to event with ID $EVENT_ID with server running on local port $SERVER_PORT..." >>/var/log/sailing.out
echo "Use Event ${server_name}.sapsailing.com \"$EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
echo "Use Event-SSL ${server_name}.sapsailing.com \"$EVENT_ID\" 127.0.0.1 $SERVER_PORT" >>$APACHE_CONFIG_DIR/001-events.conf
HTTP_LOGROTATE=/etc/logrotate.d/httpd
echo "Patching $HTTP_LOGROTATE so that old logs go to /var/log/old/$SERVER_NAME/$INSTANCE_IP4" >>/var/log/sailing.out
sed -i -e "s/\/var\/log\/old\/\([^/]*\)\/\([^/ ]*\)/\/var\/log\/old\/$SERVER_NAME\/$INSTANCE_IP4/" $HTTP_LOGROTATE
Binary file not shown.
@@ -1,37 +1,63 @@
package com.sap.sailing.domain.common.impl;
import java.net.URLEncoder;
import com.sap.sse.common.Util;
import java.util.HashMap;
import java.util.Map;
/**
* This class is used by our backend, in GWT-client code and by the Android app. Therefore we cannot use classes like
* {@link URLEncoder} to help us with the encoding.
*/
public class DeviceConfigurationQRCodeUtils {
public static final String fragmentKey = "identifier";
public static String composeQRContent(String deviceIdentifier, String apkUrl) {
// poor man's uri fragment encoding: ' ' as '%20'
String encodedIdentifier = deviceIdentifier.replaceAll(" ", "%20");
return apkUrl + "#" + fragmentKey + "=" + encodedIdentifier;
public static final String deviceIdentifierKey = "identifier";
public static final String accessTokenKey = "token";
public static class DeviceConfigurationDetails {
private final String apkUrl;
private final String deviceIdentifier;
private final String accessToken;
public DeviceConfigurationDetails(String apkUrl, String deviceIdentifier, String accessToken) {
super();
this.apkUrl = apkUrl;
this.deviceIdentifier = deviceIdentifier;
this.accessToken = accessToken;
}
public String getApkUrl() {
return apkUrl;
}
public String getDeviceIdentifier() {
return deviceIdentifier;
}
public String getAccessToken() {
return accessToken;
}
}
public static Util.Pair<String, String> splitQRContent(String qrCodeContent) {
public static String composeQRContent(String deviceIdentifier, String apkUrl, String accessToken) {
// poor man's uri fragment encoding: ' ' as '%20'
String encodedIdentifier = deviceIdentifier.replaceAll(" ", "%20");
return apkUrl + "#" + deviceIdentifierKey + "=" + encodedIdentifier+"&"+accessTokenKey + "=" + accessToken;
}
public static DeviceConfigurationDetails splitQRContent(String qrCodeContent) {
int fragmentIndex = qrCodeContent.lastIndexOf('#');
if (fragmentIndex == -1 || fragmentIndex == 0 || qrCodeContent.length() == fragmentIndex + 1) {
throw new IllegalArgumentException("There is no server or identifier.");
}
String deviceIdentifier = qrCodeContent.substring(fragmentIndex + 1, qrCodeContent.length());
if (!deviceIdentifier.startsWith(fragmentKey + "=")) {
throw new IllegalArgumentException("The identifier is malformed");
String fragment = qrCodeContent.substring(fragmentIndex + 1, qrCodeContent.length());
final String[] params = fragment.split("&");
final Map<String, String> paramMap = new HashMap<>();
for (String param : params) {
final String[] keyValue = param.split("=", 2);
if (keyValue.length == 2) {
paramMap.put(keyValue[0], keyValue[1].replaceAll("%20", " "));
}
}
if (!paramMap.containsKey(deviceIdentifierKey)) {
throw new IllegalArgumentException("Device identifier missing from QR code contents");
}
deviceIdentifier = deviceIdentifier.substring((fragmentKey + "=").length());
deviceIdentifier = deviceIdentifier.replaceAll("%20", " ");
String apkUrl = qrCodeContent.substring(0, fragmentIndex);
return new Util.Pair<String, String>(deviceIdentifier, apkUrl);
return new DeviceConfigurationDetails(apkUrl, paramMap.get(deviceIdentifierKey), paramMap.get(accessTokenKey));
}
}
@@ -1,6 +1,10 @@
package com.sap.sailing.domain.common.security;
public enum Permission implements com.sap.sse.security.shared.Permission {
// AdminConsole permissions
MANAGE_EVENTS,
MANAGE_REGATTAS,
MANAGE_TRACKED_RACES,
@@ -11,6 +15,7 @@ public enum Permission implements com.sap.sse.security.shared.Permission {
MANAGE_WIND,
MANAGE_IGTIMI_ACCOUNTS,
MANAGE_LEADERBOARDS,
MANAGE_LEADERBOARD_RESULTS,
MANAGE_LEADERBOARD_GROUPS,
MANAGE_RESULT_IMPORT_URLS,
MANAGE_STRUCTURE_IMPORT_URLS,
@@ -23,10 +28,69 @@ public enum Permission implements com.sap.sse.security.shared.Permission {
MANAGE_USERS,
MANAGE_FILE_STORAGE,
MANAGE_MARK_PASSINGS,
CAN_REPLAY_DURING_LIVE_RACES;
CAN_REPLAY_DURING_LIVE_RACES,
// back-end permissions
EVENT,
REGATTA,
LEADERBOARD,
LEADERBOARD_GROUP,
TRACKED_RACE
;
// TODO once we can use Java8 here, move this up into a "default" method on the Permission interface
@Override
public String getStringPermission() {
return name()+":";
public String getStringPermission(com.sap.sse.security.shared.Permission.Mode... modes) {
final String result;
if (modes==null || modes.length==0) {
result = name();
} else {
final StringBuilder modesString = new StringBuilder();
boolean first = true;
for (com.sap.sse.security.shared.Permission.Mode mode : modes) {
if (first) {
first = false;
} else {
modesString.append(',');
}
modesString.append(mode.getStringPermission());
}
result = name()+":"+modesString.toString();
}
return result;
}
// TODO once we can use Java8 here, move this up into a "default" method on the Permission interface
@Override
public String getStringPermissionForObjects(com.sap.sse.security.shared.Permission.Mode mode, String... objectIdentifiers) {
final StringBuilder result = new StringBuilder(getStringPermission(mode));
if (objectIdentifiers!=null && objectIdentifiers.length>0) {
result.append(':');
boolean first = true;
for (String objectIdentifier : objectIdentifiers) {
if (first) {
first = false;
} else {
result.append(',');
}
result.append(objectIdentifier);
}
}
return result.toString();
}
/**
* The mode of interaction with a resource; used as the second element of a wildcard permission
*
* @author Axel Uhl (d043530)
*
*/
public static enum Mode implements com.sap.sse.security.shared.Permission.Mode {
CREATE, READ, UPDATE, DELETE;
@Override
public String getStringPermission() {
return name();
}
}
}
@@ -13,13 +13,40 @@ public class SailingPermissionsForRoleProvider implements PermissionsForRoleProv
public Iterable<String> getPermissions(String role) {
final Iterable<String> result;
if (DefaultRoles.ADMIN.getRolename().equals(role)) {
return Collections.<String>singletonList("*");
result = Collections.<String>singletonList("*");
} else if (Roles.eventmanager.getRolename().equals(role)) {
return asList(Permission.MANAGE_MEDIA, Permission.MANAGE_MARK_PASSINGS);
result = asList(
// RaceBoard:
Permission.MANAGE_MEDIA,
Permission.MANAGE_MARK_PASSINGS,
// AdminConsole:
Permission.MANAGE_ALL_COMPETITORS,
Permission.MANAGE_COURSE_LAYOUT,
Permission.MANAGE_DEVICE_CONFIGURATION,
Permission.MANAGE_EVENTS,
Permission.MANAGE_IGTIMI_ACCOUNTS,
Permission.MANAGE_LEADERBOARD_GROUPS,
Permission.MANAGE_LEADERBOARDS,
Permission.MANAGE_LEADERBOARD_RESULTS,
Permission.MANAGE_MEDIA,
Permission.MANAGE_RACELOG_TRACKING,
Permission.MANAGE_REGATTAS,
Permission.MANAGE_RESULT_IMPORT_URLS,
Permission.MANAGE_STRUCTURE_IMPORT_URLS,
Permission.MANAGE_TRACKED_RACES,
Permission.MANAGE_WIND,
// back-end:
Permission.EVENT,
Permission.REGATTA,
Permission.LEADERBOARD,
Permission.LEADERBOARD_GROUP
);
} else if (Roles.mediaeditor.getRolename().equals(role)) {
return asList(Permission.MANAGE_MEDIA);
result = asList(Permission.MANAGE_MEDIA);
} else if (Roles.moderator.getRolename().equals(role)) {
return asList(Permission.CAN_REPLAY_DURING_LIVE_RACES);
result = asList(Permission.CAN_REPLAY_DURING_LIVE_RACES);
} else {
result = Collections.emptyList();
}
@@ -16,7 +16,8 @@ Require-Bundle: org.json.simple;bundle-version="1.1.0",
com.sap.sailing.domain,
com.sap.sailing.declination,
com.sap.sse.common,
com.sap.sse
com.sap.sse,
com.sap.sse.security
Import-Package: javax.ws.rs;version="1.1.1",
javax.ws.rs.core;version="1.1.1",
javax.ws.rs.ext;version="1.1.1",
@@ -6,12 +6,14 @@ import java.util.Set;
import javax.ws.rs.core.Application;
import com.sap.sse.security.jaxrs.ShiroAuthorizationExceptionTo401ResponseMapper;
public class RestApiApplication extends Application {
public RestApiApplication() {
}
@Override
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>(Arrays.asList(new Class<?>[] { AuthorizationCallback.class }));
return new HashSet<Class<?>>(Arrays.asList(new Class<?>[] { AuthorizationCallback.class, ShiroAuthorizationExceptionTo401ResponseMapper.class }));
}
}
@@ -948,7 +948,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
try {
for (DBObject object : eventCollection.find()) {
Event event = loadEvent(object);
Boolean requiresStoreAfterMigration = loadLegacyImageAndVideoURLs(event, object);
boolean requiresStoreAfterMigration = loadLegacyImageAndVideoURLs(event, object);
requiresStoreAfterMigration |= loadLegacySailorsInfoWebsiteURL(event, object);
result.add(new Pair<Event, Boolean>(event, requiresStoreAfterMigration));
}
} catch (Exception e) {
@@ -1030,14 +1031,6 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL.");
}
}
String sailorsInfoWebSiteURLAsString = (String) eventDBObject.get(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name());
if (sailorsInfoWebSiteURLAsString != null) {
try {
result.setSailorsInfoWebsiteURL(new URL(sailorsInfoWebSiteURLAsString));
} catch (MalformedURLException e) {
logger.severe("Error parsing sailors info website URL "+sailorsInfoWebSiteURLAsString+" for event "+name+". Ignoring this URL.");
}
}
BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name());
if (images != null) {
for (Object imageObject : images) {
@@ -1056,6 +1049,18 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
}
}
BasicDBList sailorsInfoWebsiteURLs = (BasicDBList) eventDBObject.get(FieldNames.EVENT_SAILORS_INFO_WEBSITES.name());
if (sailorsInfoWebsiteURLs != null) {
for (Object sailorsInfoWebsiteObject : sailorsInfoWebsiteURLs) {
DBObject sailorsInfoWebsiteDBObject = (DBObject) sailorsInfoWebsiteObject;
URL url = loadURL(sailorsInfoWebsiteDBObject, FieldNames.SAILORS_INFO_URL);
String localeRaw = (String) sailorsInfoWebsiteDBObject.get(FieldNames.SAILORS_INFO_LOCALE.name());
if (url != null) {
Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null;
result.setSailorsInfoWebsiteURL(locale, url);
}
}
}
return result;
}
@@ -2162,4 +2167,29 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
return event.setMediaURLs(imageURLs, sponsorImageURLs, videoURLs, logoImageURL, Collections.emptyMap());
}
private boolean loadLegacySailorsInfoWebsiteURL(Event event, DBObject eventDBObject) {
final boolean modified;
final String sailorsInfoWebSiteURLAsString = (String) eventDBObject.get(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name());
if (sailorsInfoWebSiteURLAsString != null) {
try {
// The legacy sailors info URL (only used at Kieler/Travemuender Woche events) used to have 2 localized versions:
// The German version with no suffix (e.g. http://sailorsinfo.travemuender-woche.com)
// The English/international version with "/en" suffix (e.g. http://sailorsinfo.travemuender-woche.com/en)
if (!event.hasSailorsInfoWebsiteURL(null)) {
final String englishURL = sailorsInfoWebSiteURLAsString + (sailorsInfoWebSiteURLAsString.endsWith("/") ? "" : "/") + "en";
event.setSailorsInfoWebsiteURL(null, new URL(englishURL));
}
if (!event.hasSailorsInfoWebsiteURL(Locale.GERMAN)) {
event.setSailorsInfoWebsiteURL(Locale.GERMAN, new URL(sailorsInfoWebSiteURLAsString));
}
} catch (MalformedURLException e) {
logger.severe("Error parsing sailors info website URL "+sailorsInfoWebSiteURLAsString+" for event "+event.getName()+". Ignoring this URL.");
}
modified = true;
} else {
modified = false;
}
return modified;
}
}
@@ -23,6 +23,7 @@ public enum FieldNames {
EVENT_VIDEOS,
EVENT_OFFICIAL_WEBSITE_URL,
EVENT_SAILORS_INFO_WEBSITE_URL,
EVENT_SAILORS_INFO_WEBSITES,
EVENT_LOGO_IMAGE_URL,
REGATTA_NAME,
@@ -148,5 +149,8 @@ public enum FieldNames {
// video fields
VIDEO_URL, VIDEO_LOCALE, VIDEO_TITLE, VIDEO_SUBTITLE, VIDEO_MIMETYPE, VIDEO_COPYRIGHT, VIDEO_CREATEDATDATE,
VIDEO_TAGS, VIDEO_THUMBNAIL_URL, VIDEO_LENGTH_IN_SECONDS;
VIDEO_TAGS, VIDEO_THUMBNAIL_URL, VIDEO_LENGTH_IN_SECONDS,
// sailors info fileds
SAILORS_INFO_URL, SAILORS_INFO_LOCALE;
}
@@ -3,6 +3,8 @@ package com.sap.sailing.domain.persistence.impl;
import java.io.Serializable;
import java.net.URL;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -535,7 +537,6 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
/**
* StoreEvent() uses some deprecated methods of event to keep backward compatibility.
*/
@SuppressWarnings("deprecation")
@Override
public void storeEvent(Event event) {
DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name());
@@ -546,29 +547,12 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
eventDBObject.put(FieldNames.EVENT_NAME.name(), event.getName());
eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription());
eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId());
eventDBObject.put(FieldNames.EVENT_LOGO_IMAGE_URL.name(), event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null);
eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null);
eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITE_URL.name(), event.getSailorsInfoWebsiteURL() != null ? event.getSailorsInfoWebsiteURL().toString() : null);
storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE);
storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE);
eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic());
DBObject venueDBObject = getVenueAsDBObject(event.getVenue());
eventDBObject.put(FieldNames.VENUE.name(), venueDBObject);
BasicDBList imageURLs = new BasicDBList();
for (URL imageURL : event.getImageURLs()) {
imageURLs.add(imageURL.toString());
}
eventDBObject.put(FieldNames.EVENT_IMAGE_URLS.name(), imageURLs);
BasicDBList videoURLs = new BasicDBList();
for (URL videoURL : event.getVideoURLs()) {
videoURLs.add(videoURL.toString());
}
eventDBObject.put(FieldNames.EVENT_VIDEO_URLS.name(), videoURLs);
BasicDBList sponsorImageURLs = new BasicDBList();
for (URL sponsorImageURL : event.getSponsorImageURLs()) {
sponsorImageURLs.add(sponsorImageURL.toString());
}
eventDBObject.put(FieldNames.EVENT_SPONSOR_IMAGE_URLS.name(), sponsorImageURLs);
BasicDBList images = new BasicDBList();
for (ImageDescriptor image : event.getImages()) {
DBObject imageObject = createImageObject(image);
@@ -581,6 +565,12 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
videos.add(videoObject);
}
eventDBObject.put(FieldNames.EVENT_VIDEOS.name(), videos);
BasicDBList sailorsInfoWebsiteURLs = new BasicDBList();
for(Map.Entry<Locale, URL> sailorsInfoWebsite : event.getSailorsInfoWebsiteURLs().entrySet()) {
DBObject sailorsInfoWebsiteObject = createSailorsInfoWebsiteObject(sailorsInfoWebsite.getKey(), sailorsInfoWebsite.getValue());
sailorsInfoWebsiteURLs.add(sailorsInfoWebsiteObject);
}
eventDBObject.put(FieldNames.EVENT_SAILORS_INFO_WEBSITES.name(), sailorsInfoWebsiteURLs);
eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
// now store the links to the leaderboard groups
DBCollection linksCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUP_LINKS_FOR_EVENTS.name());
@@ -1477,4 +1467,11 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.VIDEO_TAGS.name(), tags);
return result;
}
private DBObject createSailorsInfoWebsiteObject(Locale locale, URL url) {
DBObject result = new BasicDBObject();
result.put(FieldNames.SAILORS_INFO_URL.name(), url.toString());
result.put(FieldNames.SAILORS_INFO_LOCALE.name(), locale != null ? locale.toLanguageTag() : null);
return result;
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.base;
import java.net.URL;
import java.util.Locale;
import java.util.Map;
import com.sap.sailing.domain.common.Renamable;
@@ -41,38 +42,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi
void setPublic(boolean isPublic);
/**
* @deprecated
* Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to image resources that can be
* used to represent the event, e.g., on a web page.
*
* @return a non-<code>null</code> value which may be empty
*/
Iterable<URL> getImageURLs();
/**
* @deprecated
* An event may have zero or more sponsors, each of which usually want to see their logo on the web page.
*
* @return the sponsors' logos; always non-<code>null</code> but possibly empty
*/
Iterable<URL> getSponsorImageURLs();
/**
* @deprecated
* An optional logo image; may return <code>null</code>.
*/
URL getLogoImageURL();
/**
* @deprecated
* Returns a non-<code>null</code> live but unmodifiable collection of URLs pointing to video resources that can be
* used to represent the event, e.g., on a web page.
*
* @return a non-<code>null</code> value which may be empty
*/
Iterable<URL> getVideoURLs();
/**
* @return the URL of the event's official web site, or <code>null</code> if such a site does not exist or its URL
* is not known
@@ -82,12 +51,43 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID, Wi
void setOfficialWebsiteURL(URL officialWebsiteURL);
/**
* @return the URL of an external web site containing sailor related information like protests, official results, etc.
* or <code>null</code> if such a site does not exist or its URL is not known.
* Returns a mapping of Locales to URLs where the URLs are meant as an external web site containing sailor related
* information like protests, official results, etc.
* The default, language independent URL has {@code null} as key.
*
* @return the URLs of an external web site containing sailor related information like protests, official results,
* etc.
*/
URL getSailorsInfoWebsiteURL();
Map<Locale, URL> getSailorsInfoWebsiteURLs();
void setSailorsInfoWebsiteURL(URL sailorsInfoWebsiteURL);
void setSailorsInfoWebsiteURLs(Map<Locale, URL> sailorsInfoWebsiteURLs);
/**
* Sets a sailorsInfoWebsiteURL for the given locale
*/
void setSailorsInfoWebsiteURL(Locale locale, URL sailorsInfoWebsiteURL);
/**
* Checks if there is a sailorsInfoWebsiteURL available for the given locale.
*
* @param locale a locale or null
* @return true if there is a sailorsInfoWebsiteURL available for the given locale
*/
boolean hasSailorsInfoWebsiteURL(Locale locale);
/**
* @param locale a locale to get the associated sailors info website URL for
* @return the URL of an external web site containing sailor related information like protests, official results, etc.
* or <code>null</code> if such a site does not exist for the given locale or its URL is not known.
*/
URL getSailorsInfoWebsiteURL(Locale locale);
/**
* Gets the sailorsInfoWebsiteURL for the given locale. If there is no sailorsInfoWebsiteURL for the specific locale
* but there is a default sailorsInfoWebsiteURL available, this one is returned.
* So this method returns the best available sailorsInfoWebsiteURL for a user who uses the given locale.
*/
URL getSailorsInfoWebsiteURLOrFallback(Locale locale);
Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups();
@@ -6,6 +6,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -18,6 +19,7 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.media.ImageSize;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.concurrent.CopyOnWriteHashMap;
import com.sap.sse.shared.media.ImageDescriptor;
import com.sap.sse.shared.media.MediaDescriptor;
import com.sap.sse.shared.media.MediaUtils;
@@ -26,7 +28,7 @@ import com.sap.sse.shared.media.impl.ImageDescriptorImpl;
import com.sap.sse.shared.media.impl.VideoDescriptorImpl;
public abstract class EventBaseImpl implements EventBase {
private static final long serialVersionUID = -5749964088848611074L;
private static final long serialVersionUID = -4055554853909324357L;
private String name;
private String description;
@@ -36,7 +38,7 @@ public abstract class EventBaseImpl implements EventBase {
private TimePoint startDate;
private TimePoint endDate;
private URL officialWebsiteURL;
private URL sailorsInfoWebsiteURL;
private CopyOnWriteHashMap<Locale, URL> sailorsInfoWebsiteURLs;
private ConcurrentLinkedQueue<ImageDescriptor> images;
private ConcurrentLinkedQueue<VideoDescriptor> videos;
@@ -57,6 +59,7 @@ public abstract class EventBaseImpl implements EventBase {
this.isPublic = isPublic;
this.images = new ConcurrentLinkedQueue<ImageDescriptor>();
this.videos = new ConcurrentLinkedQueue<VideoDescriptor>();
this.sailorsInfoWebsiteURLs = new CopyOnWriteHashMap<>("lock for sailorsInfoWebsiteURLs of event " + id.toString());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
@@ -67,6 +70,9 @@ public abstract class EventBaseImpl implements EventBase {
if (videos == null) {
videos = new ConcurrentLinkedQueue<VideoDescriptor>();
}
if (sailorsInfoWebsiteURLs == null) {
this.sailorsInfoWebsiteURLs = new CopyOnWriteHashMap<>("lock for sailorsInfoWebsiteURLs of event " + id.toString());
}
}
@Override
@@ -134,45 +140,6 @@ public abstract class EventBaseImpl implements EventBase {
this.endDate = endDate;
}
@Override
public Iterable<URL> getImageURLs() {
List<URL> result = new ArrayList<URL>();
for (ImageDescriptor image : images) {
if (!image.hasTag(MediaTagConstants.SPONSOR) && !image.hasTag(MediaTagConstants.LOGO)) {
result.add(image.getURL());
}
}
return result;
}
@Override
public Iterable<URL> getVideoURLs() {
List<URL> result = new ArrayList<URL>();
for(VideoDescriptor video: videos) {
result.add(video.getURL());
}
return result;
}
@Override
public Iterable<URL> getSponsorImageURLs() {
List<URL> result = new ArrayList<URL>();
for(MediaDescriptor media : findMediaWithTag(images, MediaTagConstants.SPONSOR)) {
result.add(media.getURL());
}
return result;
}
@Override
public URL getLogoImageURL() {
URL result = null;
ImageDescriptor media = findImageWithTag(MediaTagConstants.LOGO);
if(media != null) {
result = media.getURL();
}
return result;
}
@Override
public URL getOfficialWebsiteURL() {
return officialWebsiteURL;
@@ -182,15 +149,45 @@ public abstract class EventBaseImpl implements EventBase {
public void setOfficialWebsiteURL(URL officialWebsiteURL) {
this.officialWebsiteURL = officialWebsiteURL;
}
@Override
public URL getSailorsInfoWebsiteURL() {
return sailorsInfoWebsiteURL;
public Map<Locale, URL> getSailorsInfoWebsiteURLs() {
return Collections.unmodifiableMap(sailorsInfoWebsiteURLs);
}
@Override
public void setSailorsInfoWebsiteURLs(Map<Locale, URL> sailorsInfoWebsiteURLs) {
this.sailorsInfoWebsiteURLs.set(sailorsInfoWebsiteURLs);
}
@Override
public void setSailorsInfoWebsiteURL(URL sailorsInfoWebsiteURL) {
this.sailorsInfoWebsiteURL = sailorsInfoWebsiteURL;
public void setSailorsInfoWebsiteURL(Locale locale, URL sailorsInfoWebsiteURL) {
if (sailorsInfoWebsiteURL == null) {
this.sailorsInfoWebsiteURLs.remove(locale);
} else {
this.sailorsInfoWebsiteURLs.put(locale, sailorsInfoWebsiteURL);
}
}
@Override
public boolean hasSailorsInfoWebsiteURL(Locale locale) {
return this.sailorsInfoWebsiteURLs.containsKey(locale);
}
@Override
public URL getSailorsInfoWebsiteURL(Locale locale) {
return this.sailorsInfoWebsiteURLs.get(locale);
}
@Override
public URL getSailorsInfoWebsiteURLOrFallback(Locale locale) {
final URL result;
if (hasSailorsInfoWebsiteURL(locale)) {
result = this.sailorsInfoWebsiteURLs.get(locale);
} else {
result = this.sailorsInfoWebsiteURLs.get(null);
}
return result;
}
@Override
@@ -0,0 +1,44 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.junit.Before;
import org.junit.Test;
import com.sap.sse.concurrent.CopyOnWriteHashMap;
public class CopyOnWriteHashMapSerializationTest {
private CopyOnWriteHashMap<String, String> expected;
@Before
public void setUp() {
expected = new CopyOnWriteHashMap<>();
expected.put("a", "1");
expected.put("b", "2");
}
@Test
public void testSerializationOfCopyOnWriteHashMap() throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream ous = new ObjectOutputStream(baos);
ous.writeObject(expected);
ous.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
@SuppressWarnings("unchecked")
CopyOnWriteHashMap<String, String> deserializedInstance = (CopyOnWriteHashMap<String, String>) ois.readObject();
assertEquals(expected, deserializedInstance);
assertEquals(-1, ois.read(new byte[1]));
ois.close();
}
}
@@ -27,6 +27,8 @@ import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
*/
public interface Series extends SeriesBase {
static public final String DEFAULT_NAME = "Default";
/**
* A series consists of one or more "race columns." Some people would just say "race," but we use the term "race" for
* something that has a single start time and start line; so if each fleet in a series gets their own start for
@@ -647,6 +647,9 @@ public class CandidateFinderImpl implements CandidateFinder {
}
pos.add(po);
}
if (pos.size() != 2){
return true;
}
Bearing diff1 = pos.get(0).getBearingGreatCircle(p)
.getDifferenceTo(pos.get(0).getBearingGreatCircle(pos.get(1)));
Bearing diff2 = pos.get(1).getBearingGreatCircle(p)
@@ -757,9 +760,7 @@ public class CandidateFinderImpl implements CandidateFinder {
Position portLinePosition = race.getOrCreateTrack(posLine.getA()).getEstimatedPosition(t, false);
Position starboardLinePosition = race.getOrCreateTrack(posLine.getB()).getEstimatedPosition(t, false);
distances.add((portLinePosition != null && starboardLinePosition != null) ? p.getDistanceToLine(
portLinePosition, starboardLinePosition) : portLinePosition != null ? p
.getDistance(portLinePosition) : starboardLinePosition != null ? p
.getDistance(portLinePosition) : null);
portLinePosition, starboardLinePosition) : null);
}
break;
case Offset:
@@ -863,6 +864,9 @@ public class CandidateFinderImpl implements CandidateFinder {
}
markPositions.add(estimatedMarkPosition);
}
if (markPositions.size() != 2){
return new Util.Pair<Mark, Mark>(null, null);
}
final List<Leg> legs = race.getRace().getCourse().getLegs();
final int indexOfWaypoint = race.getRace().getCourse().getIndexOfWaypoint(w);
if (indexOfWaypoint < 0) {
+10 -1
View File
@@ -1,10 +1,19 @@
/** Add css rules here for your application. */
* {
.adminConsolePanel, .adminConsolePanel * {
font-family: Arial;
font-size: 12px;
}
body, html {
font-size: 15px;
font-family: 'Open Sans',sans-serif;
margin: 0;
}
body {
font-size: 14px;
}
/** Example rules used by the template application (remove for your app) */
h1 {
font-size: 2em;
@@ -22,6 +22,10 @@
position: absolute;
top: -1000px; }
html {
font-size: 15px;
}
body {
background: #fff;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="DE_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
<g>
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
<g>
<g>
<path fill="#FFFFFF" d="M30.129,19.783c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.225c1.625-0.066,2.232-1.035,4.193-1.035
c1.943,0,2.513,1.035,4.207,0.996c1.744-0.027,2.842-1.559,3.89-3.127c1.255-1.779,1.759-3.533,1.779-3.623
C33.508,24.923,30.162,23.647,30.129,19.783z"/>
<path fill="#FFFFFF" d="M26.929,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
c-0.806,0.942-1.526,2.486-1.34,3.938C24.558,12.204,26.017,11.382,26.929,10.306z"/>
</g>
</g>
<g>
<path fill="#FFFFFF" d="M53.681,31.502h-2.271l-1.244-3.908h-4.324l-1.185,3.908h-2.211l4.284-13.307h2.646L53.681,31.502z
M49.792,25.954l-1.125-3.475c-0.119-0.355-0.342-1.191-0.671-2.508h-0.04c-0.131,0.566-0.342,1.401-0.632,2.508l-1.105,3.475
H49.792z"/>
<path fill="#FFFFFF" d="M64.698,26.586c0,1.633-0.441,2.922-1.323,3.869c-0.79,0.844-1.771,1.264-2.942,1.264
c-1.264,0-2.172-0.453-2.725-1.361h-0.04v5.055h-2.132V25.066c0-1.027-0.027-2.08-0.079-3.16h1.875l0.119,1.521h0.04
c0.711-1.146,1.79-1.719,3.238-1.719c1.132,0,2.077,0.447,2.833,1.343S64.698,25.125,64.698,26.586z M62.526,26.665
c0-0.935-0.21-1.704-0.632-2.31c-0.461-0.633-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.175-1.431,0.523
c-0.428,0.349-0.708,0.806-0.839,1.372c-0.066,0.264-0.099,0.48-0.099,0.651v1.6c0,0.698,0.214,1.286,0.642,1.767
s0.984,0.721,1.668,0.721c0.803,0,1.428-0.309,1.875-0.928S62.526,27.679,62.526,26.665z"/>
<path fill="#FFFFFF" d="M75.736,26.586c0,1.633-0.441,2.922-1.324,3.869c-0.789,0.844-1.77,1.264-2.941,1.264
c-1.264,0-2.172-0.453-2.725-1.361h-0.039v5.055h-2.132V25.066c0-1.027-0.027-2.08-0.079-3.16h1.875l0.119,1.521h0.04
c0.711-1.146,1.79-1.719,3.239-1.719c1.131,0,2.076,0.447,2.834,1.343C75.357,23.947,75.736,25.125,75.736,26.586z M73.564,26.665
c0-0.935-0.211-1.704-0.633-2.31c-0.461-0.633-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.175-1.432,0.523
s-0.708,0.806-0.839,1.372c-0.065,0.264-0.099,0.48-0.099,0.651v1.6c0,0.698,0.214,1.286,0.641,1.767
c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.309,1.875-0.928S73.564,27.679,73.564,26.665z"/>
<path fill="#FFFFFF" d="M88.076,27.771c0,1.131-0.395,2.053-1.182,2.764c-0.867,0.777-2.076,1.164-3.625,1.164
c-1.432,0-2.582-0.275-3.449-0.828l0.494-1.777c0.934,0.566,1.961,0.85,3.08,0.85c0.805,0,1.43-0.182,1.877-0.545
c0.447-0.361,0.672-0.848,0.672-1.453c0-0.541-0.186-0.996-0.553-1.365c-0.369-0.369-0.98-0.711-1.836-1.028
c-2.33-0.87-3.496-2.142-3.496-3.816c0-1.094,0.408-1.991,1.225-2.69s1.902-1.048,3.258-1.048c1.211,0,2.219,0.211,3.021,0.632
l-0.533,1.738c-0.75-0.408-1.6-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.758,0.553c-0.355,0.329-0.533,0.73-0.533,1.204
c0,0.527,0.205,0.961,0.613,1.303c0.355,0.316,1,0.658,1.934,1.027c1.146,0.461,1.988,1,2.527,1.619
C87.807,26.08,88.076,26.85,88.076,27.771z"/>
<path fill="#FFFFFF" d="M95.123,23.506h-2.35v4.66c0,1.184,0.416,1.777,1.244,1.777c0.383,0,0.697-0.033,0.949-0.1l0.059,1.619
c-0.422,0.158-0.975,0.236-1.658,0.236c-0.844,0-1.502-0.256-1.975-0.77c-0.475-0.514-0.711-1.375-0.711-2.586v-4.838h-1.402v-1.6
h1.402v-1.757l2.092-0.632v2.389h2.35V23.506z"/>
<path fill="#FFFFFF" d="M105.727,26.625c0,1.475-0.422,2.686-1.264,3.633c-0.881,0.975-2.053,1.461-3.514,1.461
c-1.41,0-2.531-0.467-3.367-1.4c-0.836-0.936-1.254-2.113-1.254-3.535c0-1.486,0.432-2.705,1.293-3.652
c0.863-0.947,2.025-1.422,3.486-1.422c1.408,0,2.539,0.468,3.395,1.402C105.318,24.02,105.727,25.191,105.727,26.625z
M103.516,26.695c0-0.885-0.191-1.645-0.572-2.277c-0.447-0.766-1.086-1.148-1.916-1.148c-0.855,0-1.508,0.383-1.955,1.148
c-0.381,0.633-0.572,1.405-0.572,2.316c0,0.885,0.191,1.645,0.572,2.277c0.461,0.766,1.105,1.148,1.936,1.148
c0.816,0,1.455-0.391,1.916-1.168C103.318,28.346,103.516,27.579,103.516,26.695z"/>
<path fill="#FFFFFF" d="M112.656,23.782c-0.211-0.04-0.434-0.06-0.67-0.06c-0.752,0-1.33,0.283-1.738,0.85
c-0.355,0.5-0.533,1.133-0.533,1.896v5.034h-2.133l0.02-6.574c0-1.105-0.025-2.113-0.078-3.021h1.855l0.08,1.836h0.059
c0.223-0.631,0.578-1.138,1.066-1.52c0.473-0.342,0.986-0.514,1.539-0.514c0.197,0,0.375,0.014,0.533,0.039V23.782z"/>
<path fill="#FFFFFF" d="M122.193,26.25c0,0.383-0.027,0.705-0.08,0.968h-6.396c0.025,0.948,0.336,1.673,0.928,2.173
c0.539,0.447,1.238,0.67,2.094,0.67c0.947,0,1.809-0.15,2.586-0.453l0.336,1.48c-0.908,0.395-1.982,0.592-3.219,0.592
c-1.488,0-2.656-0.438-3.504-1.312c-0.85-0.875-1.273-2.051-1.273-3.524c0-1.448,0.395-2.652,1.184-3.613
c0.83-1.026,1.949-1.54,3.357-1.54c1.381,0,2.428,0.514,3.139,1.54C121.91,24.046,122.193,25.053,122.193,26.25z M120.16,25.697
c0.012-0.631-0.127-1.178-0.416-1.639c-0.367-0.592-0.934-0.889-1.697-0.889c-0.697,0-1.264,0.29-1.697,0.869
c-0.355,0.461-0.566,1.014-0.633,1.658H120.16z"/>
</g>
<g>
<g>
<path fill="#FFFFFF" d="M47.427,13.432h-3.715V6.894h1.048v5.655h2.667V13.432z"/>
<path fill="#FFFFFF" d="M52.365,13.432h-0.941l-0.077-0.543h-0.029c-0.323,0.433-0.782,0.65-1.377,0.65
c-0.446,0-0.806-0.143-1.077-0.427c-0.246-0.258-0.368-0.579-0.368-0.96c0-0.576,0.24-1.015,0.723-1.319
c0.481-0.304,1.159-0.453,2.032-0.446v-0.087c0-0.621-0.326-0.931-0.978-0.931c-0.465,0-0.875,0.117-1.229,0.349L48.83,9.028
c0.438-0.271,0.979-0.407,1.617-0.407c1.233,0,1.85,0.65,1.85,1.95v1.736C52.296,12.778,52.32,13.154,52.365,13.432z
M51.278,11.812v-0.727c-1.157-0.02-1.735,0.297-1.735,0.95c0,0.246,0.067,0.43,0.202,0.553c0.135,0.123,0.306,0.184,0.511,0.184
c0.231,0,0.445-0.073,0.642-0.218s0.317-0.331,0.362-0.558C51.272,11.944,51.278,11.883,51.278,11.812z"/>
<path fill="#FFFFFF" d="M58.32,13.432h-0.931l-0.049-0.757h-0.029c-0.297,0.576-0.802,0.864-1.513,0.864
c-0.569,0-1.041-0.223-1.416-0.669s-0.562-1.025-0.562-1.736c0-0.763,0.203-1.381,0.61-1.853c0.395-0.44,0.88-0.66,1.455-0.66
c0.634,0,1.077,0.213,1.329,0.64h0.02V6.554h1.048v5.607C58.282,12.62,58.294,13.043,58.32,13.432z M57.234,11.443v-0.786
c0-0.136-0.01-0.246-0.029-0.33c-0.059-0.252-0.186-0.464-0.38-0.635c-0.195-0.171-0.429-0.257-0.701-0.257
c-0.39,0-0.696,0.155-0.921,0.466c-0.224,0.311-0.336,0.708-0.336,1.193c0,0.466,0.107,0.844,0.322,1.135
c0.227,0.31,0.532,0.465,0.915,0.465c0.344,0,0.62-0.129,0.828-0.388C57.133,12.067,57.234,11.779,57.234,11.443z"/>
<path fill="#FFFFFF" d="M64.025,10.852c0,0.188-0.014,0.346-0.039,0.475h-3.143c0.013,0.466,0.164,0.821,0.455,1.067
c0.266,0.22,0.608,0.33,1.028,0.33c0.466,0,0.89-0.074,1.271-0.223l0.164,0.728c-0.446,0.194-0.973,0.291-1.581,0.291
c-0.73,0-1.305-0.215-1.722-0.645s-0.625-1.007-0.625-1.731c0-0.711,0.193-1.303,0.582-1.775
c0.407-0.504,0.956-0.756,1.648-0.756c0.679,0,1.193,0.252,1.542,0.756C63.885,9.769,64.025,10.263,64.025,10.852z M63.025,10.58
c0.007-0.311-0.062-0.579-0.203-0.805c-0.182-0.291-0.459-0.437-0.834-0.437c-0.343,0-0.621,0.142-0.835,0.427
c-0.174,0.227-0.277,0.498-0.31,0.815H63.025z"/>
<path fill="#FFFFFF" d="M69.641,13.432h-1.048v-2.7c0-0.832-0.316-1.248-0.95-1.248c-0.311,0-0.562,0.114-0.757,0.343
c-0.193,0.229-0.291,0.499-0.291,0.808v2.796h-1.048v-3.366c0-0.414-0.013-0.863-0.038-1.349h0.921l0.049,0.737h0.029
c0.122-0.229,0.304-0.418,0.543-0.569c0.284-0.176,0.602-0.265,0.95-0.265c0.44,0,0.806,0.142,1.097,0.427
c0.361,0.349,0.543,0.87,0.543,1.562V13.432z"/>
<path fill="#FFFFFF" d="M75.479,7.311c0,0.188-0.061,0.339-0.184,0.456c-0.123,0.117-0.281,0.175-0.475,0.175
c-0.176,0-0.322-0.06-0.441-0.179c-0.121-0.12-0.18-0.27-0.18-0.451s0.061-0.33,0.184-0.446S74.658,6.69,74.84,6.69
c0.18,0,0.332,0.059,0.455,0.175S75.479,7.13,75.479,7.311z M75.363,13.432h-1.049V8.717h1.049V13.432z"/>
<path fill="#FFFFFF" d="M83.977,13.432h-1.027V10.79c0-0.871-0.299-1.306-0.893-1.306c-0.285,0-0.514,0.108-0.684,0.324
c-0.172,0.216-0.258,0.469-0.258,0.759v2.864h-1.027v-2.777c0-0.355-0.074-0.639-0.219-0.852
c-0.146-0.213-0.361-0.319-0.645-0.319c-0.285,0-0.518,0.116-0.699,0.348c-0.182,0.232-0.271,0.497-0.271,0.793v2.806h-1.029
v-3.366c0-0.414-0.012-0.863-0.037-1.349h0.9l0.049,0.717h0.029c0.324-0.542,0.803-0.814,1.436-0.814
c0.641,0,1.074,0.294,1.301,0.882h0.02c0.148-0.246,0.332-0.443,0.553-0.591c0.277-0.194,0.598-0.291,0.959-0.291
c0.422,0,0.768,0.142,1.039,0.427c0.336,0.355,0.504,0.886,0.504,1.591V13.432z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="US_UK_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
<g>
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
<g>
<g>
<path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036
c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623
C33.507,24.924,30.161,23.647,30.128,19.784z"/>
<path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/>
</g>
</g>
<g>
<path fill="#FFFFFF" d="M53.645,31.504h-2.271l-1.244-3.909h-4.324l-1.185,3.909h-2.211l4.284-13.308h2.646L53.645,31.504z
M49.755,25.955L48.63,22.48c-0.119-0.355-0.342-1.191-0.671-2.507h-0.04c-0.131,0.566-0.342,1.402-0.632,2.507l-1.105,3.475
H49.755z"/>
<path fill="#FFFFFF" d="M64.662,26.588c0,1.632-0.441,2.922-1.323,3.869c-0.79,0.843-1.771,1.264-2.942,1.264
c-1.264,0-2.172-0.454-2.725-1.362h-0.04v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.711-1.146,1.79-1.718,3.238-1.718c1.132,0,2.077,0.447,2.833,1.342C64.284,23.949,64.662,25.127,64.662,26.588z M62.49,26.666
c0-0.934-0.21-1.704-0.632-2.31c-0.461-0.632-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.176-1.431,0.523
c-0.428,0.35-0.708,0.807-0.839,1.373c-0.066,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.642,1.768
s0.984,0.721,1.668,0.721c0.803,0,1.428-0.31,1.875-0.928C62.266,28.496,62.49,27.68,62.49,26.666z"/>
<path fill="#FFFFFF" d="M75.699,26.588c0,1.632-0.441,2.922-1.324,3.869c-0.789,0.843-1.77,1.264-2.941,1.264
c-1.264,0-2.172-0.454-2.724-1.362H68.67v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.71-1.146,1.789-1.718,3.238-1.718c1.131,0,2.076,0.447,2.834,1.342C75.32,23.949,75.699,25.127,75.699,26.588z M73.527,26.666
c0-0.934-0.211-1.704-0.633-2.31c-0.461-0.632-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.176-1.432,0.523
c-0.428,0.35-0.707,0.807-0.838,1.373c-0.065,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.64,1.768
c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.31,1.875-0.928C73.303,28.496,73.527,27.68,73.527,26.666z"/>
<path fill="#FFFFFF" d="M88.039,27.772c0,1.132-0.393,2.053-1.182,2.764c-0.867,0.777-2.074,1.165-3.625,1.165
c-1.432,0-2.58-0.276-3.449-0.829l0.494-1.777c0.936,0.566,1.963,0.85,3.082,0.85c0.803,0,1.428-0.182,1.877-0.544
c0.447-0.362,0.67-0.848,0.67-1.454c0-0.54-0.184-0.995-0.553-1.364c-0.367-0.369-0.98-0.712-1.836-1.029
c-2.33-0.869-3.494-2.142-3.494-3.816c0-1.094,0.408-1.991,1.225-2.689c0.814-0.699,1.9-1.048,3.258-1.048
c1.211,0,2.217,0.211,3.02,0.632l-0.533,1.738c-0.75-0.408-1.598-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.756,0.553
c-0.355,0.329-0.533,0.73-0.533,1.205c0,0.526,0.203,0.961,0.611,1.303c0.355,0.316,1,0.658,1.936,1.027
c1.145,0.461,1.986,1,2.527,1.618C87.77,26.081,88.039,26.852,88.039,27.772z"/>
<path fill="#FFFFFF" d="M95.088,23.508h-2.35v4.659c0,1.185,0.414,1.777,1.244,1.777c0.381,0,0.697-0.033,0.947-0.099l0.059,1.619
c-0.42,0.157-0.973,0.236-1.658,0.236c-0.842,0-1.5-0.257-1.975-0.77c-0.473-0.514-0.711-1.376-0.711-2.587v-4.837h-1.4v-1.6h1.4
v-1.757l2.094-0.632v2.389h2.35V23.508z"/>
<path fill="#FFFFFF" d="M105.691,26.627c0,1.475-0.422,2.686-1.264,3.633c-0.883,0.975-2.055,1.461-3.516,1.461
c-1.408,0-2.529-0.467-3.365-1.401s-1.254-2.113-1.254-3.534c0-1.487,0.43-2.705,1.293-3.652c0.861-0.948,2.023-1.422,3.484-1.422
c1.408,0,2.541,0.467,3.396,1.402C105.283,24.021,105.691,25.192,105.691,26.627z M103.479,26.696
c0-0.885-0.189-1.644-0.572-2.277c-0.447-0.766-1.086-1.148-1.914-1.148c-0.857,0-1.508,0.383-1.955,1.148
c-0.383,0.634-0.572,1.405-0.572,2.317c0,0.885,0.189,1.644,0.572,2.276c0.461,0.766,1.105,1.148,1.936,1.148
c0.814,0,1.453-0.39,1.914-1.168C103.281,28.347,103.479,27.58,103.479,26.696z"/>
<path fill="#FFFFFF" d="M112.621,23.783c-0.211-0.039-0.436-0.059-0.672-0.059c-0.75,0-1.33,0.283-1.738,0.85
c-0.355,0.5-0.533,1.132-0.533,1.895v5.035h-2.131l0.02-6.574c0-1.106-0.027-2.113-0.08-3.021h1.857l0.078,1.836h0.059
c0.225-0.631,0.58-1.139,1.066-1.52c0.475-0.343,0.988-0.514,1.541-0.514c0.197,0,0.375,0.014,0.533,0.039V23.783z"/>
<path fill="#FFFFFF" d="M122.156,26.252c0,0.382-0.025,0.704-0.078,0.967h-6.396c0.025,0.948,0.334,1.673,0.928,2.173
c0.539,0.447,1.236,0.671,2.092,0.671c0.947,0,1.811-0.151,2.588-0.454l0.334,1.48c-0.908,0.396-1.98,0.593-3.217,0.593
c-1.488,0-2.656-0.438-3.506-1.313c-0.848-0.875-1.273-2.05-1.273-3.524c0-1.447,0.395-2.652,1.186-3.613
c0.828-1.026,1.947-1.539,3.355-1.539c1.383,0,2.43,0.513,3.141,1.539C121.873,24.047,122.156,25.055,122.156,26.252z
M120.123,25.699c0.014-0.632-0.125-1.178-0.414-1.639c-0.369-0.593-0.936-0.889-1.699-0.889c-0.697,0-1.264,0.289-1.697,0.869
c-0.355,0.461-0.566,1.014-0.631,1.658H120.123z"/>
</g>
<g>
<g>
<path fill="#FFFFFF" d="M49.05,10.009c0,1.177-0.353,2.063-1.058,2.658c-0.653,0.549-1.581,0.824-2.783,0.824
c-0.596,0-1.106-0.026-1.533-0.078V6.982c0.557-0.09,1.157-0.136,1.805-0.136c1.145,0,2.008,0.249,2.59,0.747
C48.723,8.156,49.05,8.961,49.05,10.009z M47.945,10.038c0-0.763-0.202-1.348-0.606-1.756c-0.404-0.407-0.994-0.611-1.771-0.611
c-0.33,0-0.611,0.022-0.844,0.068v4.889c0.129,0.02,0.365,0.029,0.708,0.029c0.802,0,1.421-0.223,1.857-0.669
S47.945,10.892,47.945,10.038z"/>
<path fill="#FFFFFF" d="M54.909,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.009,0.718-1.727,0.718
c-0.692,0-1.243-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.712-0.698
c0.692,0,1.248,0.229,1.669,0.688C54.708,9.757,54.909,10.333,54.909,11.037z M53.822,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.22-0.376-0.533-0.564-0.94-0.564c-0.421,0-0.741,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.714-0.191,0.94-0.574
C53.725,11.882,53.822,11.506,53.822,11.071z"/>
<path fill="#FFFFFF" d="M62.765,8.719l-1.475,4.714h-0.96l-0.611-2.047c-0.155-0.511-0.281-1.019-0.379-1.523h-0.019
c-0.091,0.518-0.217,1.025-0.379,1.523l-0.649,2.047h-0.971l-1.387-4.714h1.077l0.533,2.241c0.129,0.53,0.235,1.035,0.32,1.513
h0.019c0.078-0.394,0.207-0.896,0.389-1.503l0.669-2.25h0.854l0.641,2.202c0.155,0.537,0.281,1.054,0.378,1.552h0.029
c0.071-0.485,0.178-1.002,0.32-1.552l0.572-2.202H62.765z"/>
<path fill="#FFFFFF" d="M68.198,13.433H67.15v-2.7c0-0.832-0.316-1.248-0.95-1.248c-0.311,0-0.562,0.114-0.757,0.343
c-0.193,0.229-0.291,0.499-0.291,0.808v2.796h-1.048v-3.366c0-0.414-0.013-0.863-0.038-1.349h0.921l0.049,0.737h0.029
c0.122-0.229,0.304-0.418,0.543-0.569c0.284-0.176,0.602-0.265,0.95-0.265c0.44,0,0.806,0.142,1.097,0.427
c0.362,0.349,0.543,0.87,0.543,1.562V13.433z"/>
<path fill="#FFFFFF" d="M71.088,13.433h-1.047V6.556h1.047V13.433z"/>
<path fill="#FFFFFF" d="M77.258,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.01,0.718-1.727,0.718
c-0.693,0-1.244-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.711-0.698
c0.693,0,1.248,0.229,1.67,0.688C77.057,9.757,77.258,10.333,77.258,11.037z M76.17,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.219-0.376-0.533-0.564-0.939-0.564c-0.422,0-0.742,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.713-0.191,0.939-0.574
C76.074,11.882,76.17,11.506,76.17,11.071z"/>
<path fill="#FFFFFF" d="M82.33,13.433h-0.941l-0.078-0.543h-0.029c-0.322,0.433-0.781,0.65-1.377,0.65
c-0.445,0-0.805-0.143-1.076-0.427c-0.246-0.258-0.369-0.579-0.369-0.96c0-0.576,0.24-1.015,0.723-1.319
c0.482-0.304,1.16-0.453,2.033-0.446V10.3c0-0.621-0.326-0.931-0.979-0.931c-0.465,0-0.875,0.117-1.229,0.349l-0.213-0.688
c0.438-0.271,0.979-0.407,1.617-0.407c1.232,0,1.85,0.65,1.85,1.95v1.736C82.262,12.78,82.285,13.155,82.33,13.433z
M81.242,11.813v-0.727c-1.156-0.02-1.734,0.297-1.734,0.95c0,0.246,0.066,0.43,0.201,0.553c0.135,0.123,0.307,0.184,0.512,0.184
c0.23,0,0.445-0.073,0.641-0.218c0.197-0.146,0.318-0.331,0.363-0.558C81.236,11.946,81.242,11.884,81.242,11.813z"/>
<path fill="#FFFFFF" d="M88.285,13.433h-0.93l-0.049-0.757h-0.029c-0.297,0.576-0.803,0.864-1.514,0.864
c-0.568,0-1.041-0.223-1.416-0.669s-0.562-1.025-0.562-1.736c0-0.763,0.203-1.381,0.611-1.853c0.395-0.44,0.879-0.66,1.455-0.66
c0.633,0,1.076,0.213,1.328,0.64h0.02V6.556h1.049v5.607C88.248,12.622,88.26,13.045,88.285,13.433z M87.199,11.445v-0.786
c0-0.136-0.01-0.246-0.029-0.33c-0.059-0.252-0.186-0.464-0.379-0.635c-0.195-0.171-0.43-0.257-0.701-0.257
c-0.391,0-0.697,0.155-0.922,0.466c-0.223,0.311-0.336,0.708-0.336,1.193c0,0.466,0.107,0.844,0.322,1.135
c0.227,0.31,0.533,0.465,0.916,0.465c0.344,0,0.619-0.129,0.828-0.388C87.1,12.069,87.199,11.781,87.199,11.445z"/>
<path fill="#FFFFFF" d="M97.248,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.008,0.718-1.727,0.718
c-0.691,0-1.242-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.713-0.698
c0.691,0,1.248,0.229,1.668,0.688C97.047,9.757,97.248,10.333,97.248,11.037z M96.162,11.071c0-0.435-0.094-0.808-0.281-1.119
c-0.221-0.376-0.533-0.564-0.941-0.564c-0.42,0-0.74,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.715-0.191,0.941-0.574
C96.064,11.882,96.162,11.506,96.162,11.071z"/>
<path fill="#FFFFFF" d="M102.883,13.433h-1.047v-2.7c0-0.832-0.316-1.248-0.951-1.248c-0.311,0-0.562,0.114-0.756,0.343
s-0.291,0.499-0.291,0.808v2.796h-1.049v-3.366c0-0.414-0.012-0.863-0.037-1.349h0.92l0.049,0.737h0.029
c0.123-0.229,0.305-0.418,0.543-0.569c0.285-0.176,0.602-0.265,0.951-0.265c0.439,0,0.805,0.142,1.096,0.427
c0.363,0.349,0.543,0.87,0.543,1.562V13.433z"/>
<path fill="#FFFFFF" d="M109.936,9.504h-1.154v2.29c0,0.582,0.205,0.873,0.611,0.873c0.188,0,0.344-0.016,0.467-0.049
l0.027,0.795c-0.207,0.078-0.479,0.117-0.814,0.117c-0.414,0-0.736-0.126-0.969-0.378c-0.234-0.252-0.35-0.676-0.35-1.271V9.504
h-0.689V8.719h0.689V7.855l1.027-0.31v1.173h1.154V9.504z"/>
<path fill="#FFFFFF" d="M115.484,13.433h-1.049v-2.68c0-0.845-0.316-1.268-0.949-1.268c-0.486,0-0.818,0.245-1,0.735
c-0.031,0.103-0.049,0.229-0.049,0.377v2.835h-1.047V6.556h1.047v2.841h0.02c0.33-0.517,0.803-0.775,1.416-0.775
c0.434,0,0.793,0.142,1.078,0.427c0.355,0.355,0.533,0.883,0.533,1.581V13.433z"/>
<path fill="#FFFFFF" d="M121.207,10.853c0,0.188-0.014,0.346-0.039,0.475h-3.143c0.014,0.466,0.164,0.821,0.455,1.067
c0.266,0.22,0.609,0.33,1.029,0.33c0.465,0,0.889-0.074,1.271-0.223l0.164,0.728c-0.447,0.194-0.973,0.291-1.582,0.291
c-0.73,0-1.305-0.215-1.721-0.645c-0.418-0.43-0.625-1.007-0.625-1.731c0-0.711,0.193-1.303,0.582-1.775
c0.406-0.504,0.955-0.756,1.648-0.756c0.678,0,1.193,0.252,1.541,0.756C121.068,9.77,121.207,10.265,121.207,10.853z
M120.207,10.582c0.008-0.311-0.061-0.579-0.203-0.805c-0.182-0.291-0.459-0.437-0.834-0.437c-0.342,0-0.621,0.142-0.834,0.427
c-0.174,0.227-0.277,0.498-0.311,0.815H120.207z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="RU_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
<g>
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
<g>
<g>
<path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036
c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623
C33.507,24.924,30.161,23.647,30.128,19.784z"/>
<path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/>
</g>
</g>
<g>
<path fill="#FFFFFF" d="M53.645,31.504h-2.271l-1.244-3.909h-4.324l-1.185,3.909h-2.211l4.284-13.308h2.646L53.645,31.504z
M49.755,25.955L48.63,22.48c-0.119-0.355-0.342-1.191-0.671-2.507h-0.04c-0.131,0.566-0.342,1.402-0.632,2.507l-1.105,3.475
H49.755z"/>
<path fill="#FFFFFF" d="M64.662,26.588c0,1.632-0.441,2.922-1.323,3.869c-0.79,0.843-1.771,1.264-2.942,1.264
c-1.264,0-2.172-0.454-2.725-1.362h-0.04v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.711-1.146,1.79-1.718,3.238-1.718c1.132,0,2.077,0.447,2.833,1.342C64.284,23.949,64.662,25.127,64.662,26.588z M62.49,26.666
c0-0.934-0.21-1.704-0.632-2.31c-0.461-0.632-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.176-1.431,0.523
c-0.428,0.35-0.708,0.807-0.839,1.373c-0.066,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.642,1.768
s0.984,0.721,1.668,0.721c0.803,0,1.428-0.31,1.875-0.928C62.266,28.496,62.49,27.68,62.49,26.666z"/>
<path fill="#FFFFFF" d="M75.699,26.588c0,1.632-0.441,2.922-1.324,3.869c-0.789,0.843-1.77,1.264-2.941,1.264
c-1.264,0-2.172-0.454-2.724-1.362H68.67v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
c0.71-1.146,1.789-1.718,3.238-1.718c1.131,0,2.076,0.447,2.834,1.342C75.32,23.949,75.699,25.127,75.699,26.588z M73.527,26.666
c0-0.934-0.211-1.704-0.633-2.31c-0.461-0.632-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.176-1.432,0.523
c-0.428,0.35-0.707,0.807-0.838,1.373c-0.065,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.64,1.768
c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.31,1.875-0.928C73.303,28.496,73.527,27.68,73.527,26.666z"/>
<path fill="#FFFFFF" d="M88.039,27.772c0,1.132-0.393,2.053-1.182,2.764c-0.867,0.777-2.074,1.165-3.625,1.165
c-1.432,0-2.58-0.276-3.449-0.829l0.494-1.777c0.936,0.566,1.963,0.85,3.082,0.85c0.803,0,1.428-0.182,1.877-0.544
c0.447-0.362,0.67-0.848,0.67-1.454c0-0.54-0.184-0.995-0.553-1.364c-0.367-0.369-0.98-0.712-1.836-1.029
c-2.33-0.869-3.494-2.142-3.494-3.816c0-1.094,0.408-1.991,1.225-2.689c0.814-0.699,1.9-1.048,3.258-1.048
c1.211,0,2.217,0.211,3.02,0.632l-0.533,1.738c-0.75-0.408-1.598-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.756,0.553
c-0.355,0.329-0.533,0.73-0.533,1.205c0,0.526,0.203,0.961,0.611,1.303c0.355,0.316,1,0.658,1.936,1.027
c1.145,0.461,1.986,1,2.527,1.618C87.77,26.081,88.039,26.852,88.039,27.772z"/>
<path fill="#FFFFFF" d="M95.088,23.508h-2.35v4.659c0,1.185,0.414,1.777,1.244,1.777c0.381,0,0.697-0.033,0.947-0.099l0.059,1.619
c-0.42,0.157-0.973,0.236-1.658,0.236c-0.842,0-1.5-0.257-1.975-0.77c-0.473-0.514-0.711-1.376-0.711-2.587v-4.837h-1.4v-1.6h1.4
v-1.757l2.094-0.632v2.389h2.35V23.508z"/>
<path fill="#FFFFFF" d="M105.691,26.627c0,1.475-0.422,2.686-1.264,3.633c-0.883,0.975-2.055,1.461-3.516,1.461
c-1.408,0-2.529-0.467-3.365-1.401s-1.254-2.113-1.254-3.534c0-1.487,0.43-2.705,1.293-3.652c0.861-0.948,2.023-1.422,3.484-1.422
c1.408,0,2.541,0.467,3.396,1.402C105.283,24.021,105.691,25.192,105.691,26.627z M103.479,26.696
c0-0.885-0.189-1.644-0.572-2.277c-0.447-0.766-1.086-1.148-1.914-1.148c-0.857,0-1.508,0.383-1.955,1.148
c-0.383,0.634-0.572,1.405-0.572,2.317c0,0.885,0.189,1.644,0.572,2.276c0.461,0.766,1.105,1.148,1.936,1.148
c0.814,0,1.453-0.39,1.914-1.168C103.281,28.347,103.479,27.58,103.479,26.696z"/>
<path fill="#FFFFFF" d="M112.621,23.783c-0.211-0.039-0.436-0.059-0.672-0.059c-0.75,0-1.33,0.283-1.738,0.85
c-0.355,0.5-0.533,1.132-0.533,1.895v5.035h-2.131l0.02-6.574c0-1.106-0.027-2.113-0.08-3.021h1.857l0.078,1.836h0.059
c0.225-0.631,0.58-1.139,1.066-1.52c0.475-0.343,0.988-0.514,1.541-0.514c0.197,0,0.375,0.014,0.533,0.039V23.783z"/>
<path fill="#FFFFFF" d="M122.156,26.252c0,0.382-0.025,0.704-0.078,0.967h-6.396c0.025,0.948,0.334,1.673,0.928,2.173
c0.539,0.447,1.236,0.671,2.092,0.671c0.947,0,1.811-0.151,2.588-0.454l0.334,1.48c-0.908,0.396-1.98,0.593-3.217,0.593
c-1.488,0-2.656-0.438-3.506-1.313c-0.848-0.875-1.273-2.05-1.273-3.524c0-1.447,0.395-2.652,1.186-3.613
c0.828-1.026,1.947-1.539,3.355-1.539c1.383,0,2.43,0.513,3.141,1.539C121.873,24.047,122.156,25.055,122.156,26.252z
M120.123,25.699c0.014-0.632-0.125-1.178-0.414-1.639c-0.369-0.593-0.936-0.889-1.699-0.889c-0.697,0-1.264,0.289-1.697,0.869
c-0.355,0.461-0.566,1.014-0.631,1.658H120.123z"/>
</g>
<g>
<g>
<path fill="#FFFFFF" d="M43.424,7.273c0.227-0.136,0.483-0.25,0.771-0.344c0.287-0.094,0.625-0.141,1.014-0.141
c0.627,0,1.121,0.149,1.483,0.446s0.543,0.698,0.543,1.203c0,0.401-0.121,0.737-0.363,1.009s-0.552,0.453-0.927,0.543v0.029
c0.207,0.033,0.403,0.089,0.587,0.17c0.185,0.081,0.347,0.189,0.485,0.325c0.139,0.136,0.249,0.294,0.33,0.476
c0.08,0.181,0.121,0.381,0.121,0.602c0,0.362-0.073,0.666-0.219,0.912s-0.336,0.446-0.572,0.602
c-0.235,0.155-0.499,0.267-0.79,0.334s-0.582,0.102-0.873,0.102c-0.311,0-0.618-0.033-0.922-0.097s-0.585-0.171-0.844-0.32
l0.262-0.805c0.168,0.084,0.385,0.165,0.65,0.243c0.265,0.078,0.533,0.116,0.805,0.116c0.446,0,0.791-0.1,1.033-0.3
c0.242-0.201,0.364-0.469,0.364-0.805c0-0.227-0.049-0.412-0.146-0.558c-0.098-0.146-0.224-0.26-0.379-0.345
c-0.155-0.084-0.328-0.142-0.519-0.174c-0.191-0.032-0.38-0.049-0.567-0.049h-0.437V9.65h0.437c0.2,0,0.386-0.025,0.558-0.078
c0.171-0.051,0.32-0.124,0.446-0.218s0.225-0.206,0.296-0.335c0.07-0.129,0.106-0.275,0.106-0.437
c0-0.291-0.104-0.519-0.311-0.684c-0.207-0.165-0.485-0.248-0.834-0.248c-0.239,0-0.479,0.039-0.718,0.116
c-0.239,0.078-0.453,0.162-0.641,0.252L43.424,7.273z"/>
<path fill="#FFFFFF" d="M51.755,13.433l-0.077-0.543h-0.029c-0.316,0.433-0.775,0.65-1.377,0.65
c-0.214,0-0.407-0.036-0.582-0.107s-0.327-0.168-0.456-0.291c-0.13-0.123-0.229-0.268-0.301-0.437
c-0.071-0.168-0.106-0.353-0.106-0.553c0-0.588,0.239-1.03,0.718-1.324c0.479-0.294,1.157-0.441,2.037-0.441V10.3
c0-0.621-0.326-0.931-0.978-0.931c-0.465,0-0.875,0.117-1.229,0.349l-0.213-0.688c0.433-0.271,0.972-0.407,1.617-0.407
c1.233,0,1.85,0.65,1.85,1.95v1.736c0,0.485,0.023,0.86,0.068,1.125H51.755z M51.61,11.086c-0.585,0-1.021,0.074-1.307,0.223
c-0.286,0.149-0.429,0.392-0.429,0.728c0,0.246,0.067,0.43,0.202,0.553c0.135,0.123,0.306,0.184,0.512,0.184
c0.135,0,0.263-0.024,0.386-0.073c0.122-0.048,0.229-0.115,0.322-0.199c0.094-0.084,0.169-0.186,0.228-0.306
c0.058-0.12,0.086-0.247,0.086-0.383V11.086z"/>
<path fill="#FFFFFF" d="M57.683,8.719v0.863h-1.96v3.851h-1.047V8.719H57.683z"/>
<path fill="#FFFFFF" d="M63.677,11.018c0,0.375-0.052,0.718-0.155,1.028c-0.104,0.311-0.247,0.576-0.432,0.795
c-0.184,0.22-0.404,0.392-0.659,0.514c-0.256,0.123-0.538,0.185-0.849,0.185c-0.621,0-1.067-0.223-1.339-0.669h-0.02v2.483
h-1.048v-5.083c0-0.252-0.003-0.506-0.01-0.762c-0.006-0.255-0.016-0.519-0.028-0.791h0.921l0.059,0.747h0.02
c0.349-0.562,0.879-0.844,1.591-0.844c0.277,0,0.535,0.058,0.771,0.174c0.236,0.117,0.441,0.28,0.616,0.49
c0.175,0.21,0.312,0.462,0.412,0.757C63.627,10.337,63.677,10.662,63.677,11.018z M62.611,11.057
c0-0.233-0.028-0.448-0.083-0.645s-0.136-0.365-0.242-0.504s-0.236-0.249-0.388-0.33c-0.152-0.081-0.322-0.121-0.51-0.121
c-0.148,0-0.294,0.033-0.437,0.097s-0.267,0.152-0.373,0.262c-0.107,0.11-0.192,0.243-0.257,0.398
c-0.065,0.155-0.098,0.32-0.098,0.495v0.786c0,0.174,0.027,0.336,0.083,0.485c0.055,0.149,0.132,0.278,0.232,0.388
s0.22,0.196,0.359,0.257c0.139,0.062,0.292,0.092,0.46,0.092c0.395,0,0.702-0.15,0.922-0.451S62.611,11.561,62.611,11.057z"/>
<path fill="#FFFFFF" d="M69.305,8.719l-1.194,3.269c-0.284,0.776-0.561,1.411-0.829,1.906c-0.269,0.495-0.525,0.855-0.771,1.082
c-0.362,0.323-0.747,0.521-1.155,0.591l-0.252-0.882c0.271-0.071,0.53-0.21,0.776-0.417c0.245-0.207,0.442-0.465,0.592-0.776
c0.052-0.103,0.077-0.174,0.077-0.213c0-0.039-0.02-0.113-0.058-0.223l-1.708-4.336h1.154l0.893,2.629
c0.046,0.123,0.091,0.262,0.136,0.417c0.046,0.155,0.094,0.327,0.146,0.514h0.02c0.032-0.104,0.068-0.234,0.106-0.393
c0.039-0.158,0.091-0.341,0.155-0.548l0.796-2.619H69.305z"/>
<path fill="#FFFFFF" d="M71.119,10.678h0.484c0.355,0,0.631-0.064,0.824-0.194s0.291-0.288,0.291-0.476
c0-0.194-0.082-0.349-0.248-0.465c-0.164-0.116-0.393-0.175-0.684-0.175c-0.188,0-0.377,0.031-0.566,0.092
c-0.191,0.062-0.367,0.138-0.529,0.228L70.42,9.01c0.271-0.148,0.541-0.25,0.811-0.305c0.268-0.055,0.537-0.083,0.809-0.083
c0.215,0,0.43,0.021,0.646,0.063c0.215,0.042,0.408,0.113,0.576,0.213s0.307,0.231,0.412,0.393
c0.107,0.162,0.16,0.362,0.16,0.602c0,0.149-0.029,0.28-0.088,0.393c-0.057,0.113-0.135,0.213-0.232,0.3
c-0.096,0.087-0.205,0.159-0.324,0.213c-0.119,0.055-0.242,0.096-0.363,0.122v0.029c0.154,0.02,0.305,0.059,0.451,0.117
c0.145,0.058,0.275,0.134,0.393,0.228c0.115,0.094,0.209,0.207,0.281,0.339c0.07,0.133,0.105,0.283,0.105,0.451
c0,0.278-0.066,0.511-0.203,0.698c-0.135,0.188-0.309,0.336-0.52,0.446c-0.209,0.11-0.441,0.189-0.693,0.238
c-0.252,0.048-0.498,0.073-0.736,0.073c-0.291,0-0.58-0.031-0.863-0.092c-0.285-0.062-0.541-0.157-0.768-0.286l0.273-0.689
c0.168,0.091,0.359,0.167,0.576,0.228s0.438,0.092,0.664,0.092c0.355,0,0.629-0.069,0.82-0.208
c0.189-0.139,0.285-0.312,0.285-0.519c0-0.136-0.031-0.25-0.096-0.344s-0.156-0.17-0.271-0.228
c-0.117-0.058-0.252-0.099-0.408-0.121c-0.154-0.023-0.324-0.034-0.504-0.034h-0.494V10.678z"/>
<path fill="#FFFFFF" d="M76.715,8.719v1.668c0,0.382-0.006,0.725-0.02,1.028c-0.014,0.304-0.029,0.624-0.049,0.96l0.02,0.019
c0.123-0.246,0.244-0.486,0.363-0.723c0.121-0.236,0.242-0.477,0.365-0.723l1.164-2.231h1.357v4.714h-0.99v-1.668
c0-0.349,0.01-0.698,0.025-1.047c0.016-0.35,0.033-0.702,0.053-1.058h-0.049c-0.109,0.291-0.219,0.543-0.33,0.757
c-0.109,0.213-0.219,0.433-0.328,0.66c-0.201,0.388-0.4,0.776-0.598,1.164c-0.197,0.388-0.406,0.786-0.625,1.193h-1.357V8.719
H76.715z"/>
<path fill="#FFFFFF" d="M85.445,8.719v0.863H84.01v3.851H82.98V9.582h-1.426V8.719H85.445z"/>
<path fill="#FFFFFF" d="M90.789,10.853c0,0.09-0.004,0.176-0.01,0.257c-0.006,0.081-0.016,0.154-0.029,0.218h-3.143
c0.014,0.446,0.154,0.791,0.422,1.033c0.268,0.242,0.623,0.364,1.062,0.364c0.459,0,0.883-0.074,1.271-0.223l0.164,0.728
c-0.447,0.194-0.973,0.291-1.582,0.291c-0.367,0-0.697-0.057-0.988-0.17c-0.291-0.113-0.537-0.273-0.738-0.48
c-0.199-0.207-0.354-0.456-0.461-0.747c-0.105-0.291-0.158-0.617-0.158-0.979s0.053-0.697,0.158-1.004
c0.107-0.307,0.258-0.574,0.451-0.8c0.195-0.227,0.43-0.404,0.703-0.534c0.275-0.129,0.582-0.194,0.918-0.194
c0.297,0,0.566,0.053,0.811,0.16c0.242,0.106,0.449,0.258,0.619,0.456c0.172,0.197,0.303,0.434,0.393,0.708
C90.744,10.211,90.789,10.517,90.789,10.853z M89.789,10.582c0-0.369-0.088-0.668-0.266-0.897S89.088,9.34,88.752,9.34
c-0.305,0-0.562,0.116-0.775,0.349s-0.336,0.53-0.369,0.893H89.789z"/>
<path fill="#FFFFFF" d="M95.01,8.758c0.188-0.032,0.426-0.058,0.717-0.078s0.588-0.029,0.893-0.029
c0.193,0,0.412,0.012,0.654,0.034s0.475,0.074,0.693,0.155c0.221,0.081,0.404,0.202,0.553,0.364s0.225,0.381,0.225,0.659
c0,0.143-0.027,0.271-0.078,0.383c-0.053,0.113-0.121,0.212-0.209,0.296s-0.188,0.154-0.301,0.208
c-0.113,0.055-0.23,0.096-0.354,0.121l0.01,0.029c0.342,0.058,0.621,0.181,0.834,0.369s0.32,0.446,0.32,0.776
c0,0.33-0.092,0.592-0.271,0.786c-0.182,0.194-0.404,0.34-0.67,0.437c-0.266,0.097-0.545,0.159-0.84,0.185
c-0.293,0.025-0.557,0.039-0.789,0.039c-0.26,0-0.514-0.006-0.762-0.02c-0.25-0.013-0.457-0.026-0.625-0.039V8.758z
M96.018,10.64h0.533c0.162,0,0.316-0.011,0.461-0.034c0.146-0.022,0.273-0.058,0.383-0.106c0.111-0.049,0.195-0.113,0.258-0.194
c0.061-0.081,0.092-0.179,0.092-0.296c0-0.213-0.088-0.37-0.268-0.47c-0.178-0.1-0.457-0.15-0.838-0.15
c-0.109,0-0.205,0.003-0.287,0.01c-0.08,0.006-0.191,0.016-0.334,0.029V10.64z M96.018,12.725
c0.129,0.013,0.238,0.022,0.324,0.029c0.088,0.007,0.189,0.01,0.307,0.01c0.143,0,0.287-0.009,0.436-0.029
c0.148-0.019,0.285-0.056,0.408-0.111c0.123-0.054,0.221-0.128,0.295-0.222c0.074-0.093,0.113-0.217,0.113-0.371
c0-0.27-0.121-0.456-0.359-0.559c-0.24-0.103-0.562-0.154-0.971-0.154h-0.553V12.725z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="SC_Download_on_the_App_Store"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="135px" height="40px"
viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
<g>
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
<g>
<g>
<path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036
c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623
C33.507,24.924,30.161,23.647,30.128,19.784z"/>
<path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/>
</g>
</g>
<g>
<path fill="#FFFFFF" d="M54.006,17.03H52l-1.1-3.455h-3.821l-1.047,3.455h-1.955l3.787-11.761h2.338L54.006,17.03z M50.568,12.127
l-0.995-3.071c-0.104-0.314-0.302-1.053-0.593-2.216h-0.035c-0.117,0.5-0.303,1.239-0.559,2.216l-0.977,3.071H50.568z"/>
<path fill="#FFFFFF" d="M63.742,12.685c0,1.443-0.389,2.583-1.168,3.42c-0.699,0.745-1.564,1.117-2.602,1.117
c-1.115,0-1.918-0.401-2.406-1.204h-0.035v4.467h-1.885v-9.144c0-0.908-0.023-1.838-0.07-2.792h1.658l0.105,1.344h0.034
c0.629-1.012,1.582-1.519,2.861-1.519c1.002,0,1.836,0.396,2.506,1.187C63.408,10.353,63.742,11.394,63.742,12.685z
M61.824,12.755c0-0.826-0.188-1.506-0.559-2.042c-0.408-0.558-0.955-0.837-1.641-0.837c-0.465,0-0.887,0.154-1.266,0.462
s-0.625,0.712-0.742,1.213c-0.059,0.232-0.086,0.425-0.086,0.576v1.414c0,0.617,0.188,1.137,0.566,1.562
c0.379,0.425,0.869,0.637,1.475,0.637c0.709,0,1.262-0.273,1.658-0.82C61.625,14.372,61.824,13.651,61.824,12.755z"/>
<path fill="#FFFFFF" d="M73.497,12.685c0,1.443-0.39,2.583-1.169,3.42c-0.698,0.745-1.564,1.117-2.601,1.117
c-1.116,0-1.919-0.401-2.407-1.204h-0.035v4.467H65.4v-9.144c0-0.908-0.023-1.838-0.069-2.792h1.657l0.104,1.344h0.035
c0.628-1.012,1.582-1.519,2.861-1.519c1.001,0,1.835,0.396,2.505,1.187C73.162,10.353,73.497,11.394,73.497,12.685z
M71.578,12.755c0-0.826-0.187-1.506-0.559-2.042c-0.407-0.558-0.954-0.837-1.641-0.837c-0.465,0-0.887,0.154-1.265,0.462
c-0.379,0.308-0.626,0.712-0.742,1.213c-0.059,0.232-0.087,0.425-0.087,0.576v1.414c0,0.617,0.188,1.137,0.567,1.562
c0.378,0.425,0.869,0.637,1.474,0.637c0.71,0,1.263-0.273,1.658-0.82S71.578,13.651,71.578,12.755z"/>
<path fill="#FFFFFF" d="M86.759,13.732c0,1-0.349,1.814-1.045,2.443c-0.766,0.687-1.834,1.029-3.203,1.029
c-1.266,0-2.281-0.244-3.048-0.733l0.436-1.57c0.826,0.5,1.734,0.75,2.724,0.75c0.71,0,1.263-0.16,1.658-0.481
c0.396-0.32,0.594-0.749,0.594-1.285c0-0.478-0.163-0.879-0.488-1.206c-0.326-0.326-0.867-0.629-1.623-0.909
c-2.06-0.769-3.089-1.894-3.089-3.374c0-0.967,0.36-1.759,1.082-2.377c0.721-0.618,1.681-0.926,2.879-0.926
c1.07,0,1.96,0.186,2.67,0.558l-0.471,1.536c-0.663-0.36-1.414-0.541-2.251-0.541c-0.663,0-1.181,0.163-1.554,0.489
c-0.313,0.291-0.471,0.646-0.471,1.064c0,0.465,0.181,0.849,0.541,1.152c0.314,0.279,0.884,0.582,1.71,0.907
c1.012,0.407,1.757,0.884,2.233,1.431C86.52,12.238,86.759,12.918,86.759,13.732z"/>
<path fill="#FFFFFF" d="M92.988,9.963h-2.077v4.118c0,1.047,0.367,1.571,1.1,1.571c0.338,0,0.616-0.029,0.838-0.087l0.053,1.431
c-0.373,0.139-0.861,0.209-1.466,0.209c-0.745,0-1.326-0.227-1.745-0.68c-0.419-0.454-0.629-1.216-0.629-2.286V9.963h-1.238V8.55
h1.238V6.997l1.85-0.558V8.55h2.077V9.963z"/>
<path fill="#FFFFFF" d="M102.358,12.72c0,1.303-0.373,2.373-1.117,3.211c-0.779,0.861-1.814,1.291-3.105,1.291
c-1.245,0-2.237-0.413-2.976-1.239c-0.739-0.826-1.108-1.867-1.108-3.124c0-1.314,0.381-2.391,1.144-3.229
c0.762-0.837,1.788-1.256,3.079-1.256c1.245,0,2.245,0.413,3.002,1.239C101.997,10.417,102.358,11.452,102.358,12.72z
M100.403,12.781c0-0.782-0.168-1.453-0.506-2.012c-0.396-0.677-0.96-1.015-1.692-1.015c-0.757,0-1.332,0.338-1.728,1.015
c-0.338,0.56-0.506,1.242-0.506,2.047c0,0.782,0.168,1.453,0.506,2.013c0.407,0.677,0.978,1.015,1.71,1.015
c0.722,0,1.285-0.344,1.692-1.033C100.229,14.24,100.403,13.563,100.403,12.781z"/>
<path fill="#FFFFFF" d="M108.482,10.208c-0.186-0.035-0.384-0.052-0.593-0.052c-0.663,0-1.176,0.25-1.536,0.75
c-0.313,0.442-0.471,1.001-0.471,1.675v4.45h-1.885l0.018-5.811c0-0.978-0.023-1.867-0.07-2.67h1.641l0.07,1.623h0.052
c0.198-0.558,0.512-1.006,0.942-1.343c0.419-0.303,0.873-0.454,1.361-0.454c0.175,0,0.331,0.012,0.471,0.035V10.208z"/>
<path fill="#FFFFFF" d="M116.91,12.389c0,0.337-0.023,0.623-0.069,0.855h-5.653c0.022,0.837,0.296,1.478,0.819,1.919
c0.478,0.396,1.094,0.593,1.85,0.593c0.838,0,1.6-0.133,2.286-0.401l0.297,1.309c-0.803,0.349-1.751,0.523-2.845,0.523
c-1.314,0-2.347-0.387-3.097-1.161c-0.751-0.773-1.126-1.812-1.126-3.115c0-1.279,0.35-2.344,1.047-3.193
c0.733-0.907,1.722-1.361,2.967-1.361c1.222,0,2.146,0.454,2.774,1.361C116.66,10.44,116.91,11.33,116.91,12.389z M115.113,11.9
c0.012-0.558-0.11-1.041-0.366-1.448c-0.326-0.523-0.826-0.785-1.501-0.785c-0.616,0-1.117,0.256-1.501,0.768
c-0.313,0.408-0.5,0.896-0.558,1.466H115.113z"/>
</g>
<g>
<g>
<path fill="#FFFFFF" d="M56.827,23.984h-6.221v10.89h-1.451v-10.89h-5.132v-1.354h12.804V23.984z M56.547,29.974l-1.056,1.056
c-1.508-1.43-3.063-2.788-4.67-4.075l1.007-0.957C53.456,27.273,55.029,28.599,56.547,29.974z"/>
<path fill="#FFFFFF" d="M65.919,28.488h-4.207c-0.286,0.506-0.522,0.908-0.71,1.205h1.205v-0.875h1.304v0.875h2.095v1.154h-2.095
v0.941l2.244-0.198l-0.231,1.155l-2.013,0.182v1.881h-1.304v-1.783l-3.498,0.363l-0.148-1.287
c1.342-0.065,2.558-0.137,3.646-0.214v-1.04h-0.99c-0.803,0-1.43,0.072-1.881,0.215l-0.363-1.205
c0.363-0.043,0.616-0.172,0.759-0.387c0.144-0.215,0.341-0.542,0.595-0.982h-1.535v-1.154h2.129
c0.132-0.275,0.247-0.562,0.347-0.858l1.237,0.362l-0.231,0.496h3.646V28.488z M71.777,31.904
c-0.177,1.298-0.363,2.105-0.562,2.426c-0.198,0.318-0.498,0.479-0.899,0.479s-0.83-0.204-1.287-0.611
c-0.456-0.406-0.85-0.869-1.18-1.386c-0.671,0.671-1.534,1.37-2.59,2.096l-1.007-0.99c1.199-0.737,2.188-1.528,2.97-2.376
c-0.274-0.814-0.473-1.817-0.594-3.012c-0.121-1.193-0.182-1.905-0.182-2.137h-7.771v-1.171h3.333v-0.94h-2.524v-1.172h2.524
v-1.336h1.32v1.336h2.376v1.172h-2.376v0.94h3.068l-0.065-3.465h1.304c0,1.397,0.021,2.552,0.065,3.465h3.845v1.171h-3.795v0.166
c0,0.22,0.038,0.762,0.115,1.625s0.182,1.576,0.313,2.137c0.562-0.836,1.028-1.837,1.402-3.004l1.205,0.463
c-0.583,1.66-1.26,2.992-2.029,3.992c0.176,0.342,0.426,0.68,0.75,1.016s0.536,0.503,0.636,0.503c0.099,0,0.184-0.157,0.256-0.47
c0.071-0.314,0.123-0.729,0.156-1.246L71.777,31.904z M71.249,24.148l-1.04,0.826c-0.594-0.727-1.227-1.408-1.897-2.047
l0.974-0.809C70.066,22.879,70.721,23.555,71.249,24.148z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Could not determine the version of your GWT SDK; using the module DTD
from GWT 1.6.4. You may want to change this. -->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
<module>
<inherits name="com.sap.sailing.gwt.common.SourceCommon" />
<inherits name="com.sap.sse.security.ui.Authentication" />
<source path='authentication' />
</module>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
<module>
<extend-property name="locale" values="en,de,zh,ru" />
<set-property name="locale" value="en,de,zh,ru" />
<set-property-fallback name="locale" value="en" />
</module>
@@ -0,0 +1,18 @@
package com.sap.sailing.gwt.common.authentication;
import com.sap.sse.gwt.common.CommonSharedResources;
import com.sap.sse.security.ui.authentication.generic.GenericAuthentication;
import com.sap.sse.security.ui.authentication.generic.sapheader.FixedFlyoutAuthenticationView;
import com.sap.sse.security.ui.authentication.view.AuthenticationMenuView;
import com.sap.sse.security.ui.client.UserService;
public class FixedSailingAuthentication extends GenericAuthentication {
private static final CommonSharedResources res = CommonSharedResources.INSTANCE;
public FixedSailingAuthentication(UserService userService, AuthenticationMenuView userManagementMenuView) {
super(userService, userManagementMenuView, new FixedFlyoutAuthenticationView(res),
SailingAuthenticationEntryPointLinkFactory.INSTANCE, res);
res.mainCss().ensureInjected();
}
}
@@ -0,0 +1,18 @@
package com.sap.sailing.gwt.common.authentication;
import com.sap.sse.gwt.common.CommonSharedResources;
import com.sap.sse.security.ui.authentication.generic.GenericAuthentication;
import com.sap.sse.security.ui.authentication.generic.sapheader.GenericFlyoutAuthenticationView;
import com.sap.sse.security.ui.authentication.view.AuthenticationMenuView;
import com.sap.sse.security.ui.client.UserService;
public class GenericSailingAuthentication extends GenericAuthentication {
private static final CommonSharedResources res = CommonSharedResources.INSTANCE;
public GenericSailingAuthentication(UserService userService, AuthenticationMenuView userManagementMenuView) {
super(userService, userManagementMenuView, new GenericFlyoutAuthenticationView(res),
SailingAuthenticationEntryPointLinkFactory.INSTANCE, res);
res.mainCss().ensureInjected();
}
}
@@ -0,0 +1,42 @@
package com.sap.sailing.gwt.common.authentication;
import java.util.HashMap;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.user.client.Window;
import com.sap.sse.gwt.client.AbstractEntryPointLinkFactory;
import com.sap.sse.security.ui.authentication.generic.GenericAuthenticationLinkFactory;
public final class SailingAuthenticationEntryPointLinkFactory extends AbstractEntryPointLinkFactory implements
GenericAuthenticationLinkFactory {
public static final GenericAuthenticationLinkFactory INSTANCE = new SailingAuthenticationEntryPointLinkFactory();
private SailingAuthenticationEntryPointLinkFactory() {
}
@Override
public final String createUserProfileLink() {
return createEntryPointLink("/gwt/Home.html#/user/profile/:", new HashMap<String, String>());
}
@Override
public final String createEmailValidationLink() {
return createFullQualifiedLink("/gwt/Home.html", "/user/confirmation/:MAIL_VERIFIED");
}
@Override
public final String createPasswordResetLink() {
return createFullQualifiedLink("/gwt/Home.html", "/user/passwordreset/:");
}
private String createFullQualifiedLink(String baseUrl, String hash) {
String path = createEntryPointLink(baseUrl, new HashMap<String, String>());
UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
for (String parameter : Window.Location.getParameterMap().keySet()) {
urlBuilder.removeParameter(parameter);
}
return urlBuilder.setPath(path).setHash(hash).buildString();
}
}
@@ -0,0 +1,40 @@
package com.sap.sailing.gwt.common.client;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.gwt.i18n.client.LocaleInfo;
import com.sap.sse.common.Util;
public final class GWTLocaleUtil {
private static final String NO_LOCALE_TEXT = "---";
private GWTLocaleUtil() {
}
public static Iterable<String> getAvailableLocales() {
List<String> result = new ArrayList<>();
result.addAll(Arrays.asList(LocaleInfo.getAvailableLocaleNames()));
result.remove("default");
return result;
}
public static Iterable<String> getAvailableLocalesAndDefault() {
List<String> result = new ArrayList<>();
result.add(null);
Util.addAll(getAvailableLocales(), result);
return result;
}
public static int getLanguageCountWithDefault() {
return Util.size(getAvailableLocalesAndDefault());
}
public static String getDecoratedLanguageDisplayNameWithDefaultLocaleSupport(String localeNameOrNull) {
if (localeNameOrNull == null || localeNameOrNull.isEmpty()) {
return NO_LOCALE_TEXT;
}
return LocaleInfo.getLocaleNativeDisplayName(localeNameOrNull) + " ["+localeNameOrNull+"]";
}
}
@@ -11,17 +11,13 @@ public interface SharedResources extends ClientBundle, CommonSharedResources {
@Source("main.gss")
MainCss mainCss();
@Source("media.gss")
@Source(CommonSharedResources.MEDIA)
MediaCss mediaCss();
public interface MainCss extends CssResource, CommonMainCss {
String mobile();
String desktop();
String wrapper();
String navbar();
String navbar_button();
String navbar_buttonhidden();
String navbar_buttonactive();
String button();
String buttontextonly();
String buttonsmall();
@@ -1,84 +0,0 @@
package com.sap.sailing.gwt.common.client.controls.tabbar;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
/**
* @author zhorvath
*
*/
public class BreadcrumbPane extends Widget {
interface Resources extends ClientBundle {
@Source("Breadcrumb.css")
Style style();
}
interface Style extends CssResource {
String event_header__breadcrumb();
String event_header__breadcrumb__item();
}
private static Resources resources;
private static Resources getResources() {
if (resources == null) {
resources = GWT.create(Resources.class);
resources.style().ensureInjected();
}
return resources;
}
private final Style style = getResources().style();
private final DivElement breadcrumDiv;
public BreadcrumbPane() {
breadcrumDiv = Document.get().createDivElement();
breadcrumDiv.addClassName(style.event_header__breadcrumb());
setElement(breadcrumDiv);
}
public void addBreadcrumbItem(String title, String link, final Runnable runnable) {
addBreadcrumbItem(title, UriUtils.fromString(link), runnable);
}
public void addBreadcrumbItem(String title, SafeUri link, final Runnable runnable) {
AnchorElement breadcrumItem = Document.get().createAnchorElement();
breadcrumItem.setHref(link);
breadcrumItem.setInnerText(title);
breadcrumItem.addClassName(style.event_header__breadcrumb__item());
breadcrumDiv.appendChild(breadcrumItem);
Event.sinkEvents(breadcrumItem, Event.ONCLICK);
Event.setEventListener(breadcrumItem, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (LinkUtil.handleLinkClick(event)) {
event.stopPropagation();
event.preventDefault();
runnable.run();
}
}
});
}
public void clear() {
breadcrumDiv.removeAllChildren();
}
}
@@ -0,0 +1,36 @@
.navbar {
font-size: 1rem;
}
.navbar_button {
font-size: 1.2em;
display: inline-block;
font-weight: 600;
color: #666;
border: 1px solid #dedede;
padding: 0.833333333333333em 0.944444444444444em;
background-color: #ebebeb;
-webkit-transition: background-color 0.2s, border-color 0.2s;
-moz-transition: background-color 0.2s, border-color 0.2s;
transition: background-color 0.2s, border-color 0.2s;
text-decoration: none;
margin-right: 0.555555555555556em;
border-top-left-radius: 0.277777777777778em;
border-top-right-radius: 0.277777777777778em;
}
.navbar_buttonhidden {
display: block;
}
.navbar_button:hover {
background-color: #dedede;
outline: none;
text-decoration: none;
}
.navbar_buttonactive {
color: #333;
background-color: #fff;
border-bottom: 1px solid #fff;
}
.navbar_buttonactive:hover {
background-color: #dedede;
border-bottom: 1px solid #dedede;
}
@@ -13,12 +13,9 @@ import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.common.client.SharedResources.MainCss;
import com.sap.sse.gwt.client.LinkUtil;
/**
* Capsulates functionality for a tab bar.
@@ -26,14 +23,15 @@ import com.sap.sailing.gwt.common.client.SharedResources.MainCss;
* @author zhorvath
*
*/
public class TabBar extends Widget implements HasSelectionHandlers<Class<Place>> {
public class TabBar<T> extends Widget implements HasSelectionHandlers<T> {
private final MainCss style = SharedResources.INSTANCE.mainCss();
private final TabBarResources.LocalCss style = TabBarResources.INSTANCE.css();
private final List<Class<Place>> knownPlaceClasses = new ArrayList<>();
private final List<T> tabObjects = new ArrayList<>();
private final DivElement tabBarDiv;
public TabBar() {
style.ensureInjected();
tabBarDiv = Document.get().createDivElement();
tabBarDiv.addClassName(style.navbar());
@@ -57,8 +55,8 @@ public class TabBar extends Widget implements HasSelectionHandlers<Class<Place>>
event.stopPropagation();
event.preventDefault();
// the specific tab was clicked -> fire SelectionEvent with the associated place
GWT.log("Found " + knownPlaceClasses.get(i));
SelectionEvent.fire(this, knownPlaceClasses.get(i));
GWT.log("Found " + tabObjects.get(i));
SelectionEvent.fire(this, tabObjects.get(i));
break;
}
}
@@ -74,16 +72,16 @@ public class TabBar extends Widget implements HasSelectionHandlers<Class<Place>>
* @param place
* the place that should get selected.
*/
public void select(Place place) {
GWT.log("Should activate: " + place.getClass().getName());
public void select(T tabObject) {
GWT.log("Should activate: " + tabObject);
// remove all previous selections
for (int i = 0; i < tabBarDiv.getChildCount(); i++) {
Element.as(tabBarDiv.getChild(i)).removeClassName(style.navbar_buttonactive());
}
// find the tab that has to be selected for the given place
for (int i = 0; i < knownPlaceClasses.size(); i++) {
if (place.getClass().equals(knownPlaceClasses.get(i))) {
GWT.log("Activate: " + place.getClass().getName());
for (int i = 0; i < tabObjects.size(); i++) {
if (tabObject.equals(tabObjects.get(i))) {
GWT.log("Activate: " + tabObject);
// found the associated tab -> set the selected style.
Element.as(tabBarDiv.getChild(i)).addClassName(style.navbar_buttonactive());
}
@@ -100,19 +98,19 @@ public class TabBar extends Widget implements HasSelectionHandlers<Class<Place>>
* @param place
* the place that should be associated with the tab.
*/
public void addTab(String title, Class<Place> place, String link) {
public void addTab(String title, T place, String link) {
AnchorElement tabElement = Document.get().createAnchorElement();
tabElement.setHref(link);
tabElement.setInnerText(title);
tabElement.addClassName(style.navbar_button());
tabBarDiv.appendChild(tabElement);
knownPlaceClasses.add(place);
tabObjects.add(place);
}
/** {@inheritDoc} */
@Override
public HandlerRegistration addSelectionHandler(SelectionHandler<Class<Place>> handler) {
public HandlerRegistration addSelectionHandler(SelectionHandler<T> handler) {
return addHandler(handler, SelectionEvent.getType());
}
}
@@ -0,0 +1,20 @@
package com.sap.sailing.gwt.common.client.controls.tabbar;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface TabBarResources extends ClientBundle {
public static final TabBarResources INSTANCE = GWT.create(TabBarResources.class);
@Source("TabBar.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String navbar();
String navbar_button();
String navbar_buttonhidden();
String navbar_buttonactive();
}
}
@@ -7,13 +7,10 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.uibinder.client.UiField;
@@ -26,7 +23,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView.State;
/**
* Defines whole layout for site, including the header with the breadcrumbs and tab bar, and the content.
* Defines the basic Layout of tabbed pages with tabs, an optional header and a content area.
* <p/>
* Created by pgtaboada on 25.11.14.
*/
@@ -41,10 +38,10 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
SimplePanel additionalHeader;
@UiField
SimplePanel tabContentPanelUi;
// Should be TabBar<Class<PLACE>> but UiBinder causes weired generics errors related to the @UiHandler that would have a nested generic too.
@UiField
TabBar tabBar;
@UiField BreadcrumbPane breadcrumbs;
@UiField DivElement breadcrumbsContainer;
TabBar<Class<?>> tabBar;
@UiField FlowPanel tabExtension;
private TABVIEW currentTab;
@@ -56,15 +53,13 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
this.presenter = presenter;
this.historyMapper = historyMapper;
initWidget(ourUiBinder.createAndBindUi(this));
breadcrumbsContainer.getStyle().setDisplay(Display.NONE);
}
public TABVIEW getCurrentTab() {
return currentTab;
}
@UiChild
@UiChild(limit = 1)
public void addHeader(Widget widget) {
additionalHeader.setWidget(widget);
}
@@ -77,7 +72,6 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
* @param title
* The label for the tab.
*/
@SuppressWarnings("unchecked")
@UiChild
public void addTabContent(final TABVIEW tab, String title) {
GWT.log("Adding TAB: " + title);
@@ -90,7 +84,7 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
if(tab.getState() == State.VISIBLE) {
String link = "#" + historyMapper.getToken(tab.placeToFire());
tabBar.addTab(title, (Class<Place>) classForActivation, link);
tabBar.addTab(title, classForActivation, link);
}
}
@@ -101,7 +95,7 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
* @param event
*/
@UiHandler("tabBar")
void onTabSelection(SelectionEvent<Class<Place>> event) {
void onTabSelection(SelectionEvent<Class<?>> event) {
TabView<?, PRESENTER> selectedTabActivity = knownTabs.get(event.getSelectedItem());
if (selectedTabActivity != null) {
@@ -149,7 +143,9 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
// TODO better error handling
logger.log(Level.SEVERE, "Error while initializing Tab for place " + placeToGo.getClass().getName(), e);
}
tabBar.select(placeToGo);
@SuppressWarnings("unchecked")
final Class<PLACE> placeClass = (Class<PLACE>) placeToGo.getClass();
tabBar.select(placeClass);
currentTab = newTab;
@@ -166,14 +162,6 @@ public class TabPanel<PLACE extends Place, PRESENTER, TABVIEW extends TabView<PL
tabContentPanelUi.setWidget(widget);
}
public void addBreadcrumbItem(String title, String link, final Runnable runnable) {
breadcrumbs.addBreadcrumbItem(title, link, runnable);
}
public void addBreadcrumbItem(String title, SafeUri link, final Runnable runnable) {
breadcrumbs.addBreadcrumbItem(title, link, runnable);
}
public HandlerRegistration addTabPanelPlaceSelectionEventHandler(TabPanelPlaceSelectionEvent.Handler handler) {
return addHandler(handler, TabPanelPlaceSelectionEvent.TYPE);
}
@@ -1,5 +1,7 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:c="urn:import:com.sap.sailing.gwt.common.client.controls.tabbar" xmlns:b="urn:import:com.sap.sse.gwt.client.controls.busyindicator">
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:c="urn:import:com.sap.sailing.gwt.common.client.controls.tabbar"
xmlns:b="urn:import:com.sap.sse.gwt.client.controls.busyindicator">
<ui:with field="res"
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
@@ -11,17 +13,6 @@
border-bottom: 1px solid #dedede;
}
.breadcrumb {
font-size: 1rem;
/* @alternate */ font-size: 0.866666666666667em;
font-weight: 600;
padding: 0.666666666666667em 0;
}
.back:hover {
background-color: #cfcfcf;
}
.content {
width: 100%;
height: 100%;
@@ -38,12 +29,6 @@
</ui:style>
<g:FlowPanel>
<g:HTMLPanel addStyleNames="{style.header}">
<div ui:field="breadcrumbsContainer" class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<c:BreadcrumbPane ui:field="breadcrumbs"
addStyleNames="{style.breadcrumb}" />
</div>
</div>
<g:SimplePanel ui:field="additionalHeader" />
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
@@ -231,4 +231,13 @@ public interface TextMessages extends Messages {
String impressum();
String playstoreCampaign();
String playstoreRacecommitteeApp();
String playstoreRacecommitteeBadge();
String appstoreStgTrainingstagebuch();
String appstoreBadgeSuffix();
}
@@ -223,3 +223,11 @@ contentStrategySimulator=Choosing the right strategy can provide great competiti
strategySimulatorReadMore=Learn More
impressum=Imprint
playstoreCampaign=utm_source=sapsailing&utm_medium=solutions&utm_content=2016.02&utm_campaign=solutions&pcampaignid=2016.sapsailing.solutions
playstoreRacecommitteeApp=https://play.google.com/store/apps/details?id=com.sap.sailing.racecommittee.app
playstoreRacecommitteeBadge=https://play.google.com/intl/en/badges/images/generic/en-play-badge.png
appstoreStgTrainingstagebuch=https://itunes.apple.com/de/app/stg-trainingstagebuch/id779563635?l=en&amp;mt=8
appstoreBadgeSuffix=_en
@@ -223,3 +223,9 @@ contentStrategySimulator=Während eines Rennens hängt viel von der Wahl der ric
strategySimulatorReadMore=Mehr erfahren
impressum=Impressum
playstoreApp=https://play.google.com/store/apps/details?id=com.sap.sailing.racecommittee.app&hl=de
playstoreBadge=https://play.google.com/intl/de-de/badges/images/generic/de-play-badge.png
appstoreStgTrainingstagebuch=https://itunes.apple.com/de/app/stg-trainingstagebuch/id779563635?l=de&amp;mt=8
appstoreBadgeSuffix=_de
@@ -221,3 +221,8 @@ strategySimulator=Тренажер стратегий
contentStrategySimulator=Выбор правильной стратегии может дать большое конкурентное преимущество во время гонки. Тренажер стратегий SAP упрощает определение лучшей стратегии хождения под парусом для различных ветровых режимов и водных течений. Поскольку ветер и течение в тренажере можно быстро изменять, надежность стратегии можно легко оценить даже в условиях изменчивой погоды.
strategySimulatorReadMore=Читать далее
playstoreApp=https://play.google.com/store/apps/details?id=com.sap.sailing.racecommittee.app&hl=ru
playstoreBadge=https://play.google.com/intl/ru/badges/images/generic/ru-play-badge.png
appstoreBadgeSuffix=_ru
@@ -220,3 +220,8 @@ strategySimulator=Strategy Simulator
contentStrategySimulator=在帆船比赛中,选择正确的策略可以提供巨大的竞争优势。Strategy Simulator 简化了多种风力情况和水流下最佳航行策略的制定过程。由于风和水流在模拟中会随时改变,甚至可以针对不确定的天气条件来轻松评估策略的稳固性。
strategySimulatorReadMore=了解更多
playstoreApp=https://play.google.com/store/apps/details?id=com.sap.sailing.racecommittee.app&hl=zh
playstoreBadge=https://play.google.com/intl/zh-cn/badges/images/generic/zh-cn-play-badge.png
appstoreBadgeSuffix=_zh
@@ -77,44 +77,6 @@ figcaption {
.mobile .wrapper {
padding-bottom: 11.333333333333334em;
}
.navbar {
font-size: 1rem;
}
.navbar_button {
font-size: 1.2em;
display: inline-block;
font-weight: 600;
color: #666;
border: 1px solid #dedede;
padding: 0.833333333333333em 0.944444444444444em;
background-color: #ebebeb;
-webkit-transition: background-color 0.2s, border-color 0.2s;
-moz-transition: background-color 0.2s, border-color 0.2s;
transition: background-color 0.2s, border-color 0.2s;
text-decoration: none;
margin-right: 0.555555555555556em;
}
.desktop .navbar_button {
border-top-left-radius: 0.277777777777778em;
border-top-right-radius: 0.277777777777778em;
}
.navbar_buttonhidden {
display: block;
}
.navbar_button:hover {
background-color: #dedede;
outline: none;
text-decoration: none;
}
.navbar_buttonactive {
color: #333;
background-color: #fff;
border-bottom: 1px solid #fff;
}
.navbar_buttonactive:hover {
background-color: #dedede;
border-bottom: 1px solid #dedede;
}
.button {
font-size: 1rem;
display: inline-block;
@@ -1,43 +0,0 @@
.siteheader {
font-size: 1rem;
background: #333;
border-bottom: 5px solid #f0ab00;
height: 70px;
line-height: 4em;
width: 100%;
overflow: hidden;
text-align:center;
}
.siteheaderLeft {
float:left;
width: 25%;
text-align: left;
}
.siteheaderCentered {
width: 50%;
display: inline-block;
margin:0 auto;
}
.siteheaderRight {
float:right;
width: 25%;
text-align: right;
}
.logo {
margin: 0.8em 10px;
float: left;
}
.logotitle {
display: inline;
color: #f6f9fc;
font-weight: bold;
}
.pagetitle {
color: #ffffff;
font-size: 1.5rem;
font-weight: bold;
}
@@ -1,51 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.sapheader;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.ParagraphElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.theme.util.FullscreenUtil;
public class SAPHeader extends Composite {
private static SAPHeaderUiBinder uiBinder = GWT.create(SAPHeaderUiBinder.class);
interface SAPHeaderUiBinder extends UiBinder<Widget, SAPHeader> {
}
@UiField ParagraphElement applicationNameUi;
@UiField DivElement pageTitleUi;
@UiField Button startFullScreenButton;
public SAPHeader(String applicationName, String pageTitle, boolean startInAutoScreenMode) {
SAPHeaderResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
applicationNameUi.setInnerText(applicationName != null ? applicationName : "&nbsp;");
pageTitleUi.setInnerText(pageTitle);
startFullScreenButton.setVisible(startInAutoScreenMode);
// the 'fullscreen' button should disappear after some seconds (10)
if(startInAutoScreenMode) {
Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() {
public boolean execute () {
startFullScreenButton.setVisible(false);
return false;
}
}, 10000);
}
}
@UiHandler("startFullScreenButton")
void startFullScreenClicked(ClickEvent e) {
FullscreenUtil.requestFullscreen();
}
}
@@ -1,25 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n"
type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res"
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res"
type="com.sap.sailing.gwt.common.theme.component.sapheader.SAPHeaderResources" />
<g:HTMLPanel>
<header class="{local_res.css.siteheader}">
<div class="{local_res.css.siteheaderLeft}">
<g:Image resource="{local_res.logo}" pixelSize="80, 40" altText="SAP Sailing Analytics" styleName="{local_res.css.logo}"/>
<p ui:field="applicationNameUi" class="{local_res.css.logotitle}"></p>
</div>
<div class="{local_res.css.siteheaderCentered}">
<div ui:field="pageTitleUi" class="{local_res.css.pagetitle}"></div>
</div>
<div class="{local_res.css.siteheaderRight}">
<g:Button ui:field="startFullScreenButton" styleName="{res.mainCss.button}" text="Fullscreen" />
<span>&nbsp;</span>
</div>
</header>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,39 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.sapheader2;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
public class SAPHeader2 extends Composite {
private static SAPHeaderUiBinder uiBinder = GWT.create(SAPHeaderUiBinder.class);
interface SAPHeaderUiBinder extends UiBinder<Widget, SAPHeader2> {
}
@UiField
DivElement applicationNameUi;
@UiField
SimplePanel pageTitleUi;
@UiField
SimplePanel rightSideUi;
public SAPHeader2(String applicationName, Widget pageTitle, boolean startInAutoScreenMode) {
SAPHeaderResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
applicationNameUi.setInnerText(applicationName != null ? applicationName : "&nbsp;");
pageTitleUi.setWidget(pageTitle);
}
public void addWidgetToRightSide(Widget widget) {
rightSideUi.add(widget);
}
}
@@ -1,22 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n"
type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res"
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res"
type="com.sap.sailing.gwt.common.theme.component.sapheader2.SAPHeaderResources" />
<g:HTMLPanel>
<header class="{local_res.css.siteheader}">
<div class="{local_res.css.siteheaderLeft}">
<g:Image resource="{local_res.logo}" pixelSize="80, 40" altText="SAP Sailing Analytics" styleName="{local_res.css.logo}"/>
<div ui:field="applicationNameUi" class="{local_res.css.logotitle}"></div>
</div>
<g:SimplePanel ui:field="pageTitleUi" styleName="{local_res.css.siteheaderCentered}">
</g:SimplePanel>
<g:SimplePanel ui:field="rightSideUi" styleName="{local_res.css.siteheaderRight}">
</g:SimplePanel>
</header>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,26 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.sapheader2;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
public interface SAPHeaderResources extends ClientBundle {
public static final SAPHeaderResources INSTANCE = GWT.create(SAPHeaderResources.class);
@Source("SAPHeader2.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String siteheader();
String siteheaderLeft();
String siteheaderCentered();
String siteheaderRight();
String logo();
String logotitle();
String pagetitle();
}
@Source("logo-small@2x.png")
ImageResource logo();
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

@@ -13,6 +13,7 @@
<inherits name="com.sap.sse.gwt.AdminConsole" />
<inherits name="com.sap.sse.security.ui.LoginPanel" />
<inherits name="com.sap.sse.security.ui.Authentication" />
<inherits name="com.sap.sse.security.ui.UserProfile" />
<!-- Highcharts API -->
<inherits name='com.sap.sse.gwt.Highcharts' />
@@ -25,9 +26,7 @@
<inherits name="com.github.gwtbootstrap.BootstrapNoResources" />
<inherits name='com.github.gwtbootstrap.datetimepicker.DatetimepickerNoResources' />
<extend-property name="locale" values="en,de,zh,ru" />
<set-property name="locale" value="en,de,zh,ru" />
<set-property-fallback name="locale" value="en"/>
<inherits name='com.sap.sailing.gwt.common.SailingLocales' />
<source path='client' />
<source path='shared' />
@@ -1,10 +1,10 @@
package com.sap.sailing.gwt.home.communication.event;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -15,11 +15,11 @@ import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO;
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO.EventType;
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sailing.gwt.home.server.EventActionUtil.LeaderboardCallback;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sailing.gwt.server.HomeServiceUtil;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
@@ -51,7 +51,8 @@ public class GetEventViewAction implements SailingAction<EventViewDTO>, IsClient
ImageDescriptor logoImage = event.findImageWithTag(MediaTagConstants.LOGO);
dto.setLogoImage(logoImage != null ? HomeServiceUtil.convertToImageDTO(logoImage) : null);
dto.setOfficialWebsiteURL(event.getOfficialWebsiteURL() == null ? null : event.getOfficialWebsiteURL().toString());
dto.setSailorsInfoWebsiteURL(event.getSailorsInfoWebsiteURL() == null ? null : event.getSailorsInfoWebsiteURL().toString());
URL sailorsInfoWebsiteURL = event.getSailorsInfoWebsiteURLOrFallback(context.getClientLocale());
dto.setSailorsInfoWebsiteURL(sailorsInfoWebsiteURL == null ? null : sailorsInfoWebsiteURL.toString());
dto.setHasMedia(HomeServiceUtil.hasMedia(event));
dto.setState(HomeServiceUtil.calculateEventState(event));
@@ -104,16 +105,6 @@ public class GetEventViewAction implements SailingAction<EventViewDTO>, IsClient
} else {
dto.setType(dto.getRegattas().size() == 1 ? EventType.SINGLE_REGATTA: EventType.MULTI_REGATTA);
}
// Special solution for localization of SailorsInfo URL
if(dto.getSailorsInfoWebsiteURL() != null && !Locale.GERMAN.equals(context.getClientLocale())) {
String localizedURL = dto.getSailorsInfoWebsiteURL();
if(!localizedURL.endsWith("/")) {
localizedURL += "/";
}
localizedURL += "en";
dto.setSailorsInfoWebsiteURL(localizedURL);
}
return dto;
}
@@ -10,12 +10,12 @@ import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.common.client.controls.tabbar.BreadcrumbPane;
import com.sap.sailing.gwt.home.desktop.partials.footer.Footer;
import com.sap.sailing.gwt.home.desktop.partials.header.Header;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.DefaultErrorReporter;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.breadcrumb.BreadcrumbPane;
import com.sap.sse.security.ui.authentication.view.AuthenticationMenuView;
/**
@@ -2,7 +2,7 @@
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:dp="urn:import:com.sap.sailing.gwt.home.desktop.partials"
xmlns:c="urn:import:com.sap.sailing.gwt.common.client.controls.tabbar">
xmlns:sse="urn:import:com.sap.sse.gwt.client">
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
.mainContent {
@@ -22,7 +22,7 @@
<div ui:field="breadcrumbWrapperUi" style="display: none;">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<c:BreadcrumbPane ui:field="breadcrumbsUi"
<sse:breadcrumb.BreadcrumbPane ui:field="breadcrumbsUi"
addStyleNames="{style.breadcrumb}" />
</div>
</div>
@@ -12,7 +12,6 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.home.communication.event.EventMetadataDTO;
import com.sap.sailing.gwt.home.communication.event.LabelType;
import com.sap.sailing.gwt.home.communication.eventlist.EventListEventSeriesDTO;
@@ -21,6 +20,7 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
import com.sap.sailing.gwt.home.shared.utils.EventDatesFormatterUtil;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sse.gwt.client.LinkUtil;
public class EventTeaser extends Composite {
@@ -16,7 +16,6 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.i18n.TextMessages;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO;
import com.sap.sailing.gwt.home.communication.eventview.HasRegattaMetadata;
@@ -31,6 +30,7 @@ import com.sap.sailing.gwt.home.shared.utils.EventDatesFormatterUtil;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sailing.gwt.home.shared.utils.LogoUtil;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
public class EventHeader extends Composite {
private static EventHeaderUiBinder uiBinder = GWT.create(EventHeaderUiBinder.class);
@@ -1,9 +1,8 @@
package com.sap.sailing.gwt.home.desktop.partials.footer;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.Collection;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.AnchorElement;
@@ -26,11 +25,13 @@ import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ValueListBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.common.client.GWTLocaleUtil;
import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator;
import com.sap.sailing.gwt.home.desktop.places.whatsnew.WhatsNewPlace;
import com.sap.sailing.gwt.home.desktop.places.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs;
import com.sap.sailing.gwt.home.shared.SwitchingEntryPoint;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
public class Footer extends Composite {
@@ -107,21 +108,21 @@ public class Footer extends Composite {
}
private void updateUI() {
Set<String> availableLocales = new HashSet<String>(Arrays.asList(LocaleInfo.getAvailableLocaleNames()));
availableLocales.remove("default");
final Iterable<String> availableLocales = GWTLocaleUtil.getAvailableLocales();
final int localeCount = Util.size(availableLocales);
if(availableLocales.size() <= 1) {
if (localeCount <= 1) {
// only current language (or removed default) available
changeLanguageLink.removeFromParent();
changeLanguageList.removeFromParent();
languageSelectionDiv.removeFromParent();
return;
}
if(availableLocales.size() == 2) {
if (Util.size(availableLocales) == 2) {
changeLanguageList.removeFromParent();
// current language + one we can switch to
for(String localeName : availableLocales) {
if(!currentLocale.getLocaleName().equals(localeName)) {
for (String localeName : availableLocales) {
if (!currentLocale.getLocaleName().equals(localeName)) {
otherLanguage = localeName;
changeLanguageLink.setText(LocaleInfo.getLocaleNativeDisplayName(otherLanguage));
return;
@@ -130,12 +131,12 @@ public class Footer extends Composite {
return;
}
changeLanguageLink.removeFromParent();
Set<Pair<String, String>> values = new HashSet<>();
Collection<Pair<String, String>> values = new ArrayList<>();
Pair<String, String> selectedValue = null;
for(String localeName : availableLocales) {
for (String localeName : availableLocales) {
Pair<String, String> value = new Pair<String, String>(localeName, LocaleInfo.getLocaleNativeDisplayName(localeName));
values.add(value);
if(currentLocale.getLocaleName().equals(localeName)) {
if (currentLocale.getLocaleName().equals(localeName)) {
selectedValue = value;
}
}
@@ -13,9 +13,9 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.home.desktop.partials.regattanavigation.RegattaNavigationResources.LocalCss;
import com.sap.sailing.gwt.home.shared.utils.DropdownHandler;
import com.sap.sse.gwt.client.LinkUtil;
public class DropdownFilter<T> extends Composite {
@@ -13,7 +13,6 @@ import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.home.communication.event.EventMetadataDTO;
import com.sap.sailing.gwt.home.communication.event.EventState;
import com.sap.sailing.gwt.home.communication.fakeseries.EventSeriesViewDTO;
@@ -26,6 +25,7 @@ import com.sap.sailing.gwt.home.shared.places.event.EventDefaultPlace;
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
public class SeriesHeader extends Composite {
private static SeriesHeaderUiBinder uiBinder = GWT.create(SeriesHeaderUiBinder.class);
@@ -7,6 +7,16 @@
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res"
type="com.sap.sailing.gwt.home.desktop.partials.solutions.SolutionsResources" />
<ui:style>
.storeBadgesContainer>a>img {
height: 60px;
width: auto;
margin-right: 10px;
}
.storeBadgesContainer {
margin: 20px 0px;
}
</ui:style>
<g:HTMLPanel>
<!-- Page displays all solutions -->
<div class="{local_res.css.solutions}">
@@ -122,6 +132,18 @@
<p>
<ui:text from='{i18n.contentSapSailingRaceManager}' />
</p>
<div
class="{style.storeBadgesContainer}"
>
<a ui:field="raceManagerPlayStoreLinkUi"
href="{i18n.playstoreRacecommitteeApp}&amp;{i18n.playstoreCampaign}"
target="_blank"
><img
ui:field="raceManagerPlayStoreImgUi"
alt="Get it on Google Play"
src="{i18n.playstoreRacecommitteeBadge}"
/></a>
</div>
<g:Anchor ui:field="raceCommitteeAppDetailsAnchor"
styleName="{res.mainCss.button}">
<ui:text from='{i18n.sapSailingRaceManagerReadMore}' />
@@ -158,11 +180,16 @@
<p>
<ui:text from='{i18n.i18nDeSolutionsTrainingText}' />
</p>
<a
href="https://itunes.apple.com/de/app/stg-trainingstagebuch/id779563635?l=en&amp;mt=8"
target="_blank" class="{local_res.css.solutions_content_linkappstore}">
<img src="images/home/appstore.png"></img>
</a>
<div
class="{style.storeBadgesContainer}"
>
<a
alt="Get it on Appstore"
href="{i18n.appstoreStgTrainingstagebuch}"
target="_blank" class="{local_res.css.solutions_content_linkappstore}">
<img src="images/home/appstore{i18n.appstoreBadgeSuffix}.svg"></img>
</a>
</div>
</div>
</div>
</div>
@@ -14,7 +14,6 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.BoatClassImageResolver;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.home.communication.event.news.AbstractRaceNewsEntryDTO;
import com.sap.sailing.gwt.home.communication.event.news.LeaderboardNewsEntryDTO;
import com.sap.sailing.gwt.home.communication.event.news.NewsEntryDTO;
@@ -22,6 +21,7 @@ import com.sap.sailing.gwt.home.desktop.places.event.EventView;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.util.ConditionalDateTimeFormatter;
import com.sap.sse.gwt.client.LinkUtil;
public class UpdatesBoxItem extends Widget {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@@ -1,32 +0,0 @@
package com.sap.sailing.gwt.home.desktop.partials.userHeader;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
public class UserHeader extends Composite {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
interface MyUiBinder extends UiBinder<Widget, UserHeader> {
}
@UiField DivElement imageUi;
@UiField DivElement nameUi;
@UiField DivElement usernameUi;
public UserHeader() {
initWidget(uiBinder.createAndBindUi(this));
}
public void setUserManagementContext(AuthenticationContext userManagementContext) {
UserHeaderResources.INSTANCE.css().ensureInjected();
imageUi.getStyle().setBackgroundImage("url(images/home/userdefault.svg)");
nameUi.setInnerText(userManagementContext.getUserTitle());
usernameUi.setInnerText(userManagementContext.getUserSubtitle());
}
}
@@ -1,86 +0,0 @@
package com.sap.sailing.gwt.home.desktop.partials.useraccountDetails;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.client.i18n.StringMessages;
import com.sap.sse.security.ui.shared.UserDTO;
public class UserAccountDetails extends Composite {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
interface MyUiBinder extends UiBinder<Widget, UserAccountDetails> {
}
public interface Presenter {
void handleSaveChangesRequest(String fullName, String company);
void handleEmailChangeRequest(String email);
void handlePasswordChangeRequest(String oldPassword, String newPassword, String newPasswordConfirmation);
}
@UiField DivElement editImageLinkUi;
@UiField InputElement usernameUi;
@UiField TextBox nameUi;
@UiField TextBox companyUi;
@UiField TextBox emailUi;
@UiField PasswordTextBox oldPasswordUi;
@UiField PasswordTextBox newPasswordUi;
@UiField PasswordTextBox newPasswordConfirmationUi;
private final Presenter presenter;
public UserAccountDetails(Presenter presenter) {
this.presenter = presenter;
UseraccountDetailsResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
StringMessages i18n = StringMessages.INSTANCE;
setPlaceholder(oldPasswordUi, i18n.oldPasswordPlaceholder());
setPlaceholder(newPasswordUi, i18n.newPasswordPlaceholder());
setPlaceholder(newPasswordConfirmationUi, i18n.passwordRepeatPlaceholder());
}
public void setUserManagementContext(AuthenticationContext userManagementContext) {
UserDTO currentUser = userManagementContext.getCurrentUser();
// TODO correct message
editImageLinkUi.setTitle("TODO picture of: " + currentUser.getName());
// TODO use image from user when field is available
editImageLinkUi.getStyle().setBackgroundImage("url(images/home/userdefault.svg)");
nameUi.setValue(currentUser.getFullName());
companyUi.setValue(currentUser.getCompany());
usernameUi.setValue(currentUser.getName());
emailUi.setValue(currentUser.getEmail());
oldPasswordUi.setValue("");
newPasswordUi.setValue("");
newPasswordConfirmationUi.setValue("");
}
private void setPlaceholder(Widget widget, String placeholderText) {
widget.getElement().setAttribute("placeholder", placeholderText);
}
@UiHandler("saveChangesUi")
void onSaveChangesClicked(ClickEvent event) {
presenter.handleSaveChangesRequest(nameUi.getValue(), companyUi.getValue());
}
@UiHandler("changeEmailUi")
void onChangeEmailClicked(ClickEvent event) {
presenter.handleEmailChangeRequest(emailUi.getValue());
}
@UiHandler("changePasswordUi")
void onChangePasswordClicked(ClickEvent event) {
presenter.handlePasswordChangeRequest(oldPasswordUi.getValue(), newPasswordUi.getValue(),
newPasswordConfirmationUi.getValue());
}
}
@@ -15,7 +15,6 @@ import com.sap.sailing.gwt.common.client.i18n.TextMessages;
import com.sap.sailing.gwt.home.desktop.partials.eventheader.EventHeader;
import com.sap.sailing.gwt.home.desktop.partials.sailorinfo.SailorInfo;
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.ui.client.StringMessages;
public class TabletAndDesktopMultiRegattaEventView extends Composite implements EventMultiregattaView {
@@ -43,7 +42,6 @@ public class TabletAndDesktopMultiRegattaEventView extends Composite implements
tabPanelUi = new TabPanel<>(currentPresenter, historyMapper);
eventHeader = new EventHeader(currentPresenter);
initWidget(uiBinder.createAndBindUi(this));
initBreadCrumbs();
String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
if(sailorsInfoURL != null && ! sailorsInfoURL.isEmpty()) {
@@ -70,21 +68,6 @@ public class TabletAndDesktopMultiRegattaEventView extends Composite implements
public void onTabSelection(TabPanelPlaceSelectionEvent e) {
currentPresenter.handleTabPlaceSelection((TabView<?, EventMultiregattaView.Presenter>) e.getSelectedActivity());
}
private void initBreadCrumbs() {
addBreadCrumbItem(i18n.home(), currentPresenter.getHomeNavigation());
addBreadCrumbItem(i18n.events(), currentPresenter.getEventsNavigation());
addBreadCrumbItem(currentPresenter.getEventDTO().getDisplayName(), currentPresenter.getCurrentEventNavigation());
}
private void addBreadCrumbItem(String label, final PlaceNavigation<?> placeNavigation) {
tabPanelUi.addBreadcrumbItem(label, placeNavigation.getTargetUrl(), new Runnable() {
@Override
public void run() {
placeNavigation.goToPlace();
}
});
}
@Override
public void showErrorInCurrentTab(IsWidget errorView) {
@@ -14,7 +14,6 @@ import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanel;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanelPlaceSelectionEvent;
@@ -27,6 +26,7 @@ import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
public class TabletAndDesktopRegattaEventView extends Composite implements EventRegattaView {
@@ -53,7 +53,6 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
tabPanelUi = new TabPanel<>(currentPresenter, historyMapper);
eventHeader = new EventHeader(currentPresenter);
initWidget(uiBinder.createAndBindUi(this));
initBreadCrumbs();
if(currentPresenter.getEventDTO().getType() == EventType.SERIES_EVENT) {
final PlaceNavigation<SeriesDefaultPlace> currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation();
@@ -102,28 +101,6 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
currentPresenter.handleTabPlaceSelection((TabView<?, EventRegattaView.Presenter>) e.getSelectedActivity());
}
private void initBreadCrumbs() {
addBreadCrumbItem(i18n.home(), currentPresenter.getHomeNavigation());
addBreadCrumbItem(i18n.events(), currentPresenter.getEventsNavigation());
if(currentPresenter.getEventDTO().getType() == EventType.SERIES_EVENT) {
addBreadCrumbItem(currentPresenter.getEventDTO().getSeriesName(), currentPresenter.getCurrentEventSeriesNavigation());
}
addBreadCrumbItem(currentPresenter.getEventDTO().getLocationOrDisplayName(), currentPresenter.getCurrentEventNavigation());
if(currentPresenter.showRegattaMetadata()) {
addBreadCrumbItem(currentPresenter.getRegattaMetadata().getDisplayName(), currentPresenter.getCurrentRegattaOverviewNavigation());
}
}
private void addBreadCrumbItem(String label, final PlaceNavigation<?> placeNavigation) {
tabPanelUi.addBreadcrumbItem(label, placeNavigation.getTargetUrl(), new Runnable() {
@Override
public void run() {
placeNavigation.goToPlace();
}
});
}
@Override
public void showErrorInCurrentTab(IsWidget errorView) {
tabPanelUi.overrideCurrentContentInTab(errorView);
@@ -5,7 +5,6 @@ import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.controls.tabbar.BreadcrumbPane;
import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator;
import com.sap.sailing.gwt.home.desktop.partials.eventsrecent.EventsOverviewRecent;
import com.sap.sailing.gwt.home.desktop.partials.eventsupcoming.EventsOverviewUpcoming;
@@ -13,6 +12,7 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.places.events.EventsPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.breadcrumb.BreadcrumbPane;
public class TabletAndDesktopEventsView extends AbstractEventsView {
private static EventsPageViewUiBinder uiBinder = GWT.create(EventsPageViewUiBinder.class);
@@ -1,6 +1,6 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:c="urn:import:com.sap.sailing.gwt.common.client.controls.tabbar"
xmlns:sse="urn:import:com.sap.sse.gwt.client"
xmlns:dp="urn:import:com.sap.sailing.gwt.home.desktop.partials">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
@@ -17,7 +17,7 @@
</ui:style>
<g:HTMLPanel addStyleNames="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<c:BreadcrumbPane ui:field="breadcrumbs" addStyleNames="{style.breadcrumb}" />
<sse:breadcrumb.BreadcrumbPane ui:field="breadcrumbs" addStyleNames="{style.breadcrumb}" />
<dp:eventsupcoming.EventsOverviewUpcoming ui:field='upcomingEventsWidget'/>
<dp:eventsrecent.EventsOverviewRecent ui:field='recentEventsWidget'/>
</div>
@@ -14,7 +14,6 @@ import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.common.client.i18n.TextMessages;
import com.sap.sailing.gwt.home.desktop.partials.seriesheader.SeriesHeader;
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.ui.client.StringMessages;
public class TabletAndDesktopSeriesView extends Composite implements SeriesView<AbstractSeriesTabPlace, SeriesView.Presenter> {
@@ -46,8 +45,6 @@ public class TabletAndDesktopSeriesView extends Composite implements SeriesView<
seriesHeader = new SeriesHeader(currentPresenter);
initWidget(uiBinder.createAndBindUi(this));
initBreadCrumbs();
}
@Override
@@ -70,21 +67,6 @@ public class TabletAndDesktopSeriesView extends Composite implements SeriesView<
currentPresenter.handleTabPlaceSelection((TabView<?, SeriesView.Presenter>) e.getSelectedActivity());
}
private void initBreadCrumbs() {
addBreadCrumbItem(i18n.home(), currentPresenter.getHomeNavigation());
addBreadCrumbItem(i18n.events(), currentPresenter.getEventsNavigation());
addBreadCrumbItem(currentPresenter.getSeriesDTO().getDisplayName(), currentPresenter.getCurrentEventSeriesNavigation());
}
private void addBreadCrumbItem(String label, final PlaceNavigation<?> placeNavigation) {
tabPanelUi.addBreadcrumbItem(label, placeNavigation.getTargetUrl(), new Runnable() {
@Override
public void run() {
placeNavigation.goToPlace();
}
});
}
@Override
public void showErrorInCurrentTab(IsWidget errorView) {
tabPanelUi.overrideCurrentContentInTab(errorView);
@@ -8,15 +8,16 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanel;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanelPlaceSelectionEvent;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.common.client.i18n.TextMessages;
import com.sap.sailing.gwt.home.desktop.partials.userHeader.UserHeader;
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.userprofile.desktop.userheader.UserHeader;
public class TabletAndDesktopUserProfileView extends Composite implements UserProfileView<AbstractUserProfilePlace, UserProfileView.Presenter> {
private static final ApplicationHistoryMapper historyMapper = GWT.<ApplicationHistoryMapper> create(ApplicationHistoryMapper.class);
@@ -44,7 +45,7 @@ public class TabletAndDesktopUserProfileView extends Composite implements UserPr
this.currentPresenter = currentPresenter;
tabPanelUi = new TabPanel<>(currentPresenter, historyMapper);
headerUi = new UserHeader();
headerUi = new UserHeader(SharedResources.INSTANCE);
initWidget(uiBinder.createAndBindUi(this));
}
@@ -64,9 +65,9 @@ public class TabletAndDesktopUserProfileView extends Composite implements UserPr
}
@Override
public void setUserManagementContext(AuthenticationContext userManagementContext) {
headerUi.setUserManagementContext(userManagementContext);
tabPanelUi.getCurrentTab().setUserManagementContext(userManagementContext);
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
headerUi.setAuthenticationContext(authenticationContext);
tabPanelUi.getCurrentTab().setAuthenticationContext(authenticationContext);
}
@SuppressWarnings("unchecked")
@@ -1,7 +1,7 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:c="urn:import:com.sap.sailing.gwt.common.client.controls.tabbar"
xmlns:dp="urn:import:com.sap.sailing.gwt.home.desktop.partials"
xmlns:uh="urn:import:com.sap.sse.security.ui.userprofile.desktop.userheader"
xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="tm" type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
@@ -40,10 +40,10 @@
<g:HTMLPanel>
<c:TabPanel ui:field="tabPanelUi">
<c:header>
<dp:userHeader.UserHeader ui:field="headerUi" />
<uh:UserHeader ui:field="headerUi" />
</c:header>
<c:tabcontent title="{i18n.details}">
<s:detailstab.UserProfileDetailsTabView />
<s:detailstab.UserProfileDetailsTabView ui:field="detailsTabUi" />
</c:tabcontent>
</c:TabPanel>
</g:HTMLPanel>
@@ -6,8 +6,6 @@ import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator;
@@ -18,10 +16,10 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.places.fakeseries.AbstractSeriesPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
import com.sap.sse.security.ui.authentication.AuthenticationManager;
import com.sap.sse.security.ui.authentication.AuthenticationRequestEvent;
import com.sap.sse.security.ui.client.component.NewAccountValidator;
import com.sap.sse.security.ui.client.UserManagementServiceAsync;
import com.sap.sse.security.ui.client.i18n.StringMessages;
public class UserProfileActivity extends AbstractActivity implements UserProfileView.Presenter {
@@ -33,16 +31,15 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile
protected final DesktopPlacesNavigator homePlacesNavigator;
private final StringMessages i18n_sec = StringMessages.INSTANCE;
private final NewAccountValidator validator = new NewAccountValidator(i18n_sec);
private UserProfileView<AbstractUserProfilePlace, UserProfileView.Presenter> currentView = new TabletAndDesktopUserProfileView();
public UserProfileActivity(AbstractUserProfilePlace place, UserProfileClientFactory clientFactory,
DesktopPlacesNavigator homePlacesNavigator, NavigationPathDisplay navigationPathDisplay) {
this.currentPlace = place;
this.clientFactory = clientFactory;
this.homePlacesNavigator = homePlacesNavigator;
initNavigationPath(navigationPathDisplay);
}
@@ -57,86 +54,16 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile
currentView.registerPresenter(this);
panel.setWidget(currentView);
currentView.navigateTabsTo(currentPlace);
currentView.setUserManagementContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
currentView.setAuthenticationContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
eventBus.addHandler(AuthenticationContextEvent.TYPE, new AuthenticationContextEvent.Handler() {
@Override
public void onUserChangeEvent(AuthenticationContextEvent event) {
currentView.setUserManagementContext(event.getCtx());
currentView.setAuthenticationContext(event.getCtx());
}
});
}
@Override
public void handleSaveChangesRequest(String fullName, String company) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
clientFactory.getUserManagementService().updateUserProperties(username, fullName, company,
new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
clientFactory.getAuthenticationManager().refreshUserInfo();
Window.alert(i18n_sec.successfullyUpdatedUserProperties(username));
}
@Override
public void onFailure(Throwable caught) {
Window.alert(i18n_sec.errorUpdatingUserProperties(caught.getMessage()));
}
});
}
@Override
public void handleEmailChangeRequest(final String email) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
final String url = Window.Location.createUrlBuilder()
.setHash(homePlacesNavigator.getMailVerifiedConfirmationNavigation().getTargetUrl()).buildString();
clientFactory.getUserManagementService().updateSimpleUserEmail(username, email, url,
new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
Window.alert(i18n_sec.successfullyUpdatedEmail(username, email));
}
@Override
public void onFailure(Throwable caught) {
Window.alert(i18n_sec.errorUpdatingEmail(caught.getMessage()));
}
});
}
@Override
public void handlePasswordChangeRequest(String oldPassword, String newPassword, String newPasswordConfirmation) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
String errorMessage = validator.validateUsernameAndPassword(username, newPassword, newPasswordConfirmation);
if (errorMessage != null && !errorMessage.isEmpty()) {
Window.alert(errorMessage);
return;
}
clientFactory.getUserManagementService().updateSimpleUserPassword(username, oldPassword, null, newPassword,
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UserManagementException) {
String message = ((UserManagementException) caught).getMessage();
if (UserManagementException.PASSWORD_DOES_NOT_MEET_REQUIREMENTS.equals(message)) {
Window.alert(i18n_sec.passwordDoesNotMeetRequirements());
} else if (UserManagementException.INVALID_CREDENTIALS.equals(message)) {
Window.alert(i18n_sec.invalidCredentials());
} else {
Window.alert(i18n_sec.errorChangingPassword(caught.getMessage()));
}
} else {
Window.alert(i18n_sec.errorChangingPassword(caught.getMessage()));
}
}
@Override
public void onSuccess(Void result) {
Window.alert(i18n_sec.passwordSuccessfullyChanged());
currentView.setUserManagementContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
}
});
}
@Override
public void handleTabPlaceSelection(TabView<?, ? extends UserProfileView.Presenter> selectedActivity) {
Place tabPlaceToGo = selectedActivity.placeToFire();
@@ -168,4 +95,20 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile
public void doTriggerLoginForm() {
clientFactory.getEventBus().fireEvent(new AuthenticationRequestEvent());
}
@Override
public AuthenticationManager getAuthenticationManager() {
return clientFactory.getAuthenticationManager();
}
@Override
public String getMailVerifiedUrl() {
return homePlacesNavigator
.getMailVerifiedConfirmationNavigation().getTargetUrl();
}
@Override
public UserManagementServiceAsync getUserManagementService() {
return clientFactory.getUserManagementService();
}
}
@@ -2,10 +2,8 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
public interface UserProfileTabView<PLACE extends AbstractUserProfilePlace> extends TabView<PLACE, UserProfileView.Presenter> {
void setUserManagementContext(AuthenticationContext userManagementContext);
public interface UserProfileTabView<PLACE extends AbstractUserProfilePlace> extends
TabView<PLACE, UserProfileView.Presenter>, NeedsAuthenticationContext {
}
@@ -4,17 +4,18 @@ import com.google.gwt.place.shared.Place;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.desktop.partials.useraccountDetails.UserAccountDetails;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.places.fakeseries.AbstractSeriesPlace;
import com.sap.sailing.gwt.home.shared.places.start.StartPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.AuthenticationManager;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.client.UserManagementServiceAsync;
public interface UserProfileView<PLACE extends AbstractUserProfilePlace, PRES extends UserProfileView.Presenter> extends IsWidget {
public interface UserProfileView<PLACE extends AbstractUserProfilePlace, PRES extends UserProfileView.Presenter> extends IsWidget, NeedsAuthenticationContext {
public interface Presenter extends UserAccountDetails.Presenter, NotLoggedInPresenter {
public interface Presenter extends NotLoggedInPresenter {
void handleTabPlaceSelection(TabView<?, ? extends Presenter> selectedActivity);
SafeUri getUrl(AbstractSeriesPlace place);
@@ -22,6 +23,12 @@ public interface UserProfileView<PLACE extends AbstractUserProfilePlace, PRES ex
PlaceNavigation<StartPlace> getHomeNavigation();
PlaceNavigation<? extends AbstractUserProfilePlace> getUserProfileNavigation();
AuthenticationManager getAuthenticationManager();
UserManagementServiceAsync getUserManagementService();
String getMailVerifiedUrl();
}
/**
@@ -39,7 +46,4 @@ public interface UserProfileView<PLACE extends AbstractUserProfilePlace, PRES ex
void navigateTabsTo(PLACE place);
void showErrorInCurrentTab(IsWidget errorView);
void setUserManagementContext(AuthenticationContext userManagementContext);
}
@@ -0,0 +1,27 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.detailstab;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsPresenter;
public class UserProfileDetailsPresenter implements UserProfileDetailsView.Presenter {
private final UserProfileDetailsView view;
private final UserDetailsPresenter userDetailsPresenter;
public UserProfileDetailsPresenter(UserProfileDetailsView view, UserProfileView.Presenter userProfilePresenter) {
this.view = view;
view.setPresenter(this);
userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(),
userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(),
userProfilePresenter.getMailVerifiedUrl());
}
@Override
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
view.getDecorator().setAuthenticationContext(authenticationContext);
userDetailsPresenter.setAuthenticationContext(authenticationContext);
}
}
@@ -1,17 +1,11 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.detailstab;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.desktop.partials.useraccountDetails.UserAccountDetails;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileTabView;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDetailsPlace;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
/**
@@ -19,18 +13,9 @@ import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
*/
public class UserProfileDetailsTabView extends Composite implements UserProfileTabView<UserProfileDetailsPlace> {
interface MyBinder extends UiBinder<Widget, UserProfileDetailsTabView> {
}
private UserProfileDetailsView.Presenter currentPresenter;
private static MyBinder ourUiBinder = GWT.create(MyBinder.class);
@UiField(provided = true)
AuthorizedContentDecoratorDesktop decoratorUi;
@UiField(provided = true)
UserAccountDetails accountDetailsUi;
private UserProfileView.Presenter currentPresenter;
private UserProfileDetailsView view;
public UserProfileDetailsTabView() {
}
@@ -47,16 +32,12 @@ public class UserProfileDetailsTabView extends Composite implements UserProfileT
@Override
public void start(UserProfileDetailsPlace myPlace, AcceptsOneWidget contentArea) {
decoratorUi = new AuthorizedContentDecoratorDesktop(currentPresenter);
accountDetailsUi = new UserAccountDetails(currentPresenter);
initWidget(ourUiBinder.createAndBindUi(this));
contentArea.setWidget(this);
contentArea.setWidget(view);
}
@Override
public void setUserManagementContext(AuthenticationContext userManagementContext) {
decoratorUi.setUserManagementContext(userManagementContext);
accountDetailsUi.setUserManagementContext(userManagementContext);
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
currentPresenter.setAuthenticationContext(authenticationContext);
}
@Override
@@ -71,6 +52,7 @@ public class UserProfileDetailsTabView extends Composite implements UserProfileT
@Override
public void setPresenter(UserProfileView.Presenter currentPresenter) {
this.currentPresenter = currentPresenter;
view = new UserProfileDetailsViewImpl();
this.currentPresenter = new UserProfileDetailsPresenter(view, currentPresenter);
}
}
@@ -0,0 +1,19 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.detailstab;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
public interface UserProfileDetailsView extends IsWidget {
void setPresenter(Presenter presenter);
UserDetailsView getUserDetailsView();
NeedsAuthenticationContext getDecorator();
public interface Presenter {
void setAuthenticationContext(AuthenticationContext userManagementContext);
}
}
@@ -0,0 +1,52 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.detailstab;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.userprofile.desktop.userdetails.UserAccountDetails;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
/**
* Created by pgtaboada on 25.11.14.
*/
public class UserProfileDetailsViewImpl extends Composite implements UserProfileDetailsView {
interface MyBinder extends UiBinder<Widget, UserProfileDetailsViewImpl> {
}
private static MyBinder ourUiBinder = GWT.create(MyBinder.class);
@UiField(provided = true)
AuthorizedContentDecoratorDesktop decoratorUi;
@UiField(provided = true)
UserAccountDetails accountDetailsUi;
private UserProfileView.Presenter currentPresenter;
public UserProfileDetailsViewImpl() {
}
public UserDetailsView getUserDetailsView() {
return accountDetailsUi;
}
@Override
public void setPresenter(Presenter presenter) {
decoratorUi = new AuthorizedContentDecoratorDesktop(currentPresenter);
accountDetailsUi = new UserAccountDetails(SharedResources.INSTANCE);
initWidget(ourUiBinder.createAndBindUi(this));
}
@Override
public NeedsAuthenticationContext getDecorator() {
return decoratorUi;
}
}
@@ -1,12 +1,13 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.partials" xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator">
xmlns:ud="urn:import:com.sap.sse.security.ui.userprofile.desktop.userdetails"
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
</ui:style>
<um:AuthorizedContentDecoratorDesktop ui:field="decoratorUi">
<um:content>
<s:useraccountDetails.UserAccountDetails ui:field="accountDetailsUi"
<ud:UserAccountDetails ui:field="accountDetailsUi"
addStyleNames="{res.mainCss.spacermargintopmediumbig} {res.mainCss.spacermarginbottommediumbig}" />
</um:content>
</um:AuthorizedContentDecoratorDesktop>
@@ -15,7 +15,6 @@ import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.i18n.TextMessages;
import com.sap.sailing.gwt.home.mobile.app.MobilePlacesNavigator;
import com.sap.sailing.gwt.home.shared.ExperimentalFeatures;
@@ -23,8 +22,9 @@ import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.app.ResettableNavigationPathDisplay;
import com.sap.sailing.gwt.home.shared.utils.DropdownHandler;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
import com.sap.sse.security.ui.authentication.AuthenticationRequestEvent;
import com.sap.sse.security.ui.authentication.AuthenticationSignOutRequestEvent;
public class Header extends Composite {
@@ -73,7 +73,7 @@ public class Header extends Composite {
signOutNavigationItem = addNavigation(com.sap.sse.security.ui.client.i18n.StringMessages.INSTANCE.signOut(), new Runnable() {
@Override
public void run() {
eventBus.fireEvent(new AuthenticationRequestEvent(false));
eventBus.fireEvent(new AuthenticationSignOutRequestEvent());
}
});
@@ -16,12 +16,12 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.home.communication.event.LabelType;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSelectionFilter;
import com.sap.sailing.gwt.home.shared.utils.CollapseAnimation;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sse.gwt.client.LinkUtil;
public class SectionHeaderContent extends Composite {
@@ -4,6 +4,16 @@
<ui:with field="i18n" type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.solutions.SolutionsResources" />
<ui:style>
.storeBadgesContainer>a>img {
height: 60px;
width: auto;
margin-right: 10px;
}
.storeBadgesContainer {
margin: 20px 0px;
}
</ui:style>
<g:HTMLPanel>
<div class="{res.mediaCss.grid}">
<div class="{local_res.css.solutions} {local_res.css.accordion}">
@@ -93,6 +103,18 @@
<p>
<ui:text from='{i18n.contentSapSailingRaceManager}' />
</p>
<div
class="{style.storeBadgesContainer}"
>
<a ui:field="raceManagerPlayStoreLinkUi"
href="{i18n.playstoreRacecommitteeApp}&amp;{i18n.playstoreCampaign}"
target="_blank"
><img
ui:field="raceManagerPlayStoreImgUi"
alt="Get it on Google Play"
src="{i18n.playstoreRacecommitteeBadge}"
/></a>
</div>
</div>
</div>
<div ui:field="postRaceAnalyticsUi"
@@ -128,6 +150,16 @@
<p>
<ui:text from='{i18n.i18nDeSolutionsTrainingText}' />
</p>
<div
class="{style.storeBadgesContainer}"
>
<a
alt="Get it on Appstore"
href="{i18n.appstoreStgTrainingstagebuch}"
target="_blank" >
<img src="images/home/appstore{i18n.appstoreBadgeSuffix}.svg"></img>
</a>
</div>
</div>
</div>
<div ui:field="strategySimulatorUi"
@@ -1,69 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="i18n_sec" type="com.sap.sse.security.ui.client.i18n.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.userdetails.UserDetailsResources" />
<g:HTMLPanel>
<div class="{local_res.css.userdetails}">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<form action="" method="">
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.username}' />
</div>
<input ui:field="usernameUi" type="text" disabled="disabled" class="{res.mainCss.input_input}" />
</div>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.name}' />
</div>
<input ui:field="nameUi" type="text" class="{res.mainCss.input_input}" />
</div>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.company}' />
</div>
<input ui:field="companyUi" type="text" class="{res.mainCss.input_input}" />
</div>
<g:Button ui:field="saveChangesUi" addStyleNames="{local_res.css.userdetails_save} {res.mainCss.button} {res.mainCss.buttonprimary}">
<ui:text from='{i18n_sec.save}' />
</g:Button>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.email}' />
</div>
<g:TextBox ui:field="emailUi" addStyleNames="{res.mainCss.input_input}" />
</div>
<g:Button ui:field="changeEmailUi" addStyleNames="{local_res.css.userdetails_save} {res.mainCss.button} {res.mainCss.buttonprimary}">
<ui:text from='{i18n_sec.save}' />
</g:Button>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.oldPassword}' />
</div>
<g:PasswordTextBox ui:field="oldPasswordUi" addStyleNames="{res.mainCss.input_input}" />
</div>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.password}' />
</div>
<g:PasswordTextBox ui:field="newPasswordUi" addStyleNames="{res.mainCss.input_input}" />
</div>
<div class="{res.mainCss.input}">
<div class="{res.mainCss.input_label}">
<ui:text from='{i18n_sec.passwordRepeat}' />
</div>
<g:PasswordTextBox ui:field="newPasswordConfirmationUi" addStyleNames="{res.mainCss.input_input}" />
</div>
<g:Button ui:field="changePasswordUi" addStyleNames="{local_res.css.userdetails_save} {res.mainCss.button} {res.mainCss.buttonprimary}">
<ui:text from='{i18n_sec.changePassword}' />
</g:Button>
</form>
</div>
</div>
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,43 +0,0 @@
package com.sap.sailing.gwt.home.mobile.partials.userheader;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.HeadingElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.shared.UserDTO;
public class UserHeader extends Composite {
interface MyUiBinder extends UiBinder<Widget, UserHeader> {
}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@UiField HeadingElement titleUi;
@UiField DivElement imageUi;
@UiField DivElement subtitleUi;
public UserHeader() {
UserHeaderResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
imageUi.getStyle().setBackgroundImage("url(images/home/userdefault.svg)");
titleUi.setInnerText("testuser");
subtitleUi.setInnerText("jennifer@auchnichtwennduderletztemenschauferdenwaerts.looser");
}
public void setUserManagementContext(AuthenticationContext userManagementContext) {
UserDTO currentUser = userManagementContext.getCurrentUser();
// TODO correct message
imageUi.setTitle("TODO picture of: " + currentUser.getName());
// TODO use image from user when field is available
imageUi.getStyle().setBackgroundImage("url(images/home/userdefault.svg)");
titleUi.setInnerText(userManagementContext.getUserTitle());
subtitleUi.setInnerText(userManagementContext.getUserSubtitle());
}
}
@@ -2,24 +2,19 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile;
import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
import com.sap.sse.security.ui.client.component.NewAccountValidator;
import com.sap.sse.security.ui.client.i18n.StringMessages;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsPresenter;
public class UserProfileDetailsActivity extends AbstractActivity implements UserProfileDetailsView.Presenter {
private final MobileApplicationClientFactory clientFactory;
private final StringMessages i18n_sec = StringMessages.INSTANCE;
private final NewAccountValidator validator = new NewAccountValidator(i18n_sec);
private final UserProfileDetailsView currentView = new UserProfileDetailsViewImpl(this);
private UserDetailsPresenter userDetailsPresenter;
public UserProfileDetailsActivity(AbstractUserProfilePlace place, MobileApplicationClientFactory clientFactory) {
this.clientFactory = clientFactory;
@@ -28,11 +23,17 @@ public class UserProfileDetailsActivity extends AbstractActivity implements User
@Override
public void start(final AcceptsOneWidget panel, final EventBus eventBus) {
panel.setWidget(currentView);
currentView.setUserManagementContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
currentView.setAuthenticationContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
userDetailsPresenter = new UserDetailsPresenter(currentView.getUserDetailsView(),
clientFactory.getAuthenticationManager(), clientFactory.getUserManagementService(), clientFactory
.getNavigator().getMailVerifiedConfirmationNavigation().getTargetUrl());
eventBus.addHandler(AuthenticationContextEvent.TYPE, new AuthenticationContextEvent.Handler() {
@Override
public void onUserChangeEvent(AuthenticationContextEvent event) {
currentView.setUserManagementContext(event.getCtx());
currentView.setAuthenticationContext(event.getCtx());
userDetailsPresenter.setAuthenticationContext(event.getCtx());
}
});
}
@@ -41,76 +42,4 @@ public class UserProfileDetailsActivity extends AbstractActivity implements User
public void doTriggerLoginForm() {
clientFactory.getNavigator().getSignInNavigation().goToPlace();
}
@Override
public void handleSaveChangesRequest(String fullName, String company) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
clientFactory.getUserManagementService().updateUserProperties(username, fullName, company,
new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
clientFactory.getAuthenticationManager().refreshUserInfo();
Window.alert(i18n_sec.successfullyUpdatedUserProperties(username));
}
@Override
public void onFailure(Throwable caught) {
Window.alert(i18n_sec.errorUpdatingUserProperties(caught.getMessage()));
}
});
}
@Override
public void handleEmailChangeRequest(final String email) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
final String url = Window.Location.createUrlBuilder()
.setHash(clientFactory.getNavigator().getMailVerifiedConfirmationNavigation().getTargetUrl())
.buildString();
clientFactory.getUserManagementService().updateSimpleUserEmail(username, email, url,
new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
Window.alert(i18n_sec.successfullyUpdatedEmail(username, email));
}
@Override
public void onFailure(Throwable caught) {
Window.alert(i18n_sec.errorUpdatingEmail(caught.getMessage()));
}
});
}
@Override
public void handlePasswordChangeRequest(String oldPassword, String newPassword, String newPasswordConfirmation) {
final String username = clientFactory.getAuthenticationManager().getAuthenticationContext().getCurrentUser().getName();
String errorMessage = validator.validateUsernameAndPassword(username, newPassword, newPasswordConfirmation);
if (errorMessage != null && !errorMessage.isEmpty()) {
Window.alert(errorMessage);
return;
}
clientFactory.getUserManagementService().updateSimpleUserPassword(username, oldPassword, null, newPassword,
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UserManagementException) {
String message = ((UserManagementException) caught).getMessage();
if (UserManagementException.PASSWORD_DOES_NOT_MEET_REQUIREMENTS.equals(message)) {
Window.alert(i18n_sec.passwordDoesNotMeetRequirements());
} else if (UserManagementException.INVALID_CREDENTIALS.equals(message)) {
Window.alert(i18n_sec.invalidCredentials());
} else {
Window.alert(i18n_sec.errorChangingPassword(caught.getMessage()));
}
} else {
Window.alert(i18n_sec.errorChangingPassword(caught.getMessage()));
}
}
@Override
public void onSuccess(Void result) {
Window.alert(i18n_sec.passwordSuccessfullyChanged());
currentView.setUserManagementContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
}
});
}
}
@@ -1,15 +1,15 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sailing.gwt.home.mobile.partials.userdetails.UserDetails;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
public interface UserProfileDetailsView extends IsWidget {
public interface UserProfileDetailsView extends IsWidget, NeedsAuthenticationContext {
void setUserManagementContext(AuthenticationContext userManagementContext);
UserDetailsView getUserDetailsView();
public interface Presenter extends UserDetails.Presenter, NotLoggedInPresenter {
public interface Presenter extends NotLoggedInPresenter {
}
}
@@ -5,10 +5,12 @@ import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.mobile.partials.userdetails.UserDetails;
import com.sap.sailing.gwt.home.mobile.partials.userheader.UserHeader;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.userprofile.mobile.userdetails.UserDetails;
import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader;
import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
public class UserProfileDetailsViewImpl extends Composite implements UserProfileDetailsView {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@@ -16,20 +18,25 @@ public class UserProfileDetailsViewImpl extends Composite implements UserProfile
interface MyUiBinder extends UiBinder<Widget, UserProfileDetailsViewImpl> {
}
@UiField UserHeader userHeaderUi;
@UiField(provided = true) AuthorizedContentDecoratorMobile decoratorUi;
@UiField(provided = true) UserDetails userDetailsUi;
@UiField(provided = true) final UserHeader userHeaderUi;
@UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi;
@UiField(provided = true) final UserDetails userDetailsUi;
public UserProfileDetailsViewImpl(Presenter presenter) {
userHeaderUi = new UserHeader(SharedResources.INSTANCE);
decoratorUi = new AuthorizedContentDecoratorMobile(presenter);
userDetailsUi = new UserDetails(presenter);
userDetailsUi = new UserDetails(SharedResources.INSTANCE);
initWidget(uiBinder.createAndBindUi(this));
}
@Override
public void setUserManagementContext(AuthenticationContext userManagementContext) {
userHeaderUi.setUserManagementContext(userManagementContext);
decoratorUi.setUserManagementContext(userManagementContext);
userDetailsUi.setUserManagementContext(userManagementContext);
public UserDetailsView getUserDetailsView() {
return userDetailsUi;
}
@Override
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
userHeaderUi.setAuthenticationContext(authenticationContext);
decoratorUi.setAuthenticationContext(authenticationContext);
}
}
@@ -1,12 +1,13 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:mp="urn:import:com.sap.sailing.gwt.home.mobile.partials"
xmlns:ud="urn:import:com.sap.sse.security.ui.userprofile.mobile.userdetails"
xmlns:uh="urn:import:com.sap.sse.security.ui.userprofile.mobile.userheader"
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator">
<g:FlowPanel>
<mp:userheader.UserHeader ui:field="userHeaderUi" />
<uh:UserHeader ui:field="userHeaderUi" />
<um:AuthorizedContentDecoratorMobile ui:field="decoratorUi">
<um:content>
<mp:userdetails.UserDetails ui:field="userDetailsUi" />
<ud:UserDetails ui:field="userDetailsUi" />
</um:content>
</um:AuthorizedContentDecoratorMobile>
</g:FlowPanel>
@@ -8,7 +8,7 @@ import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sse.gwt.client.LinkUtil;
public class PlaceNavigation<T extends Place> {
private final PlaceNavigator placeNavigator;
@@ -13,7 +13,6 @@ import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.common.client.SharedResources.MainCss;
import com.sap.sailing.gwt.common.client.i18n.TextMessages;
@@ -25,6 +24,7 @@ import com.sap.sailing.gwt.home.shared.partials.countdown.CountdownResources.Loc
import com.sap.sailing.gwt.home.shared.partials.countdowntimer.CountdownTimer;
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.LinkUtil;
public class Countdown extends Composite {
@@ -12,12 +12,12 @@ import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.LinkUtil;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.home.communication.event.LabelType;
import com.sap.sailing.gwt.home.shared.utils.ButtonUtil;
import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
import com.sap.sailing.gwt.home.shared.utils.ButtonUtil.ButtonType;
import com.sap.sse.gwt.client.LinkUtil;
public class LowerThird extends Widget {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@@ -1,34 +0,0 @@
package com.sap.sailing.gwt.home.shared.usermanagement.decorator;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.client.i18n.StringMessages;
public class AuthorizedContentDecorator extends Composite {
private final SimplePanel contentHolder = new SimplePanel();
private Widget content;
private final NotLoggedInView notLoggedInView;
public AuthorizedContentDecorator(NotLoggedInPresenter presenter, NotLoggedInView notLoggedInView) {
this.notLoggedInView = notLoggedInView;
notLoggedInView.setPresenter(presenter);
notLoggedInView.setMessage(StringMessages.INSTANCE.youAreNotSignedIn());
notLoggedInView.setSignInText(StringMessages.INSTANCE.signIn());
initWidget(contentHolder);
}
@UiChild(limit = 1)
public void addContent(Widget content) {
this.content = content;
}
public void setUserManagementContext(AuthenticationContext userManagementContext) {
contentHolder.setWidget(userManagementContext.isLoggedIn() ? content : notLoggedInView);
}
}
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.shared.usermanagement.decorator;
import com.sap.sse.security.ui.authentication.decorator.AuthorizedContentDecorator;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
public class AuthorizedContentDecoratorDesktop extends AuthorizedContentDecorator {
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.shared.usermanagement.decorator;
import com.sap.sse.security.ui.authentication.decorator.AuthorizedContentDecorator;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
public class AuthorizedContentDecoratorMobile extends AuthorizedContentDecorator {
@@ -1,5 +0,0 @@
package com.sap.sailing.gwt.home.shared.usermanagement.decorator;
public interface NotLoggedInPresenter {
void doTriggerLoginForm();
}
@@ -1,12 +0,0 @@
package com.sap.sailing.gwt.home.shared.usermanagement.decorator;
import com.google.gwt.user.client.ui.IsWidget;
public interface NotLoggedInView extends IsWidget {
void setPresenter(NotLoggedInPresenter presenter);
void setMessage(String message);
void setSignInText(String signInText);
}
@@ -9,6 +9,8 @@ import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInView;
public class NotLoggedInViewDesktopImpl extends Composite implements NotLoggedInView {
@@ -9,6 +9,8 @@ import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInView;
public class NotLoggedInViewMobileImpl extends Composite implements NotLoggedInView {
@@ -19,7 +19,7 @@ public class AuthenticationViewDesktop extends AbstractFlyoutAuthenticationView
Element anchor = Document.get().getElementById("usrMngmtFlyover");
if (anchor != null) {
int left = anchor.getAbsoluteLeft() + anchor.getOffsetWidth() - offsetWidth + 15;
popupPanel.setPopupPosition(left, anchor.getAbsoluteTop() + 20);
popupPanel.setPopupPosition(left, anchor.getAbsoluteTop() + 10);
}
getPresenter().onVisibilityChanged(true);
}
@@ -41,6 +41,7 @@
<inherits name='com.sap.sailing.gwt.ui.SourceCommon'/>
<inherits name='com.sap.sailing.gwt.ui.SourceSimulator'/>
<inherits name='com.sap.sailing.gwt.common.SourceCommon'/>
<inherits name='com.sap.sailing.gwt.common.AuthenticationCommon'/>
<inherits name='com.sap.sse.gwt.CommonControlCSS_Autoinject'/>
</module>
@@ -13,30 +13,12 @@ body {
font-weight: 500;
}
.eventDescription {
vertical-align: top;
height: 40px;
}
.repeatedInfoLabel {
margin: 10px;
font-size: 20px;
font-weight: 700;
}
.eventLabel {
color: #fff;
vertical-align: top;
font-size: 20px;
font-weight: 700;
}
.venueLabel {
color: #fff;
font-size: 18px;
vertical-align: top;
}
.clockLabel {
margin-left:30px;
@@ -14,12 +14,13 @@ import com.google.gwt.user.client.ui.Label;
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.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.common.theme.component.sapheader2.SAPHeader2;
import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
import com.sap.sse.gwt.client.URLEncoder;
import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAuthentication;
public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
@@ -33,11 +34,10 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
private DockLayoutPanel containerPanel;
private RaceDetailPanel detailPanel;
private RegattaOverviewPanel regattaPanel;
private final Label eventNameLabel = new Label();
private final Label venueNameLabel = new Label();
private final Label clockLabel = new Label();
private final RegattaOverviewResources.LocalCss style = RegattaOverviewResources.INSTANCE.css();
private SAPHeaderWithAuthentication siteHeader;
@Override
public void doOnModuleLoad() {
@@ -52,18 +52,14 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
rootPanel.add(containerPanel);
containerPanel.addStyleName(RegattaOverviewResources.INSTANCE.css().container());
FlowPanel descriptionUi = new FlowPanel();
descriptionUi.setStyleName(style.eventDescription());
eventNameLabel.addStyleName(style.eventLabel());
venueNameLabel.addStyleName(style.venueLabel());
clockLabel.addStyleName(style.clockLabel());
descriptionUi.add(eventNameLabel);
descriptionUi.add(venueNameLabel);
SAPHeader2 logoAndTitlePanel = new SAPHeader2(getStringMessages().sapSailingAnalytics(), descriptionUi, false);
siteHeader = new SAPHeaderWithAuthentication(getStringMessages()
.sapSailingAnalytics());
new FixedSailingAuthentication(getUserService(), siteHeader.getAuthenticationMenuView());
logoAndTitlePanel.addWidgetToRightSide(clockLabel);
containerPanel.addNorth(logoAndTitlePanel, 75);
siteHeader.addWidgetToRightSide(clockLabel);
containerPanel.addNorth(siteHeader, 75);
String eventIdAsString = Window.Location.getParameter(PARAM_EVENT);
if (eventIdAsString == null) {
@@ -103,9 +99,8 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
regattaPanel.addHandler(new EventDTOLoadedEvent.Handler() {
@Override
public void onEventDTOLoaded(EventDTOLoadedEvent e) {
eventNameLabel.setText(e.getCurrentEvent().getName());
venueNameLabel.setText(e.getCurrentEvent().venue.getName());
siteHeader.setHeaderTitle(e.getCurrentEvent().getName());
siteHeader.setHeaderSubTitle(e.getCurrentEvent().venue.getName());
}
}, EventDTOLoadedEvent.TYPE);
@@ -13,8 +13,6 @@ public interface RegattaOverviewResources extends ClientBundle {
public interface LocalCss extends CssResource {
String container();
String titleLabel();
String eventLabel();
String venueLabel();
String clockLabel();
String refreshStopTime();
String functionBar();
@@ -29,22 +27,13 @@ public interface RegattaOverviewResources extends ClientBundle {
String raceDetailPanel_content();
String leaderboards();
String viewerToolbar_innerElement();
String settingsButton();
String refreshButton();
String refreshButton_live();
String refreshButton_playing();
String eventDescription();
String button();
String buttonLeaderboard();
String functionBarLeft();
String repeatedInfoLabel();
}
}
Loaded 100 of 301 files, more files were not shown because too many files have changed in this diff. Show more