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