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.event.HasVisibleHandlers; 026import com.github.gwtbootstrap.client.ui.base.IsResponsive; 027import com.github.gwtbootstrap.client.ui.base.IsSearchQuery; 028import com.github.gwtbootstrap.client.ui.base.PlaceholderHelper; 029import com.github.gwtbootstrap.client.ui.base.ResponsiveHelper; 030import com.github.gwtbootstrap.client.ui.base.SearchQueryStyleHelper; 031import com.github.gwtbootstrap.client.ui.base.SizeHelper; 032import com.github.gwtbootstrap.client.ui.base.Style; 033import com.github.gwtbootstrap.client.ui.base.StyleHelper; 034import com.github.gwtbootstrap.client.ui.constants.AlternateSize; 035import com.github.gwtbootstrap.client.ui.constants.Device; 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 } 219 220 /** 221 * Configure the elements for a specific widget. 222 * Use only if you know what you are doing. 223 * 224 * @param w: the widget to configure. 225 */ 226 protected void configure(Widget w) { 227 this.decoratedElement = w.getElement(); 228 w.getElement().setAttribute("data-date-format", format); 229 w.getElement().setAttribute("data-date-language", language); 230 configure(w.getElement(), autoclose, minuteStep, todayButton, highlightToday, 231 minViewMode, startViewMode, maxViewMode, pickerPosition.getValue()); 232 } 233 234 /** 235 * dateChange event handler. 236 */ 237 public void onChange() { 238 ValueChangeEvent.fire(this, getValue()); 239 } 240 241 public void onShow(Event e) { 242 fireEvent(new ShowEvent(e)); 243 } 244 245 public void onHide(Event e) { 246 fireEvent(new HideEvent(e)); 247 } 248 public void reconfigure() { 249 removeDataIfExists(getElement()); 250 configure(); 251 } 252 253 /** 254 * configure this datetimepicker. 255 */ 256 protected void configure() { 257 configure(this); 258 } 259 260 protected native void removeDataIfExists(Element e) /*-{ 261 var $that = $wnd.jQuery(e); 262 if($that.data('datetimepicker')) { 263 console.log($that.data()); 264 $that.removeData('dateFormat'); 265 $that.removeData('dateLanguage'); 266 $that.removeData('dateWeekstart'); 267 $that.removeData('dateStartdate'); 268 $that.removeData('dateEnddate'); 269 $that.removeData('dateStartView'); 270 $that.removeData('datetimepicker'); 271 $that.off(); 272 } 273 }-*/; 274 275 /** 276 * call jquery datetimepicker plugin in a element. 277 * 278 * @param e: Element that will be transformed in a datetimepicker. 279 * @param autoclose is autoclose? 280 */ 281 @SuppressWarnings("ParameterHidesMemberVariable") 282 protected native void configure(Element e, 283 boolean autoclose, 284 int minuteStep, 285 boolean todayButton, 286 boolean highlightToday, 287 String minViewMode, 288 String startViewMode, 289 String maxViewMode, 290 String pickerPosition) /*-{ 291 var that = this; 292 $wnd.jQuery(e).datetimepicker({ 293 autoclose : autoclose, 294 minuteStep : minuteStep, 295 todayBtn : todayButton, 296 todayHighlight : highlightToday, 297 minView : minViewMode, 298 startView : startViewMode, 299 maxView : maxViewMode, 300 pickerPosition: pickerPosition 301 }) 302 .on('change' , function() { 303 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onChange()(); 304 }) 305 .on('changeDate', function () { 306 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onChange()(); 307 }) 308 .on("show", function (e) { 309 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onShow(Lcom/google/gwt/user/client/Event;)(e); 310 }) 311 .on("hide", function (e) { 312 that.@com.github.gwtbootstrap.datetimepicker.client.ui.base.DateTimeBoxBase::onHide(Lcom/google/gwt/user/client/Event;)(e); 313 }); 314 }-*/; 315 316 private native void execute(Element e, String cmd) /*-{ 317 $wnd.jQuery(e).datetimepicker(cmd); 318 }-*/; 319 320 private void execute(String cmd) { 321 execute(getElement(), cmd); 322 } 323 324 /** 325 * {@inheritDoc} 326 */ 327 @Override 328 public void show() { 329 execute("show"); 330 } 331 332 /** 333 * {@inheritDoc} 334 */ 335 @Override 336 public void hide() { 337 execute("hide"); 338 } 339 340 /** 341 * {@inheritDoc} 342 */ 343 @Override 344 public void toggle() { 345 //TODO 2012/06/21 ohashi keisuke should be support 346 throw new UnsupportedOperationException("not support toggle"); 347 } 348 349 /** 350 * {@inheritDoc} 351 */ 352 @Override 353 public HandlerRegistration addHideHandler(HideHandler handler) { 354 return addHandler(handler, HideEvent.getType()); 355 } 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override 361 public HandlerRegistration addHiddenHandler(HiddenHandler handler) { 362 //TODO 2012/06/21 ohashi keisuke should be support 363 throw new UnsupportedOperationException("not support hidden event"); 364 } 365 366 /** 367 * {@inheritDoc} 368 */ 369 @Override 370 public HandlerRegistration addShowHandler(ShowHandler handler) { 371 return addHandler(handler, ShowEvent.getType()); 372 } 373 374 /** 375 * {@inheritDoc} 376 */ 377 @Override 378 public HandlerRegistration addShownHandler(ShownHandler handler) { 379 //TODO 2012/06/21 ohashi keisuke should be support 380 throw new UnsupportedOperationException("not support shown event"); 381 } 382 383 /** 384 * {@inheritDoc} 385 */ 386 @Override 387 public void setWeekStart(int start) { 388 getElement().setAttribute("data-date-weekstart", start + ""); 389 } 390 391 /** 392 * {@inheritDoc} 393 */ 394 @Override 395 public void setStartDate(String startDate) { 396 getElement().setAttribute("data-date-startdate", startDate); 397 } 398 399 /** 400 * {@inheritDoc} 401 */ 402 @Override 403 public void setStartDate_(Date startDate) { 404 setStartDate(dtf.format(startDate)); 405 } 406 407 408 /** 409 * {@inheritDoc} 410 */ 411 @Override 412 public void setEndDate(String endDate) { 413 getElement().setAttribute("data-date-enddate", endDate); 414 } 415 416 /** 417 * {@inheritDoc} 418 */ 419 @Override 420 public void setEndDate_(Date endDate) { 421 setEndDate(dtf.format(endDate)); 422 } 423 424 /** 425 * {@inheritDoc} 426 */ 427 @Override 428 public void setAutoClose(boolean autoclose) { 429 this.autoclose = autoclose; 430 } 431 432 /** 433 * {@inheritDoc} 434 */ 435 @Override 436 public void setMinView(ViewMode mode) { 437 setMinView(mode.name()); 438 } 439 440 /** 441 * {@inheritDoc} 442 */ 443 @Override 444 public void setMinView(String mode) { 445 this.minViewMode = mode.toLowerCase(); 446 } 447 448 449 /** 450 * {@inheritDoc} 451 */ 452 @Override 453 public void setStartView(HasViewMode.ViewMode mode) { 454 setStartView(mode.name()); 455 } 456 457 /** 458 * {@inheritDoc} 459 */ 460 @Override 461 public void setStartView(String mode) { 462 this.startViewMode = mode.toLowerCase(); 463 } 464 465 /** 466 * {@inheritDoc} 467 */ 468 @Override 469 public void setMaxView(ViewMode mode) { 470 setMaxView(mode.name()); 471 } 472 473 /** 474 * {@inheritDoc} 475 */ 476 @Override 477 public void setMaxView(String mode) { 478 this.maxViewMode = mode.toLowerCase(); 479 } 480 481 482 /** 483 * Return Editor 484 * 485 * @return editor 486 */ 487 @Override 488 public TakesValueEditor<Date> asEditor() { 489 if(editor == null){ 490 editor = TakesValueEditor.of(this); 491 } 492 return editor; 493 } 494 495 @Override 496 public HandlerRegistration addChangeHandler(ChangeHandler handler) { 497 return addHandler(handler, ChangeEvent.getType()); 498 } 499 500 /** 501 * {@inheritDoc} 502 */ 503 @Override 504 public void setPlaceholder(String placeholder) { 505 placeholderHelper.setPlaceholer(getElement(), placeholder); 506 } 507 508 /** 509 * {@inheritDoc} 510 */ 511 @Override 512 public String getPlaceholder() { 513 return placeholderHelper.getPlaceholder(getElement()); 514 } 515 516 /** 517 * {@inheritDoc} 518 */ 519 @Override 520 public void setSearchQuery(boolean searchQuery) { 521 SearchQueryStyleHelper.setSearchQuery(this, searchQuery); 522 } 523 524 /** 525 * {@inheritDoc} 526 */ 527 @Override 528 public boolean isSearchQuery() { 529 return SearchQueryStyleHelper.isSearchQuery(this); 530 } 531 532 /** 533 * {@inheritDoc} 534 */ 535 @Override 536 public void setAlternateSize(AlternateSize size) { 537 StyleHelper.changeStyle(this, size, AlternateSize.class); 538 } 539 540 /** 541 * {@inheritDoc} 542 */ 543 @Override 544 public void setSize(int size) { 545 SizeHelper.setSize(this, size); 546 } 547 548 /** 549 * {@inheritDoc} 550 */ 551 @Override 552 public String getId() { 553 return getElement().getId(); 554 } 555 556 /** 557 * {@inheritDoc} 558 */ 559 @Override 560 public void setId(String id) { 561 getElement().setId(id); 562 } 563 564 /** 565 * {@inheritDoc} 566 */ 567 @Override 568 public void setShowOn(Device device) { 569 ResponsiveHelper.setShowOn(this, device); 570 } 571 572 /** 573 * {@inheritDoc} 574 */ 575 @Override 576 public void setHideOn(Device device) { 577 ResponsiveHelper.setHideOn(this, device); 578 579 } 580 581 /** 582 * {@inheritDoc} 583 */ 584 @Override 585 public void setStyle(Style style) { 586 StyleHelper.setStyle(this, style); 587 } 588 589 /** 590 * {@inheritDoc} 591 */ 592 @Override 593 public void addStyle(Style style) { 594 StyleHelper.addStyle(this, style); 595 } 596 597 /** 598 * {@inheritDoc} 599 */ 600 @Override 601 public void removeStyle(Style style) { 602 StyleHelper.removeStyle(this, style); 603 604 } 605 606 /** 607 * {@inheritDoc} 608 */ 609 @Override 610 public boolean isEnabled() { 611 return false; 612 } 613 614 /** 615 * {@inheritDoc} 616 */ 617 @Override 618 public void setEnabled(boolean enabled) { 619 box.setEnabled(enabled); 620 } 621 622 623 @Override 624 public void setDaysOfWeekDisabled(String value) { 625 getElement().setAttribute("date-days-of-week-disabled", value); 626 } 627 628 629 @Override 630 public void setMinuteStep(int minutes) { 631// getElement().setAttribute("date-days-of-week-disabled", value); 632 this.minuteStep = minutes; 633 } 634 635 636 @Override 637 public void setShowTodayButton(boolean show) { 638 this.todayButton = show; 639 } 640 641 642 @Override 643 public void setHighlightToday(boolean highlight) { 644 this.highlightToday = highlight; 645 } 646 647 public PickerPosition getPickerPosition() { 648 return pickerPosition; 649 } 650 651 public void setPickerPosition(PickerPosition pickerPosition) { 652 this.pickerPosition = pickerPosition; 653 } 654 655 private String dpGlobalFormatToDateTimeFormat(String dpGlobalFormat) 656 { 657 if(dpGlobalFormat == null || dpGlobalFormat.length() == 0) 658 return ""; 659 660 char current; 661 char last = dpGlobalFormat.charAt(0); 662 int count = 1; 663 String out = ""; 664 665 for(int index = 1; index < dpGlobalFormat.length(); index++) 666 { 667 current = dpGlobalFormat.charAt(index); 668 669 if(current == last) 670 { 671 count++; 672 continue; 673 } 674 675 out += processToken(last, count); 676 677 last = current; 678 count = 1; 679 } 680 681 out += processToken(last, count); 682 683 return out; 684 } 685 686 private String processToken(char token, int count) 687 { 688 if (token == 'y') { 689 if (count == 2) 690 return "yy"; 691 if(count == 4) 692 return "yyyy"; 693 } 694 else if(token == 'm') { 695 if(count == 1) 696 return "M"; 697 if(count == 2) 698 return "MM"; 699 } 700 else if(token == 'M') { 701 if(count == 1) 702 return "MMM"; 703 if(count == 2) 704 return "MMMM"; 705 } 706 else if(token == 'h') { 707 token = 'H'; 708 } 709 else if(token == 'i') { 710 token = 'm'; 711 } 712 713 String out = ""; 714 for(int i=0; i<count; i++) 715 out += token; 716 717 return out; 718 719 // TODO: Support PHP format so we can do more complex formatting 720 } 721 722 /* 723 DateTimeFormat 724 725 G era designator Text AD 726 y year Number 1996 727 M month in year Text or Number July (or) 07 728 d day in month Number 10 729 h hour in am/pm (1-12) Number 12 730 H hour in day (0-23) Number 0 731 m minute in hour Number 30 732 s second in minute Number 55 733 S fractional second Number 978 734 E day of week Text Tuesday 735 a am/pm marker Text PM 736 k hour in day (1-24) Number 24 737 K hour in am/pm (0-11) Number 0 738 z time zone Text Pacific Standard Time 739 Z time zone (RFC 822) Number -0800 740 v time zone (generic) Text Pacific Time 741 ' escape for text Delimiter 'Date=' 742 '' single quote Literal 'o''clock' 743 */ 744}