Commit 29f4630682371d7a32eff3d6a32c5106f5332584

Authored by bernard
1 parent f6195010

Restored accidentaly removed richfaces.schedule.js

  1 +window.RichFaces = window.RichFaces || {};
  2 +//TODO test ajax reRender
  3 +RichFaces.Schedule = function(id, locale, options, dateRangeChangeEventName, itemSelectEventName, itemMoveEventName, itemResizeEventName, viewChangeEventName, dateSelectEventName, dateRangeSelectEventName, 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 + });
  20 +
  21 +
  22 + // ---
  23 + /**
  24 + * Utility functions.
  25 + */
  26 + // ---
  27 + /**
  28 + * Converts javascript date into integer that can be used as param
  29 + * for new Date(long) - milliseconds since epoch.
  30 + */
  31 + var formatDateParam = function(date) {
  32 + return Math.round(date.getTime() / 1000);
  33 + };
  34 + /**
  35 + * Compares two dates with with an accuracy of a day.
  36 + */
  37 + var isSameDay = function(dateA, dateB) {
  38 + if (!dateA instanceof Date || !dateB instanceof Date) {
  39 + throw "Both params must be Date objects";
  40 + }
  41 + return dateA.getYear() == dateB.getYear()
  42 + && dateA.getMonth() == dateB.getMonth()
  43 + && dateA.getDate() == dateB.getDate();
  44 + };
  45 + // ---
  46 + /**
  47 + * DELEGATE SETUP.
  48 + * Delegate (fullCalendar) needs callback methods
  49 + * for various events such as item clicking, dragging, resizing or loading
  50 + * items.
  51 + * Functions below can be overriden by ones declared in "options" parameter.
  52 + */
  53 + // ---
  54 + /**
  55 + * Called by fullCalendar when it needs to load items - initial load,
  56 + * view type change, time navigation.
  57 + * If in ajax mode, then some initial items should be provided.
  58 + * If so then they are used for the first invocation of this function.
  59 + * This avoids creating additional ajax request on initial rendering.
  60 + * Custom users code cannot raise veto so any return statements there are
  61 + * ignored.
  62 + */
  63 + var dateRangeChange = function(startDate, endDate, callback) {
  64 + var firstInvocation = options.initialItems != null;
  65 + if (firstInvocation) {
  66 + var startDateData = options.initialItems.startDate;
  67 + var endDateData = options.initialItems.endDate;
  68 + var initialStartDate = new Date(startDateData.year, startDateData.month, startDateData.date);
  69 + var initialEndDate = new Date(endDateData.year, endDateData.month, endDateData.date);
  70 + var items = options.initialItems.items;
  71 + /**
  72 + * After initial load this should be cleaned so items are not cached.
  73 + */
  74 + options.initialItems = null;
  75 + /**
  76 + * In case the JSF component made a mistake in calculating initial
  77 + * date range we don't use initial items and just continue.
  78 + */
  79 + if (isSameDay(startDate, initialStartDate) && isSameDay(endDate, initialEndDate)) {
  80 + callback(items);
  81 + return;
  82 + }
  83 + }
  84 + if (submitEventFunction != null) {
  85 + submitEventFunction({} /* stub event */,
  86 + null,
  87 + dateRangeChangeEventName,
  88 + null,
  89 + formatDateParam(startDate),
  90 + formatDateParam(endDate),
  91 + null, null, null,
  92 + function(request, event, data) {
  93 + var scheduleData = request.getJSON('_ajax:scheduleData')
  94 + if (scheduleData != undefined) {
  95 + callback(scheduleData);
  96 + }
  97 + if (options.ondaterangechange != null) {
  98 + RichFaces.Schedule.eval("(function(){" + options.ondaterangechange + "})()", {
  99 + 'startDate':startDate,
  100 + 'endDate':endDate,
  101 + 'data':data,
  102 + 'items':scheduleData
  103 + });
  104 + }
  105 + }
  106 + );
  107 + } else if (!firstInvocation && options.ondaterangechange != null) {
  108 + RichFaces.Schedule.eval("(function(){" + options.ondaterangechange + "})()", {
  109 + 'startDate':startDate,
  110 + 'endDate':endDate
  111 + });
  112 + }
  113 + };
  114 + /**
  115 + * Called by fullCalendar when item has started to be dragged.
  116 + */
  117 + var itemDragStart = function(item, event, ui, view) {
  118 + if (options.onitemdragstart != null) {
  119 + RichFaces.Schedule.eval("(function(){" + options.onitemdragstart + "})()", {
  120 + 'item':item,
  121 + 'event':event,
  122 + 'ui':ui,
  123 + 'view':view
  124 + });
  125 + }
  126 + };
  127 + /**
  128 + * Called by fullCalendar when item has stopped to be dragged.
  129 + * This is invoked between itemDragStart and itemDrop.
  130 + */
  131 + var itemDragStop = function(item, event, ui, view) {
  132 + if (options.onitemdragstop != null) {
  133 + RichFaces.Schedule.eval("(function(){" + options.onitemdragstop + "})()", {
  134 + 'item':item,
  135 + 'event':event,
  136 + 'ui':ui,
  137 + 'view':view
  138 + });
  139 + }
  140 + };
  141 + /**
  142 + * Called by fullCalendar when item was dropped (dragging finished).
  143 + * This is invoked after itemDragStop.
  144 + * Custom users code may raise veto by returning "false". In such case
  145 + * changes will be reverted and no event will be sent to server.
  146 + */
  147 + var itemDrop = function(item, dayDelta, minuteDelta, allDay, revertFunc, event, ui, view) {
  148 + var result;
  149 + if (options.onbeforeitemdrop != null) {
  150 + result = RichFaces.Schedule.eval("(function(){" + options.onbeforeitemdrop + "})()", {
  151 + 'item':item,
  152 + 'dayDelta':dayDelta,
  153 + 'minuteDelta':minuteDelta,
  154 + 'allDay':allDay,
  155 + 'event':event,
  156 + 'ui':ui,
  157 + 'view':view
  158 + });
  159 + if (result === false) {
  160 + revertFunc();
  161 + return;
  162 + }
  163 + }
  164 + if (submitEventFunction != null) {
  165 + submitEventFunction(event,
  166 + null,
  167 + itemMoveEventName,
  168 + item.id,
  169 + null,
  170 + null,
  171 + dayDelta, minuteDelta, allDay,
  172 + function(request, event, data) {
  173 + var decision = request.getJSON('_ajax:scheduleData');
  174 + var vetoed = false;
  175 + if (decision != undefined && decision !== true) {
  176 + revertFunc();
  177 + vetoed = true;
  178 + }
  179 + if (options.onitemdrop != null) {
  180 + RichFaces.Schedule.eval("(function(){" + options.onitemdrop + "})()", {
  181 + 'item':item,
  182 + 'dayDelta':dayDelta,
  183 + 'minuteDelta':minuteDelta,
  184 + 'allDay':allDay,
  185 + 'event':event,
  186 + 'ui':ui,
  187 + 'view':view,
  188 + 'data':data,
  189 + 'vetoed':vetoed
  190 + });
  191 + }
  192 + }
  193 + );
  194 + }
  195 + };
  196 + /**
  197 + * Called by fullCalendar when item has started to be resized.
  198 + */
  199 + var itemResizeStart = function(item, event, ui, view) {
  200 + if (options.onitemresizestart != null) {
  201 + RichFaces.Schedule.eval("(function(){" + options.onitemresizestart + "})()", {
  202 + 'item':item,
  203 + 'event':event,
  204 + 'ui':ui,
  205 + 'view':view
  206 + });
  207 + }
  208 + };
  209 + /**
  210 + * Called by fullCalendar when item has stopped to be resized.
  211 + * This is invoked between itemResizeStart and itemResized.
  212 + */
  213 + var itemResizeStop = function(item, event, ui, view) {
  214 + if (options.onitemresizestop != null) {
  215 + RichFaces.Schedule.eval("(function(){" + options.onitemresizestop + "})()", {
  216 + 'item':item,
  217 + 'event':event,
  218 + 'ui':ui,
  219 + 'view':view
  220 + });
  221 + }
  222 + };
  223 + /**
  224 + * Called by fullCalendar when item was resized.
  225 + * This is invoked after itemResizeStop.
  226 + * Custom users code may raise veto by returning "false". In such case
  227 + * changes will be reverted and no event will be sent to server.
  228 + */
  229 + var itemResized = function(item, dayDelta, minuteDelta, revertFunc, event, ui, view) {
  230 + var result;
  231 + if (options.onbeforeitemresize != null) {
  232 + result = RichFaces.Schedule.eval("(function(){" + options.onbeforeitemresize + "})()", {
  233 + 'item':item,
  234 + 'dayDelta':dayDelta,
  235 + 'minuteDelta':minuteDelta,
  236 + 'event':event,
  237 + 'ui':ui,
  238 + 'view':view
  239 + });
  240 + if (result === false) {
  241 + revertFunc();
  242 + return;
  243 + }
  244 + }
  245 + if (submitEventFunction != null) {
  246 + submitEventFunction(event,
  247 + null,
  248 + itemResizeEventName,
  249 + item.id,
  250 + null,
  251 + null,
  252 + dayDelta, minuteDelta, null,
  253 + function(request, event, data) {
  254 + var decision = request.getJSON('_ajax:scheduleData');
  255 + var vetoed = false;
  256 + if (decision != undefined && decision !== true) {
  257 + revertFunc();
  258 + vetoed = true;
  259 + }
  260 + if (options.onitemresize != null) {
  261 + RichFaces.Schedule.eval("(function(){" + options.onitemresize + "})()", {
  262 + 'item':item,
  263 + 'dayDelta':dayDelta,
  264 + 'minuteDelta':minuteDelta,
  265 + 'event':event,
  266 + 'ui':ui,
  267 + 'view':view,
  268 + 'data':data,
  269 + 'vetoed':vetoed
  270 + });
  271 + }
  272 + }
  273 + );
  274 + }
  275 + };
  276 + /**
  277 + * Called by fullCalendar when mouse moves over item.
  278 + */
  279 + var itemMouseover = function(item, event, view) {
  280 + if (options.onitemmouseover != null) {
  281 + RichFaces.Schedule.eval("(function(){" + options.onitemmouseover + "})()", {
  282 + 'item':item,
  283 + 'event':event,
  284 + 'view':view
  285 + });
  286 + }
  287 + };
  288 + /**
  289 + * Called by fullCalendar when mouse leaves item.
  290 + */
  291 + var itemMouseout = function(item, event, view) {
  292 + if (options.onitemmouseout != null) {
  293 + RichFaces.Schedule.eval("(function(){" + options.onitemmouseout + "})()", {
  294 + 'item':item,
  295 + 'event':event,
  296 + 'view':view
  297 + });
  298 + }
  299 + };
  300 + /**
  301 + * Called by fullCalendar when item is clicked.
  302 + * Custom users code may return "false". In such case
  303 + * changes no event will be sent to server and false will be returned
  304 + * to fullCalendar, which will prevent redirecting to URL associated
  305 + * with item (if such url was defined for the item).
  306 + */
  307 + var itemClick = function(item, event, view) {
  308 + var result;
  309 + if (options.onbeforeitemselect != null) {
  310 + result = RichFaces.Schedule.eval("(function(){" + options.onbeforeitemselect + "})()", {
  311 + 'item':item,
  312 + 'event':event,
  313 + 'view':view
  314 + });
  315 + }
  316 + if (result === false) {
  317 + return false;
  318 + }
  319 + if (submitEventFunction != null) {
  320 + submitEventFunction(event,
  321 + null,
  322 + itemSelectEventName,
  323 + item.id,
  324 + null, null, null, null, null, function(request, event, data) {
  325 + if (options.onitemselect != null) {
  326 + RichFaces.Schedule.eval("(function(){" + options.onitemselect + "})()", {
  327 + 'item':item,
  328 + 'event':event,
  329 + 'view':view,
  330 + 'data':data
  331 + });
  332 + }
  333 + }
  334 + );
  335 + }
  336 + return result;
  337 + };
  338 + /**
  339 + * Called by fullCalendar when day is clicked.
  340 + * Custom users code may raise veto by returning "false". In such case
  341 + * changes will be reverted and no event will be sent to server.
  342 + */
  343 + var dayClick = function(date, allDay, event, view) {
  344 + if (options.onbeforedateselect != null) {
  345 + var result = RichFaces.Schedule.eval("(function(){" + options.onbeforedateselect + "})()", {
  346 + 'date':date,
  347 + 'allDay':allDay,
  348 + 'event':event,
  349 + 'view':view
  350 + });
  351 + if (result === false) {
  352 + return;
  353 + }
  354 + }
  355 + if (submitEventFunction != null) {
  356 + submitEventFunction(event,
  357 + null,
  358 + dateSelectEventName,
  359 + null, formatDateParam(date), null, null, null, allDay, function(request, event, data) {
  360 + if (options.ondateselect != null) {
  361 + RichFaces.Schedule.eval("(function(){" + options.ondateselect + "})()", {
  362 + 'date':date,
  363 + 'allDay':allDay,
  364 + 'event':event,
  365 + 'view':view,
  366 + 'data':data
  367 + });
  368 + }
  369 + }
  370 + );
  371 + }
  372 + };
  373 + var selectedView;
  374 + /**
  375 + * Called by fullCalendar when view or dates change.
  376 + * We want to notify user only about view change, so we cache current view
  377 + * on private variable "selectedView" and compare it with value passed
  378 + * in parameter.
  379 + * Custom users code may not raise veto so any "return" statements are
  380 + * ignored.
  381 + */
  382 + var viewChanged = function(view) {
  383 + if (selectedView != view && selectedView != undefined) {
  384 + if (submitEventFunction != null) {
  385 + submitEventFunction({},
  386 + view.name,
  387 + viewChangeEventName,
  388 + null, null, null, null, null, null, function(request, event, data) {
  389 + if (options.onviewchange != null) {
  390 + RichFaces.Schedule.eval("(function(){" + options.onviewchange + "})()", {
  391 + 'view':view,
  392 + 'data':data
  393 + });
  394 + }
  395 + }
  396 + );
  397 + } else if (options.onviewchange != null) {
  398 + RichFaces.Schedule.eval("(function(){" + options.onviewchange + "})()", {
  399 + 'view':view
  400 + });
  401 + }
  402 + }
  403 + selectedView = view;
  404 + };
  405 + /**
  406 + * Called by fullCalendar when some date range is selected (user clicks
  407 + * and drags over empty time cells).
  408 + * Custom users code may raise veto by returning "false". In such case
  409 + * changes will be reverted and no event will be sent to server.
  410 + * What is more, selection will be cleared at the end of this function.
  411 + * (This is bad, i guess, but for now i don't see other way to
  412 + * hide selection marker after selection was made, event sent to server,
  413 + * and server side listeners have created new event for that selection.
  414 + * If no unselect would happen then we selection helper would still be there
  415 + * and mess the looks)
  416 + */
  417 + var dateRangeSelected = function(startDate, endDate, allDay, view) {
  418 + if (!_this.delegate.fullCalendar('option', 'selectable')) {
  419 + return;
  420 + }
  421 + var result;
  422 + if (options.onbeforedaterangeselect != null) {
  423 + result = RichFaces.Schedule.eval("(function(){" + options.onbeforedaterangeselect + "})()", {
  424 + 'startDate':startDate,
  425 + 'endDate':endDate,
  426 + 'allDay':allDay,
  427 + 'view':view
  428 + });
  429 + }
  430 + if (result === false) {
  431 + return;
  432 + }
  433 + if (submitEventFunction != null) {
  434 + submitEventFunction({},
  435 + null,
  436 + dateRangeSelectEventName,
  437 + null, formatDateParam(startDate), formatDateParam(endDate), null, null, allDay,
  438 + function(request, event, data) {
  439 + _this.refetchItems();
  440 + if (options.ondaterangeselect != null) {
  441 + RichFaces.Schedule.eval("(function(){" + options.ondaterangeselect + "})()", {
  442 + 'startDate':startDate,
  443 + 'endDate':endDate,
  444 + 'allDay':allDay,
  445 + 'view':view,
  446 + 'data':data
  447 + });
  448 + }
  449 + }
  450 + );
  451 + }
  452 + };
  453 + options = jQuery.extend({
  454 + events: dateRangeChange,
  455 + eventDragStart: itemDragStart,
  456 + eventDragStop: itemDragStop,
  457 + eventDrop: itemDrop,
  458 + eventResizeStart: itemResizeStart,
  459 + eventResizeStop: itemResizeStop,
  460 + eventResize: itemResized,
  461 + eventClick: itemClick,
  462 + eventMouseover: itemMouseover,
  463 + eventMouseout: itemMouseout,
  464 + viewDisplay: viewChanged,
  465 + dayClick: dayClick,
  466 + select: dateRangeSelected
  467 + }, options);
  468 +
  469 +};
  470 +RichFaces.Schedule.prototype.messages = {};
  471 +/**
  472 + * This function evaluates code in template with object in ScopeChain.
  473 + * This is usefull if you need to evaluate code that uses member names
  474 + * that colide with external names that the code refers to.
  475 + * There is almost exact method in utils.js called Richfaces.eval,
  476 + * but it swallows exception thrown during evaluation, which makes debugging
  477 + * hard.
  478 + */
  479 +RichFaces.Schedule.eval = function(template, object) {
  480 + var value;
  481 + with (object) {
  482 + value = eval(template);
  483 + }
  484 + return value;
  485 +};
  486 +RichFaces.Schedule.prototype.select = function(startDate, endDate, allDay) {
  487 + this.delegate.fullCalendar('select', startDate, endDate, allDay);
  488 +};
  489 +RichFaces.Schedule.prototype.unselect = function() {
  490 + this.delegate.fullCalendar('unselect');
  491 +};
  492 +RichFaces.Schedule.prototype.render = function() {
  493 + this.delegate.fullCalendar('render');
  494 +};
  495 +RichFaces.Schedule.prototype.destroy = function() {
  496 + this.delegate.fullCalendar('destroy');
  497 +};
  498 +RichFaces.Schedule.prototype.getView = function() {
  499 + return this.delegate.fullCalendar('getView');
  500 +};
  501 +RichFaces.Schedule.prototype.changeView = function(viewName) {
  502 + this.delegate.fullCalendar('changeView', viewName);
  503 +};
  504 +RichFaces.Schedule.prototype.prev = function() {
  505 + this.delegate.fullCalendar('prev');
  506 +};
  507 +RichFaces.Schedule.prototype.next = function() {
  508 + this.delegate.fullCalendar('next');
  509 +};
  510 +RichFaces.Schedule.prototype.prevYear = function() {
  511 + this.delegate.fullCalendar('prevYear');
  512 +};
  513 +RichFaces.Schedule.prototype.nextYear = function() {
  514 + this.delegate.fullCalendar('nextYear');
  515 +};
  516 +RichFaces.Schedule.prototype.today = function() {
  517 + this.delegate.fullCalendar('today');
  518 +};
  519 +RichFaces.Schedule.prototype.gotoDate = function(year, month, date) {
  520 + this.delegate.fullCalendar('gotoDate', year, month, date);
  521 +};
  522 +RichFaces.Schedule.prototype.incrementDate = function(years, months, days) {
  523 + this.delegate.fullCalendar('incrementDate', years, months, days);
  524 +};
  525 +RichFaces.Schedule.prototype.updateItem = function(item) {
  526 + this.delegate.fullCalendar('updateItem', item);
  527 +};
  528 +RichFaces.Schedule.prototype.getItems = function(idOrFilter) {
  529 + return this.delegate.fullCalendar('clientEvents', idOrFilter);
  530 +};
  531 +RichFaces.Schedule.prototype.removeItems = function(idOrFilter) {
  532 + this.delegate.fullCalendar('removeEvents', idOrFilter);
  533 +};
  534 +RichFaces.Schedule.prototype.refetchItems = function() {
  535 + this.delegate.fullCalendar('refetchEvents');
  536 +};
  537 +RichFaces.Schedule.prototype.addItemsSource = function(source) {
  538 + this.delegate.fullCalendar('addEventSource', source);
  539 +};
  540 +RichFaces.Schedule.prototype.removeItemsSource = function(source) {
  541 + this.delegate.fullCalendar('removeEventSource', source);
  542 +};
  543 +RichFaces.Schedule.prototype.addItem = function(event, stick) {
  544 + this.delegate.fullCalendar('renderEvent', event, stick);
  545 +};
  546 +RichFaces.Schedule.prototype.reRender = function() {
  547 + this.delegate.fullCalendar('rerenderEvents');
  548 +};
Please register or login to post a comment