001package org.gwtbootstrap3.extras.datepicker.client.ui.base;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2016 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
023import java.util.Date;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.gwtbootstrap3.client.shared.event.HideEvent;
029import org.gwtbootstrap3.client.shared.event.HideHandler;
030import org.gwtbootstrap3.client.shared.event.ShowEvent;
031import org.gwtbootstrap3.client.shared.event.ShowHandler;
032import org.gwtbootstrap3.client.ui.TextBox;
033import org.gwtbootstrap3.client.ui.base.HasId;
034import org.gwtbootstrap3.client.ui.base.HasPlaceholder;
035import org.gwtbootstrap3.client.ui.base.HasResponsiveness;
036import org.gwtbootstrap3.client.ui.base.ValueBoxBase;
037import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
038import org.gwtbootstrap3.client.ui.base.mixin.BlankValidatorMixin;
039import org.gwtbootstrap3.client.ui.base.mixin.ErrorHandlerMixin;
040import org.gwtbootstrap3.client.ui.constants.DeviceSize;
041import org.gwtbootstrap3.client.ui.form.error.ErrorHandler;
042import org.gwtbootstrap3.client.ui.form.error.ErrorHandlerType;
043import org.gwtbootstrap3.client.ui.form.error.HasErrorHandler;
044import org.gwtbootstrap3.client.ui.form.validator.HasBlankValidator;
045import org.gwtbootstrap3.client.ui.form.validator.HasValidators;
046import org.gwtbootstrap3.client.ui.form.validator.ValidationChangedEvent.ValidationChangedHandler;
047import org.gwtbootstrap3.client.ui.form.validator.Validator;
048import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerDayOfWeek;
049import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerLanguage;
050import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerMinView;
051import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerPosition;
052import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasAutoClose;
053import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasDateTimePickerHandlers;
054import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasDaysOfWeekDisabled;
055import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasEndDate;
056import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasForceParse;
057import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasFormat;
058import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasHighlightToday;
059import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasKeyboardNavigation;
060import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasLanguage;
061import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasMinView;
062import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasPosition;
063import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasShowTodayButton;
064import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasShowClearButton;
065import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasStartDate;
066import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasStartView;
067import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasViewSelect;
068import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasWeekStart;
069import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeDateEvent;
070import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeDateHandler;
071import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeMonthEvent;
072import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeMonthHandler;
073import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeYearEvent;
074import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeYearHandler;
075import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ClearDateEvent;
076import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ClearDateHandler;
077
078import com.google.gwt.core.client.ScriptInjector;
079import com.google.gwt.dom.client.Element;
080import com.google.gwt.dom.client.Style;
081import com.google.gwt.editor.client.EditorError;
082import com.google.gwt.editor.client.HasEditorErrors;
083import com.google.gwt.editor.client.LeafValueEditor;
084import com.google.gwt.event.dom.client.BlurEvent;
085import com.google.gwt.event.dom.client.BlurHandler;
086import com.google.gwt.event.logical.shared.ValueChangeEvent;
087import com.google.gwt.event.logical.shared.ValueChangeHandler;
088import com.google.gwt.event.shared.HandlerRegistration;
089import com.google.gwt.i18n.client.DateTimeFormat;
090import com.google.gwt.user.client.Event;
091import com.google.gwt.user.client.ui.HasEnabled;
092import com.google.gwt.user.client.ui.HasName;
093import com.google.gwt.user.client.ui.HasValue;
094import com.google.gwt.user.client.ui.HasVisibility;
095import com.google.gwt.user.client.ui.Widget;
096
097/**
098 * @author Joshua Godi
099 * @author Steven Jardine
100 */
101public class DatePickerBase extends Widget implements HasEnabled, HasId, HasResponsiveness, HasVisibility, HasPlaceholder,
102        HasAutoClose, HasDaysOfWeekDisabled, HasEndDate, HasForceParse, HasFormat, HasHighlightToday, HasKeyboardNavigation,
103        HasMinView, HasShowTodayButton, HasShowClearButton, HasStartDate, HasStartView, HasViewSelect, HasWeekStart, HasDateTimePickerHandlers,
104        HasLanguage, HasName, HasValue<Date>, HasPosition, LeafValueEditor<Date>, HasEditorErrors<Date>, HasErrorHandler,
105        HasValidators<Date>, HasBlankValidator<Date> {
106
107    static class DatePickerValidatorMixin extends BlankValidatorMixin<DatePickerBase, Date> {
108
109        private boolean showing = false;
110
111        public void setShowing(boolean showing) {
112            this.showing = showing;
113        }
114
115        public DatePickerValidatorMixin(DatePickerBase inputWidget, ErrorHandler errorHandler) {
116            super(inputWidget, errorHandler);
117        }
118
119        @Override
120        protected com.google.web.bindery.event.shared.HandlerRegistration setupBlurValidation() {
121            return getInputWidget().addDomHandler(new BlurHandler() {
122                @Override
123                public void onBlur(BlurEvent event) {
124                    getInputWidget().validate(!showing && getValidateOnBlur());
125                }
126            }, BlurEvent.getType());
127        }
128
129    }
130
131    // Check http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/client/DateTimeFormat.html
132    // for more information on syntax
133    private static final Map<Character, Character> DATE_TIME_FORMAT_MAP = new HashMap<Character, Character>();
134
135    static {
136        DATE_TIME_FORMAT_MAP.put('m', 'M'); // months
137    }
138
139    private final TextBox textBox;
140    private DateTimeFormat dateTimeFormat;
141    private final DateTimeFormat startEndDateFormat = DateTimeFormat.getFormat("MM-dd-yyyy");
142    private LeafValueEditor<Date> editor;
143    private final ErrorHandlerMixin<Date> errorHandlerMixin = new ErrorHandlerMixin<Date>(this);
144    private final DatePickerValidatorMixin validatorMixin = new DatePickerValidatorMixin(this,
145            errorHandlerMixin.getErrorHandler());
146
147    /**
148     * DEFAULT values
149     */
150    private String format = "mm/dd/yyyy";
151    private DatePickerDayOfWeek weekStart = DatePickerDayOfWeek.SUNDAY;
152    private DatePickerDayOfWeek[] daysOfWeekDisabled = {};
153    private boolean autoClose = false;
154    private DatePickerMinView startView = DatePickerMinView.DAY;
155    private DatePickerMinView minView = DatePickerMinView.DAY;
156
157    private boolean showTodayButton = false;
158    private boolean showClearButton = false;
159    private boolean highlightToday = false;
160    private boolean keyboardNavigation = true;
161    private boolean forceParse = true;
162
163    private DatePickerMinView viewSelect = DatePickerMinView.DAY;
164
165    private Widget container = null;
166    private DatePickerLanguage language = DatePickerLanguage.EN;
167    private DatePickerPosition position = DatePickerPosition.AUTO;
168
169    public DatePickerBase() {
170        textBox = new TextBox();
171        setElement((Element) textBox.getElement());
172        setFormat(format);
173    }
174
175    public void setContainer(final Widget container) {
176        this.container = container;
177    }
178
179    public Widget getContainer() {
180        return container;
181    }
182
183    public TextBox getTextBox() {
184        return textBox;
185    }
186
187    public void setAlignment(final ValueBoxBase.TextAlignment align) {
188        textBox.setAlignment(align);
189    }
190
191    /** {@inheritDoc} */
192    @Override
193    public void setPlaceholder(final String placeHolder) {
194        textBox.setPlaceholder(placeHolder);
195    }
196
197    /** {@inheritDoc} */
198    @Override
199    public String getPlaceholder() {
200        return textBox.getPlaceholder();
201    }
202
203    public void setReadOnly(final boolean readOnly) {
204        textBox.setReadOnly(readOnly);
205    }
206
207    public boolean isReadOnly() {
208        return textBox.isReadOnly();
209    }
210
211    /** {@inheritDoc} */
212    @Override
213    public boolean isEnabled() {
214        return textBox.isEnabled();
215    }
216
217    /** {@inheritDoc} */
218    @Override
219    public void setEnabled(final boolean enabled) {
220        textBox.setEnabled(enabled);
221    }
222
223    /** {@inheritDoc} */
224    @Override
225    public void setId(final String id) {
226        textBox.setId(id);
227    }
228
229    /** {@inheritDoc} */
230    @Override
231    public String getId() {
232        return textBox.getId();
233    }
234
235    /** {@inheritDoc} */
236    @Override
237    public void setName(final String name) {
238        textBox.setName(name);
239    }
240
241    /** {@inheritDoc} */
242    @Override
243    public String getName() {
244        return textBox.getName();
245    }
246
247    /** {@inheritDoc} */
248    @Override
249    public void setVisibleOn(final DeviceSize deviceSize) {
250        StyleHelper.setVisibleOn(this, deviceSize);
251    }
252
253    /** {@inheritDoc} */
254    @Override
255    public void setHiddenOn(final DeviceSize deviceSize) {
256        StyleHelper.setHiddenOn(this, deviceSize);
257    }
258
259    /** {@inheritDoc} */
260    @Override
261    public void setLanguage(final DatePickerLanguage language) {
262        this.language = language;
263
264        // Inject the JS for the language
265        if (language.getJs() != null) {
266            ScriptInjector.fromString(language.getJs().getText()).setWindow(ScriptInjector.TOP_WINDOW).inject();
267        }
268    }
269
270    /** {@inheritDoc} */
271    @Override
272    public DatePickerLanguage getLanguage() {
273        return language;
274    }
275
276    /** {@inheritDoc} */
277    @Override
278    public void setPosition(final DatePickerPosition position) {
279        this.position = position;
280    }
281
282    /** {@inheritDoc} */
283    @Override
284    public DatePickerPosition getPosition() {
285        return position;
286    }
287
288    /**
289     * Call this whenever changing any settings: minView, startView, format, etc. If you are changing
290     * format and date value, the updates must take in such order:
291     * <p/>
292     * locales.cache.1.4.0. DateTimePicker.reload()
293     * 2. DateTimePicker.setValue(newDate); // Date newDate.
294     * <p/>
295     * Otherwise date value is not updated.
296     */
297    public void reload() {
298        configure();
299    }
300
301    public void show() {
302        show(getElement());
303    }
304
305    public void hide() {
306        hide(getElement());
307    }
308
309    /** {@inheritDoc} */
310    @Override
311    public void setAutoClose(final boolean autoClose) {
312        this.autoClose = autoClose;
313    }
314
315    /** {@inheritDoc} */
316    @Override
317    public void onShow(final Event e) {
318        validatorMixin.setShowing(true);
319        fireEvent(new ShowEvent(e));
320    }
321
322    /** {@inheritDoc} */
323    @Override
324    public HandlerRegistration addShowHandler(final ShowHandler showHandler) {
325        return addHandler(showHandler, ShowEvent.getType());
326    }
327
328    /** {@inheritDoc} */
329    @Override
330    public void onHide(final Event e) {
331        validatorMixin.setShowing(false);
332        validate(getValidateOnBlur());
333        fireEvent(new HideEvent(e));
334    }
335
336    /** {@inheritDoc} */
337    @Override
338    public HandlerRegistration addHideHandler(final HideHandler hideHandler) {
339        return addHandler(hideHandler, HideEvent.getType());
340    }
341
342    /** {@inheritDoc} */
343    @Override
344    public void onChangeDate(final Event e) {
345        fireEvent(new ChangeDateEvent(e));
346    }
347
348    /** {@inheritDoc} */
349    @Override
350    public HandlerRegistration addChangeDateHandler(final ChangeDateHandler changeDateHandler) {
351        return addHandler(changeDateHandler, ChangeDateEvent.getType());
352    }
353
354    /** {@inheritDoc} */
355    @Override
356    public void onChangeYear(final Event e) {
357        fireEvent(new ChangeYearEvent(e));
358    }
359
360    /** {@inheritDoc} */
361    @Override
362    public HandlerRegistration addChangeYearHandler(final ChangeYearHandler changeYearHandler) {
363        return addHandler(changeYearHandler, ChangeYearEvent.getType());
364    }
365
366    /** {@inheritDoc} */
367    @Override
368    public void onChangeMonth(final Event e) {
369        fireEvent(new ChangeMonthEvent(e));
370    }
371
372    /** {@inheritDoc} */
373    @Override
374    public HandlerRegistration addChangeMonthHandler(final ChangeMonthHandler changeMonthHandler) {
375        return addHandler(changeMonthHandler, ChangeMonthEvent.getType());
376    }
377
378    /** {@inheritDoc} */
379    @Override
380    public void onClearDate(final Event e) {
381        fireEvent(new ClearDateEvent(e));
382    }
383
384    /** {@inheritDoc} */
385    @Override
386    public HandlerRegistration addClearDateHandler(final ClearDateHandler clearDateHandler) {
387        return addHandler(clearDateHandler, ClearDateEvent.getType());
388    }
389
390    /** {@inheritDoc} */
391    @Override
392    public void setDaysOfWeekDisabled(final DatePickerDayOfWeek... daysOfWeekDisabled) {
393        setDaysOfWeekDisabled(getElement(), toDaysOfWeekDisabledString(daysOfWeekDisabled));
394    }
395
396    /** {@inheritDoc} */
397    @Override
398    public void setEndDate(final Date endDate) {
399        // Has to be in the format YYYY-MM-DD
400        setEndDate(startEndDateFormat.format(endDate));
401    }
402
403    /** {@inheritDoc} */
404    @Override
405    public void setEndDate(final String endDate) {
406        // Has to be in the format YYYY-MM-DD
407        setEndDate(getElement(), endDate);
408    }
409
410    /** {@inheritDoc} */
411    @Override
412    public void clearEndDate() {
413        setStartDate(getElement(), null);
414    }
415
416    /** {@inheritDoc} */
417    @Override
418    public void setForceParse(final boolean forceParse) {
419        this.forceParse = forceParse;
420    }
421
422    /** {@inheritDoc} */
423    @Override
424    public void setHighlightToday(final boolean highlightToday) {
425        this.highlightToday = highlightToday;
426    }
427
428    /** {@inheritDoc} */
429    @Override
430    public void setHasKeyboardNavigation(final boolean hasKeyboardNavigation) {
431        this.keyboardNavigation = hasKeyboardNavigation;
432    }
433
434    /** {@inheritDoc} */
435    @Override
436    public void setMinView(final DatePickerMinView datePickerMinView) {
437        this.minView = datePickerMinView;
438
439        // We keep the view select the same as the min view
440        if (viewSelect != minView) {
441            setViewSelect(datePickerMinView);
442        }
443    }
444
445    /** {@inheritDoc} */
446    @Override
447    public void setShowTodayButton(final boolean showTodayButton) {
448        this.showTodayButton = showTodayButton;
449    }
450
451    /** {@inheritDoc} */
452    @Override
453    public void setShowClearButton(boolean showClearbutton) {
454        this.showClearButton = showClearbutton;
455    }
456
457    /** {@inheritDoc} */
458    @Override
459    public void setStartDate(final Date startDate) {
460        // Has to be in the format DD-MM-YYYY
461        setStartDate(startEndDateFormat.format(startDate));
462    }
463
464    /** {@inheritDoc} */
465    @Override
466    public void setStartDate(final String startDate) {
467        // Has to be in the format DD-MM-YYYY
468        setStartDate(getElement(), startDate);
469    }
470
471    /** {@inheritDoc} */
472    @Override
473    public void clearStartDate() {
474        setStartDate(getElement(), null);
475    }
476
477    /** {@inheritDoc} */
478    @Override
479    public void setStartView(final DatePickerMinView datePickerMinView) {
480        this.startView = datePickerMinView;
481    }
482
483    /** {@inheritDoc} */
484    @Override
485    public void setViewSelect(final DatePickerMinView datePickerMinView) {
486        this.viewSelect = datePickerMinView;
487
488        // We keep the min view the same as the view select
489        if (viewSelect != minView) {
490            setMinView(datePickerMinView);
491        }
492    }
493
494    /** {@inheritDoc} */
495    @Override
496    public void setWeekStart(final DatePickerDayOfWeek weekStart) {
497        this.weekStart = weekStart;
498    }
499
500    /**
501     * Convert GWT date format to bootstrap date format
502     *
503     * @param format date format using GWT notation
504     * @return date format using bootstrap notation
505     */
506    private static String toBootstrapDateFormat(final String format) {
507        String bootstrap_format = format;
508
509        // Replace long day name "EEEE" with "DD"
510        bootstrap_format = bootstrap_format.replace("EEEE", "DD");
511        // Replace short day name "EE" with "DD"
512        bootstrap_format = bootstrap_format.replaceAll("E{1,3}", "D");
513        // If there are at least 3 Ms there is month name in wording
514        if (bootstrap_format.contains("MMM")) {
515            // Replace long date month "MMMM" with "MM"
516            bootstrap_format = bootstrap_format.replace("MMMM", "MM");
517            // Replace month name "MMM" with "M"
518            bootstrap_format = bootstrap_format.replace("MMM", "M");
519        }
520        else {
521            // Replace month number with leading 0 "MM" with "mm"
522            bootstrap_format = bootstrap_format.replace("MM", "mm");
523            // Replace month number "M" with "m"
524            bootstrap_format = bootstrap_format.replace("M", "m");
525        }
526        if (!bootstrap_format.contains("yy")) {
527            // Replace full year format "y" with "yyyy"
528            bootstrap_format = bootstrap_format.replace("y", "yyyy");
529        }
530
531        return bootstrap_format;
532    }
533
534    /**
535     * Sets format of the date using GWT notation
536     *
537     * @param format date format in GWT notation
538     */
539    public void setGWTFormat(final String format) {
540        this.format = toBootstrapDateFormat(format);
541
542        // Get the old value
543        final Date oldValue = getValue();
544
545        // Make the new DateTimeFormat
546        this.dateTimeFormat = DateTimeFormat.getFormat(format);
547
548        if (oldValue != null) {
549            setValue(oldValue);
550        }
551    }
552
553    /** {@inheritDoc} */
554    @Override
555    public void setFormat(final String format) {
556        this.format = format;
557
558        // Get the old value
559        final Date oldValue = getValue();
560
561        // Make the new DateTimeFormat
562        setDateTimeFormat(format);
563
564        if (oldValue != null) {
565            setValue(oldValue);
566        }
567    }
568
569    private void setDateTimeFormat(final String format) {
570        final StringBuilder fb = new StringBuilder(format);
571        for (int i = 0; i < fb.length(); i++) {
572            if (DATE_TIME_FORMAT_MAP.containsKey(fb.charAt(i))) {
573                fb.setCharAt(i, DATE_TIME_FORMAT_MAP.get(fb.charAt(i)));
574            }
575        }
576
577        this.dateTimeFormat = DateTimeFormat.getFormat(fb.toString());
578    }
579
580    /** {@inheritDoc} */
581    @Override
582    public Date getValue() {
583        try {
584            return dateTimeFormat != null && textBox.getValue() != null ? dateTimeFormat.parse(textBox.getValue()) : null;
585        } catch (final Exception e) {
586            return null;
587        }
588    }
589
590    public String getBaseValue() {
591        return textBox.getValue();
592    }
593
594    /** {@inheritDoc} */
595    @Override
596    public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Date> dateValueChangeHandler) {
597        textBox.addValueChangeHandler(new ValueChangeHandler<String>() {
598            @Override
599            public void onValueChange(ValueChangeEvent<String> event) {
600                ValueChangeEvent.fire(DatePickerBase.this, getValue());
601            }
602        });
603        return addHandler(dateValueChangeHandler, ValueChangeEvent.getType());
604    }
605
606    /** {@inheritDoc} */
607    @Override
608    public void setValue(final Date value) {
609        setValue(value, false);
610    }
611
612    /** {@inheritDoc} */
613    @Override
614    public void setValue(final Date value, final boolean fireEvents) {
615        errorHandlerMixin.clearErrors();
616        textBox.setValue(value != null ? dateTimeFormat.format(value) : null);
617        update(textBox.getElement());
618
619        if (fireEvents) {
620            ValueChangeEvent.fire(DatePickerBase.this, value);
621        }
622    }
623
624    /** {@inheritDoc} */
625    @Override
626    protected void onLoad() {
627        super.onLoad();
628        configure();
629
630        // With the new update the parent must have position: relative for positioning to work
631        if (getElement().getParentElement() != null) {
632            getElement().getParentElement().getStyle().setPosition(Style.Position.RELATIVE);
633        }
634    }
635
636    /** {@inheritDoc} */
637    @Override
638    protected void onUnload() {
639        super.onUnload();
640        remove(getElement());
641    }
642
643    protected void configure() {
644        // If the user hasn't specified the container, default to the widget's parent
645        // This makes sure the modal scroll with the content correctly
646        if (container == null) {
647            configure(this, this.getParent());
648        } else {
649            configure(this, container);
650        }
651    }
652
653    protected void configure(final Widget w, final Widget container) {
654        w.getElement().setAttribute("data-date-format", format);
655
656        // If configuring not for the first time, datepicker must be removed first.
657        this.remove(w.getElement());
658
659        configure(w.getElement(), container.getElement(), format, weekStart.getValue(), toDaysOfWeekDisabledString(daysOfWeekDisabled), autoClose,
660                startView.getValue(), minView.getValue(), showTodayButton, showClearButton, highlightToday, keyboardNavigation, forceParse, viewSelect.getValue(),
661                language.getCode(), position.getPosition());
662    }
663
664    protected void execute(final String cmd) {
665        execute(getElement(), cmd);
666    }
667
668    private native void execute(Element e, String cmd) /*-{
669        $wnd.jQuery(e).datepicker(cmd);
670    }-*/;
671
672    private native void remove(Element e) /*-{
673        $wnd.jQuery(e).datepicker('remove');
674        $wnd.jQuery(e).off('show');
675        $wnd.jQuery(e).off('hide');
676        $wnd.jQuery(e).off('changeDate');
677        $wnd.jQuery(e).off('changeYear');
678        $wnd.jQuery(e).off('changeMonth');
679        $wnd.jQuery(e).off('clearDate');
680    }-*/;
681
682    private native void show(Element e) /*-{
683        $wnd.jQuery(e).datepicker('show');
684    }-*/;
685
686    private native void hide(Element e) /*-{
687        $wnd.jQuery(e).datepicker('hide');
688    }-*/;
689
690    private native void update(Element e) /*-{
691        $wnd.jQuery(e).datepicker('update');
692    }-*/;
693
694    private native void setStartDate(Element e, String startDate) /*-{
695        $wnd.jQuery(e).datepicker('setStartDate', startDate);
696    }-*/;
697
698    private native void setEndDate(Element e, String endDate) /*-{
699        $wnd.jQuery(e).datepicker('setEndDate', endDate);
700    }-*/;
701
702    private native void setDaysOfWeekDisabled(Element e, String daysOfWeekDisabled) /*-{
703        $wnd.jQuery(e).datepicker('setDaysOfWeekDisabled', daysOfWeekDisabled);
704    }-*/;
705
706    protected native void configure(Element e, Element p, String format, int weekStart, String daysOfWeekDisabled, boolean autoClose, int startView,
707                                    int minViewMode, boolean todayBtn, boolean clearBtn, boolean highlightToday, boolean keyboardNavigation, boolean forceParse, int viewSelect, String language,
708                                    String orientation) /*-{
709
710        if (todayBtn) {
711            todayBtn = "linked";
712        }
713
714        var that = this;
715        $wnd.jQuery(e).datepicker({
716            format: format,
717            language: language,
718            weekStart: weekStart,
719            daysOfWeekDisabled: daysOfWeekDisabled,
720            autoclose: autoClose,
721            startView: startView,
722            minViewMode: minViewMode,
723            todayBtn: todayBtn,
724            clearBtn: clearBtn,
725            todayHighlight: highlightToday,
726            keyboardNavigation: keyboardNavigation,
727            forceParse: forceParse,
728            orientation: orientation,
729            container: p
730        })
731            .on('show', function (e) {
732                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onShow(Lcom/google/gwt/user/client/Event;)(e);
733            })
734            .on("hide", function (e) {
735                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onHide(Lcom/google/gwt/user/client/Event;)(e);
736            })
737            .on("changeDate", function (e) {
738                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onChangeDate(Lcom/google/gwt/user/client/Event;)(e);
739            })
740            .on("changeYear", function (e) {
741                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onChangeYear(Lcom/google/gwt/user/client/Event;)(e);
742            })
743            .on("changeMonth", function (e) {
744                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onChangeMonth(Lcom/google/gwt/user/client/Event;)(e);
745            })
746            .on("clearDate", function (e) {
747                that.@org.gwtbootstrap3.extras.datepicker.client.ui.base.DatePickerBase::onClearDate(Lcom/google/gwt/user/client/Event;)(e);
748            });
749    }-*/;
750
751    protected String toDaysOfWeekDisabledString(final DatePickerDayOfWeek... datePickerDayOfWeeks) {
752        this.daysOfWeekDisabled = datePickerDayOfWeeks;
753
754        final StringBuilder builder = new StringBuilder();
755
756        if (datePickerDayOfWeeks != null) {
757            int i = 0;
758            for (final DatePickerDayOfWeek dayOfWeek : datePickerDayOfWeeks) {
759                builder.append(dayOfWeek.getValue());
760
761                i++;
762                if (i < datePickerDayOfWeeks.length) {
763                    builder.append(",");
764                }
765            }
766        }
767        return builder.toString();
768    }
769
770    /** {@inheritDoc} */
771    @Override
772    public com.google.web.bindery.event.shared.HandlerRegistration addValidationChangedHandler(ValidationChangedHandler handler) {
773        return validatorMixin.addValidationChangedHandler(handler);
774    }
775
776    /** {@inheritDoc} */
777    @Override
778    public boolean getAllowBlank() {
779        return validatorMixin.getAllowBlank();
780    }
781
782    /** {@inheritDoc} */
783    @Override
784    public void setAllowBlank(boolean allowBlank) {
785        validatorMixin.setAllowBlank(allowBlank);
786    }
787
788    /** {@inheritDoc} */
789    @Override
790    public void addValidator(Validator<Date> validator) {
791        validatorMixin.addValidator(validator);
792    }
793
794    /** {@inheritDoc} */
795    @Override
796    public boolean getValidateOnBlur() {
797        return validatorMixin.getValidateOnBlur();
798    }
799
800    /** {@inheritDoc} */
801    @Override
802    public boolean removeValidator(Validator<Date> validator) {
803        return validatorMixin.removeValidator(validator);
804    }
805
806    /** {@inheritDoc} */
807    @Override
808    public void reset() {
809        validatorMixin.reset();
810    }
811
812    /** {@inheritDoc} */
813    @Override
814    public void setValidateOnBlur(boolean validateOnBlur) {
815        validatorMixin.setValidateOnBlur(validateOnBlur);
816    }
817
818    /** {@inheritDoc} */
819    @SuppressWarnings("unchecked")
820    @Override
821    public void setValidators(Validator<Date>... validators) {
822        validatorMixin.setValidators(validators);
823    }
824
825    /** {@inheritDoc} */
826    @Override
827    public boolean validate() {
828        return validatorMixin.validate();
829    }
830
831    /** {@inheritDoc} */
832    @Override
833    public boolean validate(boolean show) {
834        return validatorMixin.validate(show);
835    }
836
837    /** {@inheritDoc} */
838    @Override
839    public ErrorHandler getErrorHandler() {
840        return errorHandlerMixin.getErrorHandler();
841    }
842
843    /** {@inheritDoc} */
844    @Override
845    public void setErrorHandler(ErrorHandler errorHandler) {
846        errorHandlerMixin.setErrorHandler(errorHandler);
847        validatorMixin.setErrorHandler(errorHandler);
848    }
849
850    /** {@inheritDoc} */
851    @Override
852    public ErrorHandlerType getErrorHandlerType() {
853        return errorHandlerMixin.getErrorHandlerType();
854    }
855
856    /** {@inheritDoc} */
857    @Override
858    public void setErrorHandlerType(ErrorHandlerType errorHandlerType) {
859        errorHandlerMixin.setErrorHandlerType(errorHandlerType);
860    }
861
862    /** {@inheritDoc} */
863    @Override
864    public void showErrors(List<EditorError> errors) {
865        errorHandlerMixin.showErrors(errors);
866    }
867
868}