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:
Nathan Gray 2015-11-04 21:47:52 +00:00
parent 731e490ade
commit 36b54a7c33
5 changed files with 166 additions and 24 deletions

View File

@ -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)
{ {

View File

@ -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);
}, },
/** /**

View File

@ -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);
@ -667,6 +668,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
/* /*
var nodes = this.day_col.getDetachedNodes(); var nodes = this.day_col.getDetachedNodes();
@ -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.

View File

@ -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;

View File

@ -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>