View Javadoc
1   /**
2    * This file Copyright (c) 2012-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.vaadin.gwt.client.applauncher.widget;
35  
36  import info.magnolia.ui.vaadin.gwt.client.applauncher.event.AppActivationEvent;
37  import info.magnolia.ui.vaadin.gwt.client.applauncher.shared.AppTile;
38  
39  import java.util.Optional;
40  import java.util.function.Function;
41  
42  import com.google.gwt.event.dom.client.MouseOutEvent;
43  import com.google.gwt.event.dom.client.MouseOutHandler;
44  import com.google.gwt.event.dom.client.MouseOverEvent;
45  import com.google.gwt.event.dom.client.MouseOverHandler;
46  import com.google.gwt.user.client.DOM;
47  import com.google.gwt.user.client.Element;
48  import com.google.gwt.user.client.Event;
49  import com.google.gwt.user.client.ui.Widget;
50  import com.google.web.bindery.event.shared.EventBus;
51  import com.googlecode.mgwt.dom.client.event.touch.TouchEndEvent;
52  import com.googlecode.mgwt.dom.client.event.touch.TouchEndHandler;
53  import com.googlecode.mgwt.dom.client.event.touch.TouchStartEvent;
54  import com.googlecode.mgwt.dom.client.event.touch.TouchStartHandler;
55  import com.googlecode.mgwt.ui.client.widget.touch.TouchDelegate;
56  import com.vaadin.client.ui.Icon;
57  
58  /**
59   * The tile of one single app in AppLauncher.
60   */
61  public class AppTileWidget extends Widget {
62  
63      private final Element icon = DOM.createDiv();
64  
65      private final Element label = DOM.createDiv();
66      
67      private final Element ariaLink = DOM.createAnchor();
68  
69      private final Element root = DOM.createDiv();
70  
71      private final Element runningIndicator = DOM.createDiv();
72  
73      private final Function<String, Icon> iconSupplier;
74  
75      private final AppTile appTile;
76  
77      private final EventBus eventBus;
78  
79      private boolean isActive = false;
80  
81      private TouchDelegate touchDelegate = new TouchDelegate(this);
82  
83      public AppTileWidget(EventBus eventBus, AppTile appTile, Function<String, Icon> iconSupplier) {
84          super();
85          this.appTile = appTile;
86          this.eventBus = eventBus;
87          this.iconSupplier = iconSupplier;
88          constructDOM();
89          bindHandlers();
90          updateIcon();
91          updateCaption();
92          prepareAriaLink();
93      }
94  
95      private void constructDOM() {
96          setElement(root);
97          root.appendChild(icon);
98          root.appendChild(label);
99          root.appendChild(ariaLink);
100         root.appendChild(runningIndicator);
101         addStyleName("item");
102 
103         icon.addClassName("icon");
104         label.addClassName("label");
105         DOM.sinkEvents(getElement(), Event.MOUSEEVENTS);
106     }
107 
108     private void bindHandlers() {
109         /**
110          * Note that we have to add a explict hover class and not use the :hover
111          * pseudo-selector. This is because we need an active state for when in
112          * click that overrules the hover colors, And we cannot use an :active
113          * pseudoselector either because the colors are assigned by code, not
114          * stylesheet. But FYI, hover states are not useful for touch devices,
115          * just for desktop now.
116          */
117         addDomHandler(new MouseOverHandler() {
118             @Override
119             public void onMouseOver(MouseOverEvent event) {
120                 getElement().addClassName("hover");
121             }
122         }, MouseOverEvent.getType());
123 
124         addDomHandler(new MouseOutHandler() {
125             @Override
126             public void onMouseOut(MouseOutEvent event) {
127                 getElement().removeClassName("hover");
128                 updateColors();
129             }
130         }, MouseOutEvent.getType());
131 
132         touchDelegate.addTouchStartHandler(new TouchStartHandler() {
133             @Override
134             public void onTouchStart(TouchStartEvent event) {
135                 getElement().removeClassName("hover");
136                 setColorsClick();
137             }
138         });
139 
140         touchDelegate.addTouchEndHandler(new TouchEndHandler() {
141             @Override
142             public void onTouchEnd(TouchEndEvent event) {
143                 getElement().removeClassName("hover");
144                 setActiveState(true);
145                 eventBus.fireEvent(new AppActivationEvent(appTile.getName()));
146             }
147         });
148     }
149 
150     public void setActiveState(boolean isActive) {
151         this.isActive = isActive;
152         updateColors();
153     }
154 
155     /**
156      * ** COLORING. ********
157      */
158 
159     public void updateColors() {
160         if (isActive()) {
161             setColorsOn();
162         } else {
163             setColorsOff();
164         }
165     }
166 
167     /**
168      * Set the state: not active, not clicked.
169      */
170     private void setColorsOff() {
171         getElement().removeClassName("active");
172     }
173 
174     /**
175      * Set the the click state, whether active or not.
176      */
177     private void setColorsClick() {
178         getElement().addClassName("clicked");
179     }
180 
181     /**
182      * Set the state: active, but not in a click or touch.
183      */
184     private void setColorsOn() {
185         getElement().removeClassName("clicked");
186         getElement().addClassName("active");
187     }
188 
189     public String getName() {
190         return appTile.getName();
191     }
192 
193     public String getCaption() {
194         return appTile.getCaption();
195     }
196 
197     public boolean isActive() {
198         return isActive;
199     }
200 
201     @Override
202     public VAppTileGroup getParent() {
203         return (VAppTileGroup) super.getParent();
204     }
205 
206     public void updateCaption() {
207         if (appTile != null) {
208             label.setInnerText(appTile.getCaption());
209         }
210     }
211 
212     public void updateIcon() {
213         Optional.ofNullable(appTile.getIcon()).ifPresent(iconReference -> {
214             icon.removeAllChildren();
215             icon.appendChild(iconSupplier.apply(appTile.getIcon().getURL()).getElement());
216         });
217     }
218     
219     public void prepareAriaLink(){
220         ariaLink.setAttribute("href", "#app:" + appTile.getName());
221         ariaLink.setInnerText(appTile.getCaption());
222         ariaLink.addClassName("hidden-for-aria");
223     }
224 }