forked from extern/egroupware
Calendar display
- Add indicators for events hidden outside of work hours - Show hidden headers for events starting before current displayed time - Fix scroll animation for multi-week views
This commit is contained in:
parent
731e490ade
commit
36b54a7c33
@ -509,25 +509,28 @@ app.classes.calendar = AppJS.extend(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We clone the nodes so we can animate the transition
|
// We clone the nodes so we can animate the transition
|
||||||
var original = $j(widget.getDOMNode());
|
var original = $j(widget.getDOMNode()).closest('.et2_grid');
|
||||||
var cloned = original.clone(true).attr("id","CLONE");
|
var cloned = original.clone(true).attr("id","CLONE");
|
||||||
var wrapper = $j(document.createElement("div"));
|
|
||||||
original.parent().append(wrapper);
|
|
||||||
|
|
||||||
// This is to hide the scrollbar
|
// Moving this stuff around scrolls things around too
|
||||||
wrapper.wrap("<div style='overflow:hidden; height:"+original.outerHeight()+"px; width:" + original.outerWidth() + "px;'></div>");
|
// We need this later
|
||||||
wrapper.height(direction == "up" || direction == "down" ? 2 * original.outerHeight() : original.outerHeight());
|
|
||||||
wrapper.width(direction == "left" || direction == "right" ? 2 * original.outerWidth() : original.outerWidth());
|
|
||||||
|
|
||||||
// Moving this stuff around breaks scroll to day start in Chrome
|
|
||||||
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
|
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
|
||||||
|
|
||||||
|
// This is to hide the scrollbar
|
||||||
|
var wrapper = original.parent();
|
||||||
if(direction == "right" || direction == "left")
|
if(direction == "right" || direction == "left")
|
||||||
{
|
{
|
||||||
original.css({"display":"inline-block","width":original.width()+"px"});
|
original.css({"display":"inline-block","width":original.width()+"px"});
|
||||||
cloned.css({"display":"inline-block","width":original.width()+"px"});
|
cloned.css({"display":"inline-block","width":original.width()+"px"});
|
||||||
}
|
}
|
||||||
wrapper.append(original);
|
else
|
||||||
|
{
|
||||||
|
original.css("height",original.height() + "px");
|
||||||
|
cloned.css("height",original.height() + "px");
|
||||||
|
}
|
||||||
|
wrapper.parent().css({overflow:'hidden', height:original.outerHeight()+"px", width:original.outerWidth() + "px"});
|
||||||
|
wrapper.height(direction == "up" || direction == "down" ? 2 * original.outerHeight() : original.outerHeight());
|
||||||
|
wrapper.width(direction == "left" || direction == "right" ? 2 * original.outerWidth() : original.outerWidth());
|
||||||
|
|
||||||
// Re-scroll to previous to avoid "jumping"
|
// Re-scroll to previous to avoid "jumping"
|
||||||
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
|
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
|
||||||
@ -538,13 +541,17 @@ app.classes.calendar = AppJS.extend(
|
|||||||
// Scrolling up
|
// Scrolling up
|
||||||
// Apply the reverse quickly, then let it animate as the changes are
|
// Apply the reverse quickly, then let it animate as the changes are
|
||||||
// removed, leaving things where they should be.
|
// removed, leaving things where they should be.
|
||||||
|
|
||||||
original.parent().append(cloned);
|
original.parent().append(cloned);
|
||||||
wrapper.css({"transform": direction == "up" ? "translateY(-50%)" : "translateX(-50%)"});
|
|
||||||
// Makes it jump to destination
|
// Makes it jump to destination
|
||||||
wrapper.css({
|
wrapper.css({
|
||||||
"transition-duration": "0s",
|
"transition-duration": "0s",
|
||||||
"transition-delay": "0s"
|
"transition-delay": "0s",
|
||||||
|
"transform": direction == "up" ? "translateY(-50%)" : "translateX(-50%)"
|
||||||
});
|
});
|
||||||
|
// Stop browser from caching style by forcing reflow
|
||||||
|
wrapper[0].offsetHeight;
|
||||||
|
|
||||||
wrapper.css({
|
wrapper.css({
|
||||||
"transition-duration": "",
|
"transition-duration": "",
|
||||||
"transition-delay": ""
|
"transition-delay": ""
|
||||||
@ -567,21 +574,30 @@ app.classes.calendar = AppJS.extend(
|
|||||||
wrapper.css({"transform": translate});
|
wrapper.css({"transform": translate});
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
|
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
|
||||||
// Clean up from animation
|
|
||||||
cloned.remove();
|
cloned.remove();
|
||||||
var parent = wrapper.parent().parent();
|
|
||||||
wrapper.parent().remove();
|
// Makes it jump to destination
|
||||||
original.appendTo(parent);
|
wrapper.css({
|
||||||
|
"transition-duration": "0s",
|
||||||
|
"transition-delay": "0s"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up from animation
|
||||||
|
wrapper
|
||||||
|
.removeClass("calendar_slide")
|
||||||
|
.css({"transform": '',height: '', width:'',overflow:''});
|
||||||
|
wrapper.parent().css({overflow: '', width: '', height: ''});
|
||||||
original.css("display","");
|
original.css("display","");
|
||||||
// Re-attach events, if widget is still there
|
wrapper[0].offsetHeight;
|
||||||
if(widget && widget.getDOMNode(widget))
|
wrapper.css({
|
||||||
{
|
"transition-duration": "",
|
||||||
widget.attachToDOM();
|
"transition-delay": ""
|
||||||
}
|
});
|
||||||
|
|
||||||
// Re-scroll to start of day
|
// Re-scroll to start of day
|
||||||
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
|
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
|
||||||
|
|
||||||
|
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
if(app.calendar)
|
if(app.calendar)
|
||||||
{
|
{
|
||||||
|
@ -441,6 +441,90 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
|
|||||||
{
|
{
|
||||||
this._children[c].set_value(events[c]);
|
this._children[c].set_value(events[c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply styles to hidden events
|
||||||
|
this._out_of_view();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply styles for out-of-view and partially hidden events
|
||||||
|
*/
|
||||||
|
_out_of_view: function()
|
||||||
|
{
|
||||||
|
// Reset
|
||||||
|
this.header.children('.hiddenEventBefore').remove();
|
||||||
|
this.div.children('.hiddenEventAfter').remove();
|
||||||
|
|
||||||
|
var timegrid = this._parent;
|
||||||
|
|
||||||
|
// elem is jquery div of event
|
||||||
|
function isHidden(elem) {
|
||||||
|
var docViewTop = timegrid.scrolling.scrollTop(),
|
||||||
|
docViewBottom = docViewTop + timegrid.scrolling.height(),
|
||||||
|
elemTop = elem.position().top,
|
||||||
|
elemBottom = elemTop + elem.outerHeight();
|
||||||
|
if((elemBottom <= docViewBottom) && (elemTop >= docViewTop))
|
||||||
|
{
|
||||||
|
// Entirely visible
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var visible = {
|
||||||
|
hidden: elemTop > docViewTop ? 'bottom' : 'top',
|
||||||
|
completely: false
|
||||||
|
};
|
||||||
|
visible.completely = visible.hidden == 'top' ? elemBottom < docViewTop : elemTop > docViewBottom;
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each event
|
||||||
|
this.iterateOver(function(event) {
|
||||||
|
// Skip whole day events and events missing value
|
||||||
|
if(!event.options || !event.options.value || event.options.value.whole_day) return;
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
event.title.css('top','');
|
||||||
|
event.body.css('padding-top','');
|
||||||
|
|
||||||
|
var hidden = isHidden.call(this,event.div);
|
||||||
|
if(!hidden)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Only top is hidden, move label
|
||||||
|
// Bottom hidden is fine
|
||||||
|
if(hidden.hidden === 'top' && !hidden.completely)
|
||||||
|
{
|
||||||
|
event.title.css('top',timegrid.scrolling.scrollTop() - event.div.position().top);
|
||||||
|
event.body.css('padding-top',timegrid.scrolling.scrollTop() - event.div.position().top);
|
||||||
|
}
|
||||||
|
// Completely out of view, show indicator
|
||||||
|
else if (hidden.completely)
|
||||||
|
{
|
||||||
|
var indicator = '';
|
||||||
|
if(hidden.hidden === 'top' && $j('.hiddenEventBefore',this.header).length == 0)
|
||||||
|
{
|
||||||
|
indicator = $j('<div class="hiddenEventBefore"></div>')
|
||||||
|
.appendTo(this.header);
|
||||||
|
}
|
||||||
|
else if(hidden.hidden === 'bottom')
|
||||||
|
|
||||||
|
{
|
||||||
|
indicator = $j('.hiddenEventAfter',this.div);
|
||||||
|
if(indicator.length == 0)
|
||||||
|
{
|
||||||
|
indicator = $j('<div class="hiddenEventAfter"></div>');
|
||||||
|
this.div.append(indicator);
|
||||||
|
}
|
||||||
|
indicator.css('top',timegrid.scrolling.height() + timegrid.scrolling.scrollTop()-indicator.height());
|
||||||
|
}
|
||||||
|
// Match color to the event
|
||||||
|
if(indicator != '')
|
||||||
|
{
|
||||||
|
// Use border-top-color, Firefox doesn't give a value with border-color
|
||||||
|
indicator.css('border-color', event.div.css('border-top-color'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this, et2_calendar_event);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,7 +532,8 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz
|
|||||||
this.scrolling
|
this.scrolling
|
||||||
.css('height', (this.options.height - header_height)+'px')
|
.css('height', (this.options.height - header_height)+'px')
|
||||||
.appendTo(this.div)
|
.appendTo(this.div)
|
||||||
.empty();
|
.empty()
|
||||||
|
.off().on('scroll', jQuery.proxy(this._scroll, this));
|
||||||
|
|
||||||
// Percent
|
// Percent
|
||||||
var rowHeight = (100/rowsToDisplay).toFixed(1);
|
var rowHeight = (100/rowsToDisplay).toFixed(1);
|
||||||
@ -666,6 +667,9 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz
|
|||||||
|
|
||||||
// Scroll to start of day
|
// Scroll to start of day
|
||||||
this.scrolling.scrollTop(this._top_time);
|
this.scrolling.scrollTop(this._top_time);
|
||||||
|
|
||||||
|
// Handle not fully visible elements
|
||||||
|
this._scroll();
|
||||||
|
|
||||||
// TODO: Figure out how to do this with detached nodes
|
// TODO: Figure out how to do this with detached nodes
|
||||||
/*
|
/*
|
||||||
@ -681,6 +685,21 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz
|
|||||||
*/
|
*/
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update UI while scrolling within the selected time
|
||||||
|
*
|
||||||
|
* Toggles out of view indicators and adjusts not visible headers
|
||||||
|
* @param {Event} event Scroll event
|
||||||
|
*/
|
||||||
|
_scroll: function(event)
|
||||||
|
{
|
||||||
|
// Loop through days, let them deal with it
|
||||||
|
for(var day = 0; day < this.day_widgets.length; day++)
|
||||||
|
{
|
||||||
|
this.day_widgets[day]._out_of_view();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate a list of days between start and end date, skipping weekends if
|
* Calculate a list of days between start and end date, skipping weekends if
|
||||||
* desired.
|
* desired.
|
||||||
|
@ -246,6 +246,28 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid silver;
|
border-bottom: 1px solid silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Indicators for offscreen events */
|
||||||
|
.calendar_calDayColHeader .hiddenEventBefore, .calendar_calDayCol .hiddenEventAfter {
|
||||||
|
width: 80%;
|
||||||
|
height: 5px;
|
||||||
|
left: 10%;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 5px solid;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
z-index: 40;
|
||||||
|
}
|
||||||
|
.calendar_calDayColHeader .hiddenEventBefore {
|
||||||
|
bottom: -7px;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
.calendar_calDayCol .hiddenEventAfter {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.calendar_calDayColAllDay {
|
.calendar_calDayColAllDay {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@ -318,6 +340,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
|||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
z-index: 29;
|
z-index: 29;
|
||||||
border-bottom: 1px solid silver;
|
border-bottom: 1px solid silver;
|
||||||
|
min-height: 45px;
|
||||||
}
|
}
|
||||||
#calendar-view_view tbody.ui-sortable {
|
#calendar-view_view tbody.ui-sortable {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
@ -13,7 +13,7 @@ Egroupware
|
|||||||
|
|
||||||
<overlay>
|
<overlay>
|
||||||
<template id="calendar.view">
|
<template id="calendar.view">
|
||||||
<grid id="view" width="100%" height="100%">
|
<grid id="view" width="100%">
|
||||||
<columns>
|
<columns>
|
||||||
<column/>
|
<column/>
|
||||||
</columns>
|
</columns>
|
||||||
|
Loading…
Reference in New Issue
Block a user