Calendar scrolling, swiping and keyhandler for page up & page down

This commit is contained in:
Nathan Gray 2015-10-27 16:45:37 +00:00
parent c6390b378e
commit 252a8fd11a
4 changed files with 259 additions and 191 deletions

View File

@ -106,6 +106,9 @@ app.classes.calendar = AppJS.extend(
delete window.top.app.calendar; delete window.top.app.calendar;
} }
jQuery('body').off('.calendar'); jQuery('body').off('.calendar');
egw_unregisterGlobalShortcut(jQuery.ui.keyCode.PAGE_UP, false, false, false);
egw_unregisterGlobalShortcut(jQuery.ui.keyCode.PAGE_DOWN, false, false, false);
}, },
/** /**
@ -252,6 +255,7 @@ app.classes.calendar = AppJS.extend(
} }
break; break;
case 'calendar': case 'calendar':
// Regular refresh
if(_id) if(_id)
{ {
var event = egw.dataGetUIDdata('calendar::'+_id); var event = egw.dataGetUIDdata('calendar::'+_id);
@ -457,36 +461,27 @@ app.classes.calendar = AppJS.extend(
* When the user scrolls, we'll move enddate - startdate days * When the user scrolls, we'll move enddate - startdate days
*/ */
_scroll: function() { _scroll: function() {
// Bind only once, to the whole thing /**
jQuery('body').off('.calendar') * Function we can pass all this off to
//.on('wheel','.et2_container:#calendar-list,#calendar-sidebox)', *
.on('wheel.calendar','.et2_container .calendar_calTimeGrid, .et2_container .calendar_plannerWidget', * @param {String} direction up, down, left or right
function(e) * @param {number} delta Integer for how many we're moving, should be +/- 1
*/
var scroll_animate = function(direction, delta)
{ {
// Ignore if they're going the other way
var direction = e.originalEvent.deltaY > 0 ? 1 : -1;
var at_bottom = direction !== -1;
var at_top = direction !== 1;
$j(this).children(":not(.calendar_calGridHeader)").each(function() {
at_bottom = at_bottom && this.scrollTop === (this.scrollHeight - this.offsetHeight)
}).each(function() {
at_top = at_top && this.scrollTop === 0;
});
if(!at_bottom && !at_top) return;
// Scrolling too fast? // Scrolling too fast?
if(app.calendar._scroll_disabled) return; if(app.calendar._scroll_disabled) return;
e.preventDefault();
var delta = 1;
var start = new Date(app.calendar.state.date);
var end = null;
// Find the template // Find the template
var id = $j(this).closest('.et2_container').attr('id'); var id = $j(this).closest('.et2_container').attr('id');
if(!id) return; if(id)
{
var template = etemplate2.getById(id); var template = etemplate2.getById(id);
}
else
{
template = app.classes.calendar.views[app.calendar.state.view].etemplates[0];
}
if(!template) return; if(!template) return;
// Prevent scrolling too fast // Prevent scrolling too fast
@ -497,23 +492,46 @@ app.classes.calendar = AppJS.extend(
template.widgetContainer.iterateOver(function(w) { template.widgetContainer.iterateOver(function(w) {
if (w.getDOMNode() == this) widget = w; if (w.getDOMNode() == this) widget = w;
},this,et2_widget); },this,et2_widget);
if(widget == null)
{
template.widgetContainer.iterateOver(function(w) {
widget = w;
},this, et2_calendar_timegrid);
if(widget == null) return; if(widget == null) return;
}
// We apply the reverse quickly, then let it animate as the changes are // We clone the nodes so we can animate the transition
// removed, leaving things where they should be. var original = $j(widget.getDOMNode());
var original = $j(this);
var cloned = original.clone(true).attr("id","CLONE"); var cloned = original.clone(true).attr("id","CLONE");
var wrapper = $j(document.createElement("div")); var wrapper = $j(document.createElement("div"));
original.parent().append(wrapper); original.parent().append(wrapper);
// This is to hide the scrollbar // This is to hide the scrollbar
wrapper.wrap("<div style='overflow:hidden; height:"+original.outerHeight()+"px'></div>"); wrapper.wrap("<div style='overflow:hidden; height:"+original.outerHeight()+"px; width:" + original.outerWidth() + "px;'></div>");
wrapper.height(original.outerHeight() + cloned.outerHeight()); wrapper.height(direction == "up" || direction == "down" ? 2 * original.outerHeight() : original.outerHeight());
wrapper.append(original); wrapper.width(direction == "left" || direction == "right" ? 2 * original.outerWidth() : original.outerWidth());
if(direction == -1)
// Moving this stuff around breaks scroll to day start in Chrome
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
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);
// Re-scroll to previous to avoid "jumping"
$j('.calendar_calTimeGridScroll',original).scrollTop(scrollTop);
switch(direction)
{
case "up":
case "left":
// Scrolling up // 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); original.parent().append(cloned);
wrapper.css({"transform": "translateY(" + (direction * 50) + "%)"}); 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",
@ -523,29 +541,32 @@ app.classes.calendar = AppJS.extend(
"transition-duration": "", "transition-duration": "",
"transition-delay": "" "transition-delay": ""
}); });
} break;
else case "down":
{ case "right":
// Scrolling down // Scrolling down
$j(this).parent().prepend(cloned); original.parent().prepend(cloned);
$j('.calendar_calTimeGridScroll',cloned).scrollTop(10000); break;
} }
// Scroll clone to match to avoid "jumping"
$j('.calendar_calTimeGridScroll',cloned).scrollTop(scrollTop);
// Remove // Remove
var remove = function() { var remove = function() {
// Starting animation // Starting animation
wrapper.addClass("calendar_slide"); wrapper.addClass("calendar_slide");
wrapper.css({"transform": direction == 1 ? "translateY(-50%)" : ""}); var translate = direction == "down" ? "translateY(-50%)" : (direction == "right" ? "translateX(-50%)" : "");
wrapper.css({"transform": translate});
window.setTimeout(function() { window.setTimeout(function() {
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
// Clean up from animation // Clean up from animation
cloned.remove(); cloned.remove();
// Moving this stuff around breaks scroll to day start in Chrome
var scrollTop = $j('.calendar_calTimeGridScroll',original).scrollTop();
var parent = wrapper.parent().parent(); var parent = wrapper.parent().parent();
wrapper.parent().remove(); wrapper.parent().remove();
original.appendTo(parent); original.appendTo(parent);
// Also detaches events original.css("display","");
if(widget) // Re-attach events, if widget is still there
if(widget && widget.getDOMNode(widget))
{ {
widget.attachToDOM(); widget.attachToDOM();
} }
@ -558,17 +579,20 @@ app.classes.calendar = AppJS.extend(
{ {
app.calendar._scroll_disabled = false; app.calendar._scroll_disabled = false;
} }
}, 500); }, 100);
},1000); },2000);
} }
// If detecting the transition end worked, we wouldn't need to use a timeout. // If detecting the transition end worked, we wouldn't need to use a timeout.
window.setTimeout(remove,100); window.setTimeout(remove,100);
// Get the view to calculate // Get the view to calculate - this actually loads the new data
// Using a timeout make it a little faster (in Chrome)
window.setTimeout(function() {
var view = app.classes.calendar.views[app.calendar.state.view] || false; var view = app.classes.calendar.views[app.calendar.state.view] || false;
var start = new Date(app.calendar.state.date);
if (view && view.etemplates.indexOf(template) !== -1) if (view && view.etemplates.indexOf(template) !== -1)
{ {
start = view.scroll(direction * delta); start = view.scroll(delta);
app.calendar.update_state({date:app.calendar.date.toString(start)}); app.calendar.update_state({date:app.calendar.date.toString(start)});
} }
else else
@ -576,38 +600,85 @@ app.classes.calendar = AppJS.extend(
// Home - always 1 week // Home - always 1 week
// TODO // TODO
return false; return false;
/*
var widget = [];
var value = [];
template.widgetContainer.iterateOver(function(w) {
if(typeof w.set_start_date === 'function' && typeof w.set_value === 'function')
{
widget.push(w);
} }
},this,et2_valueWidget); },0);
for(var i = 0; i < widget.length; i++)
{
var state = template.widgetContainer.getParent().settings.favorite.state || {};
debugger;
var start = new Date(widget[i].options.start_date || state.start);
start.setUTCDate(start.getUTCDate() + (7 * direction * delta));
var end = new Date(widget[i].options.end_date || state.end);
end.setUTCDate(end.getUTCDate() + (7 * direction * delta));
// Get data
value[i] = {
start_date: start,
end_date: end
}; };
app.calendar._need_data([value[i]], state);
widget[i].set_value(value[i]); // Bind only once, to the whole thing
} jQuery('body').off('.calendar')
*/ //.on('wheel','.et2_container:#calendar-list,#calendar-sidebox)',
} .on('wheel.calendar','.et2_container .calendar_calTimeGrid, .et2_container .calendar_plannerWidget',
function(e)
{
// Consume scroll if in the middle of something
if(app.calendar._scroll_disabled) return false;
// Ignore if they're going the other way
var direction = e.originalEvent.deltaY > 0 ? 1 : -1;
var at_bottom = direction !== -1;
var at_top = direction !== 1;
$j(this).children(":not(.calendar_calGridHeader)").each(function() {
// Check for less than 2px from edge, as sometimes we can't scroll anymore, but still have
// 2px left to go
at_bottom = at_bottom && Math.abs(this.scrollTop - (this.scrollHeight - this.offsetHeight)) <= 2;
}).each(function() {
at_top = at_top && this.scrollTop === 0;
});
if(!at_bottom && !at_top) return;
e.preventDefault();
scroll_animate.call(this, direction > 0 ? "down" : "up", direction);
return false; return false;
} }
); )
.swipe({
//Generic swipe handler for all directions
swipe:function(event, direction, distance, duration, fingerCount) {
if(direction == "up" || direction == "down")
{
var at_bottom = direction !== -1;
var at_top = direction !== 1;
$j(this).children(":not(.calendar_calGridHeader)").each(function() {
// Check for less than 2px from edge, as sometimes we can't scroll anymore, but still have
// 2px left to go
at_bottom = at_bottom && Math.abs(this.scrollTop - (this.scrollHeight - this.offsetHeight)) <= 2;
}).each(function() {
at_top = at_top && this.scrollTop === 0;
});
if(!at_bottom && !at_top && fingerCount == 1) return;
}
var delta = direction == "down" || direction == "right" ? -1 : 1;
// But we animate in the opposite direction to the swipe
var opposite = {"down": "up", "up": "down", "left": "right", "right": "left"};
direction = opposite[direction];
scroll_animate.call($j(event.target).closest('.calendar_calTimeGrid, .calendar_plannerWidget')[0], direction, delta)
return false;
},
allowPageScroll: jQuery.fn.swipe.pageScroll.VERTICAL
});
// Page up & page down
egw_registerGlobalShortcut(jQuery.ui.keyCode.PAGE_UP, false, false, false, function() {
if(app.calendar.state.view == 'listview')
{
return false
}
scroll_animate.call(this,"up", -1);
return true;
});
egw_registerGlobalShortcut(jQuery.ui.keyCode.PAGE_DOWN, false, false, false, function() {
if(app.calendar.state.view == 'listview')
{
return false
}
scroll_animate.call(this,"down", 1);
return true;
});
}, },
/** /**

View File

@ -463,15 +463,15 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz
getDOMNode: function(_sender) { getDOMNode: function(_sender) {
if(_sender === this || !_sender) if(_sender === this || !_sender)
{ {
return this.div[0]; return this.div ? this.div[0] : null;
} }
else if (_sender.instanceOf(et2_calendar_daycol)) else if (_sender.instanceOf(et2_calendar_daycol))
{ {
return this.days[0]; return this.days ? this.days[0] : null;
} }
else if (_sender) else if (_sender)
{ {
return this.gridHeader[0]; return this.gridHeader ? this.gridHeader[0] : null;
} }
}, },

View File

@ -812,8 +812,9 @@ img.calendar_print_button, img.calendar_print_appicon {
* View animation stuff * View animation stuff
*/ */
.calendar_slide { .calendar_slide {
transition-duration: 1s; /* There is a cleanup timeout in calendar app.js line 563 that must match */
transition-delay: 100ms; transition-duration: 2s;
transition-delay: 50ms;
} }
/** /**

View File

@ -258,13 +258,11 @@ function egw_keyHandler(_keyCode, _shift, _ctrl, _alt) {
{ {
var shortcut = egw_registeredShortcuts[idx]; var shortcut = egw_registeredShortcuts[idx];
// Call the registered shortcut function and return its result. // Call the registered shortcut function and return its result, if it handled it
shortcut.handler.call(shortcut.context, shortcut.shortcut); var result = shortcut.handler.call(shortcut.context, shortcut.shortcut);
if(result) return result;
return true;
} }
else
{
// Pass the keypress to the currently focused action object // Pass the keypress to the currently focused action object
// Get the object manager and fetch the container of the currently // Get the object manager and fetch the container of the currently
@ -328,8 +326,6 @@ function egw_keyHandler(_keyCode, _shift, _ctrl, _alt) {
} }
} }
}
return false; return false;
} }