001    package org.gwtbootstrap3.client.ui;
002    
003    /*
004     * #%L
005     * GwtBootstrap3
006     * %%
007     * Copyright (C) 2013 GwtBootstrap3
008     * %%
009     * Licensed under the Apache License, Version 2.0 (the "License");
010     * you may not use this file except in compliance with the License.
011     * You may obtain a copy of the License at
012     * 
013     *      http://www.apache.org/licenses/LICENSE-2.0
014     * 
015     * Unless required by applicable law or agreed to in writing, software
016     * distributed under the License is distributed on an "AS IS" BASIS,
017     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018     * See the License for the specific language governing permissions and
019     * limitations under the License.
020     * #L%
021     */
022    
023    import java.util.List;
024    
025    import org.gwtbootstrap3.client.ui.base.ComplexWidget;
026    import org.gwtbootstrap3.client.ui.base.HasDataParent;
027    import org.gwtbootstrap3.client.ui.base.HasDataTarget;
028    import org.gwtbootstrap3.client.ui.base.HasDataToggle;
029    import org.gwtbootstrap3.client.ui.base.HasHref;
030    import org.gwtbootstrap3.client.ui.base.HasIcon;
031    import org.gwtbootstrap3.client.ui.base.HasIconPosition;
032    import org.gwtbootstrap3.client.ui.base.HasPull;
033    import org.gwtbootstrap3.client.ui.base.HasTarget;
034    import org.gwtbootstrap3.client.ui.base.HasTargetHistoryToken;
035    import org.gwtbootstrap3.client.ui.base.mixin.AttributeMixin;
036    import org.gwtbootstrap3.client.ui.base.mixin.DataParentMixin;
037    import org.gwtbootstrap3.client.ui.base.mixin.DataTargetMixin;
038    import org.gwtbootstrap3.client.ui.base.mixin.DataToggleMixin;
039    import org.gwtbootstrap3.client.ui.base.mixin.EnabledMixin;
040    import org.gwtbootstrap3.client.ui.base.mixin.FocusableMixin;
041    import org.gwtbootstrap3.client.ui.base.mixin.IconTextMixin;
042    import org.gwtbootstrap3.client.ui.base.mixin.PullMixin;
043    import org.gwtbootstrap3.client.ui.constants.Attributes;
044    import org.gwtbootstrap3.client.ui.constants.IconFlip;
045    import org.gwtbootstrap3.client.ui.constants.IconPosition;
046    import org.gwtbootstrap3.client.ui.constants.IconRotate;
047    import org.gwtbootstrap3.client.ui.constants.IconSize;
048    import org.gwtbootstrap3.client.ui.constants.IconType;
049    import org.gwtbootstrap3.client.ui.constants.Pull;
050    import org.gwtbootstrap3.client.ui.constants.Styles;
051    import org.gwtbootstrap3.client.ui.constants.Toggle;
052    
053    import com.google.gwt.dom.client.AnchorElement;
054    import com.google.gwt.dom.client.Document;
055    import com.google.gwt.event.dom.client.ClickEvent;
056    import com.google.gwt.event.dom.client.ClickHandler;
057    import com.google.gwt.event.dom.client.DoubleClickEvent;
058    import com.google.gwt.event.dom.client.DoubleClickHandler;
059    import com.google.gwt.event.dom.client.HasClickHandlers;
060    import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
061    import com.google.gwt.event.shared.HandlerRegistration;
062    import com.google.gwt.user.client.DOM;
063    import com.google.gwt.user.client.Event;
064    import com.google.gwt.user.client.History;
065    import com.google.gwt.user.client.ui.Focusable;
066    import com.google.gwt.user.client.ui.HasEnabled;
067    import com.google.gwt.user.client.ui.HasHTML;
068    import com.google.gwt.user.client.ui.Widget;
069    
070    /**
071     * Anchor {@code <a>} element with text and optional icon.
072     *
073     * @author Sven Jacobs
074     * @author Joshua Godi
075     * @author Grant Slender
076     */
077    public class Anchor extends ComplexWidget implements HasEnabled, HasClickHandlers, HasDoubleClickHandlers, HasHref, HasDataToggle, HasDataParent,
078            HasTargetHistoryToken, HasHTML, HasIcon, HasIconPosition, Focusable, HasDataTarget, HasTarget, HasPull {
079    
080        private final PullMixin<Anchor> pullMixin = new PullMixin<Anchor>(this);
081        private final DataToggleMixin<Anchor> toggleMixin = new DataToggleMixin<Anchor>(this);
082        private final DataParentMixin<Anchor> parentMixin = new DataParentMixin<Anchor>(this);
083        private final IconTextMixin<Anchor> iconTextMixin = new IconTextMixin<Anchor>(this);
084        private final DataTargetMixin<Anchor> targetMixin = new DataTargetMixin<Anchor>(this);
085        private final AttributeMixin<Anchor> attributeMixin = new AttributeMixin<Anchor>(this);
086        private final FocusableMixin<Anchor> focusableMixin = new FocusableMixin<Anchor>(this);
087        private final EnabledMixin<Anchor> enabledMixin = new EnabledMixin<Anchor>(this);
088        private String targetHistoryToken;
089    
090        /**
091         * Creates an anchor widget with the desired HREF
092         *
093         * @param href href for the anchor
094         */
095        public Anchor(final String href) {
096            setElement(Document.get().createAnchorElement());
097            setHref(href);
098            iconTextMixin.addTextWidgetToParent();
099        }
100    
101        /**
102         * Creates an achor widget with the desired HREF and text
103         *
104         * @param text text for the anchor
105         * @param href href for the anchor
106         */
107        public Anchor(final String text, final String href) {
108            this(href);
109            setText(text);
110        }
111    
112        /**
113         * Creates a default anchor with a default href
114         */
115        public Anchor() {
116            this(EMPTY_HREF);
117        }
118    
119        /**
120         * {@inheritDoc}
121         */
122        @Override
123        public HandlerRegistration addClickHandler(final ClickHandler handler) {
124            return addDomHandler(handler, ClickEvent.getType());
125        }
126    
127        /**
128         * {@inheritDoc}
129         */
130        @Override
131        public HandlerRegistration addDoubleClickHandler(final DoubleClickHandler handler) {
132            return addDomHandler(handler, DoubleClickEvent.getType());
133        }
134    
135        /**
136         * {@inheritDoc}
137         */
138        @Override
139        public void setText(final String text) {
140            iconTextMixin.setText(text);
141        }
142    
143        /**
144         * {@inheritDoc}
145         */
146        @Override
147        public String getText() {
148            return iconTextMixin.getText();
149        }
150    
151        /**
152         * {@inheritDoc}
153         */
154        @Override
155        public void setIcon(final IconType iconType) {
156            iconTextMixin.setIcon(iconType);
157        }
158    
159        /**
160         * {@inheritDoc}
161         */
162        @Override
163        public IconType getIcon() {
164            return iconTextMixin.getIcon();
165        }
166    
167        /**
168         * {@inheritDoc}
169         */
170        @Override
171        public void setIconPosition(final IconPosition iconPosition) {
172            iconTextMixin.setIconPosition(iconPosition);
173        }
174    
175        /**
176         * {@inheritDoc}
177         */
178        @Override
179        public IconPosition getIconPosition() {
180            return iconTextMixin.getIconPosition();
181        }
182    
183        /**
184         * {@inheritDoc}
185         */
186        @Override
187        public void setIconSize(final IconSize iconSize) {
188            iconTextMixin.setIconSize(iconSize);
189        }
190    
191        /**
192         * {@inheritDoc}
193         */
194        @Override
195        public IconSize getIconSize() {
196            return iconTextMixin.getIconSize();
197        }
198    
199        /**
200         * {@inheritDoc}
201         */
202        @Override
203        public void setIconFlip(final IconFlip iconFlip) {
204            iconTextMixin.setIconFlip(iconFlip);
205        }
206    
207        /**
208         * {@inheritDoc}
209         */
210        @Override
211        public IconFlip getIconFlip() {
212            return iconTextMixin.getIconFlip();
213        }
214    
215        /**
216         * {@inheritDoc}
217         */
218        @Override
219        public void setIconRotate(final IconRotate iconRotate) {
220            iconTextMixin.setIconRotate(iconRotate);
221        }
222    
223        /**
224         * {@inheritDoc}
225         */
226        @Override
227        public IconRotate getIconRotate() {
228            return iconTextMixin.getIconRotate();
229        }
230    
231        /**
232         * {@inheritDoc}
233         */
234        @Override
235        public void setIconBordered(final boolean iconBordered) {
236            iconTextMixin.setIconBordered(iconBordered);
237        }
238    
239        /**
240         * {@inheritDoc}
241         */
242        @Override
243        public boolean isIconBordered() {
244            return iconTextMixin.isIconBordered();
245        }
246    
247        /**
248         * {@inheritDoc}
249         */
250        @Override
251        public void setIconMuted(final boolean iconMuted) {
252            iconTextMixin.setIconMuted(iconMuted);
253        }
254    
255        /**
256         * {@inheritDoc}
257         */
258        @Override
259        public boolean isIconMuted() {
260            return iconTextMixin.isIconMuted();
261        }
262    
263        /**
264         * {@inheritDoc}
265         */
266        @Override
267        public void setIconLight(final boolean iconLight) {
268            iconTextMixin.setIconLight(iconLight);
269        }
270    
271        /**
272         * {@inheritDoc}
273         */
274        @Override
275        public boolean isIconLight() {
276            return iconTextMixin.isIconLight();
277        }
278    
279        /**
280         * {@inheritDoc}
281         */
282        @Override
283        public void setIconSpin(final boolean iconSpin) {
284            iconTextMixin.setIconSpin(iconSpin);
285        }
286    
287        /**
288         * {@inheritDoc}
289         */
290        @Override
291        public boolean isIconSpin() {
292            return iconTextMixin.isIconSpin();
293        }
294    
295        /**
296         * {@inheritDoc}
297         */
298        @Override
299        public void setIconFixedWidth(final boolean iconFixedWidth) {
300            iconTextMixin.setIconFixedWidth(iconFixedWidth);
301        }
302    
303        /**
304         * {@inheritDoc}
305         */
306        @Override
307        public boolean isIconFixedWidth() {
308            return iconTextMixin.isIconFixedWidth();
309        }
310    
311        /**
312         * {@inheritDoc}
313         */
314        @Override
315        public void setHref(final String href) {
316            AnchorElement.as(getElement()).setHref(href);
317        }
318    
319        /**
320         * {@inheritDoc}
321         */
322        @Override
323        public String getHref() {
324            return AnchorElement.as(getElement()).getHref();
325        }
326    
327        /**
328         * {@inheritDoc}
329         */
330        @Override
331        public void setTargetHistoryToken(final String targetHistoryToken) {
332            this.targetHistoryToken = targetHistoryToken;
333            final String hash = History.encodeHistoryToken(targetHistoryToken);
334            setHref("#" + hash);
335        }
336    
337        /**
338         * {@inheritDoc}
339         */
340        @Override
341        public String getTargetHistoryToken() {
342            return targetHistoryToken;
343        }
344    
345        /**
346         * {@inheritDoc}
347         */
348        @Override
349        public void setDataParent(final String dataParent) {
350            parentMixin.setDataParent(dataParent);
351        }
352    
353        /**
354         * {@inheritDoc}
355         */
356        @Override
357        public String getDataParent() {
358            return parentMixin.getDataParent();
359        }
360    
361        /**
362         * {@inheritDoc}
363         */
364        @Override
365        public void setDataToggle(final Toggle toggle) {
366            toggleMixin.setDataToggle(toggle);
367        }
368    
369        /**
370         * {@inheritDoc}
371         */
372        @Override
373        public Toggle getDataToggle() {
374            return toggleMixin.getDataToggle();
375        }
376    
377        /**
378         * {@inheritDoc}
379         */
380        @Override
381        public int getTabIndex() {
382            return focusableMixin.getTabIndex();
383        }
384    
385        /**
386         * {@inheritDoc}
387         */
388        @Override
389        public void setTabIndex(final int index) {
390            focusableMixin.setTabIndex(index);
391        }
392    
393        /**
394         * {@inheritDoc}
395         */
396        @Override
397        public void setAccessKey(final char key) {
398            focusableMixin.setAccessKey(key);
399        }
400    
401        /**
402         * {@inheritDoc}
403         */
404        @Override
405        public void setFocus(final boolean focused) {
406            focusableMixin.setFocus(focused);
407        }
408    
409        /**
410         * {@inheritDoc}
411         */
412        @Override
413        public String getHTML() {
414            return getElement().getInnerHTML();
415        }
416    
417        /**
418         * {@inheritDoc}
419         */
420        @Override
421        public void setHTML(final String html) {
422            getElement().setInnerHTML(html);
423        }
424    
425        @Override
426        public void setDataTargetWidgets(final List<Widget> widgets) {
427            targetMixin.setDataTargetWidgets(widgets);
428        }
429    
430        @Override
431        public void setDataTargetWidget(final Widget widget) {
432            targetMixin.setDataTargetWidget(widget);
433        }
434    
435        /**
436         * {@inheritDoc}
437         */
438        @Override
439        public void setDataTarget(final String dataTarget) {
440            targetMixin.setDataTarget(dataTarget);
441        }
442    
443        /**
444         * {@inheritDoc}
445         */
446        @Override
447        public String getDataTarget() {
448            return targetMixin.getDataTarget();
449        }
450    
451        /**
452         * {@inheritDoc}
453         */
454        @Override
455        public void setTarget(final String target) {
456            attributeMixin.setAttribute(Attributes.TARGET, target);
457        }
458    
459        /**
460         * {@inheritDoc}
461         */
462        @Override
463        public String getTarget() {
464            return attributeMixin.getAttribute(Attributes.TARGET);
465        }
466    
467        /**
468         * {@inheritDoc}
469         */
470        @Override
471        public void setPull(final Pull pull) {
472            pullMixin.setPull(pull);
473        }
474    
475        /**
476         * {@inheritDoc}
477         */
478        @Override
479        public Pull getPull() {
480            return pullMixin.getPull();
481        }
482    
483        /**
484         * {@inheritDoc}
485         */
486        @Override
487        public boolean isEnabled() {
488            return enabledMixin.isEnabled();
489        }
490    
491        /**
492         * {@inheritDoc}
493         */
494        @Override
495        public void setEnabled(final boolean enabled) {
496            enabledMixin.setEnabled(enabled);
497        }
498    
499        /**
500         * {@inheritDoc}
501         */
502        @Override
503        protected void onAttach() {
504            super.onAttach();
505    
506            // Adding styles to the heading depending on the parent
507            if (getParent() != null) {
508                if (getParent() instanceof Alert) {
509                    addStyleName(Styles.ALERT_LINK);
510                }
511            }
512        }
513    
514        /**
515         * We override this because the <a></a> tag doesn't support the disabled property. So on clicks and focus, if disabled then ignore
516         *
517         * @param event dom event
518         */
519        @Override
520        public void onBrowserEvent(final Event event) {
521            switch (DOM.eventGetType(event)) {
522                case Event.ONDBLCLICK:
523                case Event.ONFOCUS:
524                case Event.ONCLICK:
525                    if (!isEnabled()) {
526                        return;
527                    }
528                    break;
529            }
530            super.onBrowserEvent(event);
531        }
532    }