001    package org.gwtbootstrap3.extras.datetimepicker.client.ui.base;
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 com.google.gwt.core.client.ScriptInjector;
024    import com.google.gwt.dom.client.Element;
025    import com.google.gwt.dom.client.Style;
026    import com.google.gwt.editor.client.IsEditor;
027    import com.google.gwt.editor.client.LeafValueEditor;
028    import com.google.gwt.editor.client.adapters.TakesValueEditor;
029    import com.google.gwt.event.logical.shared.ValueChangeEvent;
030    import com.google.gwt.event.logical.shared.ValueChangeHandler;
031    import com.google.gwt.event.shared.HandlerRegistration;
032    import com.google.gwt.i18n.client.DateTimeFormat;
033    import com.google.gwt.user.client.Event;
034    import com.google.gwt.user.client.ui.HasEnabled;
035    import com.google.gwt.user.client.ui.HasName;
036    import com.google.gwt.user.client.ui.HasValue;
037    import com.google.gwt.user.client.ui.HasVisibility;
038    import com.google.gwt.user.client.ui.Widget;
039    import org.gwtbootstrap3.client.shared.event.HideEvent;
040    import org.gwtbootstrap3.client.shared.event.HideHandler;
041    import org.gwtbootstrap3.client.shared.event.ShowEvent;
042    import org.gwtbootstrap3.client.shared.event.ShowHandler;
043    import org.gwtbootstrap3.client.ui.TextBox;
044    import org.gwtbootstrap3.client.ui.base.HasId;
045    import org.gwtbootstrap3.client.ui.base.HasPlaceholder;
046    import org.gwtbootstrap3.client.ui.base.HasResponsiveness;
047    import org.gwtbootstrap3.client.ui.base.ValueBoxBase;
048    import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
049    import org.gwtbootstrap3.client.ui.constants.DeviceSize;
050    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.DateTimePickerDayOfWeek;
051    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.DateTimePickerLanguage;
052    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.DateTimePickerPosition;
053    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.DateTimePickerView;
054    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasAutoClose;
055    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasDateTimePickerHandlers;
056    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasDaysOfWeekDisabled;
057    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasEndDate;
058    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasForceParse;
059    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasFormat;
060    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasHighlightToday;
061    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasKeyboardNavigation;
062    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasLanguage;
063    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasMaxView;
064    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasMinView;
065    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasMinuteStep;
066    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasPosition;
067    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasShowMeridian;
068    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasShowTodayButton;
069    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasStartDate;
070    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasStartView;
071    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasViewSelect;
072    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.constants.HasWeekStart;
073    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeDateEvent;
074    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeDateHandler;
075    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeMonthEvent;
076    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeMonthHandler;
077    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeYearEvent;
078    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.ChangeYearHandler;
079    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.OutOfRangeEvent;
080    import org.gwtbootstrap3.extras.datetimepicker.client.ui.base.events.OutOfRangeHandler;
081    
082    import java.util.Date;
083    import java.util.HashMap;
084    import java.util.Map;
085    
086    /**
087     * @author Joshua Godi
088     */
089    public class DateTimePickerBase extends Widget implements HasEnabled, HasId, HasResponsiveness,
090            HasVisibility, HasPlaceholder, HasAutoClose, HasDaysOfWeekDisabled, HasEndDate, HasForceParse,
091            HasFormat, HasHighlightToday, HasKeyboardNavigation, HasMaxView, HasMinuteStep, HasMinView,
092            HasShowMeridian, HasShowTodayButton, HasStartDate, HasStartView, HasViewSelect, HasWeekStart,
093            HasDateTimePickerHandlers, HasLanguage, HasName, HasValue<Date>, HasPosition, IsEditor<LeafValueEditor<Date>> {
094    
095        // Check http://www.gwtproject.org/javadoc/latest/com/google/gwt/i18n/client/DateTimeFormat.html
096        // for more information on syntax
097        private static final Map<Character, Character> DATE_TIME_FORMAT_MAP = new HashMap<Character, Character>();
098        static {
099            DATE_TIME_FORMAT_MAP.put('h', 'H'); // 12/24 hours
100            DATE_TIME_FORMAT_MAP.put('H', 'h'); // 12/24 hours
101            DATE_TIME_FORMAT_MAP.put('m', 'M'); // months
102            DATE_TIME_FORMAT_MAP.put('i', 'm'); // minutes
103            DATE_TIME_FORMAT_MAP.put('p', 'a'); // meridian
104            DATE_TIME_FORMAT_MAP.put('P', 'a'); // meridian
105        }   
106    
107        private final TextBox textBox;
108        private DateTimeFormat dateTimeFormat;
109        private final DateTimeFormat startEndDateFormat = DateTimeFormat.getFormat("yyyy-MM-dd");
110        private LeafValueEditor<Date> editor;
111    
112        /**
113         * DEFAULT values
114         */
115        private String format = "mm/dd/yyyy HH:ii";
116        private DateTimePickerDayOfWeek weekStart = DateTimePickerDayOfWeek.SUNDAY;
117        private DateTimePickerDayOfWeek[] daysOfWeekDisabled = {};
118        private boolean autoClose = false;
119        private DateTimePickerView startView = DateTimePickerView.MONTH;
120        private DateTimePickerView minView = DateTimePickerView.HOUR;
121        private DateTimePickerView maxView = DateTimePickerView.DECADE;
122        private boolean showTodayButton = false;
123        private boolean highlightToday = false;
124        private boolean keyboardNavigation = true;
125        private boolean forceParse = true;
126        private int minuteStep = 5;
127        private DateTimePickerView viewSelect = DateTimePickerView.HOUR;
128        private boolean showMeridian = false;
129        private Widget container = null;
130        private DateTimePickerLanguage language = DateTimePickerLanguage.EN;
131        private DateTimePickerPosition position = DateTimePickerPosition.BOTTOM_RIGHT;
132    
133        public DateTimePickerBase() {
134            textBox = new TextBox();
135            setElement((Element) textBox.getElement());
136            setFormat(format);
137        }
138    
139        public void setContainer(final Widget container) {
140            this.container = container;
141        }
142    
143        public Widget getContainer() {
144            return container;
145        }
146    
147        public TextBox getTextBox() {
148            return textBox;
149        }
150    
151        public void setAlignment(final ValueBoxBase.TextAlignment align) {
152            textBox.setAlignment(align);
153        }
154    
155        @Override
156        public void setPlaceholder(final String placeHolder) {
157            textBox.setPlaceholder(placeHolder);
158        }
159    
160        @Override
161        public String getPlaceholder() {
162            return textBox.getPlaceholder();
163        }
164    
165        public void setReadOnly(final boolean readOnly) {
166            textBox.setReadOnly(readOnly);
167        }
168    
169        public boolean isReadOnly() {
170            return textBox.isReadOnly();
171        }
172    
173        @Override
174        public boolean isEnabled() {
175            return textBox.isEnabled();
176        }
177    
178        @Override
179        public void setEnabled(final boolean enabled) {
180            textBox.setEnabled(enabled);
181        }
182    
183        @Override
184        public void setId(final String id) {
185            textBox.setId(id);
186        }
187    
188        @Override
189        public String getId() {
190            return textBox.getId();
191        }
192    
193        @Override
194        public void setName(final String name) {
195            textBox.setName(name);
196        }
197    
198        @Override
199        public String getName() {
200            return textBox.getName();
201        }
202    
203        @Override
204        public void setVisibleOn(final DeviceSize deviceSize) {
205            StyleHelper.setVisibleOn(this, deviceSize);
206        }
207    
208        @Override
209        public void setHiddenOn(final DeviceSize deviceSize) {
210            StyleHelper.setHiddenOn(this, deviceSize);
211        }
212    
213        @Override
214        public void setLanguage(final DateTimePickerLanguage language) {
215            this.language = language;
216    
217            // Inject the JS for the language
218            if (language.getJs() != null) {
219                ScriptInjector.fromString(language.getJs().getText())
220                        .setWindow(ScriptInjector.TOP_WINDOW).inject();
221            }
222        }
223    
224        @Override
225        public DateTimePickerLanguage getLanguage() {
226            return language;
227        }
228    
229        @Override
230        public void setPosition(final DateTimePickerPosition position) {
231            this.position = position;
232        }
233    
234        @Override
235        public DateTimePickerPosition getPosition() {
236            return position;
237        }
238    
239        /**
240         * Call this whenever changing any settings: minView, startView, format, etc. If you are changing
241         * format and date value, the updates must take in such order:
242         * <p/>
243         * 1. DateTimePicker.reload()
244         * 2. DateTimePicker.setValue(newDate); // Date newDate.
245         * <p/>
246         * Otherwise date value is not updated.
247         */
248        public void reload() {
249            configure();
250        }
251    
252        public void show() {
253            show(getElement());
254        }
255    
256        public void hide() {
257            hide(getElement());
258        }
259    
260        @Override
261        public void setAutoClose(final boolean autoClose) {
262            this.autoClose = autoClose;
263        }
264    
265        @Override
266        public void onShow(final Event e) {
267            // On show we put focus on the textbox
268            textBox.setFocus(true);
269    
270            fireEvent(new ShowEvent(e));
271        }
272    
273        @Override
274        public HandlerRegistration addShowHandler(final ShowHandler showHandler) {
275            return addHandler(showHandler, ShowEvent.getType());
276        }
277    
278        @Override
279        public void onHide(final Event e) {
280            // On hide we remove focus from the textbox
281            textBox.setFocus(false);
282    
283            fireEvent(new HideEvent(e));
284        }
285    
286        @Override
287        public HandlerRegistration addHideHandler(final HideHandler hideHandler) {
288            return addHandler(hideHandler, HideEvent.getType());
289        }
290    
291        @Override
292        public void onChangeDate(final Event e) {
293            fireEvent(new ChangeDateEvent(e));
294        }
295    
296        @Override
297        public HandlerRegistration addChangeDateHandler(final ChangeDateHandler changeDateHandler) {
298            return addHandler(changeDateHandler, ChangeDateEvent.getType());
299        }
300    
301        @Override
302        public void onChangeYear(final Event e) {
303            fireEvent(new ChangeYearEvent(e));
304        }
305    
306        @Override
307        public HandlerRegistration addChangeYearHandler(final ChangeYearHandler changeYearHandler) {
308            return addHandler(changeYearHandler, ChangeYearEvent.getType());
309        }
310    
311        @Override
312        public void onChangeMonth(final Event e) {
313            fireEvent(new ChangeMonthEvent(e));
314        }
315    
316        @Override
317        public HandlerRegistration addChangeMonthHandler(final ChangeMonthHandler changeMonthHandler) {
318            return addHandler(changeMonthHandler, ChangeMonthEvent.getType());
319        }
320    
321        @Override
322        public void onOutOfRange(final Event e) {
323            fireEvent(new OutOfRangeEvent(e));
324        }
325    
326        @Override
327        public HandlerRegistration addOutOfRangeHandler(final OutOfRangeHandler outOfRangeHandler) {
328            return addHandler(outOfRangeHandler, OutOfRangeEvent.getType());
329        }
330    
331        @Override
332        public void setDaysOfWeekDisabled(final DateTimePickerDayOfWeek... daysOfWeekDisabled) {
333            setDaysOfWeekDisabled(getElement(), toDaysOfWeekDisabledString(daysOfWeekDisabled));
334        }
335    
336        @Override
337        public void setEndDate(final Date endDate) {
338            // Has to be in the format YYYY-MM-DD
339            setEndDate(startEndDateFormat.format(endDate));
340        }
341    
342        @Override
343        public void setEndDate(final String endDate) {
344            // Has to be in the format YYYY-MM-DD
345            setEndDate(getElement(), endDate);
346        }
347    
348        @Override
349        public void clearEndDate() {
350            setStartDate(getElement(), null);
351        }
352    
353        @Override
354        public void setForceParse(final boolean forceParse) {
355            this.forceParse = forceParse;
356        }
357    
358        @Override
359        public void setHighlightToday(final boolean highlightToday) {
360            this.highlightToday = highlightToday;
361        }
362    
363        @Override
364        public void setHasKeyboardNavigation(final boolean hasKeyboardNavigation) {
365            this.keyboardNavigation = hasKeyboardNavigation;
366        }
367    
368        @Override
369        public void setMaxView(final DateTimePickerView dateTimePickerView) {
370            this.maxView = dateTimePickerView;
371        }
372    
373        @Override
374        public void setMinView(final DateTimePickerView dateTimePickerView) {
375            this.minView = dateTimePickerView;
376    
377            // We keep the view select the same as the min view
378            if (viewSelect != minView) {
379                setViewSelect(dateTimePickerView);
380            }
381        }
382    
383        @Override
384        public void setMinuteStep(final int minuteStep) {
385            this.minuteStep = minuteStep;
386        }
387    
388        @Override
389        public void setShowMeridian(final boolean showMeridian) {
390            this.showMeridian = showMeridian;
391        }
392    
393        @Override
394        public void setShowTodayButton(final boolean showTodayButton) {
395            this.showTodayButton = showTodayButton;
396        }
397    
398        @Override
399        public void setStartDate(final Date startDate) {
400            // Has to be in the format YYYY-MM-DD
401            setStartDate(startEndDateFormat.format(startDate));
402        }
403    
404        @Override
405        public void setStartDate(final String startDate) {
406            // Has to be in the format YYYY-MM-DD
407            setStartDate(getElement(), startDate);
408        }
409    
410        @Override
411        public void clearStartDate() {
412            setStartDate(getElement(), null);
413        }
414    
415        @Override
416        public void setStartView(final DateTimePickerView dateTimePickerView) {
417            this.startView = dateTimePickerView;
418        }
419    
420        @Override
421        public void setViewSelect(final DateTimePickerView dateTimePickerView) {
422            this.viewSelect = dateTimePickerView;
423    
424            // We keep the min view the same as the view select
425            if (viewSelect != minView) {
426                setMinView(dateTimePickerView);
427            }
428        }
429    
430        @Override
431        public void setWeekStart(final DateTimePickerDayOfWeek weekStart) {
432            this.weekStart = weekStart;
433        }
434    
435        @Override
436        public void setFormat(final String format) {
437            this.format = format;
438    
439            // Get the old value
440            final Date oldValue = getValue();
441    
442            // Make the new DateTimeFormat
443            setDateTimeFormat(format);
444    
445            if (oldValue != null) {
446                setValue(oldValue);
447            }
448        }
449    
450        private void setDateTimeFormat(final String format) {
451            final StringBuilder fb = new StringBuilder(format);
452            for (int i = 0; i < fb.length(); i++) {
453                if (DATE_TIME_FORMAT_MAP.containsKey(fb.charAt(i))) {
454                    fb.setCharAt(i, DATE_TIME_FORMAT_MAP.get(fb.charAt(i)));
455                }
456            }
457    
458            this.dateTimeFormat = DateTimeFormat.getFormat(fb.toString());
459        }
460    
461        @Override
462        public Date getValue() {
463            try {
464                return dateTimeFormat != null && textBox.getValue() != null ? dateTimeFormat.parse(textBox.getValue()) : null;
465            } catch (final Exception e) {
466                return null;
467            }
468        }
469    
470        public String getBaseValue() {
471            return textBox.getValue();
472        }
473    
474        @Override
475        public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Date> dateValueChangeHandler) {
476            return addHandler(dateValueChangeHandler, ValueChangeEvent.getType());
477        }
478    
479        @Override
480        public void setValue(final Date value) {
481            setValue(value, false);
482        }
483    
484        @Override
485        public void setValue(final Date value, final boolean fireEvents) {
486            textBox.setValue(value != null ? dateTimeFormat.format(value) : null);
487            update(textBox.getElement());
488    
489            if (fireEvents) {
490                ValueChangeEvent.fire(DateTimePickerBase.this, value);
491            }
492        }
493    
494        @Override
495        public LeafValueEditor<Date> asEditor() {
496            if (editor == null) {
497                editor = TakesValueEditor.of(this);
498            }
499            return editor;
500        }
501    
502        /**
503         * {@inheritDoc}
504         */
505        @Override
506        protected void onLoad() {
507            super.onLoad();
508            configure();
509    
510            // With the new update (2.3.1), the parent must have position: relative for positioning to work
511            if (getElement().getParentElement() != null) {
512                getElement().getParentElement().getStyle().setPosition(Style.Position.RELATIVE);
513            }
514        }
515    
516        @Override
517        protected void onUnload() {
518            super.onUnload();
519            remove(getElement());
520        }
521    
522        protected void configure() {
523            // If the user hasn't specified the container, default to the widget's parent
524            // This makes sure the modal scroll with the content correctly
525            if (container == null) {
526                configure(this, this.getParent());
527            } else {
528                configure(this, container);
529            }
530        }
531    
532        protected void configure(final Widget w, final Widget container) {
533            w.getElement().setAttribute("data-date-format", format);
534    
535            // If configuring not for the first time, datetimepicker must be removed first.
536            this.remove(w.getElement());
537    
538            configure(w.getElement(), container.getElement(), format, weekStart.getValue(), toDaysOfWeekDisabledString(daysOfWeekDisabled), autoClose,
539                    startView.getValue(), minView.getValue(), maxView.getValue(), showTodayButton, highlightToday,
540                    keyboardNavigation, forceParse, minuteStep, viewSelect.getValue(), showMeridian, language.getCode(), position.getPosition());
541        }
542    
543        protected void execute(final String cmd) {
544            execute(getElement(), cmd);
545        }
546    
547        private native void execute(Element e, String cmd) /*-{
548            $wnd.jQuery(e).datetimepicker(cmd);
549        }-*/;
550    
551        private native void remove(Element e) /*-{
552            $wnd.jQuery(e).datetimepicker('remove');
553            $wnd.jQuery(e).off('show');
554            $wnd.jQuery(e).off('hide');
555            $wnd.jQuery(e).off('changeDate');
556            $wnd.jQuery(e).off('changeYear');
557            $wnd.jQuery(e).off('changeMonth');
558            $wnd.jQuery(e).off('outOfRange');
559        }-*/;
560    
561        private native void show(Element e) /*-{
562            $wnd.jQuery(e).datetimepicker('show');
563        }-*/;
564    
565        private native void hide(Element e) /*-{
566            $wnd.jQuery(e).datetimepicker('hide');
567        }-*/;
568    
569        private native void update(Element e) /*-{
570            $wnd.jQuery(e).datetimepicker('update');
571        }-*/;
572    
573        private native void setStartDate(Element e, String startDate) /*-{
574            $wnd.jQuery(e).datetimepicker('setStartDate', startDate);
575        }-*/;
576    
577        private native void setEndDate(Element e, String endDate) /*-{
578            $wnd.jQuery(e).datetimepicker('setEndDate', endDate);
579        }-*/;
580    
581        private native void setDaysOfWeekDisabled(Element e, String daysOfWeekDisabled) /*-{
582            $wnd.jQuery(e).datetimepicker('setDaysOfWeekDisabled', daysOfWeekDisabled);
583        }-*/;
584    
585        protected native void configure(Element e, Element p, String format, int weekStart, String daysOfWeekDisabled,
586                                        boolean autoClose, int startView, int minView,
587                                        int maxView, boolean todayBtn, boolean highlightToday, boolean keyboardNavigation,
588                                        boolean forceParse, int minuteStep, int viewSelect, boolean showMeridian, String language,
589                                        String position) /*-{
590            var that = this;
591            $wnd.jQuery(e).datetimepicker({
592                format: format,
593                language: language,
594                weekStart: weekStart,
595                daysOfWeekDisabled: daysOfWeekDisabled,
596                autoclose: autoClose,
597                startView: startView,
598                minView: minView,
599                maxView: maxView,
600                todayBtn: todayBtn,
601                todayHighlight: highlightToday,
602                keyboardNavigation: keyboardNavigation,
603                forceParse: forceParse,
604                minuteStep: minuteStep,
605                showMeridian: showMeridian,
606                pickerPosition: position,
607                container: p
608            })
609                .on('show', function (e) {
610                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onShow(Lcom/google/gwt/user/client/Event;)(e);
611                })
612                .on("hide", function (e) {
613                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onHide(Lcom/google/gwt/user/client/Event;)(e);
614                })
615                .on("changeDate", function (e) {
616                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onChangeDate(Lcom/google/gwt/user/client/Event;)(e);
617                })
618                .on("changeYear", function (e) {
619                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onChangeYear(Lcom/google/gwt/user/client/Event;)(e);
620                })
621                .on("changeMonth", function (e) {
622                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onChangeMonth(Lcom/google/gwt/user/client/Event;)(e);
623                })
624                .on("outOfRange", function (e) {
625                    that.@org.gwtbootstrap3.extras.datetimepicker.client.ui.base.DateTimePickerBase::onOutOfRange(Lcom/google/gwt/user/client/Event;)(e);
626                });
627        }-*/;
628    
629        protected String toDaysOfWeekDisabledString(final DateTimePickerDayOfWeek... dateTimePickerDayOfWeeks) {
630            this.daysOfWeekDisabled = dateTimePickerDayOfWeeks;
631    
632            final StringBuilder builder = new StringBuilder();
633    
634            if (dateTimePickerDayOfWeeks != null) {
635                int i = 0;
636                for (final DateTimePickerDayOfWeek dayOfWeek : dateTimePickerDayOfWeeks) {
637                    builder.append(dayOfWeek.getValue());
638    
639                    i++;
640                    if (i < dateTimePickerDayOfWeeks.length) {
641                        builder.append(",");
642                    }
643                }
644            }
645            return builder.toString();
646        }
647    }