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