Commit ca5fc992656a716429d484b6cff775efc3d1dcae

Authored by bernard
1 parent a1b82974

Made final solution to internationalization.

Changed all html entities in fullcalendar.js to numeric entities.
Added JavaScript API sample.
... ... @@ -861,10 +861,6 @@
861 861 <classname>javax.faces.el.MethodBinding</classname>
862 862 </property>
863 863
864   - <property exist="false" existintag="false" hidden="true">
865   - <name>oncomplete</name>
866   - </property>
867   -
868 864
869 865 </component>
870 866 &listeners;
... ...
... ... @@ -10,6 +10,7 @@ import javax.faces.context.FacesContext;
10 10 import java.io.ByteArrayInputStream;
11 11 import java.io.InputStream;
12 12 import java.io.UnsupportedEncodingException;
  13 +import java.util.Iterator;
13 14 import java.util.Locale;
14 15 import java.util.MissingResourceException;
15 16 import java.util.ResourceBundle;
... ... @@ -19,7 +20,6 @@ public class ScheduleMessages extends ClientScript {
19 20 public static final String BUNDLE_NAME = "org.richfaces.component.UIScheduleMessages";
20 21 private static final String MESSAGE_KEY_BASE = "org.richfaces.component.UISchedule.";
21 22 private static final Log log = LogFactory.getLog(ClientScript.class);
22   -// private Locale recentLocale;
23 23
24 24 @Override
25 25 public InputStream getResourceAsStream(ResourceContext context) {
... ... @@ -27,25 +27,30 @@ public class ScheduleMessages extends ClientScript {
27 27 ClassLoader loader = Thread.currentThread().getContextClassLoader();
28 28 FacesContext facesContext = FacesContext.getCurrentInstance();
29 29 Application application = facesContext.getApplication();
30   - Locale locale = application.getViewHandler().calculateLocale(facesContext);
31   -// recentLocale = locale;
32   - ResourceBundle applicationBundle = ResourceBundle.getBundle(application.getMessageBundle(), locale, loader);
33   - ResourceBundle stockBundle = ResourceBundle.getBundle(BUNDLE_NAME, locale, loader);
34   - String[] months = new String[]{"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"};
35   - String[] days = new String[]{"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
36 30 StringBuilder out = new StringBuilder();
37   - out.append("RichFaces.Schedule.prototype.messages=jQuery.extend(RichFaces.Schedule.prototype.messages,{").append("'").append(locale.toString()).append("':{");
38   - out.append("allDayText:'").append(escape(getMessageFromBundle(MESSAGE_KEY_BASE + "allDay", applicationBundle, stockBundle))).append("',");
39   - appendArray(out, applicationBundle, stockBundle, "monthNames", "monthNames", months);
40   - out.append(",");
41   - appendArray(out, applicationBundle, stockBundle, "monthNamesShort", "monthNamesShort", months);
42   - out.append(",");
43   - appendArray(out, applicationBundle, stockBundle, "dayNames", "dayNames", days);
44   - out.append(",");
45   - appendArray(out, applicationBundle, stockBundle, "dayNamesShort", "dayNamesShort", days);
46   - out.append(",");
47   - appendMap(out, applicationBundle, stockBundle, "buttonText", "buttonTexts", new String[]{"prev", "next", "prevYear", "nextYear", "today", "month", "day", "week"});
48   - out.append("}").append("})");
  31 + out.append("RichFaces.Schedule.prototype.messages=jQuery.extend(RichFaces.Schedule.prototype.messages,{");
  32 + Iterator<Locale> supportedLocales = application.getSupportedLocales();
  33 + while (supportedLocales.hasNext()) {
  34 + Locale locale = supportedLocales.next();
  35 + ResourceBundle applicationBundle = ResourceBundle.getBundle(application.getMessageBundle(), locale, loader);
  36 + ResourceBundle stockBundle = ResourceBundle.getBundle(BUNDLE_NAME, locale, loader);
  37 + String[] months = new String[]{"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"};
  38 + String[] days = new String[]{"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
  39 + out.append("'").append(locale.toString()).append("':{");
  40 + out.append("allDayText:'").append(escape(getMessageFromBundle(MESSAGE_KEY_BASE + "allDay", applicationBundle, stockBundle))).append("',");
  41 + appendArray(out, applicationBundle, stockBundle, "monthNames", "monthNames", months);
  42 + out.append(",");
  43 + appendArray(out, applicationBundle, stockBundle, "monthNamesShort", "monthNamesShort", months);
  44 + out.append(",");
  45 + appendArray(out, applicationBundle, stockBundle, "dayNames", "dayNames", days);
  46 + out.append(",");
  47 + appendArray(out, applicationBundle, stockBundle, "dayNamesShort", "dayNamesShort", days);
  48 + out.append(",");
  49 + appendMap(out, applicationBundle, stockBundle, "buttonText", "buttonTexts", new String[]{"prev", "next", "prevYear", "nextYear", "today", "month", "day", "week"});
  50 + out.append("},");
  51 + }
  52 + out.delete(out.length() - 1, out.length());
  53 + out.append("})");
49 54 try {
50 55 // TODO where to get encoding from? It should match properties file's encoding, but probably be converted to response encoding
51 56 return new ByteArrayInputStream(out.toString().getBytes(application.getViewHandler().calculateCharacterEncoding(facesContext)));
... ... @@ -108,21 +113,4 @@ public class ScheduleMessages extends ClientScript {
108 113 public boolean requireFacesContext() {
109 114 return true;
110 115 }
111   -//TODO if locale changes then recreate this resource
112   -// @Override
113   -// public boolean isCacheable(ResourceContext resourceContext) {
114   -// if (resourceContext instanceof FacesResourceContext) {
115   -// FacesContext facesContext = ((FacesResourceContext) resourceContext).getFacesContext();
116   -// Locale locale = facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
117   -
118   - // if (locale != null && !locale.equals(recentLocale)) {
119   -// return false;
120   -// }
121   -// }
122   -// return super.isCacheable(resourceContext);
123   -// }
124   - public boolean isCacheable(ResourceContext resourceContext) {
125   - return false;
126   - }
127   -
128 116 }
... ...
... ... @@ -719,7 +719,7 @@
719 719 var prevButton;
720 720 $.each(this.split(','), function(j, buttonName) {
721 721 if (buttonName == 'title') {
722   - tr.append("<td><h2 class='fc-header-title'>&nbsp;</h2></td>");
  722 + tr.append("<td><h2 class='fc-header-title'>&#160;</h2></td>");
723 723 if (prevButton) {
724 724 prevButton.addClass(tm + '-corner-right');
725 725 }
... ... @@ -1115,7 +1115,7 @@
1115 1115 ' fc-today ' + tm + '-state-highlight' :
1116 1116 ' fc-not-today') + "'>" +
1117 1117 (showNumbers ? "<div class='fc-day-number'>" + d.getDate() + "</div>" : '') +
1118   - "<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></td>";
  1118 + "<div class='fc-day-content'><div style='position:relative'>&#160;</div></div></td>";
1119 1119 addDays(d, 1);
1120 1120 if (nwe) {
1121 1121 skipWeekend(d);
... ... @@ -1146,7 +1146,7 @@
1146 1146 tm + '-state-default fc-new fc-day' + (i * colCnt + j) +
1147 1147 (j == dit ? ' fc-leftmost' : '') + "'>" +
1148 1148 (showNumbers ? "<div class='fc-day-number'></div>" : '') +
1149   - "<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div>" +
  1149 + "<div class='fc-day-content'><div style='position:relative'>&#160;</div></div>" +
1150 1150 "</td>";
1151 1151 addDays(d, 1);
1152 1152 if (nwe) {
... ... @@ -1833,7 +1833,7 @@
1833 1833 "<table style='width:100%'>" +
1834 1834 "<tr class='fc-first" + (options.allDaySlot ? '' : ' fc-last') + "'>" +
1835 1835 "<th class='fc-leftmost " +
1836   - tm + "-state-default'>&nbsp;</th>";
  1836 + tm + "-state-default'>&#160;</th>";
1837 1837 for (i = 0; i < colCnt; i++) {
1838 1838 s += "<th class='fc-" +
1839 1839 dayIDs[d.getDay()] + ' ' + // needs to be first
... ... @@ -1844,13 +1844,13 @@
1844 1844 skipWeekend(d, dis);
1845 1845 }
1846 1846 }
1847   - s += "<th class='" + tm + "-state-default'>&nbsp;</th></tr>";
  1847 + s += "<th class='" + tm + "-state-default'>&#160;</th></tr>";
1848 1848 if (options.allDaySlot) {
1849 1849 s += "<tr class='fc-all-day'>" +
1850 1850 "<th class='fc-axis fc-leftmost " + tm + "-state-default'>" + options.allDayText + "</th>" +
1851 1851 "<td colspan='" + colCnt + "' class='" + tm + "-state-default'>" +
1852   - "<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></td>" +
1853   - "<th class='" + tm + "-state-default'>&nbsp;</th>" +
  1852 + "<div class='fc-day-content'><div style='position:relative'>&#160;</div></div></td>" +
  1853 + "<th class='" + tm + "-state-default'>&#160;</th>" +
1854 1854 "</tr><tr class='fc-divider fc-last'><th colspan='" + (colCnt + 2) + "' class='" +
1855 1855 tm + "-state-default fc-leftmost'><div/></th></tr>";
1856 1856 }
... ... @@ -1871,9 +1871,9 @@
1871 1871 s += "<tr class='" +
1872 1872 (!i ? 'fc-first' : (!minutes ? '' : 'fc-minor')) +
1873 1873 "'><th class='fc-axis fc-leftmost " + tm + "-state-default'>" +
1874   - ((!slotNormal || !minutes) ? formatDate(d, options.axisFormat) : '&nbsp;') +
  1874 + ((!slotNormal || !minutes) ? formatDate(d, options.axisFormat) : '&#160;') +
1875 1875 "</th><td class='fc-slot" + i + ' ' +
1876   - tm + "-state-default'><div style='position:relative'>&nbsp;</div></td></tr>";
  1876 + tm + "-state-default'><div style='position:relative'>&#160;</div></td></tr>";
1877 1877 addMinutes(d, options.slotMinutes);
1878 1878 slotCnt++;
1879 1879 }
... ... @@ -1897,7 +1897,7 @@
1897 1897 tm + '-state-default ' +
1898 1898 (!i ? 'fc-leftmost ' : '') +
1899 1899 (+d == +today ? tm + '-state-highlight fc-today' : 'fc-not-today') +
1900   - "'><div class='fc-day-content'><div>&nbsp;</div></div></td>";
  1900 + "'><div class='fc-day-content'><div>&#160;</div></div></td>";
1901 1901 addDays(d, dis);
1902 1902 if (nwe) {
1903 1903 skipWeekend(d, dis);
... ... @@ -3873,11 +3873,11 @@
3873 3873
3874 3874 function htmlEscape(s) {
3875 3875 return s
3876   - .replace(/&/g, '&amp;')
3877   - .replace(/</g, '&lt;')
3878   - .replace(/>/g, '&gt;')
3879   - .replace(/'/g, '&#039;')
3880   - .replace(/"/g, '&quot;');
  3876 + .replace(/&/g, '&#38;')
  3877 + .replace(/</g, '&#60;')
  3878 + .replace(/>/g, '&#62;')
  3879 + .replace(/'/g, '&#39;')
  3880 + .replace(/"/g, '&#34;');
3881 3881 }
3882 3882
3883 3883
... ...
1 1 window.RichFaces = window.RichFaces || {};
2   -window.RichFaces.Schedule = (function() {
  2 +//TODO test ajax reRender
  3 +RichFaces.Schedule = function(id, locale, options, loadItemsEventName, itemSelectedEventName, itemMovedEventName, itemResizedEventName, viewChangedEventName, daySelectedEventName, dateRangeSelectedEventName, submitEventFunction) {
  4 +
  5 + var _this = this;
  6 + this.scheduleNode = document.getElementById(id);
  7 + this.scheduleNode.component = this;
  8 + if (!this.scheduleNode) {
  9 + throw "No element with id '" + id + "' found.";
  10 + }
  11 +
  12 + /**
  13 + * Message bundle setup.
  14 + */
  15 + options = jQuery.extend(this.messages[locale], options);
  16 +
  17 + jQuery(document).ready(function() {
  18 + _this.delegate = jQuery(_this.scheduleNode).fullCalendar(options);
  19 + window.status = _this.delegate;
  20 + });
  21 +
  22 +
  23 + // ---
  24 + /**
  25 + * Utility functions.
  26 + */
  27 + // ---
  28 + /**
  29 + * Converts javascript date into integer that can be used as param
  30 + * for new Date(long) - milliseconds since epoch.
  31 + */
3 32 var formatDateParam = function(date) {
4 33 return Math.round(date.getTime() / 1000);
5 34 };
6   -
7   - return function(id, locale, options, loadItemsEventName, itemSelectedEventName, itemMovedEventName, itemResizedEventName, viewChangedEventName, daySelectedEventName, dateRangeSelectedEventName, submitEventFunction) {
8   - this.id = id;
9   - var component;
10   - /**
11   - * submitEventFunction should have following params:
12   - * event,view,eventType,itemId,startDate,endDate,dayDelta,minuteDelta,allDay,callback
13   - */
14   - this.submitEventFunction = submitEventFunction;
15   - options = jQuery.extend(this.messages[locale], options);
16   - var elt = document.getElementById(id);
17   - if (!elt) {
18   - throw "No element with id '" + id + "' found.";
  35 + /**
  36 + * Compares two dates with with an accuracy of a day.
  37 + */
  38 + var isSameDay = function(dateA, dateB) {
  39 + if (!dateA instanceof Date || !dateB instanceof Date) {
  40 + throw "Both params must be Date objects";
19 41 }
20   - var _this = this;
21   - var isSameDay = function(a, b) {
22   - if (!a instanceof Date || !b instanceof Date) {
23   - throw "Both params must be Date objects";
24   - }
25   - return a.getYear() == b.getYear()
26   - && a.getMonth() == b.getMonth()
27   - && a.getDate() == b.getDate();
28   - };
29   - var fillCalendarFunction = function(startDate, endDate, callback) {
30   - if (options.initialItems != null) {
31   - var startDateData = options.initialItems.startDate;
32   - var endDateData = options.initialItems.endDate;
33   - var initialStartDate = new Date(startDateData.year, startDateData.month, startDateData.date);
34   - var initialEndDate = new Date(endDateData.year, endDateData.month, endDateData.date);
35   - if (isSameDay(startDate, initialStartDate) && isSameDay(endDate, initialEndDate)) {
36   - callback(options.initialItems.items);
37   - /**
38   - * After initial load this should be cleaned so items are not cached.
39   - */
40   - options.initialItems = null;
41   - return;
42   - }
43   - }
44   - if (options.onDateRangeChanged != null) {
45   - RichFaces.Schedule.eval("(function(){" + options.onDateRangeChanged + "})()", {
46   - 'startDate':startDate,
47   - 'endDate':endDate
48   - });
  42 + return dateA.getYear() == dateB.getYear()
  43 + && dateA.getMonth() == dateB.getMonth()
  44 + && dateA.getDate() == dateB.getDate();
  45 + };
  46 + // ---
  47 + /**
  48 + * DELEGATE SETUP.
  49 + * Delegate (fullCalendar) needs callback methods
  50 + * for various events such as item clicking, dragging, resizing or loading
  51 + * items.
  52 + * Functions below can be overriden by ones declared in "options" parameter.
  53 + */
  54 + // ---
  55 + /**
  56 + * Called by fullCalendar when it needs to load items - initial load,
  57 + * view type change, time navigation.
  58 + * If in ajax mode, then some initial items should be provided.
  59 + * If so then they are used for the first invocation of this function.
  60 + * This avoids creating additional ajax request on initial rendering.
  61 + * Custom users code cannot raise veto so any return statements there are
  62 + * ignored.
  63 + */
  64 + var dateRangeChange = function(startDate, endDate, callback) {
  65 + var firstInvocation = options.initialItems != null;
  66 + if (firstInvocation) {
  67 + var startDateData = options.initialItems.startDate;
  68 + var endDateData = options.initialItems.endDate;
  69 + var initialStartDate = new Date(startDateData.year, startDateData.month, startDateData.date);
  70 + var initialEndDate = new Date(endDateData.year, endDateData.month, endDateData.date);
  71 + var items = options.initialItems.items;
  72 + /**
  73 + * After initial load this should be cleaned so items are not cached.
  74 + */
  75 + options.initialItems = null;
  76 + /**
  77 + * In case the JSF component made a mistake in calculating initial
  78 + * date range we don't use initial items and just continue.
  79 + */
  80 + if (isSameDay(startDate, initialStartDate) && isSameDay(endDate, initialEndDate)) {
  81 + callback(items);
  82 + return;
49 83 }
50   - if (_this.submitEventFunction != null) {
51   - _this.submitEventFunction({} /* stub event */,
52   - null,
53   - loadItemsEventName,
54   - null,
55   - formatDateParam(startDate),
56   - formatDateParam(endDate),
57   - null, null, null,
58   - function(request, event, data) {
59   - var scheduleData = request.getJSON('_ajax:scheduleData')
60   - if (scheduleData != undefined) {
61   - callback(scheduleData);
62   - }
63   - if (options.onDateRangeChangedComplete != null) {
64   - RichFaces.Schedule.eval("(function(){" + options.onDateRangeChangedComplete + "})()", {
65   - 'startDate':startDate,
66   - 'endDate':endDate,
67   - 'request':request,
68   - 'data':data,
69   - 'items':scheduleData
70   - });
71   - }
  84 + }
  85 + if (!firstInvocation && options.onDateRangeChanged != null) {
  86 + RichFaces.Schedule.eval("(function(){" + options.onDateRangeChanged + "})()", {
  87 + 'startDate':startDate,
  88 + 'endDate':endDate
  89 + });
  90 + }
  91 + if (submitEventFunction != null) {
  92 + submitEventFunction({} /* stub event */,
  93 + null,
  94 + loadItemsEventName,
  95 + null,
  96 + formatDateParam(startDate),
  97 + formatDateParam(endDate),
  98 + null, null, null,
  99 + function(request, event, data) {
  100 + var scheduleData = request.getJSON('_ajax:scheduleData')
  101 + if (scheduleData != undefined) {
  102 + callback(scheduleData);
72 103 }
73   - );
74   - }
75   - };
76   - var itemDragStart = function(item, event, ui, view) {
77   - if (options.onItemDragStart != null) {
78   - RichFaces.Schedule.eval("(function(){" + options.onItemDragStart + "})()", {
79   - 'item':item,
80   - 'event':event,
81   - 'ui':ui,
82   - 'view':view
83   - });
84   - }
85   - };
86   - var itemDragStop = function(item, event, ui, view) {
87   - if (options.onItemDragStop != null) {
88   - RichFaces.Schedule.eval("(function(){" + options.onItemDragStop + "})()", {
89   - 'item':item,
90   - 'event':event,
91   - 'ui':ui,
92   - 'view':view
93   - });
94   - }
95   - };
96   - var itemDrop = function(item, dayDelta, minuteDelta, allDay, revertFunc, event, ui, view) {
97   - var result;
98   - if (options.onItemDrop != null) {
99   - result = RichFaces.Schedule.eval("(function(){" + options.onItemDrop + "})()", {
100   - 'item':item,
101   - 'dayDelta':dayDelta,
102   - 'minuteDelta':minuteDelta,
103   - 'allDay':allDay,
104   - 'event':event,
105   - 'ui':ui,
106   - 'view':view
107   - });
108   - if (result === false) {
109   - revertFunc();
110   - return;
111   - }
112   - }
113   - if (_this.submitEventFunction != null) {
114   - _this.submitEventFunction(event,
115   - null,
116   - itemMovedEventName,
117   - item.id,
118   - null,
119   - null,
120   - dayDelta, minuteDelta, allDay,
121   - function(request, event, data) {
122   - var decision = request.getJSON('_ajax:scheduleData');
123   - var vetoed = false;
124   - if (decision != undefined && decision !== true) {
125   - revertFunc();
126   - vetoed = true;
127   - }
128   - if (options.onItemDropComplete != null) {
129   - RichFaces.Schedule.eval("(function(){" + options.onItemDropComplete + "})()", {
130   - 'item':item,
131   - 'dayDelta':dayDelta,
132   - 'minuteDelta':minuteDelta,
133   - 'allDay':allDay,
134   - 'event':event,
135   - 'ui':ui,
136   - 'view':view,
137   - 'request':request,
138   - 'data':data,
139   - 'vetoed':vetoed
140   - });
141   - }
  104 + if (options.onDateRangeChangedComplete != null) {
  105 + RichFaces.Schedule.eval("(function(){" + options.onDateRangeChangedComplete + "})()", {
  106 + 'startDate':startDate,
  107 + 'endDate':endDate,
  108 + 'request':request,
  109 + 'data':data,
  110 + 'items':scheduleData
  111 + });
142 112 }
143   - );
144   - }
145   - return;
146   - };
147   - var itemResized = function(item, dayDelta, minuteDelta, revertFunc, event, ui, view) {
148   - var result;
149   - if (options.onItemResized != null) {
150   - result = RichFaces.Schedule.eval("(function(){" + options.onItemResized + "})()", {
151   - 'item':item,
152   - 'dayDelta':dayDelta,
153   - 'minuteDelta':minuteDelta,
154   - 'event':event,
155   - 'ui':ui,
156   - 'view':view
157   - });
158   - if (result === false) {
159   - revertFunc();
160   - return;
161   - }
  113 + }
  114 + );
  115 + }
  116 + };
  117 + /**
  118 + * Called by fullCalendar when item has started to be dragged.
  119 + */
  120 + var itemDragStart = function(item, event, ui, view) {
  121 + if (options.onItemDragStart != null) {
  122 + RichFaces.Schedule.eval("(function(){" + options.onItemDragStart + "})()", {
  123 + 'item':item,
  124 + 'event':event,
  125 + 'ui':ui,
  126 + 'view':view
  127 + });
  128 + }
  129 + };
  130 + /**
  131 + * Called by fullCalendar when item has stopped to be dragged.
  132 + * This is invoked between itemDragStart and itemDrop.
  133 + */
  134 + var itemDragStop = function(item, event, ui, view) {
  135 + if (options.onItemDragStop != null) {
  136 + RichFaces.Schedule.eval("(function(){" + options.onItemDragStop + "})()", {
  137 + 'item':item,
  138 + 'event':event,
  139 + 'ui':ui,
  140 + 'view':view
  141 + });
  142 + }
  143 + };
  144 + /**
  145 + * Called by fullCalendar when item was dropped (dragging finished).
  146 + * This is invoked after itemDragStop.
  147 + * Custom users code may raise veto by returning "false". In such case
  148 + * changes will be reverted and no event will be sent to server.
  149 + */
  150 + var itemDrop = function(item, dayDelta, minuteDelta, allDay, revertFunc, event, ui, view) {
  151 + var result;
  152 + if (options.onItemDrop != null) {
  153 + result = RichFaces.Schedule.eval("(function(){" + options.onItemDrop + "})()", {
  154 + 'item':item,
  155 + 'dayDelta':dayDelta,
  156 + 'minuteDelta':minuteDelta,
  157 + 'allDay':allDay,
  158 + 'event':event,
  159 + 'ui':ui,
  160 + 'view':view
  161 + });
  162 + if (result === false) {
  163 + revertFunc();
  164 + return;
162 165 }
163   - if (_this.submitEventFunction != null) {
164   - _this.submitEventFunction(event,
165   - null,
166   - itemResizedEventName,
167   - item.id,
168   - null,
169   - null,
170   - dayDelta, minuteDelta, null,
171   - function(request, event, data) {
172   - var decision = request.getJSON('_ajax:scheduleData');
173   - var vetoed = false;
174   - if (decision != undefined && decision !== true) {
175   - revertFunc();
176   - vetoed = true;
177   - }
178   - if (options.onItemResizedComplete != null) {
179   - RichFaces.Schedule.eval("(function(){" + options.onItemResizedComplete + "})()", {
180   - 'item':item,
181   - 'dayDelta':dayDelta,
182   - 'minuteDelta':minuteDelta,
183   - 'event':event,
184   - 'ui':ui,
185   - 'view':view,
186   - 'request':request,
187   - 'data':data,
188   - 'vetoed':vetoed
189   - });
190   - }
  166 + }
  167 + if (submitEventFunction != null) {
  168 + submitEventFunction(event,
  169 + null,
  170 + itemMovedEventName,
  171 + item.id,
  172 + null,
  173 + null,
  174 + dayDelta, minuteDelta, allDay,
  175 + function(request, event, data) {
  176 + var decision = request.getJSON('_ajax:scheduleData');
  177 + var vetoed = false;
  178 + if (decision != undefined && decision !== true) {
  179 + revertFunc();
  180 + vetoed = true;
191 181 }
192   - );
193   - }
194   - };
195   - var itemResizeStart = function(item, event, ui, view) {
196   - if (options.onItemResizeStart != null) {
197   - RichFaces.Schedule.eval("(function(){" + options.onItemResizeStart + "})()", {
198   - 'item':item,
199   - 'event':event,
200   - 'ui':ui,
201   - 'view':view
202   - });
203   - }
204   - };
205   - var itemResizeStop = function(item, event, ui, view) {
206   - if (options.onItemResizeStop != null) {
207   - RichFaces.Schedule.eval("(function(){" + options.onItemResizeStop + "})()", {
208   - 'item':item,
209   - 'event':event,
210   - 'ui':ui,
211   - 'view':view
212   - });
213   - }
214   - };
215   - var itemMouseover = function(item, event, view) {
216   - if (options.onItemMouseover != null) {
217   - RichFaces.Schedule.eval("(function(){" + options.onItemMouseover + "})()", {
218   - 'item':item,
219   - 'event':event,
220   - 'view':view
221   - });
222   - }
223   - };
224   - var itemMouseout = function(item, event, view) {
225   - if (options.onItemMouseout != null) {
226   - RichFaces.Schedule.eval("(function(){" + options.onItemMouseout + "})()", {
227   - 'item':item,
228   - 'event':event,
229   - 'view':view
230   - });
  182 + if (options.onItemDropComplete != null) {
  183 + RichFaces.Schedule.eval("(function(){" + options.onItemDropComplete + "})()", {
  184 + 'item':item,
  185 + 'dayDelta':dayDelta,
  186 + 'minuteDelta':minuteDelta,
  187 + 'allDay':allDay,
  188 + 'event':event,
  189 + 'ui':ui,
  190 + 'view':view,
  191 + 'request':request,
  192 + 'data':data,
  193 + 'vetoed':vetoed
  194 + });
  195 + }
  196 + }
  197 + );
  198 + }
  199 + return;
  200 + };
  201 + /**
  202 + * Called by fullCalendar when item has started to be resized.
  203 + */
  204 + var itemResizeStart = function(item, event, ui, view) {
  205 + if (options.onItemResizeStart != null) {
  206 + RichFaces.Schedule.eval("(function(){" + options.onItemResizeStart + "})()", {
  207 + 'item':item,
  208 + 'event':event,
  209 + 'ui':ui,
  210 + 'view':view
  211 + });
  212 + }
  213 + };
  214 + /**
  215 + * Called by fullCalendar when item has stopped to be resized.
  216 + * This is invoked between itemResizeStart and itemResized.
  217 + */
  218 + var itemResizeStop = function(item, event, ui, view) {
  219 + if (options.onItemResizeStop != null) {
  220 + RichFaces.Schedule.eval("(function(){" + options.onItemResizeStop + "})()", {
  221 + 'item':item,
  222 + 'event':event,
  223 + 'ui':ui,
  224 + 'view':view
  225 + });
  226 + }
  227 + };
  228 + /**
  229 + * Called by fullCalendar when item was resized.
  230 + * This is invoked after itemResizeStop.
  231 + * Custom users code may raise veto by returning "false". In such case
  232 + * changes will be reverted and no event will be sent to server.
  233 + */
  234 + var itemResized = function(item, dayDelta, minuteDelta, revertFunc, event, ui, view) {
  235 + var result;
  236 + if (options.onItemResized != null) {
  237 + result = RichFaces.Schedule.eval("(function(){" + options.onItemResized + "})()", {
  238 + 'item':item,
  239 + 'dayDelta':dayDelta,
  240 + 'minuteDelta':minuteDelta,
  241 + 'event':event,
  242 + 'ui':ui,
  243 + 'view':view
  244 + });
  245 + if (result === false) {
  246 + revertFunc();
  247 + return;
231 248 }
232   - };
233   - var itemClick = function(item, event, view) {
234   - var result;
235   - if (options.onItemSelected != null) {
236   - result = RichFaces.Schedule.eval("(function(){" + options.onItemSelected + "})()", {
237   - 'item':item,
238   - 'event':event,
239   - 'view':view
240   - });
  249 + }
  250 + if (submitEventFunction != null) {
  251 + submitEventFunction(event,
  252 + null,
  253 + itemResizedEventName,
  254 + item.id,
  255 + null,
  256 + null,
  257 + dayDelta, minuteDelta, null,
  258 + function(request, event, data) {
  259 + var decision = request.getJSON('_ajax:scheduleData');
  260 + var vetoed = false;
  261 + if (decision != undefined && decision !== true) {
  262 + revertFunc();
  263 + vetoed = true;
  264 + }
  265 + if (options.onItemResizedComplete != null) {
  266 + RichFaces.Schedule.eval("(function(){" + options.onItemResizedComplete + "})()", {
  267 + 'item':item,
  268 + 'dayDelta':dayDelta,
  269 + 'minuteDelta':minuteDelta,
  270 + 'event':event,
  271 + 'ui':ui,
  272 + 'view':view,
  273 + 'request':request,
  274 + 'data':data,
  275 + 'vetoed':vetoed
  276 + });
  277 + }
  278 + }
  279 + );
  280 + }
  281 + };
  282 + /**
  283 + * Called by fullCalendar when mouse moves over item.
  284 + */
  285 + var itemMouseover = function(item, event, view) {
  286 + if (options.onItemMouseover != null) {
  287 + RichFaces.Schedule.eval("(function(){" + options.onItemMouseover + "})()", {
  288 + 'item':item,
  289 + 'event':event,
  290 + 'view':view
  291 + });
  292 + }
  293 + };
  294 + /**
  295 + * Called by fullCalendar when mouse leaves item.
  296 + */
  297 + var itemMouseout = function(item, event, view) {
  298 + if (options.onItemMouseout != null) {
  299 + RichFaces.Schedule.eval("(function(){" + options.onItemMouseout + "})()", {
  300 + 'item':item,
  301 + 'event':event,
  302 + 'view':view
  303 + });
  304 + }
  305 + };
  306 + /**
  307 + * Called by fullCalendar when item is clicked.
  308 + * Custom users code may return "false". In such case
  309 + * changes no event will be sent to server and false will be returned
  310 + * to fullCalendar, which will prevent redirecting to URL associated
  311 + * with item (if such url was defined for the item).
  312 + */
  313 + var itemClick = function(item, event, view) {
  314 + var result;
  315 + if (options.onItemSelected != null) {
  316 + result = RichFaces.Schedule.eval("(function(){" + options.onItemSelected + "})()", {
  317 + 'item':item,
  318 + 'event':event,
  319 + 'view':view
  320 + });
  321 + }
  322 + if (result === false) {
  323 + return false;
  324 + }
  325 + if (submitEventFunction != null) {
  326 + submitEventFunction(event,
  327 + null,
  328 + itemSelectedEventName,
  329 + item.id,
  330 + null, null, null, null, null, function(request, event, data) {
  331 + if (options.onItemSelectedComplete != null) {
  332 + RichFaces.Schedule.eval("(function(){" + options.onItemSelectedComplete + "})()", {
  333 + 'item':item,
  334 + 'event':event,
  335 + 'view':view,
  336 + 'request':request,
  337 + 'data':data
  338 + });
  339 + }
241 340 }
  341 + );
  342 + }
  343 + return result;
  344 + };
  345 + /**
  346 + * Called by fullCalendar when day is clicked.
  347 + * Custom users code may raise veto by returning "false". In such case
  348 + * changes will be reverted and no event will be sent to server.
  349 + */
  350 + var dayClick = function(date, allDay, event, view) {
  351 + if (options.onDateSelected != null) {
  352 + var result = RichFaces.Schedule.eval("(function(){" + options.onDateSelected + "})()", {
  353 + 'date':date,
  354 + 'allDay':allDay,
  355 + 'event':event,
  356 + 'view':view
  357 + });
242 358 if (result === false) {
243   - return false;
  359 + return;
244 360 }
245   - if (_this.submitEventFunction != null) {
246   - _this.submitEventFunction(event,
247   - null,
248   - itemSelectedEventName,
249   - item.id,
250   - null, null, null, null, null, function(request, event, data) {
251   - if (options.onItemSelectedComplete != null) {
252   - RichFaces.Schedule.eval("(function(){" + options.onItemSelectedComplete + "})()", {
253   - 'item':item,
254   - 'event':event,
255   - 'view':view,
256   - 'request':request,
257   - 'data':data
258   - });
259   - }
  361 + }
  362 + if (submitEventFunction != null) {
  363 + submitEventFunction(event,
  364 + null,
  365 + daySelectedEventName,
  366 + null, formatDateParam(date), null, null, null, allDay, function(request, event, data) {
  367 + if (options.onDateSelectedComplete != null) {
  368 + RichFaces.Schedule.eval("(function(){" + options.onDateSelectedComplete + "})()", {
  369 + 'date':date,
  370 + 'allDay':allDay,
  371 + 'request':request,
  372 + 'event':event,
  373 + 'view':view,
  374 + 'data':data
  375 + });
260 376 }
261   - );
262 377 }
263   - return result;
264   - };
265   - var dayClick = function(date, allDay, event, view) {
266   - var result;
267   - if (options.onDateSelected != null) {
268   - result = RichFaces.Schedule.eval("(function(){" + options.onDateSelected + "})()", {
269   - 'date':date,
270   - 'allDay':allDay,
271   - 'event':event,
  378 + );
  379 + }
  380 + };
  381 + var selectedView;
  382 + /**
  383 + * Called by fullCalendar when view or dates change.
  384 + * We want to notify user only about view change, so we cache current view
  385 + * on private variable "selectedView" and compare it with value passed
  386 + * in parameter.
  387 + * Custom users code may not raise veto so any "return" statements are
  388 + * ignored.
  389 + */
  390 + var viewChanged = function(view) {
  391 + if (selectedView != view && selectedView != undefined) {
  392 + if (options.onViewChanged != null) {
  393 + RichFaces.Schedule.eval("(function(){" + options.onViewChanged + "})()", {
272 394 'view':view
273 395 });
274 396 }
275   - if (result === false) {
276   - return false;
277   - }
278   - if (_this.submitEventFunction != null) {
279   - _this.submitEventFunction(event,
280   - null,
281   - daySelectedEventName,
282   - null, formatDateParam(date), null, null, null, allDay, function(request, event, data) {
283   - if (options.onDateSelectedComplete != null) {
284   - RichFaces.Schedule.eval("(function(){" + options.onDateSelectedComplete + "})()", {
285   - 'date':date,
286   - 'allDay':allDay,
287   - 'request':request,
288   - 'event':event,
  397 + if (submitEventFunction != null) {
  398 + submitEventFunction({},
  399 + view.name,
  400 + viewChangedEventName,
  401 + null, null, null, null, null, null, function(request, event, data) {
  402 + if (options.onViewChangedComplete != null) {
  403 + RichFaces.Schedule.eval("(function(){" + options.onViewChangedComplete + "})()", {
289 404 'view':view,
  405 + 'request':request,
290 406 'data':data
291 407 });
292 408 }
293 409 }
294 410 );
295 411 }
296   - return result;
297   - };
298   - var selectedView;
299   - var viewChanged = function(view) {
300   - if (selectedView != view && selectedView != undefined) {
301   - if (options.onViewChanged != null) {
302   - RichFaces.Schedule.eval("(function(){" + options.onViewChanged + "})()", {
303   - 'view':view
304   - });
305   - }
306   - if (_this.submitEventFunction != null) {
307   - _this.submitEventFunction({},
308   - view.name,
309   - viewChangedEventName,
310   - null, null, null, null, null, null, function(request, event, data) {
311   - if (options.onViewChangedComplete != null) {
312   - RichFaces.Schedule.eval("(function(){" + options.onViewChangedComplete + "})()", {
  412 + }
  413 + selectedView = view;
  414 + };
  415 + /**
  416 + * Called by fullCalendar when some date range is selected (user clicks
  417 + * and drags over empty time cells).
  418 + * Custom users code may raise veto by returning "false". In such case
  419 + * changes will be reverted and no event will be sent to server.
  420 + * What is more, selection will be cleared at the end of this function.
  421 + * (This is bad, i guess, but for now i don't see other way to
  422 + * hide selection marker after selection was made, event sent to server,
  423 + * and server side listeners have created new event for that selection.
  424 + * If no unselect would happen then we selection helper would still be there
  425 + * and mess the looks)
  426 + */
  427 + var dateRangeSelected = function(startDate, endDate, allDay, view) {
  428 + if (!_this.delegate.fullCalendar('option', 'selectable')) {
  429 + return;
  430 + }
  431 + var result;
  432 + if (options.onDateRangeSelected != null) {
  433 + result = RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelected + "})()", {
  434 + 'startDate':startDate,
  435 + 'endDate':endDate,
  436 + 'allDay':allDay,
  437 + 'view':view
  438 + });
  439 + }
  440 + if (result === false) {
  441 + return;
  442 + }
  443 + if (submitEventFunction != null) {
  444 + submitEventFunction({},
  445 + null,
  446 + dateRangeSelectedEventName,
  447 + null, formatDateParam(startDate), formatDateParam(endDate), null, null, allDay,
  448 + function(request, event, data) {
  449 + _this.refetchItems();
  450 + if (options.onDateRangeSelectedComplete != null) {
  451 + RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelectedComplete + "})()", {
  452 + 'startDate':startDate,
  453 + 'endDate':endDate,
  454 + 'allDay':allDay,
313 455 'view':view,
314 456 'request':request,
315 457 'data':data
316 458 });
317 459 }
318 460 }
319   - );
320   - }
321   - }
322   - selectedView = view;
323   - };
324   - var onDateRangeSelected = function(startDate, endDate, allDay, view) {
325   - if (!component.fullCalendar('option', 'selectable')) {
326   - return false;
327   - }
328   - var result;
329   - if (options.onDateRangeSelected != null) {
330   - result = RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelected + "})()", {
331   - 'startDate':startDate,
332   - 'endDate':endDate,
333   - 'allDay':allDay,
334   - 'view':view
335   - });
336   - }
337   - if (result === false) {
338   - /**
339   - * Unselect must be in all three places below in order to
340   - * avoid situation where, while event is being sent via ajax
341   - * to server, client side selection disapeares.
342   - * Current implementation shortens delay between selection
343   - * disapearing and potentialy created event appearing.
344   - */
345   - component.fullCalendar('unselect');
346   - return false;
347   - }
348   - if (_this.submitEventFunction != null) {
349   - _this.submitEventFunction({},
350   - null,
351   - dateRangeSelectedEventName,
352   - null, formatDateParam(startDate), formatDateParam(endDate), null, null, allDay,
353   - function(request, event, data) {
354   - component.fullCalendar('refetchEvents');
355   - component.fullCalendar('unselect');
356   - if (options.onDateRangeSelected != null) {
357   - RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelectedComplete + "})()", {
358   - 'startDate':startDate,
359   - 'endDate':endDate,
360   - 'allDay':allDay,
361   - 'view':view,
362   - 'request':request,
363   - 'data':data
364   - });
365   - }
366   - }
367   - );
368   - } else {
369   - component.fullCalendar('unselect');
370   - }
371   - return result;
372   - };
373   - options = jQuery.extend({
374   - events: fillCalendarFunction,
375   - eventDragStart: itemDragStart,
376   - eventDragStop: itemDragStop,
377   - eventDrop: itemDrop,
378   - eventResizeStart: itemResizeStart,
379   - eventResizeStop: itemResizeStop,
380   - eventResize: itemResized,
381   - eventClick: itemClick,
382   - eventMouseover: itemMouseover,
383   - eventMouseout: itemMouseout,
384   - viewDisplay: viewChanged,
385   - dayClick: dayClick,
386   - select: onDateRangeSelected
387   - }, options);
388   - jQuery(document).ready(function() {
389   - component = jQuery(elt).fullCalendar(options);
390   - elt.component = _this;
391   - _this.component = component;
392   - });
  461 + );
  462 + }
393 463 };
  464 + options = jQuery.extend({
  465 + events: dateRangeChange,
  466 + eventDragStart: itemDragStart,
  467 + eventDragStop: itemDragStop,
  468 + eventDrop: itemDrop,
  469 + eventResizeStart: itemResizeStart,
  470 + eventResizeStop: itemResizeStop,
  471 + eventResize: itemResized,
  472 + eventClick: itemClick,
  473 + eventMouseover: itemMouseover,
  474 + eventMouseout: itemMouseout,
  475 + viewDisplay: viewChanged,
  476 + dayClick: dayClick,
  477 + select: dateRangeSelected
  478 + }, options);
394 479
395   -}());
396   -window.RichFaces.Schedule.prototype.refetchItems = function() {
397   - this.component.fullCalendar('refetchEvents');
398 480 };
399   -window.RichFaces.Schedule.prototype.messages = {};
400   -window.RichFaces.Schedule.eval = function(template, object) {
  481 +RichFaces.Schedule.prototype.messages = {};
  482 +/**
  483 + * This function evaluates code in template with object in ScopeChain.
  484 + * This is usefull if you need to evaluate code that uses member names
  485 + * that colide with external names that the code refers to.
  486 + * There is almost exact method in utils.js called Richfaces.eval,
  487 + * but it swallows exception thrown during evaluation, which makes debugging
  488 + * hard.
  489 + */
  490 +RichFaces.Schedule.eval = function(template, object) {
401 491 var value = '';
402 492 with (object) {
403 493 value = eval(template);
404 494 }
405 495 return value;
406   -};
\ No newline at end of file
  496 +}
  497 +RichFaces.Schedule.prototype.select = function(startDate, endDate, allDay) {
  498 + this.delegate.fullCalendar('select', startDate, endDate, allDay);
  499 +}
  500 +RichFaces.Schedule.prototype.unselect = function() {
  501 + this.delegate.fullCalendar('unselect');
  502 +}
  503 +RichFaces.Schedule.prototype.render = function() {
  504 + this.delegate.fullCalendar('render');
  505 +}
  506 +RichFaces.Schedule.prototype.destroy = function() {
  507 + this.delegate.fullCalendar('destroy');
  508 +}
  509 +RichFaces.Schedule.prototype.getView = function() {
  510 + return this.delegate.fullCalendar('getView');
  511 +}
  512 +RichFaces.Schedule.prototype.changeView = function(viewName) {
  513 + this.delegate.fullCalendar('changeView', viewName);
  514 +}
  515 +RichFaces.Schedule.prototype.prev = function() {
  516 + this.delegate.fullCalendar('prev');
  517 +}
  518 +RichFaces.Schedule.prototype.next = function() {
  519 + this.delegate.fullCalendar('next');
  520 +}
  521 +RichFaces.Schedule.prototype.prevYear = function() {
  522 + this.delegate.fullCalendar('prevYear');
  523 +}
  524 +RichFaces.Schedule.prototype.nextYear = function() {
  525 + this.delegate.fullCalendar('nextYear');
  526 +}
  527 +RichFaces.Schedule.prototype.today = function() {
  528 + this.delegate.fullCalendar('today');
  529 +}
  530 +RichFaces.Schedule.prototype.gotoDate = function(year, month, date) {
  531 + this.delegate.fullCalendar('gotoDate', year, month, date);
  532 +}
  533 +RichFaces.Schedule.prototype.incrementDate = function(years, months, days) {
  534 + this.delegate.fullCalendar('incrementDate', years, months, days);
  535 +}
  536 +RichFaces.Schedule.prototype.updateItem = function(item) {
  537 + this.delegate.fullCalendar('updateItem', item);
  538 +}
  539 +RichFaces.Schedule.prototype.getItems = function(idOrFilter) {
  540 + return this.delegate.fullCalendar('clientEvents', idOrFilter);
  541 +}
  542 +RichFaces.Schedule.prototype.removeItems = function(idOrFilter) {
  543 + this.delegate.fullCalendar('removeEvents', idOrFilter);
  544 +}
  545 +RichFaces.Schedule.prototype.refetchItems = function() {
  546 + this.delegate.fullCalendar('refetchEvents');
  547 +}
  548 +RichFaces.Schedule.prototype.addItemsSource = function(source) {
  549 + this.delegate.fullCalendar('addEventSource', source);
  550 +}
  551 +RichFaces.Schedule.prototype.removeItemsSource = function(source) {
  552 + this.delegate.fullCalendar('removeEventSource', source);
  553 +}
  554 +RichFaces.Schedule.prototype.addItem = function(event, stick) {
  555 + this.delegate.fullCalendar('renderEvent', event, stick);
  556 +}
  557 +RichFaces.Schedule.prototype.reRender = function() {
  558 + this.delegate.fullCalendar('rerenderEvents');
  559 +}
\ No newline at end of file
... ...
... ... @@ -16,7 +16,6 @@
16 16 <h:scripts>org.ajax4jsf.javascript.AjaxScript,
17 17 /org/ajax4jsf/javascript/scripts/form.js,
18 18 /org/richfaces/renderkit/html/scripts/form.js,
19   - /org/richfaces/renderkit/html/scripts/utils.js,
20 19 /org/richfaces/renderkit/html/scripts/jquery/jquery.js,
21 20 /org/richfaces/renderkit/html/scripts/ui.core.js,
22 21 /org/richfaces/renderkit/html/scripts/ui.draggable.js,
... ...
Please register or login to post a comment