001/* 002 * Copyright 2012 GWT-Bootstrap 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.github.gwtbootstrap.datetimepicker.client.ui.base; 017 018import com.github.gwtbootstrap.client.ui.TextBox; 019import com.github.gwtbootstrap.client.ui.base.HasAlternateSize; 020import com.github.gwtbootstrap.client.ui.base.HasId; 021import com.github.gwtbootstrap.client.ui.base.HasPlaceholder; 022import com.github.gwtbootstrap.client.ui.base.HasSize; 023import com.github.gwtbootstrap.client.ui.base.HasStyle; 024import com.github.gwtbootstrap.client.ui.base.HasVisibility; 025import com.github.gwtbootstrap.client.ui.base.IsResponsive; 026import com.github.gwtbootstrap.client.ui.base.IsSearchQuery; 027import com.github.gwtbootstrap.client.ui.base.PlaceholderHelper; 028import com.github.gwtbootstrap.client.ui.base.ResponsiveHelper; 029import com.github.gwtbootstrap.client.ui.base.SearchQueryStyleHelper; 030import com.github.gwtbootstrap.client.ui.base.SizeHelper; 031import com.github.gwtbootstrap.client.ui.base.Style; 032import com.github.gwtbootstrap.client.ui.base.StyleHelper; 033import com.github.gwtbootstrap.client.ui.constants.AlternateSize; 034import com.github.gwtbootstrap.client.ui.constants.Device; 035import com.github.gwtbootstrap.client.ui.event.HasVisibleHandlers; 036import com.github.gwtbootstrap.client.ui.event.HiddenHandler; 037import com.github.gwtbootstrap.client.ui.event.HideEvent; 038import com.github.gwtbootstrap.client.ui.event.HideHandler; 039import com.github.gwtbootstrap.client.ui.event.ShowEvent; 040import com.github.gwtbootstrap.client.ui.event.ShowHandler; 041import com.github.gwtbootstrap.client.ui.event.ShownHandler; 042import com.github.gwtbootstrap.datetimepicker.client.ui.util.LocaleUtil; 043import com.google.gwt.core.client.GWT; 044import com.google.gwt.dom.client.Element; 045import com.google.gwt.editor.client.IsEditor; 046import com.google.gwt.editor.client.adapters.TakesValueEditor; 047import com.google.gwt.event.dom.client.ChangeEvent; 048import com.google.gwt.event.dom.client.ChangeHandler; 049import com.google.gwt.event.dom.client.HasChangeHandlers; 050import com.google.gwt.event.logical.shared.HasValueChangeHandlers; 051import com.google.gwt.event.logical.shared.ValueChangeEvent; 052import com.google.gwt.event.logical.shared.ValueChangeHandler; 053import com.google.gwt.event.shared.HandlerRegistration; 054import com.google.gwt.i18n.client.DateTimeFormat; 055import com.google.gwt.i18n.client.LocaleInfo; 056import com.google.gwt.user.client.Event; 057import com.google.gwt.user.client.ui.HasEnabled; 058import com.google.gwt.user.client.ui.HasValue; 059import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment; 060import com.google.gwt.user.client.ui.Widget; 061 062import java.util.Date; 063 064/** 065 * Base DateTimePicker component. 066 * 067 * @author Carlos Alexandro Becker 068 * @author ohashi keisuke 069 * @author Alain Penders 070 * @since 2.1.1.0 071 */ 072public class DateTimeBoxBase 073 extends Widget implements HasValue<Date>,HasEnabled, HasValueChangeHandlers<Date>, HasVisibility, 074 HasChangeHandlers, HasVisibleHandlers, 075 HasAllDateTimePickerHandlers, IsEditor<TakesValueEditor<Date>>, HasPlaceholder, HasAlternateSize, IsSearchQuery, HasSize, HasId, IsResponsive , HasStyle { 076 077 private final TextBox box; 078 private String format; 079 private String language; 080 private DateTimeFormat dtf; 081 private TakesValueEditor<Date> editor; 082 083 /** placeholderHelper */ 084 private PlaceholderHelper placeholderHelper = GWT.create(PlaceholderHelper.class); 085 private boolean autoclose; 086 private int minuteStep = 5; 087 private boolean todayButton; 088 private boolean highlightToday; 089 private String minViewMode = ViewMode.HOUR.name().toLowerCase(); 090 private String startViewMode = ViewMode.MONTH.name().toLowerCase(); 091 private String maxViewMode = ViewMode.DECADE.name().toLowerCase(); 092 private PickerPosition pickerPosition = PickerPosition.BOTTOM_RIGHT; 093 private Element decoratedElement; 094 095 public DateTimeBoxBase() { 096 this.box = new TextBox(); 097 this.language = LocaleUtil.getLanguage(); 098 setElement(box.getElement()); 099 setFormat("yyyy/mm/dd hh:ii"); 100 setWeekStart(LocaleInfo.getCurrentLocale().getDateTimeFormatInfo().firstDayOfTheWeek()); 101 setValue(new Date()); 102 } 103 104 public void setAlignment(TextAlignment align) { 105 box.setAlignment(align); 106 } 107 108 /** 109 * @see com.google.gwt.user.client.ui.ValueBoxBase#isReadOnly() 110 */ 111 public boolean isReadOnly() { 112 return box.isReadOnly(); 113 } 114 115 /** 116 * @see com.google.gwt.user.client.ui.ValueBoxBase#setReadOnly(boolean) 117 */ 118 public void setReadOnly(boolean readonly) { 119 box.setReadOnly(readonly); 120 } 121 122 /** 123 * {@inheritDoc} 124 */ 125 @Override 126 public void setFormat(String format) { 127 this.format = format; 128 Date oldValue = getValue(); 129 this.dtf = DateTimeFormat.getFormat(dpGlobalFormatToDateTimeFormat(format)); 130 if (oldValue != null) { 131 setValue(oldValue); 132 } 133 } 134 135 public void setLanguage(String language) { 136 this.language = language; 137 LocaleUtil.forceLocale(language); 138 } 139 140 /** 141 * Returns the internal instance of textbox element. Use only if know what you are doing. 142 * 143 * @return internal textbox intance. 144 */ 145 protected TextBox getBox() { 146 return box; 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public Date getValue() { 154 try { 155 return dtf != null && box.getValue() != null ? dtf.parse(box.getValue()) : null; 156 } catch(Exception e) { 157 return null; 158 } 159 } 160 161 /** 162 * Get un-transformed text 163 * @return text box value 164 */ 165 public String getOriginalValue() { 166 return box.getValue(); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public void setValue(Date value) { 174 setValue(value, false); 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public void setValue(Date value, boolean fireEvents) { 182 box.setValue(value != null ? dtf.format(value) : null); 183 184 updateValue(decoratedElement); 185 186 if (fireEvents) { 187 ValueChangeEvent.fire(this, value); 188 } 189 } 190 191 protected native void updateValue(Element e)/*-{ 192 if($wnd.jQuery(e).data('datetimepicker')) { 193 $wnd.jQuery(e).data('datetimepicker').update(); 194 } 195 }-*/; 196 197 /** 198 * {@inheritDoc} 199 */ 200 @Override 201 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Date> dateValueChangeHandler) { 202 return addHandler(dateValueChangeHandler, ValueChangeEvent.getType()); 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 protected void onLoad() { 210 super.onLoad(); 211 configure(); 212 } 213 214 @Override 215 protected void onUnload() { 216 super.onUnload(); 217 execute("remove"); 218 removeDataIfExists(getElement()); 219 } 220 221 /** 222 * Configure the elements for a specific widget. 223 * Use only if you know what you are doing. 224 * 225 * @param w: the widget to configure. 226 */ 227 protected void configure(Widget w) { 228 this.decoratedElement = w.getElement(); 229 w.getElement().setAttribute("data-date-format", format); 230 w.getElement().setAttribute("data-date-language", language); 231 configure(w.getElement(), autoclose, minuteStep, todayButton, highlightToday, 232 minViewMode, startViewMode, maxViewMode, pickerPosition.getValue()); 233 } 234 235 /** 236 * dateChange event handler. 237 */ 238 public void onChange() { 239 ValueChangeEvent.fire(this, getValue()); 240 } 241 242 public void onShow(Event e) { 243 fireEvent(new ShowEvent(e)); 244 } 245 246 public void onHide(Event e) { 247 fireEvent(new HideEvent(e)); 248 } 249 250 public void reconfigure() { 251 removeDataIfExists(getElement()); 252 configure(); 253 } 254 255 /** 256 * configure this datetimepicker. 257 */ 258 protected void configure() { 259 configure(this); 260 } 261 262 protected native void removeDataIfExists(Element e) /*-{ 263 var $that = $wnd.jQuery(e); 264 dtpData = $that.data('datetimepicker'); 265 if(dtpData) { 266 picker = dtpData.picker; 267 $that.removeData('dateFormat'); 268 $that.removeData('dateLanguage'); 269 $that.removeData('dateWeekstart'); 270 $that.removeData('dateStartdate'); 271 $that.removeData('dateEnddate'); 272 $that.removeData('dateStartView'); 273 $that.removeData('datetimepicker'); 274 picker.remove(); 275 $that.off(); 276 } 277 }-*/; 278 279 /** 280 * call jquery datetimepicker plugin in a element. 281 * 282 * @param e: Element that will be transformed in a datetimepicker. 283 * @param autoclose is autoclose? 284 */ 285 @SuppressWarnings("ParameterHidesMemberVariable") 286 protected native void configure(Element e, 287 boolean autoclose, 288 int minuteStep, 289 boolean todayButton, 290 boolean highlightToday, 291 String minViewMode, 292 String startViewMode, 293 String maxViewMode, 294 String pickerPosition) /*-{ 295 var that = this; 296 $wnd.jQuery(e).datetimepicker({ 297 autoclose : autoclose, 298 minuteStep : minuteStep, 299 todayBtn : todayButton, 300 todayHighlight : highlightToday, 301 minView : minViewMode, 302 startView : startViewMode, 303 maxView : maxViewMode, 304 pickerPosition: pickerPosition 305 }) 306 .on('change' , function() { 307 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onChange()(); 308 }) 309 .on('changeDate', function () { 310 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onChange()(); 311 }) 312 .on("show", function (e) { 313 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onShow(Lcom/google/gwt/user/client/Event;)(e); 314 }) 315 .on("hide", function (e) { 316 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onHide(Lcom/google/gwt/user/client/Event;)(e); 317 }); 318 }-*/; 319 320 private native void execute(Element e, String cmd) /*-{ 321 $wnd.jQuery(e).datetimepicker(cmd); 322 }-*/; 323 324 private void execute(String cmd) { 325 execute(getElement(), cmd); 326 } 327 328 /** 329 * {@inheritDoc} 330 */ 331 @Override 332 public void show() { 333 execute("show"); 334 } 335 336 /** 337 * {@inheritDoc} 338 */ 339 @Override 340 public void hide() { 341 execute("hide"); 342 } 343 344 /** 345 * {@inheritDoc} 346 */ 347 @Override 348 public void toggle() { 349 //TODO 2012/06/21 ohashi keisuke should be support 350 throw new UnsupportedOperationException("not support toggle"); 351 } 352 353 /** 354 * {@inheritDoc} 355 */ 356 @Override 357 public HandlerRegistration addHideHandler(HideHandler handler) { 358 return addHandler(handler, HideEvent.getType()); 359 } 360 361 /** 362 * {@inheritDoc} 363 */ 364 @Override 365 public HandlerRegistration addHiddenHandler(HiddenHandler handler) { 366 //TODO 2012/06/21 ohashi keisuke should be support 367 throw new UnsupportedOperationException("not support hidden event"); 368 } 369 370 /** 371 * {@inheritDoc} 372 */ 373 @Override 374 public HandlerRegistration addShowHandler(ShowHandler handler) { 375 return addHandler(handler, ShowEvent.getType()); 376 } 377 378 /** 379 * {@inheritDoc} 380 */ 381 @Override 382 public HandlerRegistration addShownHandler(ShownHandler handler) { 383 //TODO 2012/06/21 ohashi keisuke should be support 384 throw new UnsupportedOperationException("not support shown event"); 385 } 386 387 /** 388 * {@inheritDoc} 389 */ 390 @Override 391 public void setWeekStart(int start) { 392 getElement().setAttribute("data-date-weekstart", start + ""); 393 } 394 395 /** 396 * {@inheritDoc} 397 */ 398 @Override 399 public void setStartDate(String startDate) { 400 getElement().setAttribute("data-date-startdate", startDate); 401 } 402 403 /** 404 * {@inheritDoc} 405 */ 406 @Override 407 public void setStartDate_(Date startDate) { 408 setStartDate(dtf.format(startDate)); 409 } 410 411 412 /** 413 * {@inheritDoc} 414 */ 415 @Override 416 public void setEndDate(String endDate) { 417 getElement().setAttribute("data-date-enddate", endDate); 418 } 419 420 /** 421 * {@inheritDoc} 422 */ 423 @Override 424 public void setEndDate_(Date endDate) { 425 setEndDate(dtf.format(endDate)); 426 } 427 428 /** 429 * {@inheritDoc} 430 */ 431 @Override 432 public void setAutoClose(boolean autoclose) { 433 this.autoclose = autoclose; 434 } 435 436 /** 437 * {@inheritDoc} 438 */ 439 @Override 440 public void setMinView(ViewMode mode) { 441 setMinView(mode.name()); 442 } 443 444 /** 445 * {@inheritDoc} 446 */ 447 @Override 448 public void setMinView(String mode) { 449 this.minViewMode = mode.toLowerCase(); 450 } 451 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override 457 public void setStartView(HasViewMode.ViewMode mode) { 458 setStartView(mode.name()); 459 } 460 461 /** 462 * {@inheritDoc} 463 */ 464 @Override 465 public void setStartView(String mode) { 466 this.startViewMode = mode.toLowerCase(); 467 } 468 469 /** 470 * {@inheritDoc} 471 */ 472 @Override 473 public void setMaxView(ViewMode mode) { 474 setMaxView(mode.name()); 475 } 476 477 /** 478 * {@inheritDoc} 479 */ 480 @Override 481 public void setMaxView(String mode) { 482 this.maxViewMode = mode.toLowerCase(); 483 } 484 485 486 /** 487 * Return Editor 488 * 489 * @return editor 490 */ 491 @Override 492 public TakesValueEditor<Date> asEditor() { 493 if(editor == null){ 494 editor = TakesValueEditor.of(this); 495 } 496 return editor; 497 } 498 499 @Override 500 public HandlerRegistration addChangeHandler(ChangeHandler handler) { 501 return addHandler(handler, ChangeEvent.getType()); 502 } 503 504 /** 505 * {@inheritDoc} 506 */ 507 @Override 508 public void setPlaceholder(String placeholder) { 509 placeholderHelper.setPlaceholer(getElement(), placeholder); 510 } 511 512 /** 513 * {@inheritDoc} 514 */ 515 @Override 516 public String getPlaceholder() { 517 return placeholderHelper.getPlaceholder(getElement()); 518 } 519 520 /** 521 * {@inheritDoc} 522 */ 523 @Override 524 public void setSearchQuery(boolean searchQuery) { 525 SearchQueryStyleHelper.setSearchQuery(this, searchQuery); 526 } 527 528 /** 529 * {@inheritDoc} 530 */ 531 @Override 532 public boolean isSearchQuery() { 533 return SearchQueryStyleHelper.isSearchQuery(this); 534 } 535 536 /** 537 * {@inheritDoc} 538 */ 539 @Override 540 public void setAlternateSize(AlternateSize size) { 541 StyleHelper.changeStyle(this, size, AlternateSize.class); 542 } 543 544 /** 545 * {@inheritDoc} 546 */ 547 @Override 548 public void setSize(int size) { 549 SizeHelper.setSize(this, size); 550 } 551 552 /** 553 * {@inheritDoc} 554 */ 555 @Override 556 public String getId() { 557 return getElement().getId(); 558 } 559 560 /** 561 * {@inheritDoc} 562 */ 563 @Override 564 public void setId(String id) { 565 getElement().setId(id); 566 } 567 568 /** 569 * {@inheritDoc} 570 */ 571 @Override 572 public void setShowOn(Device device) { 573 ResponsiveHelper.setShowOn(this, device); 574 } 575 576 /** 577 * {@inheritDoc} 578 */ 579 @Override 580 public void setHideOn(Device device) { 581 ResponsiveHelper.setHideOn(this, device); 582 583 } 584 585 /** 586 * {@inheritDoc} 587 */ 588 @Override 589 public void setStyle(Style style) { 590 StyleHelper.setStyle(this, style); 591 } 592 593 /** 594 * {@inheritDoc} 595 */ 596 @Override 597 public void addStyle(Style style) { 598 StyleHelper.addStyle(this, style); 599 } 600 601 /** 602 * {@inheritDoc} 603 */ 604 @Override 605 public void removeStyle(Style style) { 606 StyleHelper.removeStyle(this, style); 607 608 } 609 610 /** 611 * {@inheritDoc} 612 */ 613 @Override 614 public boolean isEnabled() { 615 return false; 616 } 617 618 /** 619 * {@inheritDoc} 620 */ 621 @Override 622 public void setEnabled(boolean enabled) { 623 box.setEnabled(enabled); 624 } 625 626 627 @Override 628 public void setDaysOfWeekDisabled(String value) { 629 getElement().setAttribute("date-days-of-week-disabled", value); 630 } 631 632 633 @Override 634 public void setMinuteStep(int minutes) { 635// getElement().setAttribute("date-days-of-week-disabled", value); 636 this.minuteStep = minutes; 637 } 638 639 640 @Override 641 public void setShowTodayButton(boolean show) { 642 this.todayButton = show; 643 } 644 645 646 @Override 647 public void setHighlightToday(boolean highlight) { 648 this.highlightToday = highlight; 649 } 650 651 public PickerPosition getPickerPosition() { 652 return pickerPosition; 653 } 654 655 public void setPickerPosition(PickerPosition pickerPosition) { 656 this.pickerPosition = pickerPosition; 657 } 658 659 private String dpGlobalFormatToDateTimeFormat(String dpGlobalFormat) 660 { 661 if(dpGlobalFormat == null || dpGlobalFormat.length() == 0) 662 return ""; 663 664 char current; 665 char last = dpGlobalFormat.charAt(0); 666 int count = 1; 667 String out = ""; 668 669 for(int index = 1; index < dpGlobalFormat.length(); index++) 670 { 671 current = dpGlobalFormat.charAt(index); 672 673 if(current == last) 674 { 675 count++; 676 continue; 677 } 678 679 out += processToken(last, count); 680 681 last = current; 682 count = 1; 683 } 684 685 out += processToken(last, count); 686 687 return out; 688 } 689 690 private String processToken(char token, int count) 691 { 692 if (token == 'y') { 693 if (count == 2) 694 return "yy"; 695 if(count == 4) 696 return "yyyy"; 697 } 698 else if(token == 'm') { 699 if(count == 1) 700 return "M"; 701 if(count == 2) 702 return "MM"; 703 } 704 else if(token == 'M') { 705 if(count == 1) 706 return "MMM"; 707 if(count == 2) 708 return "MMMM"; 709 } 710 else if(token == 'h') { 711 token = 'H'; 712 } 713 else if(token == 'i') { 714 token = 'm'; 715 } 716 717 String out = ""; 718 for(int i=0; i<count; i++) 719 out += token; 720 721 return out; 722 723 // TODO: Support PHP format so we can do more complex formatting 724 } 725 726 /* 727 DateTimeFormat 728 729 G era designator Text AD 730 y year Number 1996 731 M month in year Text or Number July (or) 07 732 d day in month Number 10 733 h hour in am/pm (1-12) Number 12 734 H hour in day (0-23) Number 0 735 m minute in hour Number 30 736 s second in minute Number 55 737 S fractional second Number 978 738 E day of week Text Tuesday 739 a am/pm marker Text PM 740 k hour in day (1-24) Number 24 741 K hour in am/pm (0-11) Number 0 742 z time zone Text Pacific Standard Time 743 Z time zone (RFC 822) Number -0800 744 v time zone (generic) Text Pacific Time 745 ' escape for text Delimiter 'Date=' 746 '' single quote Literal 'o''clock' 747 */ 748}