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
var original = $j(widget.getDOMNode());
var original = $j(widget.getDOMNode()).closest('.et2_grid');
var cloned = original.clone(true).attr("id","CLONE");
var wrapper = $j(document.createElement("div"));
original.parent().append(wrapper);
// This is to hide the scrollbar
wrapper.wrap("<div style='overflow:hidden; height:"+original.outerHeight()+"px; width:" + original.outerWidth() + "px;'></div>");
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
// Moving this stuff around scrolls things around too
// We need this later
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
// This is to hide the scrollbar
var wrapper = original.parent();
if(direction == "right" || direction == "left")
{
original.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"
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
@ -538,13 +541,17 @@ app.classes.calendar = AppJS.extend(
// Scrolling up
// Apply the reverse quickly, then let it animate as the changes are
// removed, leaving things where they should be.
original.parent().append(cloned);
wrapper.css({"transform": direction == "up" ? "translateY(-50%)" : "translateX(-50%)"});
// Makes it jump to destination
wrapper.css({
"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({
"transition-duration": "",
"transition-delay": ""
@ -567,21 +574,30 @@ app.classes.calendar = AppJS.extend(
wrapper.css({"transform": translate});
window.setTimeout(function() {
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
// Clean up from animation
cloned.remove();
var parent = wrapper.parent().parent();
wrapper.parent().remove();
original.appendTo(parent);
// Makes it jump to destination
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","");
// Re-attach events, if widget is still there
if(widget && widget.getDOMNode(widget))
{
widget.attachToDOM();
}
wrapper[0].offsetHeight;
wrapper.css({
"transition-duration": "",
"transition-delay": ""
});
// Re-scroll to start of day
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
window.setTimeout(function() {
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]);
}
// 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
.css('height', (this.options.height - header_height)+'px')
.appendTo(this.div)
.empty();
.empty()
.off().on('scroll', jQuery.proxy(this._scroll, this));
// Percent
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
this.scrolling.scrollTop(this._top_time);
// Handle not fully visible elements
this._scroll();
// 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
* desired.

View File

@ -246,6 +246,28 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
text-align: center;
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 {
display: flex;
flex-wrap: wrap;
@ -318,6 +340,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
padding-left: 3px;
z-index: 29;
border-bottom: 1px solid silver;
min-height: 45px;
}
#calendar-view_view tbody.ui-sortable {
cursor: default;

View File

@ -13,7 +13,7 @@ Egroupware
<overlay>
<template id="calendar.view">
<grid id="view" width="100%" height="100%">
<grid id="view" width="100%">
<columns>
<column/>
</columns>