001package org.gwtbootstrap3.extras.fullcalendar.client.ui; 002 003/* 004 * #%L 005 * GwtBootstrap3 006 * %% 007 * Copyright (C) 2013 - 2015 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 com.google.gwt.core.client.JavaScriptObject; 024import com.google.gwt.core.client.JsArray; 025import com.google.gwt.core.client.JsDate; 026import com.google.gwt.core.client.ScriptInjector; 027import com.google.gwt.dom.client.Document; 028import com.google.gwt.dom.client.Element; 029import com.google.gwt.event.dom.client.DomEvent; 030import com.google.gwt.event.dom.client.HasLoadHandlers; 031import com.google.gwt.event.dom.client.LoadEvent; 032import com.google.gwt.event.dom.client.LoadHandler; 033import com.google.gwt.event.shared.HandlerRegistration; 034import com.google.gwt.user.client.ui.FlowPanel; 035 036import java.util.Date; 037import java.util.HashMap; 038import java.util.List; 039import java.util.Map; 040 041/** 042 * Wrapper around FullCalendar 043 * 044 * @author Jeff Isenhart 045 * @see http://arshaw.com/fullcalendar/ 046 */ 047public class FullCalendar extends FlowPanel implements HasLoadHandlers { 048 049 private ViewOption currentView;//http://arshaw.com/fullcalendar/docs/views/defaultView/ 050 private CalendarConfig config;//a bunch of options and events encapsulated in one place 051 private final boolean editable;//@see http://arshaw.com/fullcalendar/docs/event_ui/editable/ 052 private boolean loaded; 053 private static Map<String, JavaScriptObject> languageScripts; 054 055 public FullCalendar(final String id, final ViewOption defaultView, final boolean editable) { 056 this(id, defaultView, null, editable); 057 } 058 059 public FullCalendar(final String id, final ViewOption defaultView, final boolean editable, final Header header) { 060 this(id, defaultView, new CalendarConfig(header), editable); 061 } 062 063 public FullCalendar(final String id, final ViewOption defaultView, final CalendarConfig config, final boolean editable) { 064 getElement().setId(id); 065 this.currentView = defaultView == null ? ViewOption.month : defaultView; 066 this.config = config; 067 this.editable = editable; 068 loaded = false; 069 if (languageScripts == null) { 070 languageScripts = new HashMap<String, JavaScriptObject>(); 071 } 072 } 073 074 /** 075 * This method is called immediately after a widget becomes attached to the 076 * browser's document. 077 */ 078 @Override 079 protected void onLoad() { 080 super.onLoad(); 081 loaded = true; 082 renderCalendar(); 083 } 084 085 private void renderCalendar() { 086 boolean selectable = false; 087 boolean selectHelper = false; 088 boolean unselectAuto = true; 089 boolean selectOverlap = true; 090 091 JsArray<JavaScriptObject> javascriptParams = null; 092 String language = null; 093 String timezone = null; 094 String weekNumberTitle = null; 095 String unselectCancel = null; 096 String selectContraint = null; 097 if (config != null) { 098 selectable = config.isSelectable(); 099 selectHelper = config.isSelectHelper(); 100 unselectAuto = config.isUnselectAuto(); 101 selectOverlap = config.isSelectOverlap(); 102 timezone = config.getTimezone(); 103 weekNumberTitle = config.getWeekNumberTitle(); 104 unselectCancel = config.getUnselectCancel(); 105 selectContraint = config.getSelectContraint(); 106 javascriptParams = config.getJavaScriptParameters(); 107 if (config.getLangauge() != null) { 108 language = config.getLangauge().getCode(); 109 ensureInjected(config.getLangauge()); 110 } 111 } 112 addCalendar(getElement().getId(), 113 currentView.name(), 114 editable, 115 selectable, 116 selectHelper, 117 unselectAuto, 118 selectOverlap, 119 language, 120 timezone, 121 weekNumberTitle, 122 unselectCancel, 123 selectContraint, 124 javascriptParams 125 ); 126 //Let everyone know it is ok to add events and set properties on the instance 127 DomEvent.fireNativeEvent(Document.get().createLoadEvent(), this); 128 } 129 130 public void changeLangauge(final Language language) { 131 if (language != null) { 132 if (config == null) { 133 config = new CalendarConfig(); 134 } 135 config.setLangauge(language); 136 destroy(); 137 renderCalendar(); 138 } 139 } 140 141 public void changeTimezone(final String timezone) { 142 if (timezone != null) { 143 if (config == null) { 144 config = new CalendarConfig(); 145 } 146 config.setTimezone(timezone); 147 destroy(); 148 renderCalendar(); 149 } 150 } 151 152 private void ensureInjected(final Language language) { 153 if (!languageScripts.isEmpty()) { 154 for (final JavaScriptObject script : languageScripts.values()) { 155 try { 156 final Element ele = (Element) script; 157 ele.removeFromParent(); 158 } catch (final Exception e) { 159 // TODO: handle exception 160 } 161 } 162 } 163 final JavaScriptObject scriptElement = ScriptInjector.fromString(language.getResource().getText()).setWindow(ScriptInjector.TOP_WINDOW).inject(); 164 languageScripts.put(language.getCode(), scriptElement); 165 } 166 167 private native void addCalendar(String id, 168 String currentView, 169 boolean editable, 170 boolean selectable, 171 boolean selectHelper, 172 boolean unselectAuto, 173 boolean selectOverlap, 174 String lang, 175 String timezone, 176 String weekNumberTitle, 177 String unselectCancel, 178 String selectContraint, 179 JsArray<JavaScriptObject> options 180 ) /*-{ 181 var fullCalendarParams = { 182 defaultView: currentView, 183 selectable: selectable, 184 selectHelper: selectHelper, 185 editable: editable, 186 unselectAuto: unselectAuto, 187 selectOverlap: selectOverlap 188 }; 189 if (lang) { 190 fullCalendarParams.lang = lang; 191 } 192 if (timezone) { 193 fullCalendarParams.timezone = timezone; 194 } 195 if (weekNumberTitle) { 196 fullCalendarParams.weekNumberTitle = weekNumberTitle; 197 } 198 if (unselectCancel) { 199 fullCalendarParams.unselectCancel = unselectCancel; 200 } 201 if (selectContraint) { 202 fullCalendarParams.selectContraint = selectContraint; 203 } 204 if (options) { 205 for (var i = 0; i < options.length; i++) { 206 $wnd.jQuery.extend(fullCalendarParams, options[i]); 207 } 208 } 209 $wnd.jQuery('#' + id).fullCalendar(fullCalendarParams); 210 }-*/; 211 212 public void addEvent(final Event event) { 213 if (loaded && event != null) { 214 addEvent(getElement().getId(), event.toJavaScript()); 215 } 216 } 217 218 public void addEvents(final List<Event> events) { 219 if (loaded && events != null && !events.isEmpty()) { 220 JsArray<JavaScriptObject> jsEvents = JavaScriptObject.createArray(events.size()).cast(); 221 int i = 0; 222 for (final Event evt : events) { 223 jsEvents.set(i++, evt.toJavaScript()); 224 } 225 addEventSource(getElement().getId(), jsEvents); 226 } 227 } 228 229 private native void addEventSource(String id, JsArray<JavaScriptObject> events) /*-{ 230 $wnd.jQuery('#' + id).fullCalendar('addEventSource', events); 231 }-*/; 232 233 public ViewOption getCurrentView() { 234 return currentView; 235 } 236 237 private native void addEvent(String id, JavaScriptObject event) /*-{ 238 $wnd.jQuery('#' + id).fullCalendar('renderEvent', event, true); 239 }-*/; 240 241 public void setView(final ViewOption view) { 242 if (view != null) { 243 currentView = view; 244 setView(getElement().getId(), view.name()); 245 } 246 } 247 248 private native void setView(String id, String viewName) /*-{ 249 $wnd.jQuery('#' + id).fullCalendar('changeView', viewName); 250 }-*/; 251 252 public void goToDate(final Date d) { 253 if (d != null) { 254 JsDate date = JsDate.create((double) d.getTime()); 255 goToDate(getElement().getId(), date); 256 } 257 } 258 259 private native void goToDate(String id, JsDate date) /*-{ 260 $wnd.jQuery('#' + id).fullCalendar('gotoDate',date); 261 }-*/; 262 263 @Override 264 public HandlerRegistration addLoadHandler(final LoadHandler handler) { 265 return super.addDomHandler(handler, LoadEvent.getType()); 266 } 267 268 public JsArray<JavaScriptObject> getEvent(final String eventId) { 269 if (eventId != null) { 270 return getEvent(getElement().getId(), eventId); 271 } 272 return null; 273 } 274 275 public native JsArray<JavaScriptObject> getEvent(String id, String eventId) /*-{ 276 return $wnd.jQuery('#' + id).fullCalendar('clientEvents', eventId); 277 }-*/; 278 279 public void removeEvent(final String eventId) { 280 if (eventId != null) { 281 removeEvent(getElement().getId(), eventId); 282 } 283 } 284 285 public void removeAllEvents() { 286 removeAllEvents(getElement().getId()); 287 } 288 289 private native void removeAllEvents(String id) /*-{ 290 $wnd.jQuery('#' + id).fullCalendar('removeEvents'); 291 }-*/; 292 293 public native void removeEvent(String id, String eventId) /*-{ 294 $wnd.jQuery('#' + id).fullCalendar('removeEvents', eventId); 295 }-*/; 296 297 public void updateEvent(final Event evt) { 298 if (evt != null && evt.getId() != null) { 299 updateEvent(getElement().getId(), evt.toJavaScript()); 300 } 301 } 302 303 public native void updateEvent(String id, JavaScriptObject event) /*-{ 304 $wnd.jQuery('#' + id).fullCalendar('updateEvent', event); 305 }-*/; 306 307 public void addEventSource(final EventSource eventSource) { 308 if (eventSource != null) { 309 addEventSource(getElement().getId(), eventSource.toJavaScript()); 310 } 311 } 312 313 private native void addEventSource(String id, JavaScriptObject eventSource) /*-{ 314 $wnd.jQuery('#' + id).fullCalendar('addEventSource', eventSource); 315 }-*/; 316 317 public void removeEventSource(final EventSource eventSource) { 318 if (eventSource != null) { 319 removeEventSource(getElement().getId(), eventSource.toJavaScript()); 320 } 321 } 322 323 private native void removeEventSource(String id, JavaScriptObject eventSource) /*-{ 324 $wnd.jQuery('#' + id).fullCalendar('removeEventSource', eventSource); 325 }-*/; 326 327 public void previous() { 328 previous(getElement().getId()); 329 } 330 331 private native void previous(String id) /*-{ 332 $wnd.jQuery('#' + id).fullCalendar('prev'); 333 }-*/; 334 335 public void next() { 336 next(getElement().getId()); 337 } 338 339 private native void next(String id) /*-{ 340 $wnd.jQuery('#' + id).fullCalendar('next'); 341 }-*/; 342 343 public Date getDate() { 344 final JsDate jsDate = getDate(getElement().getId()); 345 final long time = (long) jsDate.getTime(); 346 return new Date(time); 347 } 348 349 private native JsDate getDate(String id) /*-{ 350 return $wnd.jQuery('#' + id).fullCalendar('getDate').toDate(); 351 }-*/; 352 353 public void today() { 354 today(getElement().getId()); 355 } 356 357 private native void today(String id) /*-{ 358 $wnd.jQuery('#' + id).fullCalendar('today'); 359 }-*/; 360 361 public View getView() { 362 return new View(getView(getElement().getId())); 363 } 364 365 private native JavaScriptObject getView(String id) /*-{ 366 $wnd.jQuery('#' + id).fullCalendar('getView'); 367 }-*/; 368 369 public void destroy() { 370 destroy(getElement().getId()); 371 } 372 373 private native void destroy(String id) /*-{ 374 $wnd.jQuery('#' + id).fullCalendar('destroy'); 375 }-*/; 376 377 public void render() { 378 render(getElement().getId()); 379 } 380 381 private native void render(String id) /*-{ 382 $wnd.jQuery('#' + id).fullCalendar('render'); 383 }-*/; 384 385 public void setHeight(final int height) { 386 if (height >= 0) { 387 setHeight(getElement().getId(), height); 388 } 389 } 390 391 private native void setHeight(String id, int height) /*-{ 392 $wnd.jQuery('#' + id).fullCalendar('option', 'height', height); 393 }-*/; 394 395 public void setContentHeight(final int height) { 396 if (height >= 0) { 397 setContentHeight(getElement().getId(), height); 398 } 399 } 400 401 private native void setContentHeight(String id, int height) /*-{ 402 $wnd.jQuery('#' + id).fullCalendar('option', 'contentHeight', height); 403 }-*/; 404 405 public void setAspectRatio(final double ratio) { 406 if (ratio > 0) { 407 setAspectRatio(getElement().getId(), ratio); 408 } 409 } 410 411 private native void setAspectRatio(String id, double ratio) /*-{ 412 $wnd.jQuery('#' + id).fullCalendar('option', 'aspectRatio', ratio); 413 }-*/; 414 415 /** 416 * Useful for callback cancel/revert functions 417 * 418 * @param revertFunction 419 */ 420 public native void executeFunction(JavaScriptObject revertFunction)/*-{ 421 revertFunction(); 422 }-*/; 423 424 public void select(Date start, Date end) { 425 select(getElement().getId(), Event.getDateAsISO8601(start), Event.getDateAsISO8601(end)); 426 } 427 428 public void select(String start, String end) { 429 select(getElement().getId(), start, end); 430 } 431 432 private native void select(String id, String start, String end) /*-{ 433 $wnd.jQuery('#' + id).fullCalendar('select', start, end); 434 }-*/; 435 436 public void unselect() { 437 unselect(getElement().getId()); 438 } 439 440 private native void unselect(String id) /*-{ 441 $wnd.jQuery('#' + id).fullCalendar('unselect'); 442 }-*/; 443}