View Javadoc
1   /**
2    * This file Copyright (c) 2010-2017 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.formsection.widget.InlineMessageWidget;
37  
38  import com.google.gwt.dom.client.Element;
39  import com.google.gwt.dom.client.SpanElement;
40  import com.google.gwt.event.dom.client.BlurEvent;
41  import com.google.gwt.event.dom.client.BlurHandler;
42  import com.google.gwt.event.dom.client.ClickEvent;
43  import com.google.gwt.event.dom.client.ClickHandler;
44  import com.google.gwt.event.dom.client.FocusEvent;
45  import com.google.gwt.event.dom.client.FocusHandler;
46  import com.google.gwt.event.dom.client.HasBlurHandlers;
47  import com.google.gwt.event.dom.client.HasFocusHandlers;
48  import com.google.gwt.event.shared.HandlerRegistration;
49  import com.google.gwt.regexp.shared.MatchResult;
50  import com.google.gwt.regexp.shared.RegExp;
51  import com.google.gwt.user.client.DOM;
52  import com.google.gwt.user.client.ui.Button;
53  import com.google.gwt.user.client.ui.FlowPanel;
54  import com.google.gwt.user.client.ui.Widget;
55  import com.google.gwt.user.client.ui.impl.FocusImpl;
56  import com.vaadin.client.ui.aria.AriaHelper;
57  
58  /**
59   * Wrapper widget that provides help and error indication.
60   */
61  public class FormFieldWrapper extends FlowPanel implements HasFocusHandlers, HasBlurHandlers {
62  
63      private final static RegExp localisedPropertyCaptionPattern = RegExp.compile("^(.+)\\s(\\([a-zA-Z]{2}\\))$");
64  
65      private Element label = DOM.createDiv();
66  
67      private Element fieldWrapper = DOM.createDiv();
68  
69      private Element root;
70  
71      private Element requirementAsterisk = null;
72  
73      private final HelpIconWidget helpButton = new HelpIconWidget();
74  
75      private Button errorAction = new Button();
76  
77      private InlineMessageWidget errorSection = null;
78  
79      private InlineMessageWidget helpSection = null;
80  
81      private String helpDescription = null;
82  
83      private Widget field = null;
84  
85      public FormFieldWrapper() {
86          super();
87          addStyleName("v-form-field-section");
88          root = super.getElement();
89          construct();
90          setHelpEnabled(false);
91  
92          helpButton.addDomHandler(new ClickHandler() {
93              @Override
94              public void onClick(ClickEvent event) {
95                  if (helpSection == null) {
96                      showHelp();
97                  } else {
98                      hideHelp();
99                  }
100             }
101         }, ClickEvent.getType());
102 
103     }
104 
105     public void hideHelp() {
106         if (helpSection != null) {
107             remove(helpSection);
108         }
109         helpSection = null;
110         helpButton.setHighlighted(false);
111     }
112 
113     public void showHelp() {
114         if (helpDescription == null || "".equals(helpDescription)) {
115             return;
116         }
117         helpSection = InlineMessageWidget.createHelpMessage();
118         helpSection.setMessage(helpDescription);
119         add(helpSection, root);
120         helpButton.setHighlighted(true);
121     }
122 
123     private void construct() {
124         label.addClassName("v-form-field-label");
125         fieldWrapper.addClassName("v-form-field-container");
126         errorAction.addStyleName("action-validation");
127 
128         root.appendChild(label);
129         root.appendChild(fieldWrapper);
130         add(helpButton, fieldWrapper);
131         add(errorAction, fieldWrapper);
132     }
133 
134     public void showError(final String errorDescription) {
135         helpButton.setVisible(false);
136         errorAction.setVisible(true);
137         fieldWrapper.addClassName("validation-highlight");
138         if (errorSection == null) {
139             errorSection = InlineMessageWidget.createErrorMessage();
140         }
141         errorSection.setMessage(errorDescription);
142         add(errorSection, root);
143     }
144 
145     public void setCaption(String caption) {
146         final MatchResult localisedPropertyMatcher = localisedPropertyCaptionPattern.exec(caption);
147         if (localisedPropertyMatcher != null && localisedPropertyMatcher.getGroupCount() > 2) {
148             caption = localisedPropertyMatcher.getGroup(1);
149             label.setInnerText(caption);
150 
151             final Element localeLabel = SpanElement.as(DOM.createSpan());
152             localeLabel.setClassName("locale-label");
153             localeLabel.setInnerText(localisedPropertyMatcher.getGroup(2));
154 
155             if (requirementAsterisk != null  && label.isOrHasChild(requirementAsterisk)) {
156                 label.insertAfter(localeLabel, requirementAsterisk);
157             } else {
158                 label.insertFirst(localeLabel);
159             }
160         } else {
161             label.setInnerText(caption);
162         }
163 
164         if (caption != null) {
165             label.setTitle(caption);
166         }
167     }
168 
169     public void setRequired(boolean required) {
170         if (required) {
171             if (requirementAsterisk == null) {
172                 requirementAsterisk = SpanElement.as(DOM.createSpan());
173                 requirementAsterisk.setClassName("requiredfield");
174                 requirementAsterisk.setInnerText("*");
175             }
176             label.insertFirst(requirementAsterisk);
177         } else if (requirementAsterisk != null && label.isOrHasChild(requirementAsterisk)) {
178             label.removeChild(requirementAsterisk);
179         }
180     }
181 
182     @Override
183     public void add(Widget child) {
184         add(child, fieldWrapper);
185     }
186 
187     public void setField(Widget child) {
188         if (this.field != null) {
189             remove(field);
190         }
191         this.field = child;
192         if (child != null) {
193             child.removeFromParent();
194             AriaHelper.bindCaption(child, label);
195             getChildren().add(child);
196             fieldWrapper.insertBefore(child.getElement(), helpButton.getElement());
197             adopt(child);
198         }
199     }
200 
201     public boolean isDisplayingHelpSection() {
202         return helpSection != null;
203     }
204 
205     public void clearError() {
206         if (errorSection != null) {
207             remove(errorSection);
208             errorSection = null;
209         }
210         fieldWrapper.removeClassName("validation-highlight");
211         errorAction.setVisible(false);
212         if (helpDescription != null && !"".equals(helpDescription)) {
213             helpButton.setVisible(true);
214         }
215     }
216 
217     public void setHelpEnabled(boolean isHelpEnabled) {
218         helpButton.setVisible(helpDescription != null && !"".equals(helpDescription) && !errorAction.isVisible());
219         if (!isHelpEnabled && helpSection != null) {
220             hideHelp();
221             return;
222         }
223         if (isHelpEnabled && helpButton.isVisible() && helpSection == null) {
224             showHelp();
225         }
226     }
227 
228     public void setHelpDescription(String description) {
229         this.helpDescription = description;
230         if (helpSection != null && getWidgetIndex(helpSection) >= 0) {
231             helpSection.setMessage(helpDescription);
232         }
233         if (description != null && !"".equals(description)) {
234             helpButton.setVisible(true);
235         } else {
236             helpButton.setVisible(false);
237         }
238     }
239 
240     public void focusField() {
241         if (field != null) {
242             FocusImpl.getFocusImplForWidget().focus(field.getElement());
243         }
244     }
245 
246     public Widget getField() {
247         return field;
248     }
249 
250     @Override
251     public HandlerRegistration addFocusHandler(FocusHandler handler) {
252         return field.addDomHandler(handler, FocusEvent.getType());
253     }
254 
255     @Override
256     public HandlerRegistration addBlurHandler(BlurHandler handler) {
257         return field.addDomHandler(handler, BlurEvent.getType());
258     }
259 }