View Javadoc
1   /**
2    * This file Copyright (c) 2010-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.form.widget;
35  
36  import info.magnolia.ui.vaadin.gwt.client.form.tab.widget.FormTabWidget;
37  import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryWrapper;
38  import info.magnolia.ui.vaadin.gwt.client.tabsheet.event.ActiveTabChangedEvent;
39  import info.magnolia.ui.vaadin.gwt.client.tabsheet.event.TabSetChangedEvent;
40  import info.magnolia.ui.vaadin.gwt.client.tabsheet.tab.widget.MagnoliaTabWidget;
41  import info.magnolia.ui.vaadin.gwt.client.tabsheet.widget.MagnoliaTabSheetView;
42  
43  import java.util.ArrayList;
44  import java.util.List;
45  
46  import com.google.gwt.event.dom.client.ClickEvent;
47  import com.google.gwt.event.dom.client.ClickHandler;
48  import com.google.gwt.event.dom.client.FocusEvent;
49  import com.google.gwt.event.dom.client.FocusHandler;
50  import com.google.gwt.user.client.DOM;
51  import com.google.gwt.user.client.Element;
52  import com.google.gwt.user.client.Event;
53  import com.google.gwt.user.client.ui.FlowPanel;
54  import com.google.gwt.user.client.ui.HTML;
55  import com.google.gwt.user.client.ui.Widget;
56  import com.vaadin.client.Util;
57  
58  /**
59   * Actual client side implementation of the form view. Provides the methods for
60   * the client side presenter {@link com.vaadin.client.ui.form.FormConnector}.
61   */
62  public class FormViewImpl extends FlowPanel implements FormView {
63  
64      private static final String CLASSNAME = "form-panel";
65  
66      private static final String CLASSNAME_CONTENT = "form-content";
67  
68      private static final String ClASSNAME_ERROR = "form-error";
69  
70      private final List<FormTabWidget> formTabs = new ArrayList<FormTabWidget>();
71  
72      private final Element contentEl = DOM.createDiv();
73  
74      private FormFieldWrapper lastFocused = null;
75  
76      private MagnoliaTabSheetView tabSheet;
77  
78      private Presenter presenter;
79  
80      private boolean hasErrors = false;
81  
82      private FlowPanel errorPanel = new FlowPanel();
83  
84      private String errorsLabel;
85  
86      private String nextErrorLabel;
87  
88      public FormViewImpl() {
89          super();
90          setStylePrimaryName(CLASSNAME);
91  
92          errorPanel.addStyleName(ClASSNAME_ERROR);
93          errorPanel.setVisible(false);
94          add(errorPanel);
95  
96          contentEl.addClassName(CLASSNAME_CONTENT);
97          getElement().appendChild(contentEl);
98      }
99  
100     @Override
101     public void setContent(Widget contentWidget) {
102         if (contentWidget instanceof MagnoliaTabSheetView) {
103             if (tabSheet != null) {
104                 remove(tabSheet);
105             }
106 
107             this.tabSheet = (MagnoliaTabSheetView) contentWidget;
108             tabSheet.addTabSetChangedHandler(new TabSetChangedEvent.Handler() {
109                 @Override
110                 public void onTabSetChanged(TabSetChangedEvent event) {
111                     final List<MagnoliaTabWidget> tabs = event.getTabSheet().getTabs();
112                     formTabs.clear();
113                     for (final MagnoliaTabWidget tab : tabs) {
114                         if (tab instanceof FormTabWidget) {
115                             formTabs.add((FormTabWidget) tab);
116                         }
117                     }
118                 }
119             });
120 
121             tabSheet.addActiveTabChangedHandler(new ActiveTabChangedEvent.Handler() {
122                 @Override
123                 public void onActiveTabChanged(ActiveTabChangedEvent event) {
124                     // Focus the first field on the form of the current tab.
125                     if (!hasErrors) {
126                         if (!event.isShowingAllTabs()) {
127                             focusFirstFieldInTab((FormTabWidget) event.getTab());
128                         } else {
129                             focusFirstFieldInTab(formTabs.get(0));
130                         }
131                     }
132 
133                     // Keep track of last focused field by adding focus handlers to every field.
134                     lastFocused = null;
135                     if (!event.isShowingAllTabs()) {
136                         setFieldFocusHandler((FormTabWidget) event.getTab());
137                     } else {
138                         for (FormTabWidget tab : formTabs) {
139                             setFieldFocusHandler(tab);
140                         }
141                     }
142                 }
143 
144                 private void focusFirstFieldInTab(FormTabWidget tab) {
145                     if (tab.getFields().isEmpty()) {
146                         return;
147                     }
148                     FormFieldWrapper firstField = tab.getFields().get(0);
149                     firstField.focusField();
150                 }
151 
152                 private void setFieldFocusHandler(FormTabWidget tab) {
153                     final List<FormFieldWrapper> fields = tab.getFields();
154                     for (final FormFieldWrapper field : fields) {
155                         field.addFocusHandler(new FocusHandler() {
156                             @Override
157                             public void onFocus(FocusEvent event) {
158                                 final Element target = event.getRelativeElement().cast();
159                                 lastFocused = Util.findWidget(target, FormFieldWrapper.class);
160                             }
161                         });
162                     }
163                 }
164             });
165             add(tabSheet.asWidget(), contentEl);
166         }
167     }
168 
169     @Override
170     public void setErrorsLabel(String errorsLabel) {
171         this.errorsLabel = errorsLabel;
172     }
173 
174     @Override
175     public void setNextErrorLabel(String nextErrorLabel) {
176         this.nextErrorLabel = nextErrorLabel;
177     }
178 
179     @Override
180     public void setErrorAmount(int totalProblematicFields) {
181         hasErrors = (totalProblematicFields > 0);
182 
183         errorPanel.setVisible(totalProblematicFields > 0);
184         if (totalProblematicFields > 0) {
185             String formattedTotal = String.valueOf(totalProblematicFields);
186             errorPanel.getElement().setInnerHTML("<span>" + errorsLabel.replaceFirst("#", formattedTotal) + "</span>");
187             final HTML errorButton = new HTML("[" + nextErrorLabel + "]");
188             errorButton.setStyleName("action-jump-to-next-error");
189             DOM.sinkEvents(errorButton.getElement(), Event.MOUSEEVENTS);
190             errorButton.addDomHandler(new ClickHandler() {
191                 @Override
192                 public void onClick(ClickEvent event) {
193                     jumpToNextError();
194                 }
195             }, ClickEvent.getType());
196             errorPanel.add(errorButton);
197             presenter.onErrorsDisplayed();
198         }
199     }
200 
201     @Override
202     public void setPresenter(final Presenter presenter) {
203         this.presenter = presenter;
204     }
205 
206     @Override
207     public void setDescriptionVisible(boolean isVisible) {
208         for (final FormTabWidget tab : formTabs) {
209             tab.setDescriptionVisible(isVisible);
210         }
211     }
212 
213     public void jumpToNextError() {
214         presenter.jumpToNextError(lastFocused);
215     }
216 
217     @Override
218     public void setMaxHeight(int height) {
219         if (this.hasErrors) {
220             height -= JQueryWrapper.select(errorPanel).marginHeight();
221         }
222         if (this.tabSheet != null) {
223             this.tabSheet.setMaxHeight(height);
224         }
225     }
226 }