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    }