001 package org.gwtbootstrap3.extras.fullcalendar.client.ui;
002
003 /*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2013 - 2014 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.JavaScriptObject;
024 import com.google.gwt.core.client.JsArray;
025 import com.google.gwt.core.client.JsDate;
026 import com.google.gwt.core.client.ScriptInjector;
027 import com.google.gwt.dom.client.Document;
028 import com.google.gwt.dom.client.Element;
029 import com.google.gwt.event.dom.client.DomEvent;
030 import com.google.gwt.event.dom.client.HasLoadHandlers;
031 import com.google.gwt.event.dom.client.LoadEvent;
032 import com.google.gwt.event.dom.client.LoadHandler;
033 import com.google.gwt.event.shared.HandlerRegistration;
034 import com.google.gwt.user.client.ui.FlowPanel;
035
036 import java.util.Date;
037 import java.util.HashMap;
038 import java.util.List;
039 import java.util.Map;
040
041 /**
042 * Wrapper around FullCalendar
043 *
044 * @author Jeff Isenhart
045 * @see http://arshaw.com/fullcalendar/
046 */
047 public 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 JsArray<JavaScriptObject> javascriptParams = null;
087 String language = null;
088 String timezone = null;
089 String weekNumberTitle = null;
090 if (config != null) {
091 timezone = config.getTimezone();
092 weekNumberTitle = config.getWeekNumberTitle();
093 javascriptParams = config.getJavaScriptParameters();
094 if (config.getLangauge() != null) {
095 language = config.getLangauge().getCode();
096 ensureInjected(config.getLangauge());
097 }
098 }
099 addCalendar(getElement().getId(),
100 currentView.name(),
101 editable,
102 language,
103 timezone,
104 weekNumberTitle,
105 javascriptParams
106 );
107 //Let everyone know it is ok to add events and set properties on the instance
108 DomEvent.fireNativeEvent(Document.get().createLoadEvent(), this);
109 }
110
111 public void changeLangauge(final Language language) {
112 if (language != null) {
113 if (config == null) {
114 config = new CalendarConfig();
115 }
116 config.setLangauge(language);
117 destroy();
118 renderCalendar();
119 }
120 }
121
122 public void changeTimezone(final String timezone) {
123 if (timezone != null) {
124 if (config == null) {
125 config = new CalendarConfig();
126 }
127 config.setTimezone(timezone);
128 destroy();
129 renderCalendar();
130 }
131 }
132
133 private void ensureInjected(final Language language) {
134 if (!languageScripts.isEmpty()) {
135 for (final JavaScriptObject script : languageScripts.values()) {
136 try {
137 final Element ele = (Element) script;
138 ele.removeFromParent();
139 } catch (final Exception e) {
140 // TODO: handle exception
141 }
142 }
143 }
144 final JavaScriptObject scriptElement = ScriptInjector.fromString(language.getResource().getText()).setWindow(ScriptInjector.TOP_WINDOW).inject();
145 languageScripts.put(language.getCode(), scriptElement);
146 }
147
148 private native void addCalendar(String id,
149 String currentView,
150 boolean editable,
151 String lang,
152 String timezone,
153 String weekNumberTitle,
154 JsArray<JavaScriptObject> options
155 ) /*-{
156 var fullCalendarParams = {
157 defaultView: currentView,
158 selectable: true,
159 selectHelper: true,
160 editable: editable
161
162 };
163 if (lang) {
164 fullCalendarParams.lang = lang;
165 }
166 if (timezone) {
167 fullCalendarParams.timezone = timezone;
168 }
169 if (weekNumberTitle) {
170 fullCalendarParams.weekNumberTitle = weekNumberTitle;
171 }
172 if (options) {
173 for (var i = 0; i < options.length; i++) {
174 $wnd.jQuery.extend(fullCalendarParams, options[i]);
175 }
176 }
177 $wnd.jQuery('#' + id).fullCalendar(fullCalendarParams);
178 }-*/;
179
180 public void addEvent(final Event event) {
181 if (loaded && event != null) {
182 addEvent(getElement().getId(), event.toJavaScript());
183 }
184 }
185
186 public void addEvents(final List<Event> events) {
187 if (loaded && events != null && !events.isEmpty()) {
188 for (final Event evt : events) {
189 addEvent(getElement().getId(), evt.toJavaScript());
190 }
191 }
192 }
193
194 public ViewOption getCurrentView() {
195 return currentView;
196 }
197
198 private native void addEvent(String id, JavaScriptObject event) /*-{
199 $wnd.jQuery('#' + id).fullCalendar('renderEvent', event, true);
200 }-*/;
201
202 public void setView(final ViewOption view) {
203 if (view != null) {
204 currentView = view;
205 setView(getElement().getId(), view.name());
206 }
207 }
208
209 private native void setView(String id, String viewName) /*-{
210 $wnd.jQuery('#' + id).fullCalendar('changeView', viewName);
211 }-*/;
212
213 public void goToDate(final Date d) {
214 if (d != null) {
215 JsDate date = JsDate.create((double) d.getTime());
216 goToDate(getElement().getId(), date);
217 }
218 }
219
220 private native void goToDate(String id, JsDate date) /*-{
221 $wnd.jQuery('#' + id).fullCalendar('gotoDate',date);
222 }-*/;
223
224 @Override
225 public HandlerRegistration addLoadHandler(final LoadHandler handler) {
226 return super.addDomHandler(handler, LoadEvent.getType());
227 }
228
229 public JsArray<JavaScriptObject> getEvent(final String eventId) {
230 if (eventId != null) {
231 return getEvent(getElement().getId(), eventId);
232 }
233 return null;
234 }
235
236 public native JsArray<JavaScriptObject> getEvent(String id, String eventId) /*-{
237 return $wnd.jQuery('#' + id).fullCalendar('clientEvents', eventId);
238 }-*/;
239
240 public void removeEvent(final String eventId) {
241 if (eventId != null) {
242 removeEvent(getElement().getId(), eventId);
243 }
244 }
245
246 public native void removeEvent(String id, String eventId) /*-{
247 $wnd.jQuery('#' + id).fullCalendar('removeEvents', eventId);
248 }-*/;
249
250 public void updateEvent(final Event evt) {
251 if (evt != null && evt.getId() != null) {
252 updateEvent(getElement().getId(), evt.toJavaScript());
253 }
254 }
255
256 public native void updateEvent(String id, JavaScriptObject event) /*-{
257 $wnd.jQuery('#' + id).fullCalendar('updateEvent', event);
258 }-*/;
259
260 public void addEventSource(final EventSource eventSource) {
261 if (eventSource != null) {
262 addEventSource(getElement().getId(), eventSource.toJavaScript());
263 }
264 }
265
266 private native void addEventSource(String id, JavaScriptObject eventSource) /*-{
267 $wnd.jQuery('#' + id).fullCalendar('addEventSource', eventSource);
268 }-*/;
269
270 public void removeEventSource(final EventSource eventSource) {
271 if (eventSource != null) {
272 removeEventSource(getElement().getId(), eventSource.toJavaScript());
273 }
274 }
275
276 private native void removeEventSource(String id, JavaScriptObject eventSource) /*-{
277 $wnd.jQuery('#' + id).fullCalendar('removeEventSource', eventSource);
278 }-*/;
279
280 public void previous() {
281 previous(getElement().getId());
282 }
283
284 private native void previous(String id) /*-{
285 $wnd.jQuery('#' + id).fullCalendar('prev');
286 }-*/;
287
288 public void next() {
289 next(getElement().getId());
290 }
291
292 private native void next(String id) /*-{
293 $wnd.jQuery('#' + id).fullCalendar('next');
294 }-*/;
295
296 public Date getDate() {
297 final JsDate jsDate = getDate(getElement().getId());
298 final long time = (long) jsDate.getTime();
299 return new Date(time);
300 }
301
302 private native JsDate getDate(String id) /*-{
303 return $wnd.jQuery('#' + id).fullCalendar('getDate').toDate();
304 }-*/;
305
306 public void today() {
307 today(getElement().getId());
308 }
309
310 private native void today(String id) /*-{
311 $wnd.jQuery('#' + id).fullCalendar('today');
312 }-*/;
313
314 public View getView() {
315 return new View(getView(getElement().getId()));
316 }
317
318 private native JavaScriptObject getView(String id) /*-{
319 $wnd.jQuery('#' + id).fullCalendar('getView');
320 }-*/;
321
322 public void destroy() {
323 destroy(getElement().getId());
324 }
325
326 private native void destroy(String id) /*-{
327 $wnd.jQuery('#' + id).fullCalendar('destroy');
328 }-*/;
329
330 public void render() {
331 render(getElement().getId());
332 }
333
334 private native void render(String id) /*-{
335 $wnd.jQuery('#' + id).fullCalendar('render');
336 }-*/;
337
338 public void setHeight(final int height) {
339 if (height >= 0) {
340 setHeight(getElement().getId(), height);
341 }
342 }
343
344 private native void setHeight(String id, int height) /*-{
345 $wnd.jQuery('#' + id).fullCalendar('option', 'height', height);
346 }-*/;
347
348 public void setContentHeight(final int height) {
349 if (height >= 0) {
350 setContentHeight(getElement().getId(), height);
351 }
352 }
353
354 private native void setContentHeight(String id, int height) /*-{
355 $wnd.jQuery('#' + id).fullCalendar('option', 'contentHeight', height);
356 }-*/;
357
358 public void setAspectRatio(final double ratio) {
359 if (ratio > 0) {
360 setAspectRatio(getElement().getId(), ratio);
361 }
362 }
363
364 private native void setAspectRatio(String id, double ratio) /*-{
365 $wnd.jQuery('#' + id).fullCalendar('option', 'aspectRatio', ratio);
366 }-*/;
367
368 /**
369 * Useful for callback cancel/revert functions
370 *
371 * @param revertFunction
372 */
373 public native void excecuteFunction(JavaScriptObject revertFunction)/*-{
374 revertFunction();
375 }-*/;
376
377 public void unselect() {
378 unselect(getElement().getId());
379 }
380
381 private native void unselect(String id) /*-{
382 $wnd.jQuery('#' + id).fullCalendar('unselect');
383 }-*/;
384 }