bug4104: Sharing of tags is now supported

This commit is contained in:
D067890 committed 2018-09-18 12:30:06 +02:00
1 parent f56e708848
commit a5a512acc6
10 files changed
+205 -13

No files matched your search

@@ -2113,6 +2113,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String tagAddTag();
String tagEditTag();
String tagDeleteTag();
String tagShareTag();
String tagAddTags();
String tagSavedSuccessfully();
String tagNotSaved();
@@ -2157,4 +2158,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String close();
String username();
String tagPublicModificationPermissionMissing();
String tagNotFound();
String tagInvalidURL();
String tagSharedDialog();
String tagSharedURL();
}
@@ -2109,6 +2109,7 @@ tagNoTagsFound=No tags found!
tagAddTag=Add Tag
tagEditTag=Edit Tag
tagDeleteTag=Delete Tag
tagShareTag=Share Tag
tagAddTags=Add Tags
tagSavedSuccessfully=Saved tag successfully
tagNotSaved=Could not save tag!
@@ -2153,3 +2154,7 @@ username=User name
confirm=Confirm
cancel=Cancel
close=Close
tagNotFound=Tag could not be found!
tagInvalidURL=Invalid URL parameter
tagSharedDialog=Shared tag
tagSharedURL=URL:
@@ -2104,6 +2104,7 @@ tagNoTagsFound=Keine Tags gefunden!
tagAddTag=Tag hinzufügen
tagEditTag=Tag bearbeiten
tagDeleteTag=Tag löschen
tagShareTag=Tag teilen
tagAddTags=Tags hinzufügen
tagSavedSuccessfully=Tag erfolgreich gespeichert
tagNotSaved=Tag konnte nicht gespeichert werden!
@@ -2148,3 +2149,7 @@ username=Benutzername
confirm=Fortfahren
cancel=Abbrechen
close=Schließen
tagNotFound=Tag wurde nicht gefunden!
tagInvalidURL=URL Parameter nicht gültig
tagSharedDialog=Geteilter Tag
tagSharedURL=URL:
@@ -302,10 +302,16 @@ public class RaceBoardPanel
raceMap.getRightHeaderPanel().add(userManagementMenuView);
addChildComponent(raceMap);
// add panel for tagging functionality, hidden by default
// add panel for tagging functionality, hidden if no url parameter "tags" is passed default
taggingPanel = new TaggingPanel(parent, componentContext, stringMessages, sailingService, userService, timer, raceTimesInfoProvider);
addChildComponent(taggingPanel);
taggingPanel.setVisible(false);
if(Window.Location.getParameter("tag") != null) {
taggingPanel.setVisible(true);
}
else {
taggingPanel.setVisible(false);
}
// Determine if the screen is large enough to initially display the leaderboard panel on the left side of the
// map based on the initial screen width. Afterwards, the leaderboard panel visibility can be toggled as usual.
@@ -14,10 +14,13 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.Window;
import com.sap.sailing.domain.common.dto.TagDTO;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.raceboard.tagging.TagPanelResources.TagPanelStyle;
import com.sap.sailing.gwt.ui.raceboard.tagging.TaggingPanel.State;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.security.ui.client.UserService;
/**
@@ -29,7 +32,7 @@ public class TagCell extends AbstractCell<TagDTO> {
* Contains different configurations for {@link TagCell}s. Used as {@link SafeHtmlTemplates template} for
* {@link TagCell}s. <br/>
* <br/>
* <b>Notice:</b> CSS classes need to be provied as parameters as CSS classnames are context sensitive and can't be
* <b>Notice:</b> CSS classes need to be provided as parameters as CSS classnames are context sensitive and can't be
* hardcoded.
*/
protected interface TagCellTemplate extends SafeHtmlTemplates {
@@ -49,11 +52,13 @@ public class TagCell extends AbstractCell<TagDTO> {
* @param content
* available configurations are {@link #contentWithCommentWithImage},
* {@link #contentWithCommentWithoutImage} and {@link #contentWithoutCommentWithImage}.
* @param shareButton
* @param content2
* @return {@link SafeHtml HTML template}
*/
@Template("<div class='{0}'><div class='{1}'>{3}{4}{5}</div><div class='{2}'>{6}</div>{7}</div>")
@Template("<div class='{0}'><div class='{1}'>{3}{4}{5}{8}</div><div class='{2}'>{6}</div>{7}</div>")
SafeHtml cell(String classTag, String classTagHeading, String classTagCreated, SafeHtml icon, SafeHtml buttons,
SafeHtml tag, SafeHtml created, SafeHtml content);
SafeHtml tag, SafeHtml created, SafeHtml content, SafeHtml shareButtonHeader);
/**
* Renders content with maximal configuration (comment and image).
@@ -105,6 +110,14 @@ public class TagCell extends AbstractCell<TagDTO> {
SafeHtml headerButtonsDeletableAndModifyable(String classTagHeadingButtons, SafeHtml editButton,
SafeHtml deleteButton);
/**
* Renders part of heading holding a button to share a tag.
*
* @return {@link SafeHtml HTML template}
*/
@Template("<div class='{0}'>{1}</div>")
SafeHtml shareButtonHeader(String classTagHeadingButtons, SafeHtml shareButton);
/**
* Renders icon with given source.
*
@@ -185,6 +198,10 @@ public class TagCell extends AbstractCell<TagDTO> {
icon = tagCellTemplate.icon(safeIsPrivateImageUri);
}
SafeHtml shareButton = tagCellTemplate.button(style.tagActionButton() + " " + style.tagShareButton(),
stringMessages.tagShareTag(), tagCellTemplate.icon(resources.shareIcon().getSafeUri()));
SafeHtml shareButtonHeader = tagCellTemplate.shareButtonHeader(style.tagCellHeadingButtons(), shareButton);
SafeHtml headingButtons = SafeHtmlUtils.EMPTY_SAFE_HTML;
// preview cells do not show buttons
if (!isPreviewCell) {
@@ -213,7 +230,7 @@ public class TagCell extends AbstractCell<TagDTO> {
cellStyle = style.tagCell() + " " + style.tagCellActive();
}
SafeHtml cell = tagCellTemplate.cell(cellStyle, style.tagCellHeading(), style.tagCellCreated(), icon,
headingButtons, safeTag, safeCreated, content);
headingButtons, safeTag, safeCreated, content, shareButtonHeader);
htmlBuilder.append(cell);
}
@@ -251,6 +268,11 @@ public class TagCell extends AbstractCell<TagDTO> {
});
} else if (button.hasClassName(style.tagEditButton())) {
taggingPanel.setCurrentState(State.EDIT_TAG);
} else if (button.hasClassName(style.tagShareButton())) {
String currentURL = Window.Location.getHref();
String urlWithTagParam = currentURL
.concat("&tag=" + tag.getRaceTimepoint().asMillis() + tag.getTag());
new TagSharedURLDialog(taggingPanel, urlWithTagParam).show();
}
}
}
@@ -11,6 +11,9 @@ import com.google.gwt.resources.client.ImageResource;
public interface TagPanelResources extends ClientBundle {
public static final TagPanelResources INSTANCE = GWT.create(TagPanelResources.class);
@Source("com/sap/sailing/gwt/ui/client/images/share.png")
ImageResource shareIcon();
@Source("com/sap/sailing/gwt/ui/client/images/edit.png")
ImageResource editIcon();
@@ -62,6 +65,7 @@ public interface TagPanelResources extends ClientBundle {
String tagActionButton();
String tagEditButton();
String tagDeleteButton();
String tagShareButton();
String tagCellCreated();
String tagCellComment();
String tagCellImage();
@@ -100,6 +104,11 @@ public interface TagPanelResources extends ClientBundle {
String tagFilterSearchBox();
String tagFilterSearchInput();
String tagFilterCurrentSelection();
//shared tag dialog
String tagSharedURLLabel();
String tagSharedURLTextBox();
String tagSharedURLDialog();
// images
String imageActiveFilter();
@@ -108,6 +117,7 @@ public interface TagPanelResources extends ClientBundle {
String imageClearSearch();
String imageSettings();
String imagePusTransparent();
String imageShare();
String imageEdit();
String imageDelete();
}
@@ -0,0 +1,65 @@
package com.sap.sailing.gwt.ui.raceboard.tagging;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.TextBox;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.raceboard.tagging.TagPanelResources.TagPanelStyle;
/**
* A Dialog to show the URL of shared tags
*/
public class TagSharedURLDialog extends DialogBox {
private final TagPanelResources resources = TagPanelResources.INSTANCE;
private final TagPanelStyle style = resources.style();
/**
* Creates a Dialog which shows the user the URL of the tag he wants to share
*
* @param taggingPanel
* {@link TaggingPanel} which creates this {@link TagSharedURLDialog}.
* @param url
* A URL which if called opens the {@link TaggingPanel} and selects the shared tag.
*/
public TagSharedURLDialog(TaggingPanel taggingPanel, String url) {
StringMessages stringMessages = taggingPanel.getStringMessages();
Panel mainPanel = new FlowPanel();
Label descriptionLabel = new Label();
descriptionLabel.setText(stringMessages.tagSharedURL());
descriptionLabel.setStyleName(style.tagSharedURLLabel());
descriptionLabel.addStyleName("gwt-Label");
TextBox urlTextBox = new TextBox();
urlTextBox.setText(url);
urlTextBox.setStyleName(style.tagSharedURLTextBox());
urlTextBox.addStyleName("gwt-TextBox");
Panel buttonPanel = new FlowPanel();
buttonPanel.setStyleName(style.buttonsPanel());
Button closeButton = new Button(stringMessages.close());
closeButton.setStyleName(style.tagDialogButton());
closeButton.addStyleName("gwt-Button");
closeButton.addClickHandler(event -> {
hide();
});
buttonPanel.add(closeButton);
mainPanel.add(descriptionLabel);
mainPanel.add(urlTextBox);
mainPanel.add(buttonPanel);
setGlassEnabled(true);
setText(stringMessages.tagSharedDialog());
addStyleName(style.tagSharedURLDialog());
setWidget(mainPanel);
center();
}
}
@@ -8,6 +8,7 @@ import java.util.Map;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -51,9 +52,9 @@ import com.sap.sse.security.ui.shared.UserDTO;
* will be stored in the {@link com.sap.sse.security.UserStore UserStore}.<br/>
* <br/>
* The TaggingPanel is also used as a data provider for all of its subcomponents like header, footer and content
* section. Therefor the TaggingPanel provides references to important services, string messages, its current state ando
* section. Therefore the TaggingPanel provides references to important services, string messages, its current state ando
* so on.
* Best practise: The constructor of subcomponents of the TaggingPanel contains only the TaggingPanel as a parameter.
* Best practice: The constructor of subcomponents of the TaggingPanel contains only the TaggingPanel as a parameter.
* Every other required shared resource (string messages, service references, ...) can be requested from the
* TaggingPanel itself.
*/
@@ -100,6 +101,11 @@ public class TaggingPanel extends ComponentWithoutSettings
// current state of the Tagging-Panel
private State currentState;
//Needed for sharing Tags
private boolean firstTimePublicTagsLoaded = true;
private final TimePoint sharedTimePoint;
private final String sharedTag;
public TaggingPanel(Component<?> parent, ComponentContext<?> context, StringMessages stringMessages,
SailingServiceAsync sailingService, UserService userService, Timer timer,
@@ -132,6 +138,26 @@ public class TaggingPanel extends ComponentWithoutSettings
raceTimesInfoProvider.addRaceTimesInfoProviderListener(this);
setCurrentState(State.VIEW);
//Get the url parameter "tag" and divide it into the logical timepoint and the tag title
String urlParameter = Window.Location.getParameter("tag");
if(urlParameter != null) {
if(urlParameter.length() > 13) {
String timeMillisString = urlParameter.substring(0, 13);//Works till "Nov 20 2286", afterwards timeMillis length increases from 13 to 14 chars
String tagString = urlParameter.substring(13, urlParameter.length());
sharedTimePoint = new MillisecondsTimePoint(Long.parseLong(timeMillisString));
sharedTag = tagString;
}
else {
Notification.notify(stringMessages.tagInvalidURL(), NotificationType.WARNING);
sharedTimePoint = null;
sharedTag = null;
}
}
else {
sharedTimePoint = null;
sharedTag = null;
}
initializePanel();
}
@@ -236,7 +262,7 @@ public class TaggingPanel extends ComponentWithoutSettings
NotificationType.WARNING);
} else if (!isLoggedInAndRaceLogAvailable()) {
// User is not logged in or race can not be identifed because regatta, race column or fleet are missing.
// User is not logged in or race can not be identified because regatta, race column or fleet are missing.
Notification.notify(stringMessages.tagNotSaved(), NotificationType.ERROR);
} else if (tag.isEmpty()) {
@@ -540,7 +566,7 @@ public class TaggingPanel extends ComponentWithoutSettings
for (TagDTO tag : raceInfo.getTags()) {
if (tag.getRevokedAt() != null) {
// received tag is revoked => latestReceivedTagTime will be revokedAt if revoke event
// occured before latestReceivedTagTime
// occurred before latestReceivedTagTime
currentTags.remove(tag);
modifiedTags = true;
if (latestReceivedTagTime == null || (latestReceivedTagTime != null
@@ -550,7 +576,7 @@ public class TaggingPanel extends ComponentWithoutSettings
}
} else if (!currentTags.contains(tag)) {
// received tag is NOT revoked => latestReceivedTagTime will be createdAt if tag event
// occured before latestReceivedTagTime
// occurred before latestReceivedTagTime
currentTags.add(tag);
modifiedTags = true;
if (latestReceivedTagTime == null || (latestReceivedTagTime != null
@@ -569,6 +595,30 @@ public class TaggingPanel extends ComponentWithoutSettings
if (modifiedTags) {
updateContent();
}
//After tags were added for the first time, find tag which matches the URL Parameter "tag", hightlight it and jump to its logical timepoint
if(firstTimePublicTagsLoaded && raceInfo.getTags() != null) {
firstTimePublicTagsLoaded = false;
if(sharedTimePoint != null) {
timer.setTime(sharedTimePoint.asMillis());
if(sharedTag != null) {
TagDTO matchingTag = null;
for(TagDTO tag: tagListProvider.getAllTags()) {
if(tag.getRaceTimepoint().equals(sharedTimePoint) && tag.getTag().equals(sharedTag)) {
matchingTag = tag;
break;
}
}
if(matchingTag != null) {
tagSelectionModel.clear();
tagSelectionModel.setSelected(matchingTag, true);
}
else {
Notification.notify(stringMessages.tagNotFound(), NotificationType.WARNING);
}
}
}
}
});
}
}
@@ -70,6 +70,7 @@
display: inline-block;
}
/**************************** Tag-Cells ****************************/
.tagCell {
box-shadow: 1px 2px 3px lightgrey;
@@ -380,6 +381,20 @@
margin-top: 5px;
}
/**************************** SharedTag Dialog ****************************/
.tagSharedURLLabel{
margin-bottom: 5px;
}
.tagSharedURLTextBox{
width: 100%;
margin-bottom: 5px;
}
.tagSharedURLDialog{
}
/**************************** Disabled tags (during editing) ****************************/
.taggingPanelDisabled .tagCell {
background-color: lightgrey;
@@ -389,19 +404,28 @@
.taggingPanelDisabled .tagCell.tagCellActive {
background-color: #e5f2f9;
}
.taggingPanelDisabled .tagCellHeadingButtons,
.taggingPanelDisabled .tagCellHeadingButtons .tagEditButton,
.taggingPanelDisabled .tagCellHeadingButtons .tagEditButton:hover,
.taggingPanelDisabled .tagCellHeadingButtons .tagEditButton:focus,
.taggingPanelDisabled .tagCellHeadingButtons .tagDeleteButton,
.taggingPanelDisabled .tagCellHeadingButtons .tagDeleteButton:hover,
.taggingPanelDisabled .tagCellHeadingButtons .tagDeleteButton:focus {
.taggingPanelDisabled .tagCellHeadingButtons .tagDeleteButton:focus,
.taggingPanelDisabled .tagCellHeadingButtons .tagShareButton,
.taggingPanelDisabled .tagCellHeadingButtons .tagShareButton:hover,
.taggingPanelDisabled .tagCellHeadingButtons .tagShareButton:focus{
cursor: not-allowed;
outline: none;
}
/**************************** Images ****************************/
.imageShare {
gwt-sprite: "shareIcon";
width: 2em;
height: 2em;
background-size: contain;
}
.imageEdit {
gwt-sprite: "editIcon";
width: 2em;
Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B