Merge remote-tracking branch 'upstream/master'
@@ -1,4 +1,23 @@
|
||||
|
||||
version 1.6.3 (8/10/13)
|
||||
- viewRender callback (PR 15)
|
||||
- viewDestroy callback (PR 15)
|
||||
- eventDestroy callback (PR 111)
|
||||
- handleWindowResize option (PR 54)
|
||||
- eventStartEditable/startEditable options (PR 49)
|
||||
- eventDurationEditable/durationEditable options (PR 49)
|
||||
- specify function for $.ajax `data` parameter for JSON event sources (PR 59)
|
||||
- fixed bug with agenda event dropping in wrong column (PR 55)
|
||||
- easier event element z-index customization (PR 58)
|
||||
- classNames on past/future days (PR 88)
|
||||
- allow null/undefined event titles (PR 84)
|
||||
- small optimize for agenda event rendering (PR 56)
|
||||
- deprecated:
|
||||
- viewDisplay
|
||||
- disableDragging
|
||||
- disableResizing
|
||||
- bundled with latest jQuery (1.10.2) and jQuery UI (1.10.3)
|
||||
|
||||
version 1.6.2 (7/18/13)
|
||||
- hiddenDays option (issue 686)
|
||||
- bugfix: when eventRender returns false, incorrect stacking of events (issue 762)
|
||||
|
||||
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 312 B |
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
|
Before Width: | Height: | Size: 249 B After Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
@@ -1,6 +1,6 @@
|
||||
/*! jQuery UI - v1.10.2 - 2013-03-16
|
||||
/*! jQuery UI - v1.10.3 - 2013-08-10
|
||||
* http://jqueryui.com
|
||||
* Includes: jquery.ui.core.css, jquery.ui.resizable.css
|
||||
* Includes: jquery.ui.core.css, jquery.ui.tabs.css
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande%2CLucida%20Sans%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=deedf7&bgTextureHeader=highlight_soft&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=highlight_hard&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=glass&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=3baae3&bgTextureActive=glass&bgImgOpacityActive=50&borderColorActive=2694e8&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=ffef8f&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=flat&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=eeeeee&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=90&opacityOverlay=80&bgColorShadow=000000&bgTextureShadow=highlight_hard&bgImgOpacityShadow=70&opacityShadow=30&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
|
||||
* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
|
||||
|
||||
@@ -86,73 +86,47 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-resizable {
|
||||
.ui-tabs {
|
||||
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||
padding: .2em;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav {
|
||||
margin: 0;
|
||||
padding: .2em .2em 0;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 1px .2em 0 0;
|
||||
border-bottom-width: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ui-resizable-handle {
|
||||
position: absolute;
|
||||
font-size: 0.1px;
|
||||
.ui-tabs .ui-tabs-nav li a {
|
||||
float: left;
|
||||
padding: .5em 1em;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
||||
margin-bottom: -1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active a,
|
||||
.ui-tabs .ui-tabs-nav li.ui-state-disabled a,
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
|
||||
cursor: text;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
|
||||
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-tabs .ui-tabs-panel {
|
||||
display: block;
|
||||
}
|
||||
.ui-resizable-disabled .ui-resizable-handle,
|
||||
.ui-resizable-autohide .ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
.ui-resizable-n {
|
||||
cursor: n-resize;
|
||||
height: 7px;
|
||||
width: 100%;
|
||||
top: -5px;
|
||||
left: 0;
|
||||
}
|
||||
.ui-resizable-s {
|
||||
cursor: s-resize;
|
||||
height: 7px;
|
||||
width: 100%;
|
||||
bottom: -5px;
|
||||
left: 0;
|
||||
}
|
||||
.ui-resizable-e {
|
||||
cursor: e-resize;
|
||||
width: 7px;
|
||||
right: -5px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-resizable-w {
|
||||
cursor: w-resize;
|
||||
width: 7px;
|
||||
left: -5px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-resizable-se {
|
||||
cursor: se-resize;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
}
|
||||
.ui-resizable-sw {
|
||||
cursor: sw-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
left: -5px;
|
||||
bottom: -5px;
|
||||
}
|
||||
.ui-resizable-nw {
|
||||
cursor: nw-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
left: -5px;
|
||||
top: -5px;
|
||||
}
|
||||
.ui-resizable-ne {
|
||||
cursor: ne-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
right: -5px;
|
||||
top: -5px;
|
||||
border-width: 0;
|
||||
padding: 1em 1.4em;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Component containers
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "fullcalendar",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"dependencies": {
|
||||
"jquery": "~1.9.1"
|
||||
"jquery": "~1.10.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"jquery-ui": "~1.10.2"
|
||||
"jquery-ui": "~1.10.3"
|
||||
},
|
||||
|
||||
"title": "FullCalendar",
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
"modules": {
|
||||
"jquery": {
|
||||
"scripts": [
|
||||
"lib/jquery-1.9.1.min.js"
|
||||
"lib/jquery-1.10.2.min.js"
|
||||
]
|
||||
},
|
||||
"jquery-ui": {
|
||||
"scripts": [
|
||||
"lib/jquery-ui-1.10.2.custom.min.js"
|
||||
"lib/jquery-ui-1.10.3.custom.min.js"
|
||||
]
|
||||
},
|
||||
"fullcalendar": {
|
||||
|
||||
@@ -44,10 +44,8 @@ function Calendar(element, options, eventSources) {
|
||||
var content;
|
||||
var tm; // for making theme classes
|
||||
var currentView;
|
||||
var viewInstances = {};
|
||||
var elementOuterWidth;
|
||||
var suggestedViewHeight;
|
||||
var absoluteViewElement;
|
||||
var resizeUID = 0;
|
||||
var ignoreWindowResize = 0;
|
||||
var date = new Date();
|
||||
@@ -66,11 +64,11 @@ function Calendar(element, options, eventSources) {
|
||||
function render(inc) {
|
||||
if (!content) {
|
||||
initialRender();
|
||||
}else{
|
||||
}
|
||||
else if (elementVisible()) {
|
||||
// mainly for the public API
|
||||
calcSize();
|
||||
markSizesDirty();
|
||||
markEventsDirty();
|
||||
renderView(inc);
|
||||
_renderView(inc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,15 +85,22 @@ function Calendar(element, options, eventSources) {
|
||||
if (options.theme) {
|
||||
element.addClass('ui-widget');
|
||||
}
|
||||
|
||||
content = $("<div class='fc-content' style='position:relative'/>")
|
||||
.prependTo(element);
|
||||
|
||||
header = new Header(t, options);
|
||||
headerElement = header.render();
|
||||
if (headerElement) {
|
||||
element.prepend(headerElement);
|
||||
}
|
||||
|
||||
changeView(options.defaultView);
|
||||
$(window).resize(windowResize);
|
||||
|
||||
if (options.handleWindowResize) {
|
||||
$(window).resize(windowResize);
|
||||
}
|
||||
|
||||
// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
|
||||
if (!bodyVisible()) {
|
||||
lateRender();
|
||||
@@ -115,21 +120,27 @@ function Calendar(element, options, eventSources) {
|
||||
|
||||
|
||||
function destroy() {
|
||||
|
||||
if (currentView) {
|
||||
trigger('viewDestroy', currentView, currentView, currentView.element);
|
||||
currentView.triggerEventDestroy();
|
||||
}
|
||||
|
||||
$(window).unbind('resize', windowResize);
|
||||
|
||||
header.destroy();
|
||||
content.remove();
|
||||
element.removeClass('fc fc-rtl ui-widget');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function elementVisible() {
|
||||
return _element.offsetWidth !== 0;
|
||||
return element.is(':visible');
|
||||
}
|
||||
|
||||
|
||||
function bodyVisible() {
|
||||
return $('body')[0].offsetWidth !== 0;
|
||||
return $('body').is(':visible');
|
||||
}
|
||||
|
||||
|
||||
@@ -137,133 +148,97 @@ function Calendar(element, options, eventSources) {
|
||||
/* View Rendering
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// TODO: improve view switching (still weird transition in IE, and FF has whiteout problem)
|
||||
|
||||
|
||||
function changeView(newViewName) {
|
||||
if (!currentView || newViewName != currentView.name) {
|
||||
ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached
|
||||
|
||||
unselect();
|
||||
|
||||
var oldView = currentView;
|
||||
var newViewElement;
|
||||
|
||||
if (oldView) {
|
||||
(oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera)
|
||||
setMinHeight(content, content.height());
|
||||
oldView.element.hide();
|
||||
}else{
|
||||
setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
|
||||
}
|
||||
content.css('overflow', 'hidden');
|
||||
|
||||
currentView = viewInstances[newViewName];
|
||||
if (currentView) {
|
||||
currentView.element.show();
|
||||
}else{
|
||||
currentView = viewInstances[newViewName] = new fcViews[newViewName](
|
||||
newViewElement = absoluteViewElement =
|
||||
$("<div class='fc-view fc-view-" + newViewName + "' style='position:absolute'/>")
|
||||
.appendTo(content),
|
||||
t // the calendar object
|
||||
);
|
||||
}
|
||||
|
||||
if (oldView) {
|
||||
header.deactivateButton(oldView.name);
|
||||
}
|
||||
header.activateButton(newViewName);
|
||||
|
||||
renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null
|
||||
|
||||
content.css('overflow', '');
|
||||
if (oldView) {
|
||||
setMinHeight(content, 1);
|
||||
}
|
||||
|
||||
if (!newViewElement) {
|
||||
(currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)
|
||||
}
|
||||
|
||||
ignoreWindowResize--;
|
||||
_changeView(newViewName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function _changeView(newViewName) {
|
||||
ignoreWindowResize++;
|
||||
|
||||
if (currentView) {
|
||||
trigger('viewDestroy', currentView, currentView, currentView.element);
|
||||
unselect();
|
||||
currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event
|
||||
freezeContentHeight();
|
||||
currentView.element.remove();
|
||||
header.deactivateButton(currentView.name);
|
||||
}
|
||||
|
||||
header.activateButton(newViewName);
|
||||
|
||||
currentView = new fcViews[newViewName](
|
||||
$("<div class='fc-view fc-view-" + newViewName + "' style='position:relative'/>")
|
||||
.appendTo(content),
|
||||
t // the calendar object
|
||||
);
|
||||
|
||||
renderView();
|
||||
unfreezeContentHeight();
|
||||
|
||||
ignoreWindowResize--;
|
||||
}
|
||||
|
||||
|
||||
function renderView(inc) {
|
||||
if (elementVisible()) {
|
||||
ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached
|
||||
|
||||
unselect();
|
||||
|
||||
if (suggestedViewHeight === undefined) {
|
||||
calcSize();
|
||||
if (
|
||||
!currentView.start || // never rendered before
|
||||
inc || date < currentView.start || date >= currentView.end // or new date range
|
||||
) {
|
||||
if (elementVisible()) {
|
||||
_renderView(inc);
|
||||
}
|
||||
|
||||
var forceEventRender = false;
|
||||
if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {
|
||||
// view must render an entire new date range (and refetch/render events)
|
||||
currentView.render(date, inc || 0); // responsible for clearing events
|
||||
setSize(true);
|
||||
forceEventRender = true;
|
||||
}
|
||||
else if (currentView.sizeDirty) {
|
||||
// view must resize (and rerender events)
|
||||
currentView.clearEvents();
|
||||
setSize();
|
||||
forceEventRender = true;
|
||||
}
|
||||
else if (currentView.eventsDirty) {
|
||||
currentView.clearEvents();
|
||||
forceEventRender = true;
|
||||
}
|
||||
currentView.sizeDirty = false;
|
||||
currentView.eventsDirty = false;
|
||||
updateEvents(forceEventRender);
|
||||
|
||||
elementOuterWidth = element.outerWidth();
|
||||
|
||||
header.updateTitle(currentView.title);
|
||||
var today = new Date();
|
||||
if (today >= currentView.start && today < currentView.end) {
|
||||
header.disableButton('today');
|
||||
}else{
|
||||
header.enableButton('today');
|
||||
}
|
||||
|
||||
ignoreWindowResize--;
|
||||
currentView.trigger('viewDisplay', _element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _renderView(inc) { // assumes elementVisible
|
||||
ignoreWindowResize++;
|
||||
|
||||
if (currentView.start) { // already been rendered?
|
||||
trigger('viewDestroy', currentView, currentView, currentView.element);
|
||||
unselect();
|
||||
clearEvents();
|
||||
}
|
||||
|
||||
freezeContentHeight();
|
||||
currentView.render(date, inc || 0); // the view's render method ONLY renders the skeleton, nothing else
|
||||
setSize();
|
||||
unfreezeContentHeight();
|
||||
(currentView.afterRender || noop)();
|
||||
|
||||
updateTitle();
|
||||
updateTodayButton();
|
||||
|
||||
trigger('viewRender', currentView, currentView, currentView.element);
|
||||
currentView.trigger('viewDisplay', _element); // deprecated
|
||||
|
||||
ignoreWindowResize--;
|
||||
|
||||
getAndRenderEvents();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Resizing
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function updateSize() {
|
||||
markSizesDirty();
|
||||
if (elementVisible()) {
|
||||
unselect();
|
||||
clearEvents();
|
||||
calcSize();
|
||||
setSize();
|
||||
unselect();
|
||||
currentView.clearEvents();
|
||||
currentView.renderEvents(events);
|
||||
currentView.sizeDirty = false;
|
||||
renderEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function markSizesDirty() {
|
||||
$.each(viewInstances, function(i, inst) {
|
||||
inst.sizeDirty = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function calcSize() {
|
||||
function calcSize() { // assumes elementVisible
|
||||
if (options.contentHeight) {
|
||||
suggestedViewHeight = options.contentHeight;
|
||||
}
|
||||
@@ -276,15 +251,20 @@ function Calendar(element, options, eventSources) {
|
||||
}
|
||||
|
||||
|
||||
function setSize(dateChanged) { // todo: dateChanged?
|
||||
ignoreWindowResize++;
|
||||
currentView.setHeight(suggestedViewHeight, dateChanged);
|
||||
if (absoluteViewElement) {
|
||||
absoluteViewElement.css('position', 'relative');
|
||||
absoluteViewElement = null;
|
||||
function setSize() { // assumes elementVisible
|
||||
|
||||
if (suggestedViewHeight === undefined) {
|
||||
calcSize(); // for first time
|
||||
// NOTE: we don't want to recalculate on every renderView because
|
||||
// it could result in oscillating heights due to scrollbars.
|
||||
}
|
||||
currentView.setWidth(content.width(), dateChanged);
|
||||
|
||||
ignoreWindowResize++;
|
||||
currentView.setHeight(suggestedViewHeight);
|
||||
currentView.setWidth(content.width());
|
||||
ignoreWindowResize--;
|
||||
|
||||
elementOuterWidth = element.outerWidth();
|
||||
}
|
||||
|
||||
|
||||
@@ -313,52 +293,85 @@ function Calendar(element, options, eventSources) {
|
||||
|
||||
/* Event Fetching/Rendering
|
||||
-----------------------------------------------------------------------------*/
|
||||
// TODO: going forward, most of this stuff should be directly handled by the view
|
||||
|
||||
|
||||
function refetchEvents() { // can be called as an API method
|
||||
clearEvents();
|
||||
fetchAndRenderEvents();
|
||||
}
|
||||
|
||||
|
||||
function rerenderEvents(modifiedEventID) { // can be called as an API method
|
||||
clearEvents();
|
||||
renderEvents(modifiedEventID);
|
||||
}
|
||||
|
||||
|
||||
function renderEvents(modifiedEventID) { // TODO: remove modifiedEventID hack
|
||||
if (elementVisible()) {
|
||||
currentView.setEventData(events); // for View.js, TODO: unify with renderEvents
|
||||
currentView.renderEvents(events, modifiedEventID); // actually render the DOM elements
|
||||
currentView.trigger('eventAfterAllRender');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clearEvents() {
|
||||
currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event
|
||||
currentView.clearEvents(); // actually remove the DOM elements
|
||||
currentView.clearEventData(); // for View.js, TODO: unify with clearEvents
|
||||
}
|
||||
|
||||
|
||||
// fetches events if necessary, rerenders events if necessary (or if forced)
|
||||
function updateEvents(forceRender) {
|
||||
|
||||
function getAndRenderEvents() {
|
||||
if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {
|
||||
refetchEvents();
|
||||
fetchAndRenderEvents();
|
||||
}
|
||||
else if (forceRender) {
|
||||
rerenderEvents();
|
||||
else {
|
||||
renderEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function refetchEvents() {
|
||||
fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents
|
||||
|
||||
|
||||
function fetchAndRenderEvents() {
|
||||
fetchEvents(currentView.visStart, currentView.visEnd);
|
||||
// ... will call reportEvents
|
||||
// ... which will call renderEvents
|
||||
}
|
||||
|
||||
|
||||
|
||||
// called when event data arrives
|
||||
function reportEvents(_events) {
|
||||
events = _events;
|
||||
rerenderEvents();
|
||||
renderEvents();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// called when a single event's data has been changed
|
||||
function reportEventChange(eventID) {
|
||||
rerenderEvents(eventID);
|
||||
}
|
||||
|
||||
|
||||
// attempts to rerenderEvents
|
||||
function rerenderEvents(modifiedEventID) {
|
||||
markEventsDirty();
|
||||
if (elementVisible()) {
|
||||
currentView.clearEvents();
|
||||
currentView.renderEvents(events, modifiedEventID);
|
||||
currentView.eventsDirty = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Header Updating
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function updateTitle() {
|
||||
header.updateTitle(currentView.title);
|
||||
}
|
||||
|
||||
|
||||
function markEventsDirty() {
|
||||
$.each(viewInstances, function(i, inst) {
|
||||
inst.eventsDirty = true;
|
||||
});
|
||||
|
||||
|
||||
function updateTodayButton() {
|
||||
var today = new Date();
|
||||
if (today >= currentView.start && today < currentView.end) {
|
||||
header.disableButton('today');
|
||||
}
|
||||
else {
|
||||
header.enableButton('today');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -439,6 +452,29 @@ function Calendar(element, options, eventSources) {
|
||||
function getDate() {
|
||||
return cloneDate(date);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Height "Freezing"
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function freezeContentHeight() {
|
||||
content.css({
|
||||
width: '100%',
|
||||
height: content.height(),
|
||||
overflow: 'hidden'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function unfreezeContentHeight() {
|
||||
content.css({
|
||||
width: '',
|
||||
height: '',
|
||||
overflow: ''
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -136,7 +136,22 @@ function EventManager(options, _sources) {
|
||||
var success = source.success;
|
||||
var error = source.error;
|
||||
var complete = source.complete;
|
||||
var data = $.extend({}, source.data || {});
|
||||
|
||||
// retrieve any outbound GET/POST $.ajax data from the options
|
||||
var customData;
|
||||
if ($.isFunction(source.data)) {
|
||||
// supplied as a function that returns a key/value object
|
||||
customData = source.data();
|
||||
}
|
||||
else {
|
||||
// supplied as a straight key/value object
|
||||
customData = source.data;
|
||||
}
|
||||
|
||||
// use a copy of the custom data so we can modify the parameters
|
||||
// and not affect the passed-in object.
|
||||
var data = $.extend({}, customData || {});
|
||||
|
||||
var startParam = firstDefined(source.startParam, options.startParam);
|
||||
var endParam = firstDefined(source.endParam, options.endParam);
|
||||
if (startParam) {
|
||||
@@ -145,6 +160,7 @@ function EventManager(options, _sources) {
|
||||
if (endParam) {
|
||||
data[endParam] = Math.round(+rangeEnd / 1000);
|
||||
}
|
||||
|
||||
pushLoading();
|
||||
$.ajax($.extend({}, ajaxDefaults, source, {
|
||||
data: data,
|
||||
|
||||
@@ -16,8 +16,6 @@ function AgendaEventRenderer() {
|
||||
var isEventDraggable = t.isEventDraggable;
|
||||
var isEventResizable = t.isEventResizable;
|
||||
var eventEnd = t.eventEnd;
|
||||
var reportEvents = t.reportEvents;
|
||||
var reportEventClear = t.reportEventClear;
|
||||
var eventElementHandlers = t.eventElementHandlers;
|
||||
var setHeight = t.setHeight;
|
||||
var getDaySegmentContainer = t.getDaySegmentContainer;
|
||||
@@ -26,6 +24,7 @@ function AgendaEventRenderer() {
|
||||
var getMaxMinute = t.getMaxMinute;
|
||||
var getMinMinute = t.getMinMinute;
|
||||
var timePosition = t.timePosition;
|
||||
var getIsCellAllDay = t.getIsCellAllDay;
|
||||
var colContentLeft = t.colContentLeft;
|
||||
var colContentRight = t.colContentRight;
|
||||
var cellToDate = t.cellToDate;
|
||||
@@ -58,7 +57,6 @@ function AgendaEventRenderer() {
|
||||
|
||||
|
||||
function renderEvents(events, modifiedEventId) {
|
||||
reportEvents(events);
|
||||
var i, len=events.length,
|
||||
dayEvents=[],
|
||||
slotEvents=[];
|
||||
@@ -76,13 +74,10 @@ function AgendaEventRenderer() {
|
||||
}
|
||||
|
||||
renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
|
||||
|
||||
trigger('eventAfterAllRender');
|
||||
}
|
||||
|
||||
|
||||
function clearEvents() {
|
||||
reportEventClear();
|
||||
getDaySegmentContainer().empty();
|
||||
getSlotSegmentContainer().empty();
|
||||
}
|
||||
@@ -332,14 +327,20 @@ function AgendaEventRenderer() {
|
||||
}
|
||||
html +=
|
||||
" class='" + classes.join(' ') + "'" +
|
||||
" style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" +
|
||||
" style=" +
|
||||
"'" +
|
||||
"position:absolute;" +
|
||||
"top:" + seg.top + "px;" +
|
||||
"left:" + seg.left + "px;" +
|
||||
skinCss +
|
||||
"'" +
|
||||
">" +
|
||||
"<div class='fc-event-inner'>" +
|
||||
"<div class='fc-event-time'>" +
|
||||
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
||||
"</div>" +
|
||||
"<div class='fc-event-title'>" +
|
||||
htmlEscape(event.title) +
|
||||
htmlEscape(event.title || '') +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='fc-event-bg'></div>";
|
||||
@@ -386,7 +387,6 @@ function AgendaEventRenderer() {
|
||||
var snapMinutes = getSnapMinutes();
|
||||
var minMinute = getMinMinute();
|
||||
eventElement.draggable({
|
||||
zIndex: 9,
|
||||
opacity: opt('dragOpacity', 'month'), // use whatever the month view was using
|
||||
revertDuration: opt('dragRevertDuration'),
|
||||
start: function(ev, ui) {
|
||||
@@ -472,80 +472,147 @@ function AgendaEventRenderer() {
|
||||
// when event starts out IN TIMESLOTS
|
||||
|
||||
function draggableSlotEvent(event, eventElement, timeElement) {
|
||||
var origPosition;
|
||||
var allDay = false;
|
||||
var dayDelta;
|
||||
var minuteDelta;
|
||||
var prevMinuteDelta;
|
||||
var hoverListener = getHoverListener();
|
||||
var coordinateGrid = t.getCoordinateGrid();
|
||||
var colCnt = getColCnt();
|
||||
var colWidth = getColWidth();
|
||||
var snapHeight = getSnapHeight();
|
||||
var snapMinutes = getSnapMinutes();
|
||||
|
||||
// states
|
||||
var origPosition; // original position of the element, not the mouse
|
||||
var origCell;
|
||||
var isInBounds, prevIsInBounds;
|
||||
var isAllDay, prevIsAllDay;
|
||||
var colDelta, prevColDelta;
|
||||
var dayDelta; // derived from colDelta
|
||||
var minuteDelta, prevMinuteDelta;
|
||||
|
||||
eventElement.draggable({
|
||||
zIndex: 9,
|
||||
scroll: false,
|
||||
grid: [colWidth, snapHeight],
|
||||
grid: [ colWidth, snapHeight ],
|
||||
axis: colCnt==1 ? 'y' : false,
|
||||
opacity: opt('dragOpacity'),
|
||||
revertDuration: opt('dragRevertDuration'),
|
||||
start: function(ev, ui) {
|
||||
|
||||
trigger('eventDragStart', eventElement, event, ev, ui);
|
||||
hideEvents(event, eventElement);
|
||||
|
||||
coordinateGrid.build();
|
||||
|
||||
// initialize states
|
||||
origPosition = eventElement.position();
|
||||
origCell = coordinateGrid.cell(ev.pageX, ev.pageY);
|
||||
isInBounds = prevIsInBounds = true;
|
||||
isAllDay = prevIsAllDay = getIsCellAllDay(origCell);
|
||||
colDelta = prevColDelta = 0;
|
||||
dayDelta = 0;
|
||||
minuteDelta = prevMinuteDelta = 0;
|
||||
hoverListener.start(function(cell, origCell) {
|
||||
eventElement.draggable('option', 'revert', !cell);
|
||||
clearOverlays();
|
||||
if (cell) {
|
||||
var origDate = cellToDate(0, origCell.col);
|
||||
var date = cellToDate(0, cell.col);
|
||||
dayDelta = dayDiff(date, origDate);
|
||||
if (opt('allDaySlot') && !cell.row) {
|
||||
// over full days
|
||||
if (!allDay) {
|
||||
// convert to temporary all-day event
|
||||
allDay = true;
|
||||
timeElement.hide();
|
||||
eventElement.draggable('option', 'grid', null);
|
||||
}
|
||||
renderDayOverlay(
|
||||
addDays(cloneDate(event.start), dayDelta),
|
||||
addDays(exclEndDay(event), dayDelta)
|
||||
);
|
||||
}else{
|
||||
// on slots
|
||||
resetElement();
|
||||
}
|
||||
}
|
||||
}, ev, 'drag');
|
||||
|
||||
},
|
||||
drag: function(ev, ui) {
|
||||
minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes;
|
||||
if (minuteDelta != prevMinuteDelta) {
|
||||
if (!allDay) {
|
||||
updateTimeText(minuteDelta);
|
||||
|
||||
// NOTE: this `cell` value is only useful for determining in-bounds and all-day.
|
||||
// Bad for anything else due to the discrepancy between the mouse position and the
|
||||
// element position while snapping. (problem revealed in PR #55)
|
||||
//
|
||||
// PS- the problem exists for draggableDayEvent() when dragging an all-day event to a slot event.
|
||||
// We should overhaul the dragging system and stop relying on jQuery UI.
|
||||
var cell = coordinateGrid.cell(ev.pageX, ev.pageY);
|
||||
|
||||
// update states
|
||||
isInBounds = !!cell;
|
||||
if (isInBounds) {
|
||||
isAllDay = getIsCellAllDay(cell);
|
||||
|
||||
// calculate column delta
|
||||
colDelta = Math.round((ui.position.left - origPosition.left) / colWidth);
|
||||
if (colDelta != prevColDelta) {
|
||||
// calculate the day delta based off of the original clicked column and the column delta
|
||||
var origDate = cellToDate(0, origCell.col);
|
||||
var col = origCell.col + colDelta;
|
||||
col = Math.max(0, col);
|
||||
col = Math.min(colCnt-1, col);
|
||||
var date = cellToDate(0, col);
|
||||
dayDelta = dayDiff(date, origDate);
|
||||
}
|
||||
|
||||
// calculate minute delta (only if over slots)
|
||||
if (!isAllDay) {
|
||||
minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes;
|
||||
}
|
||||
}
|
||||
|
||||
// any state changes?
|
||||
if (
|
||||
isInBounds != prevIsInBounds ||
|
||||
isAllDay != prevIsAllDay ||
|
||||
colDelta != prevColDelta ||
|
||||
minuteDelta != prevMinuteDelta
|
||||
) {
|
||||
|
||||
updateUI();
|
||||
|
||||
// update previous states for next time
|
||||
prevIsInBounds = isInBounds;
|
||||
prevIsAllDay = isAllDay;
|
||||
prevColDelta = colDelta;
|
||||
prevMinuteDelta = minuteDelta;
|
||||
}
|
||||
|
||||
// if out-of-bounds, revert when done, and vice versa.
|
||||
eventElement.draggable('option', 'revert', !isInBounds);
|
||||
|
||||
},
|
||||
stop: function(ev, ui) {
|
||||
var cell = hoverListener.stop();
|
||||
|
||||
clearOverlays();
|
||||
trigger('eventDragStop', eventElement, event, ev, ui);
|
||||
if (cell && (dayDelta || minuteDelta || allDay)) {
|
||||
// changed!
|
||||
eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
|
||||
}else{
|
||||
// either no change or out-of-bounds (draggable has already reverted)
|
||||
resetElement();
|
||||
|
||||
if (isInBounds && (isAllDay || dayDelta || minuteDelta)) { // changed!
|
||||
eventDrop(this, event, dayDelta, isAllDay ? 0 : minuteDelta, isAllDay, ev, ui);
|
||||
}
|
||||
else { // either no change or out-of-bounds (draggable has already reverted)
|
||||
|
||||
// reset states for next time, and for updateUI()
|
||||
isInBounds = true;
|
||||
isAllDay = false;
|
||||
colDelta = 0;
|
||||
dayDelta = 0;
|
||||
minuteDelta = 0;
|
||||
|
||||
updateUI();
|
||||
eventElement.css('filter', ''); // clear IE opacity side-effects
|
||||
eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
|
||||
updateTimeText(0);
|
||||
|
||||
// sometimes fast drags make event revert to wrong position, so reset.
|
||||
// also, if we dragged the element out of the area because of snapping,
|
||||
// but the *mouse* is still in bounds, we need to reset the position.
|
||||
eventElement.css(origPosition);
|
||||
|
||||
showEvents(event, eventElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function updateUI() {
|
||||
clearOverlays();
|
||||
if (isInBounds) {
|
||||
if (isAllDay) {
|
||||
timeElement.hide();
|
||||
eventElement.draggable('option', 'grid', null); // disable grid snapping
|
||||
renderDayOverlay(
|
||||
addDays(cloneDate(event.start), dayDelta),
|
||||
addDays(exclEndDay(event), dayDelta)
|
||||
);
|
||||
}
|
||||
else {
|
||||
updateTimeText(minuteDelta);
|
||||
timeElement.css('display', ''); // show() was causing display=inline
|
||||
eventElement.draggable('option', 'grid', [colWidth, snapHeight]); // re-enable grid snapping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimeText(minuteDelta) {
|
||||
var newStart = addMinutes(cloneDate(event.start), minuteDelta);
|
||||
var newEnd;
|
||||
@@ -554,14 +621,7 @@ function AgendaEventRenderer() {
|
||||
}
|
||||
timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
|
||||
}
|
||||
function resetElement() {
|
||||
// convert back to original slot-event
|
||||
if (allDay) {
|
||||
timeElement.css('display', ''); // show() was causing display=inline
|
||||
eventElement.draggable('option', 'grid', [colWidth, snapHeight]);
|
||||
allDay = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -582,7 +642,6 @@ function AgendaEventRenderer() {
|
||||
start: function(ev, ui) {
|
||||
snapDelta = prevSnapDelta = 0;
|
||||
hideEvents(event, eventElement);
|
||||
eventElement.css('z-index', 9);
|
||||
trigger('eventResizeStart', this, event, ev, ui);
|
||||
},
|
||||
resize: function(ev, ui) {
|
||||
@@ -605,7 +664,6 @@ function AgendaEventRenderer() {
|
||||
if (snapDelta) {
|
||||
eventResize(this, event, 0, snapMinutes*snapDelta, ev, ui);
|
||||
}else{
|
||||
eventElement.css('z-index', 8);
|
||||
showEvents(event, eventElement);
|
||||
// BUG: if event was really short, need to put title back in span
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ function AgendaView(element, calendar, viewName) {
|
||||
t.renderAgenda = renderAgenda;
|
||||
t.setWidth = setWidth;
|
||||
t.setHeight = setHeight;
|
||||
t.beforeHide = beforeHide;
|
||||
t.afterShow = afterShow;
|
||||
t.afterRender = afterRender;
|
||||
t.defaultEventEnd = defaultEventEnd;
|
||||
t.timePosition = timePosition;
|
||||
t.getIsCellAllDay = getIsCellAllDay;
|
||||
t.allDayRow = getAllDayRow;
|
||||
t.getCoordinateGrid = function() { return coordinateGrid }; // specifically for AgendaEventRenderer
|
||||
t.getHoverListener = function() { return hoverListener };
|
||||
t.colLeft = colLeft;
|
||||
t.colRight = colRight;
|
||||
@@ -66,7 +66,6 @@ function AgendaView(element, calendar, viewName) {
|
||||
AgendaEventRenderer.call(t);
|
||||
var opt = t.opt;
|
||||
var trigger = t.trigger;
|
||||
var clearEvents = t.clearEvents;
|
||||
var renderOverlay = t.renderOverlay;
|
||||
var clearOverlays = t.clearOverlays;
|
||||
var reportSelection = t.reportSelection;
|
||||
@@ -119,7 +118,6 @@ function AgendaView(element, calendar, viewName) {
|
||||
var colPositions;
|
||||
var colContentPositions;
|
||||
var slotTopCache = {};
|
||||
var savedScrollTop;
|
||||
|
||||
var tm;
|
||||
var rtl;
|
||||
@@ -141,11 +139,12 @@ function AgendaView(element, calendar, viewName) {
|
||||
function renderAgenda(c) {
|
||||
colCnt = c;
|
||||
updateOptions();
|
||||
if (!dayTable) {
|
||||
|
||||
if (!dayTable) { // first time rendering?
|
||||
buildSkeleton(); // builds day table, slot area, events containers
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
buildDayTable(); // rebuilds day table
|
||||
clearEvents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +195,7 @@ function AgendaView(element, calendar, viewName) {
|
||||
if (opt('allDaySlot')) {
|
||||
|
||||
daySegmentContainer =
|
||||
$("<div style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
$("<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
.appendTo(slotLayer);
|
||||
|
||||
s =
|
||||
@@ -235,7 +234,7 @@ function AgendaView(element, calendar, viewName) {
|
||||
.appendTo(slotScroller);
|
||||
|
||||
slotSegmentContainer =
|
||||
$("<div style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
$("<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
.appendTo(slotContainer);
|
||||
|
||||
s =
|
||||
@@ -388,6 +387,12 @@ function AgendaView(element, calendar, viewName) {
|
||||
'fc-today'
|
||||
);
|
||||
}
|
||||
else if (date < today) {
|
||||
classNames.push('fc-past');
|
||||
}
|
||||
else {
|
||||
classNames.push('fc-future');
|
||||
}
|
||||
|
||||
cellHTML =
|
||||
"<td class='" + classNames.join(' ') + "'>" +
|
||||
@@ -419,7 +424,7 @@ function AgendaView(element, calendar, viewName) {
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function setHeight(height, dateChanged) {
|
||||
function setHeight(height) {
|
||||
if (height === undefined) {
|
||||
height = viewHeight;
|
||||
}
|
||||
@@ -444,10 +449,6 @@ function AgendaView(element, calendar, viewName) {
|
||||
|
||||
snapRatio = opt('slotMinutes') / snapMinutes;
|
||||
snapHeight = slotHeight / snapRatio;
|
||||
|
||||
if (dateChanged) {
|
||||
resetScroll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -514,15 +515,10 @@ function AgendaView(element, calendar, viewName) {
|
||||
scroll();
|
||||
setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
|
||||
}
|
||||
|
||||
|
||||
function beforeHide() {
|
||||
savedScrollTop = slotScroller.scrollTop();
|
||||
}
|
||||
|
||||
|
||||
function afterShow() {
|
||||
slotScroller.scrollTop(savedScrollTop);
|
||||
|
||||
|
||||
function afterRender() { // after the view has been freshly rendered and sized
|
||||
resetScroll();
|
||||
}
|
||||
|
||||
|
||||
@@ -715,7 +711,11 @@ function AgendaView(element, calendar, viewName) {
|
||||
slotI = Math.floor(minutes / slotMinutes),
|
||||
slotTop = slotTopCache[slotI];
|
||||
if (slotTop === undefined) {
|
||||
slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization???
|
||||
slotTop = slotTopCache[slotI] =
|
||||
slotTable.find('tr').eq(slotI).find('td div')[0].offsetTop;
|
||||
// .eq() is faster than ":eq()" selector
|
||||
// [0].offsetTop is faster than .position().top (do we really need this optimization?)
|
||||
// a better optimization would be to cache all these divs
|
||||
}
|
||||
return Math.max(0, Math.round(
|
||||
slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
|
||||
@@ -779,7 +779,6 @@ function AgendaView(element, calendar, viewName) {
|
||||
var helperRes = helperOption(startDate, endDate);
|
||||
if (helperRes) {
|
||||
rect.position = 'absolute';
|
||||
rect.zIndex = 8;
|
||||
selectionHelper = $(helperRes)
|
||||
.css(rect)
|
||||
.appendTo(slotContainer);
|
||||
|
||||
@@ -13,14 +13,11 @@ function BasicEventRenderer() {
|
||||
|
||||
|
||||
function renderEvents(events, modifiedEventId) {
|
||||
t.reportEvents(events);
|
||||
t.renderDayEvents(events, modifiedEventId);
|
||||
t.trigger('eventAfterAllRender');
|
||||
}
|
||||
|
||||
|
||||
function clearEvents() {
|
||||
t.reportEventClear();
|
||||
t.getDaySegmentContainer().empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ function BasicView(element, calendar, viewName) {
|
||||
BasicEventRenderer.call(t);
|
||||
var opt = t.opt;
|
||||
var trigger = t.trigger;
|
||||
var clearEvents = t.clearEvents;
|
||||
var renderOverlay = t.renderOverlay;
|
||||
var clearOverlays = t.clearOverlays;
|
||||
var daySelectionMousedown = t.daySelectionMousedown;
|
||||
@@ -95,12 +94,11 @@ function BasicView(element, calendar, viewName) {
|
||||
colCnt = _colCnt;
|
||||
showNumbers = _showNumbers;
|
||||
updateOptions();
|
||||
var firstTime = !body;
|
||||
if (firstTime) {
|
||||
|
||||
if (!body) {
|
||||
buildEventContainer();
|
||||
}else{
|
||||
clearEvents();
|
||||
}
|
||||
|
||||
buildTable();
|
||||
}
|
||||
|
||||
@@ -123,7 +121,7 @@ function BasicView(element, calendar, viewName) {
|
||||
|
||||
function buildEventContainer() {
|
||||
daySegmentContainer =
|
||||
$("<div style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
$("<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>")
|
||||
.appendTo(element);
|
||||
}
|
||||
|
||||
@@ -131,7 +129,6 @@ function BasicView(element, calendar, viewName) {
|
||||
function buildTable() {
|
||||
var html = buildTableHTML();
|
||||
|
||||
lockHeight(); // the unlock happens later, in setHeight()...
|
||||
if (table) {
|
||||
table.remove();
|
||||
}
|
||||
@@ -266,6 +263,12 @@ function BasicView(element, calendar, viewName) {
|
||||
tm + '-state-highlight'
|
||||
);
|
||||
}
|
||||
else if (date < today) {
|
||||
classNames.push('fc-past');
|
||||
}
|
||||
else {
|
||||
classNames.push('fc-future');
|
||||
}
|
||||
|
||||
html +=
|
||||
"<td" +
|
||||
@@ -312,14 +315,13 @@ function BasicView(element, calendar, viewName) {
|
||||
bodyFirstCells.each(function(i, _cell) {
|
||||
if (i < rowCnt) {
|
||||
cell = $(_cell);
|
||||
setMinHeight(
|
||||
cell.find('> div'),
|
||||
cell.find('> div').css(
|
||||
'min-height',
|
||||
(i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
unlockHeight();
|
||||
}
|
||||
|
||||
|
||||
@@ -514,19 +516,5 @@ function BasicView(element, calendar, viewName) {
|
||||
function allDayRow(i) {
|
||||
return bodyRows.eq(i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// makes sure height doesn't collapse while we destroy/render new cells
|
||||
// (this causes a bad end-user scrollbar jump)
|
||||
// TODO: generalize this for all view rendering. (also in Calendar.js)
|
||||
|
||||
function lockHeight() {
|
||||
setMinHeight(element, element.height());
|
||||
}
|
||||
|
||||
function unlockHeight() {
|
||||
setMinHeight(element, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -307,7 +307,6 @@ function DayEventRenderer() {
|
||||
" style=" +
|
||||
"'" +
|
||||
"position:absolute;" +
|
||||
"z-index:8;" + // TODO: move this into a constant or put it in the stylesheet
|
||||
"left:" + segment.left + "px;" +
|
||||
skinCss +
|
||||
"'" +
|
||||
@@ -322,7 +321,9 @@ function DayEventRenderer() {
|
||||
"</span>";
|
||||
}
|
||||
html +=
|
||||
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
||||
"<span class='fc-event-title'>" +
|
||||
htmlEscape(event.title || '') +
|
||||
"</span>" +
|
||||
"</div>";
|
||||
if (segment.isEnd && isEventResizable(event)) {
|
||||
html +=
|
||||
@@ -366,7 +367,6 @@ function DayEventRenderer() {
|
||||
triggerRes = $(triggerRes)
|
||||
.css({
|
||||
position: 'absolute',
|
||||
zIndex: 8, // TODO: move this into a constant or put it in the stylesheet
|
||||
left: segment.left
|
||||
});
|
||||
|
||||
@@ -610,7 +610,6 @@ function DayEventRenderer() {
|
||||
var hoverListener = getHoverListener();
|
||||
var dayDelta;
|
||||
eventElement.draggable({
|
||||
zIndex: 9,
|
||||
delay: 50,
|
||||
opacity: opt('dragOpacity'),
|
||||
revertDuration: opt('dragRevertDuration'),
|
||||
|
||||
@@ -12,10 +12,11 @@ function View(element, calendar, viewName) {
|
||||
t.trigger = trigger;
|
||||
t.isEventDraggable = isEventDraggable;
|
||||
t.isEventResizable = isEventResizable;
|
||||
t.reportEvents = reportEvents;
|
||||
t.setEventData = setEventData;
|
||||
t.clearEventData = clearEventData;
|
||||
t.eventEnd = eventEnd;
|
||||
t.reportEventElement = reportEventElement;
|
||||
t.reportEventClear = reportEventClear;
|
||||
t.triggerEventDestroy = triggerEventDestroy;
|
||||
t.eventElementHandlers = eventElementHandlers;
|
||||
t.showEvents = showEvents;
|
||||
t.hideEvents = hideEvents;
|
||||
@@ -33,9 +34,9 @@ function View(element, calendar, viewName) {
|
||||
|
||||
|
||||
// locals
|
||||
var eventsByID = {};
|
||||
var eventElements = [];
|
||||
var eventElementsByID = {};
|
||||
var eventsByID = {}; // eventID mapped to array of events (there can be multiple b/c of repeating events)
|
||||
var eventElementsByID = {}; // eventID mapped to array of jQuery elements
|
||||
var eventElementCouples = []; // array of objects, { event, element } // TODO: unify with segment system
|
||||
var options = calendar.options;
|
||||
|
||||
|
||||
@@ -59,21 +60,34 @@ function View(element, calendar, viewName) {
|
||||
|
||||
|
||||
/* Event Editable Boolean Calculations
|
||||
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function isEventDraggable(event) {
|
||||
return isEventEditable(event) && !opt('disableDragging');
|
||||
var source = event.source || {};
|
||||
return firstDefined(
|
||||
event.startEditable,
|
||||
source.startEditable,
|
||||
opt('eventStartEditable'),
|
||||
event.editable,
|
||||
source.editable,
|
||||
opt('editable')
|
||||
)
|
||||
&& !opt('disableDragging'); // deprecated
|
||||
}
|
||||
|
||||
|
||||
function isEventResizable(event) { // but also need to make sure the seg.isEnd == true
|
||||
return isEventEditable(event) && !opt('disableResizing');
|
||||
}
|
||||
|
||||
|
||||
function isEventEditable(event) {
|
||||
return firstDefined(event.editable, (event.source || {}).editable, opt('editable'));
|
||||
var source = event.source || {};
|
||||
return firstDefined(
|
||||
event.durationEditable,
|
||||
source.durationEditable,
|
||||
opt('eventDurationEditable'),
|
||||
event.editable,
|
||||
source.editable,
|
||||
opt('editable')
|
||||
)
|
||||
&& !opt('disableResizing'); // deprecated
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +96,7 @@ function View(element, calendar, viewName) {
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// report when view receives new events
|
||||
function reportEvents(events) { // events are already normalized at this point
|
||||
function setEventData(events) { // events are already normalized at this point
|
||||
eventsByID = {};
|
||||
var i, len=events.length, event;
|
||||
for (i=0; i<len; i++) {
|
||||
@@ -95,6 +108,13 @@ function View(element, calendar, viewName) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clearEventData() {
|
||||
eventsByID = {};
|
||||
eventElementsByID = {};
|
||||
eventElementCouples = [];
|
||||
}
|
||||
|
||||
|
||||
// returns a Date object for an event's end
|
||||
@@ -110,18 +130,19 @@ function View(element, calendar, viewName) {
|
||||
|
||||
// report when view creates an element for an event
|
||||
function reportEventElement(event, element) {
|
||||
eventElements.push(element);
|
||||
eventElementCouples.push({ event: event, element: element });
|
||||
if (eventElementsByID[event._id]) {
|
||||
eventElementsByID[event._id].push(element);
|
||||
}else{
|
||||
eventElementsByID[event._id] = [element];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reportEventClear() {
|
||||
eventElements = [];
|
||||
eventElementsByID = {};
|
||||
|
||||
|
||||
function triggerEventDestroy() {
|
||||
$.each(eventElementCouples, function(i, couple) {
|
||||
t.trigger('eventDestroy', couple.event, couple.event, couple.element);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +179,8 @@ function View(element, calendar, viewName) {
|
||||
|
||||
|
||||
function eachEventElement(event, exceptElement, funcName) {
|
||||
// NOTE: there may be multiple events per ID (repeating events)
|
||||
// and multiple segments per event
|
||||
var elements = eventElementsByID[event._id],
|
||||
i, len = elements.length;
|
||||
for (i=0; i<len; i++) {
|
||||
|
||||
@@ -138,6 +138,15 @@
|
||||
|
||||
/* Global Event Styles
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event-container > * {
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.fc-event-container > .ui-draggable-dragging,
|
||||
.fc-event-container > .ui-resizable-resizing {
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.fc-event {
|
||||
border: 1px solid #3a87ad; /* default BORDER color */
|
||||
|
||||
@@ -70,7 +70,9 @@ var defaults = {
|
||||
//selectable: false,
|
||||
unselectAuto: true,
|
||||
|
||||
dropAccept: '*'
|
||||
dropAccept: '*',
|
||||
|
||||
handleWindowResize: true
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -102,10 +102,11 @@ html .fc,
|
||||
|
||||
.fc-content {
|
||||
clear: both;
|
||||
zoom: 1; /* for IE7, gives accurate coordinates for [un]freezeContentHeight */
|
||||
}
|
||||
|
||||
.fc-view {
|
||||
width: 100%; /* needed for view switching (when view is absolute) */
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,15 +113,6 @@ function vborders(element) {
|
||||
}
|
||||
|
||||
|
||||
function setMinHeight(element, height) {
|
||||
height = (typeof height == 'number' ? height + 'px' : height);
|
||||
element.each(function(i, _element) {
|
||||
_element.style.cssText += ';min-height:' + height + ';_height:' + height;
|
||||
// why can't we just use .css() ? i forget
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Misc Utils
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href='../build/out/fullcalendar.css' rel='stylesheet' />
|
||||
<link href='../build/out/fullcalendar.print.css' rel='stylesheet' media='print' />
|
||||
<script src='../build/out/jquery.js'></script>
|
||||
<script src='../build/out/jquery-ui.js'></script>
|
||||
<script src='../build/out/fullcalendar.js'></script>
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
year: 2010,
|
||||
month: 0,
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||
},
|
||||
editable: true,
|
||||
events: {
|
||||
url: "many_events_json.txt",
|
||||
data: function() {
|
||||
var custom_data = { q: 'custom data value' }; // should see this in Networking
|
||||
console.log('setting custom_data as part of the eventSource fetch');
|
||||
return custom_data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
body {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||
}
|
||||
|
||||
#calendar {
|
||||
width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='calendar'></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,6 +21,8 @@
|
||||
//weekMode: 'variable',
|
||||
minTime: '5:30am',
|
||||
maxTime: '5:30pm',
|
||||
|
||||
//handleWindowResize: false,
|
||||
|
||||
// TODO: there is a bug switching into agendaWeek from month with a 1280x1024 (with firebug showing)
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href='../build/out/fullcalendar.css' rel='stylesheet' />
|
||||
<link href='../build/out/fullcalendar.print.css' rel='stylesheet' media='print' />
|
||||
<script src='../build/out/jquery.js'></script>
|
||||
<script src='../build/out/jquery-ui.js'></script>
|
||||
<script src='../build/out/fullcalendar.js'></script>
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var date = new Date();
|
||||
var d = date.getDate();
|
||||
var m = date.getMonth();
|
||||
var y = date.getFullYear();
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||
},
|
||||
editable: true,
|
||||
events: [
|
||||
{
|
||||
title: null,
|
||||
start: new Date(y, m, 1)
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
start: new Date(y, m, d-5),
|
||||
end: new Date(y, m, d-2)
|
||||
},
|
||||
{
|
||||
start: new Date(y, m, d, 10, 30),
|
||||
allDay: false
|
||||
}
|
||||
],
|
||||
eventRender: function(event, el) {
|
||||
el.find('.fc-event-title').text("something");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
body {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||
}
|
||||
|
||||
#calendar {
|
||||
width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='calendar'></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href='../build/out/fullcalendar.css' rel='stylesheet' />
|
||||
<link href='../build/out/fullcalendar.print.css' rel='stylesheet' media='print' />
|
||||
<script src='../build/out/jquery.js'></script>
|
||||
<script src='../build/out/jquery-ui.js'></script>
|
||||
<script src='../build/out/fullcalendar.js'></script>
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var date = new Date();
|
||||
var d = date.getDate();
|
||||
var m = date.getMonth();
|
||||
var y = date.getFullYear();
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||
},
|
||||
editable: true,
|
||||
events: [
|
||||
{
|
||||
title: 'All Day Event',
|
||||
start: new Date(y, m, 1)
|
||||
},
|
||||
{
|
||||
title: 'Long Event',
|
||||
start: new Date(y, m, d-5),
|
||||
end: new Date(y, m, d-2)
|
||||
},
|
||||
{
|
||||
id: 999,
|
||||
title: 'Repeating Event',
|
||||
start: new Date(y, m, d-3, 16, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 999,
|
||||
title: 'Repeating Event',
|
||||
start: new Date(y, m, d+4, 16, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Meeting',
|
||||
start: new Date(y, m, d, 10, 30),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Lunch',
|
||||
start: new Date(y, m, d, 12, 5),
|
||||
end: new Date(y, m, d, 14, 43),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Birthday Party',
|
||||
start: new Date(y, m, d+1, 19, 0),
|
||||
end: new Date(y, m, d+1, 22, 30),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Click for Google',
|
||||
start: new Date(y, m, 28),
|
||||
end: new Date(y, m, 29),
|
||||
url: 'http://google.com/'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
body {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||
}
|
||||
|
||||
#calendar {
|
||||
width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.fc-past {
|
||||
background: #fbc0fc;
|
||||
}
|
||||
|
||||
.fc-future {
|
||||
background: #a4ffa4;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='calendar'></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -59,9 +59,13 @@ $(document).ready(function() {
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||
},
|
||||
|
||||
editable: true,
|
||||
//disableResizing: true,
|
||||
//disableDragging: true,
|
||||
//eventStartEditable: false,
|
||||
//eventDurationEditable: false,
|
||||
//disableResizing: true, // deprecated
|
||||
//disableDragging: true, // deprecated
|
||||
|
||||
selectable: true,
|
||||
selectHelper: true,
|
||||
dragOpacity: .5,
|
||||
@@ -98,9 +102,14 @@ $(document).ready(function() {
|
||||
|
||||
{
|
||||
color: 'purple',
|
||||
//editable: false,
|
||||
//startEditable: false,
|
||||
//durationEditable: false,
|
||||
events: [
|
||||
{
|
||||
title: 'All Day Event',
|
||||
//startEditable: false,
|
||||
//durationEditable: false,
|
||||
start: new Date(y, m, 1)
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#tabs').tabs({
|
||||
show: function() {
|
||||
activate: function() {
|
||||
$('#calendar').fullCalendar('render');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href='../build/out/fullcalendar.css' rel='stylesheet' />
|
||||
<link href='../build/out/fullcalendar.print.css' rel='stylesheet' media='print' />
|
||||
<script src='../build/out/jquery.js'></script>
|
||||
<script src='../build/out/jquery-ui.js'></script>
|
||||
<script src='../build/out/fullcalendar.js'></script>
|
||||
<script src='../build/out/gcal.js'></script>
|
||||
<script>
|
||||
|
||||
var date = new Date();
|
||||
var d = date.getDate();
|
||||
var m = date.getMonth();
|
||||
var y = date.getFullYear();
|
||||
|
||||
var verbose = false;
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#calendar').fullCalendar({
|
||||
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
|
||||
},
|
||||
editable: true,
|
||||
selectable: true,
|
||||
|
||||
viewRender: function(view, element) {
|
||||
console.log('viewRender');
|
||||
//alert('viewRender');
|
||||
if (verbose) {
|
||||
console.log(' this', this);
|
||||
console.log(' view', view);
|
||||
console.log(' element', element);
|
||||
}
|
||||
},
|
||||
|
||||
eventAfterAllRender: function(view) {
|
||||
console.log('eventAfterAllRender');
|
||||
if (verbose) {
|
||||
console.log(' this', this);
|
||||
console.log(' view', view);
|
||||
}
|
||||
},
|
||||
|
||||
viewDestroy: function(view, element) {
|
||||
console.log('viewDestroy');
|
||||
//alert('viewDestroy');
|
||||
if (verbose) {
|
||||
console.log(' this', this);
|
||||
console.log(' view', view);
|
||||
console.log(' element', element);
|
||||
}
|
||||
},
|
||||
|
||||
eventDestroy: function(event, element) {
|
||||
console.log('eventDestroy');
|
||||
//alert('eventDestroy');
|
||||
if (verbose) {
|
||||
console.log(' this', this);
|
||||
console.log(' event', event);
|
||||
console.log(' element', element);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
viewDisplay: function(view) { // deprecated
|
||||
console.log('viewDisplay');
|
||||
if (verbose) {
|
||||
console.log('The new title of the view is ' + view.title);
|
||||
}
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
eventSources: [
|
||||
{
|
||||
url: "http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic",
|
||||
editable: true,
|
||||
className: 'holiday'
|
||||
},
|
||||
{
|
||||
events: [
|
||||
{
|
||||
title: 'All Day Event',
|
||||
start: new Date(y, m, 1)
|
||||
},
|
||||
{
|
||||
title: 'Long Event',
|
||||
start: new Date(y, m, d-5),
|
||||
end: new Date(y, m, d-2)
|
||||
},
|
||||
{
|
||||
id: 999,
|
||||
title: 'Repeating Event',
|
||||
start: new Date(y, m, d-3, 16, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 999,
|
||||
title: 'Repeating Event',
|
||||
start: new Date(y, m, d+4, 16, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 888,
|
||||
title: 'Meeting',
|
||||
start: new Date(y, m, d, 10, 30),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 777,
|
||||
title: 'Lunch',
|
||||
start: new Date(y, m, d, 12, 0),
|
||||
end: new Date(y, m, d, 14, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Birthday Party',
|
||||
start: new Date(y, m, d+1, 19, 0),
|
||||
end: new Date(y, m, d+1, 22, 30),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
title: 'Click for Google',
|
||||
start: new Date(y, m, 28),
|
||||
end: new Date(y, m, 29),
|
||||
url: 'http://google.com/'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function hyperJump() {console.log('hyperJump');
|
||||
$('#calendar').fullCalendar('changeView', 'agendaWeek');
|
||||
//alert('pause');
|
||||
$('#calendar').fullCalendar('gotoDate', new Date(y, m+2, d));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body style='font-size:14px'>
|
||||
<button onclick='hyperJump()'>changeView+gotoDate</button>
|
||||
<div id='calendar' style='width:75%;margin:20px auto 0;font-family:arial'></div>
|
||||
</body>
|
||||
</html>
|
||||