Refactor & more intelligence in grid views for speed improvements

This commit is contained in:
Nathan Gray 2016-01-05 20:43:19 +00:00
parent 34d896f8ee
commit 7d1de17438
12 changed files with 408 additions and 200 deletions

View File

@ -796,6 +796,9 @@ class calendar_ui
{ {
$event['app_id'] .= ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts'); $event['app_id'] .= ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts');
} }
// set id for grid
$event['row_id'] = $event['id'].($event['recur_type'] ? ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts') : '');
$event['parts'] = implode(",\n",$this->bo->participants($event,false)); $event['parts'] = implode(",\n",$this->bo->participants($event,false));
$event['date'] = $this->bo->date2string($event['start']); $event['date'] = $this->bo->date2string($event['start']);

View File

@ -462,9 +462,6 @@ class calendar_uilist extends calendar_ui
$event['edit_link'] = $this->popup($view_link).'; return false;'; $event['edit_link'] = $this->popup($view_link).'; return false;';
} }
// set id for grid
$event['row_id'] = $event['id'].($event['recur_type'] ? ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts') : '');
// Format start and end with timezone // Format start and end with timezone
foreach(array('start','end') as $time) foreach(array('start','end') as $time)
{ {

View File

@ -661,6 +661,21 @@ class calendar_uiviews extends calendar_ui
$content = array('view' => array()); $content = array('view' => array());
if(!$home)
{
// Fill with the minimum needed 'weeks'
$min = max(
6, // Some months need 6 weeks for full display
$this->cal_prefs['multiple_weeks'], // WeekN view
$this->cal_prefs['week_consolidate'] // We collapse after this many users
);
for($i = 0; $i < $min; $i++)
{
$content['view'][] = array();
}
}
else
{
// Always do 7 days for a week so scrolling works properly // Always do 7 days for a week so scrolling works properly
$this->last = ($days == 4 ? $this->last : $search_params['end'] = strtotime("+$days days",$this->first) - 1); $this->last = ($days == 4 ? $this->last : $search_params['end'] = strtotime("+$days days",$this->first) - 1);
if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row
@ -677,6 +692,7 @@ class calendar_uiviews extends calendar_ui
+ array('owner' => $uid); + array('owner' => $uid);
} }
} }
}
$tmpl = $home ? $home :new etemplate_new('calendar.view'); $tmpl = $home ? $home :new etemplate_new('calendar.view');
$tmpl->setElementAttribute('view','show_weekend', $days == 7); $tmpl->setElementAttribute('view','show_weekend', $days == 7);

View File

@ -1594,7 +1594,7 @@ app.classes.calendar = AppJS.extend(
* *
* @param {Object} _set New settings * @param {Object} _set New settings
*/ */
update_state: function(_set) update_state: function update_state(_set)
{ {
// Make sure we're running in top window // Make sure we're running in top window
if(window !== window.top) if(window !== window.top)
@ -1632,7 +1632,7 @@ app.classes.calendar = AppJS.extend(
* *
* @return {object} description * @return {object} description
*/ */
getState: function() getState: function getState()
{ {
var state = jQuery.extend({},this.state); var state = jQuery.extend({},this.state);
@ -1683,7 +1683,7 @@ app.classes.calendar = AppJS.extend(
* *
* @param {object} state containing "name" attribute to be used as "favorite" GET parameter to a nextmatch * @param {object} state containing "name" attribute to be used as "favorite" GET parameter to a nextmatch
*/ */
setState: function(state) setState: function setState(state)
{ {
// State should be an object, not a string, but we'll parse // State should be an object, not a string, but we'll parse
if(typeof state == "string") if(typeof state == "string")
@ -1730,7 +1730,7 @@ app.classes.calendar = AppJS.extend(
} }
// Check for valid cache // Check for valid cache
var cachable_changes = ['date','view','days','planner_days','sortby']; var cachable_changes = ['date','weekend','view','days','planner_days','sortby'];
var keys = jQuery.unique(Object.keys(this.state).concat(Object.keys(state.state))); var keys = jQuery.unique(Object.keys(this.state).concat(Object.keys(state.state)));
for(var i = 0; i < keys.length; i++) for(var i = 0; i < keys.length; i++)
{ {
@ -1838,19 +1838,18 @@ app.classes.calendar = AppJS.extend(
var grid = view.etemplates[0].widgetContainer.getWidgetById('view'); var grid = view.etemplates[0].widgetContainer.getWidgetById('view');
/* /*
If the count is different, we need to have the correct number (just remove all & re-create) If the count is different, we need to have the correct number
If the count is > 1, it's either because there are multiple date spans (weekN, month) and we need the correct span If the count is > 1, it's either because there are multiple date spans (weekN, month) and we need the correct span
per row, or there are multiple owners and we need the correct owner per row. per row, or there are multiple owners and we need the correct owner per row.
*/ */
if(grid && (grid_count !== grid._children.length || grid_count > 1)) if(grid)
{ {
// Need to redo the number of grids
var value = []; var value = [];
state.state.first = view.start_date(state.state).toJSON(); state.state.first = view.start_date(state.state).toJSON();
// We'll modify this one, so it needs to be a new object // We'll modify this one, so it needs to be a new object
var date = new Date(state.state.first); var date = new Date(state.state.first);
// Determine the different end date // Determine the different end date & varying values
switch(state.state.view) switch(state.state.view)
{ {
case 'month': case 'month':
@ -1861,59 +1860,147 @@ app.classes.calendar = AppJS.extend(
for(var week = 0; week < grid_count; week++) for(var week = 0; week < grid_count; week++)
{ {
var val = { var val = {
id: ""+date.getUTCFullYear() + sprintf("%02d",date.getUTCMonth()) + sprintf("%02d",date.getUTCDate()), id: app.classes.calendar._daywise_cache_id(date,state.state.owner),
start_date: date.toJSON(), start_date: date.toJSON(),
end_date: new Date(date.toJSON()), end_date: new Date(date.toJSON()),
owner: state.state.owner owner: state.state.owner
}; };
val.end_date.setUTCHours(24*7-1); val.end_date.setUTCHours(24*7-1);
val.end_date.setUTCMinutes(59);
val.end_date.setUTCSeconds(59);
val.end_date = val.end_date.toJSON(); val.end_date = val.end_date.toJSON();
value.push(val); value.push(val);
date.setUTCHours(24*7); date.setUTCHours(24*7);
} }
state.state.last=val.end_date; state.state.last=val.end_date;
break; break;
case 'day':
var end = state.state.last = view.end_date(state.state).toJSON();
value.push({
id: app.classes.calendar._daywise_cache_id(date,state.state.owner),
start_date: state.state.first,
end_date: state.state.last,
owner: view.owner(state.state)
});
break;
default: default:
var end = state.state.last = view.end_date(state.state).toJSON(); var end = state.state.last = view.end_date(state.state).toJSON();
for(var owner = 0; owner < grid_count && owner < state.state.owner.length; owner++) for(var owner = 0; owner < grid_count && owner < state.state.owner.length; owner++)
{ {
var _owner = grid_count > 1 ? state.state.owner[owner] || 0 : state.state.owner
value.push({ value.push({
id: ""+date.getUTCFullYear() + sprintf("%02d",date.getUTCMonth()) + sprintf("%02d",date.getUTCDate()), id: app.classes.calendar._daywise_cache_id(date,_owner),
start_date: date, start_date: date,
end_date: end, end_date: end,
owner: grid_count > 1 ? state.state.owner[owner] || 0 : state.state.owner owner: _owner
}); });
} }
break; break;
} }
// If we have cached data for the timespan, pass it along // If we have cached data for the timespan, pass it along
this._need_data(value,state.state); this._need_data(value,state.state);
if(grid)
{
grid.set_value(
{content: value}
);
// Weekend needs to be done seperately var row_index = 0;
// Find any matching, existing rows - they can be kept
grid.iterateOver(function(widget) { grid.iterateOver(function(widget) {
for(var i = 0; i < value.length; i++)
{
if(widget.id == value[i].id)
{
// Keep it, but move it
if(i > row_index)
{
for(var j = i-row_index; j > 0; j--)
{
// Move from the end to the start
grid._children.unshift(grid._children.pop());
// Swap DOM nodes
var a = grid._children[0].getDOMNode().parentNode.parentNode;
var b = grid._children[1].getDOMNode().parentNode.parentNode;
a.parentNode.insertBefore(a,b);
}
}
else if (row_index > i)
{
for(var j = row_index - i; j > 0; j--)
{
// Move from the start to the end
grid._children.push(grid._children.shift());
// Swap DOM nodes
var a = grid._children[grid._children.length - 1].getDOMNode().parentNode.parentNode;
a.parentNode.insertBefore(a,null);
}
}
break;
}
}
row_index++;
},this,et2_calendar_view);
row_index = 0;
// Set rows that need it
grid.iterateOver(function(widget) {
if(row_index < value.length)
{
widget.set_disabled(false);
}
else
{
widget.set_disabled(true);
return;
}
if(widget.set_show_weekend) if(widget.set_show_weekend)
{ {
widget.set_show_weekend(view.show_weekend(state.state)); widget.set_show_weekend(view.show_weekend(state.state));
} }
if(widget.id == value[row_index].id &&
widget.get_end_date().toJSON() == value[row_index].end_date
)
{
// Do not need to re-set this row, but we do need to re-do
// the times, as they may have changed
widget.invalidate();
row_index++;
return;
}
if(widget.set_value)
{
widget.set_value(value[row_index++]);
}
},this, et2_calendar_view); },this, et2_calendar_view);
// Granularity needs to be done seperately
grid.iterateOver(function(widget) { grid.iterateOver(function(widget) {
if(widget.set_granularity) if(widget.set_granularity)
{ {
widget.set_granularity(view.granularity(state.state)); widget.set_granularity(view.granularity(state.state));
} }
},this, et2_calendar_view); if(widget.resize)
{
widget.resize();
}
},this,et2_calendar_view);
// Single day with multiple owners still needs owners split to satisfy
// caching keys, otherwise they'll cache consolidated
if(state.state.view == 'day' && state.state.owner.length < parseInt(this.egw.preference('day_consolidate','calendar')))
{
value = [];
for(var i = 0; i < state.state.owner.length; i++)
{
value.push({
start_date: state.state.first,
end_date: state.state.last,
owner: state.state.owner[i]
});
}
this._need_data(value,state.state);
} }
} }
else else
{ {
// Simple, easy case - just one widget for the selected time span. // Simple, easy case - just one widget for the selected time span. (planner)
// Update existing view's special attribute filters, defined in the view list // Update existing view's special attribute filters, defined in the view list
for(var updater in view) for(var updater in view)
{ {
@ -1936,19 +2023,6 @@ app.classes.calendar = AppJS.extend(
} }
} }
var value = [{start_date: state.state.first, end_date: state.state.last}]; var value = [{start_date: state.state.first, end_date: state.state.last}];
// Single day with multiple owners still needs owners split
if(state.state.view == 'day' && state.state.owner.length < parseInt(this.egw.preference('day_consolidate','calendar')))
{
value = [];
for(var i = 0; i < state.state.owner.length; i++)
{
value.push({
start_date: state.state.first,
end_date: state.state.last,
owner: state.state.owner[i]
});
}
}
this._need_data(value,state.state); this._need_data(value,state.state);
} }
// Include first & last dates in state, mostly for server side processing // Include first & last dates in state, mostly for server side processing
@ -2488,7 +2562,7 @@ app.classes.calendar = AppJS.extend(
{start: start, num_rows:200}, {start: start, num_rows:200},
query, query,
this.id, this.id,
function(data) { function calendar_handleResponse(data) {
console.log(data); console.log(data);
// Look for any updated select options // Look for any updated select options
if(data.rows && data.rows.sel_options && this.sidebox_et2) if(data.rows && data.rows.sel_options && this.sidebox_et2)
@ -3282,10 +3356,6 @@ jQuery.extend(app.classes.calendar,{
// Always 7 days, we just turn weekends on or off // Always 7 days, we just turn weekends on or off
d.setUTCHours(24*7-1); d.setUTCHours(24*7-1);
return d; return d;
},
granularity: function(state) {
// Does not care how many users you select
return parseInt(egw.preference('interval','calendar')) || 30;
} }
}), }),
month: app.classes.calendar.prototype.View.extend({ month: app.classes.calendar.prototype.View.extend({

View File

@ -93,6 +93,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
// Percentage; not yet available // Percentage; not yet available
titleHeight: 2.0 titleHeight: 2.0
} }
this.registeredUID = null;
}, },
doLoadingFinished: function() { doLoadingFinished: function() {
@ -122,7 +124,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
this.date_helper.destroy(); this.date_helper.destroy();
this.date_helper = null; this.date_helper = null;
egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); egw.dataUnregisterUID(this.registeredUID,false,this);
}, },
/** /**
@ -248,9 +250,11 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
return; return;
} }
if(this.options.date) var cache_id = app.classes.calendar._daywise_cache_id(new_date,this.options.owner);
if(this.options.date && this.registeredUID &&
cache_id !== this.registeredUID)
{ {
egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); egw.dataUnregisterUID(this.registeredUID,false,this);
// Remove existing events // Remove existing events
while(this._children.length > 0) while(this._children.length > 0)
@ -271,11 +275,10 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
// Register for updates on events for this day // Register for updates on events for this day
var cache_id = app.classes.calendar._daywise_cache_id(new_date,this.options.owner); if(this.registeredUID !== cache_id)
egw.dataRegisterUID(cache_id, this._data_callback,this,this.getInstanceManager().execId,this.id); {
this.registeredUID = cache_id;
if(events) { egw.dataRegisterUID(this.registeredUID, this._data_callback,this,this.getInstanceManager().execId,this.id);
this._update_events(events);
} }
}, },
@ -295,17 +298,22 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
return; return;
} }
egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); var cache_id = app.classes.calendar._daywise_cache_id(this.options.date,_owner)
if(this.options.date && this.registeredUID &&
cache_id !== this.registeredUID)
{
egw.dataUnregisterUID(this.registeredUID,false,this);
}
this.options.owner = _owner; this.options.owner = _owner;
this.title this.title
.attr("data-owner", this.options.owner); .attr("data-owner", this.options.owner);
// Register for updates on events for this day if(this.registeredUID !== cache_id)
egw.dataRegisterUID( {
app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner), this.registeredUID = cache_id;
this._data_callback,this,this.getInstanceManager().execId,this.id egw.dataRegisterUID(this.registeredUID, this._data_callback,this,this.getInstanceManager().execId,this.id);
); }
}, },
/** /**
@ -445,22 +453,20 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
{ {
// Create event // Create event
var event = et2_createWidget('calendar-event',{ var event = et2_createWidget('calendar-event',{
id:events[c].id, id:'event_'+events[c].id,
value: events[c] value: events[c]
},this); },this);
if(this.isInTree())
{
event.doLoadingFinished();
}
// Copy actions set in parent
event._link_actions(this._parent._parent.options.actions||{});
} }
// Seperate loop so column sorting finds all children in the right place // Seperate loop so column sorting finds all children in the right place
for(var c = 0; c < events.length && c < this._children.length; c++) for(var c = 0; c < events.length && c < this._children.length; c++)
{ {
this.getWidgetById(events[c].id).set_value(events[c]); var event = this.getWidgetById('event_'+events[c].id);
if(!event) continue;
if(this.isInTree())
{
event.doLoadingFinished();
}
} }
// Apply styles to hidden events // Apply styles to hidden events

View File

@ -97,6 +97,16 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
this.options.date = ''; this.options.date = '';
this.set_date(date); this.set_date(date);
} }
if(this.options.value && this.options.value.row_id)
{
egw.dataRegisterUID(
'calendar::'+this.options.value.row_id,
this._UID_callback ,
this,
this.getInstanceManager().execId,
this.id
);
}
}, },
destroy: function() { destroy: function() {
@ -131,14 +141,27 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Un-register for updates // Un-register for updates
if(this.options.value) if(this.options.value)
{ {
var old_app_id = this.options.value.app_id; var old_id = this.options.value.row_id;
egw.dataUnregisterUID('calendar::'+old_app_id,false,this); if(!_value || !_value.row_id || old_id !== _value.row_id)
{
egw.dataUnregisterUID('calendar::'+old_id,false,this);
}
} }
this.options.value = _value; this.options.value = _value;
// Register for updates // Register for updates
var app_id = this.options.value.app_id; var id = this.options.value.row_id;
egw.dataRegisterUID('calendar::'+app_id, function _UID_callback(event) { if(!old_id || old_id !== id)
{
egw.dataRegisterUID('calendar::'+id, this._UID_callback ,this,this.getInstanceManager().execId,this.id);
}
if(_value && !egw.dataHasUID('calendar::'+id))
{
egw.dataStoreUID('calendar::'+id, _value);
}
},
_UID_callback: function _UID_callback(event) {
// Make sure id is a string // Make sure id is a string
this._values_check(event); this._values_check(event);
@ -164,15 +187,15 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Parent may remove this if the date isn't the same // Parent may remove this if the date isn't the same
if(this._parent) if(this._parent)
{ {
// This gives some slight speed enhancements over doing it immediately,
// but it looks weird
/*
window.setTimeout(jQuery.proxy(function() {
if(this.options) this._update(this.options.value);
},this),100);
*/
this._update(this.options.value); this._update(this.options.value);
} }
},this,this.getInstanceManager().execId,this.id);
if(_value && !egw.dataHasUID('calendar::'+app_id))
{
egw.dataStoreUID('calendar::'+app_id, _value);
}
}, },
_update: function(event) { _update: function(event) {
@ -180,15 +203,19 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Copy new information // Copy new information
this.options.value = event; this.options.value = event;
var app_id = event.app_id ? event.app_id : event.id + (event.recur_type ? ':'+event.recur_date : ''); var id = event.row_id ? event.row_id : event.id + (event.recur_type ? ':'+event.recur_date : '');
this._parent.date_helper.set_value(event.start.valueOf ? new Date(event.start) : event.start); this._parent.date_helper.set_value(event.start.valueOf ? new Date(event.start) : event.start);
var formatted_start = this._parent.date_helper.getValue(); var formatted_start = this._parent.date_helper.getValue();
this.set_id('event_' + event.app_id); this.set_id('event_' + id);
if(this._actionObject) if(this._actionObject)
{ {
this._actionObject.id = 'calendar::' + event.app_id; this._actionObject.id = 'calendar::' + id;
} }
// Copy actions set in parent
this._link_actions(this._parent._parent._parent.options.actions||{});
// Make sure category stuff is there // Make sure category stuff is there
// Fake it to use the cache / call - if already there, these will return // Fake it to use the cache / call - if already there, these will return
// immediately. // immediately.
@ -217,7 +244,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Put everything we need for basic interaction here, so it's available immediately // Put everything we need for basic interaction here, so it's available immediately
.attr('data-id', event.id) .attr('data-id', event.id)
.attr('data-app', event.app || 'calendar') .attr('data-app', event.app || 'calendar')
.attr('data-app_id', app_id) .attr('data-app_id', event.app_id)
.attr('data-start', formatted_start) .attr('data-start', formatted_start)
.attr('data-owner', event.owner) .attr('data-owner', event.owner)
.attr('data-recur_type', event.recur_type) .attr('data-recur_type', event.recur_type)

View File

@ -692,30 +692,29 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
window.clearTimeout(this.update_timer); window.clearTimeout(this.update_timer);
} }
this.update_timer = window.setTimeout(jQuery.proxy(function() { this.update_timer = window.setTimeout(jQuery.proxy(function() {
this.doInvalidate = false; this.widget.doInvalidate = false;
this.widget.value = this.widget._fetch_data();
// Show AJAX loader // Show AJAX loader
framework.applications.calendar.sidemenuEntry.showAjaxLoader(); this.widget.loader.show();
this.widget.value = this.widget._fetch_data();
this.widget._drawGrid(); this.widget._drawGrid();
// Update actions // Update actions
if(this._actionManager) if(this.widget._actionManager)
{ {
this._link_actions(this._actionManager.children); this.widget._link_actions(this.widget._actionManager.children);
} }
// Hide AJAX loader
framework.applications.calendar.sidemenuEntry.hideAjaxLoader();
if(this.trigger) if(this.trigger)
{ {
this.widget.change(); this.widget.change();
} }
this.widget.update_timer = null; this.widget.update_timer = null;
this.doInvalidate = true; this.widget.doInvalidate = true;
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this.widget),100);
},{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT);
}, },

View File

@ -227,22 +227,20 @@ var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM],
{ {
// Create event // Create event
var event = et2_createWidget('calendar-event',{ var event = et2_createWidget('calendar-event',{
id:events[c].id, id:'event_'+events[c].row_id,
value: events[c] value: events[c]
},this); },this);
if(this.isInTree())
{
event.doLoadingFinished();
}
// Copy actions set in parent
event._link_actions(this._parent._parent.options.actions||this._parent.options.actions||{});
} }
// Seperate loop so column sorting finds all children in the right place // Seperate loop so column sorting finds all children in the right place
for(var c = 0; c < events.length && c < this._children.length; c++) for(var c = 0; c < events.length && c < this._children.length; c++)
{ {
this.getWidgetById(events[c].id).set_value(events[c]); var event = this.getWidgetById('event_'+events[c].row_id);
if(!event) continue;
if(this.isInTree())
{
event.doLoadingFinished();
}
} }
}, },

View File

@ -96,7 +96,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Contains times / rows // Contains times / rows
this.scrolling = $j(document.createElement('div')) this.scrolling = $j(document.createElement('div'))
.addClass("calendar_calTimeGridScroll") .addClass("calendar_calTimeGridScroll")
.appendTo(this.div); .appendTo(this.div)
.append('<div class="calendar_calTimeLabels"></div>');
// Contains days / columns // Contains days / columns
this.days = $j(document.createElement("div")) this.days = $j(document.createElement("div"))
@ -500,10 +501,13 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.day_list = []; this.day_list = [];
// Wait a bit to see if anything else changes, then re-draw the days // Wait a bit to see if anything else changes, then re-draw the days
if(this.update_timer === null) if(this.update_timer)
{ {
window.clearTimeout(this.update_timer);
}
this.update_timer = window.setTimeout(jQuery.proxy(function() { this.update_timer = window.setTimeout(jQuery.proxy(function() {
this.widget.update_timer = null; this.widget.update_timer = null;
this.widget.loader.hide().show();
// Update actions // Update actions
if(this.widget._actionManager) if(this.widget._actionManager)
@ -512,13 +516,16 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
} }
this.widget._drawDays(); this.widget._drawDays();
this.widget._resizeTimes(); // We have to completely re-do times, as they may have changed in
// scale to the point where more labels are needed / need to be removed
this.widget._drawTimes();
if(this.trigger) if(this.trigger)
{ {
this.widget.change(); this.widget.change();
} }
// Hide loader
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this.widget),100);
},{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT);
}
}, },
detachFromDOM: function() { detachFromDOM: function() {
@ -562,6 +569,14 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
} }
}, },
set_disabled: function(disabled) {
this._super.apply(this, arguments);
if(disabled)
{
this.loader.show();
}
},
/** /**
* Clear everything, and redraw the whole grid * Clear everything, and redraw the whole grid
*/ */
@ -569,6 +584,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.div.css('height', this.options.height) this.div.css('height', this.options.height)
.empty(); .empty();
this.loader.prependTo(this.div).show();
// Draw in the horizontal - the times // Draw in the horizontal - the times
this._drawTimes(); this._drawTimes();
@ -605,7 +621,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.scrolling this.scrolling
.css('height', (this.div.innerHeight() - header_height)+'px') .css('height', (this.div.innerHeight() - header_height)+'px')
.appendTo(this.div) .appendTo(this.div)
.empty()
.off().on('scroll', jQuery.proxy(this._scroll, this)); .off().on('scroll', jQuery.proxy(this._scroll, this));
// Percent // Percent
@ -615,10 +630,18 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// We need a reasonable bottom limit here... // We need a reasonable bottom limit here...
if(this.rowHeight < 5 && this.div.is(':visible')) if(this.rowHeight < 5 && this.div.is(':visible'))
{
if(this.rowHeight === 0)
{
// Something is not right...
this.rowHeight = 5;
}
else
{ {
this.options.granularity *= 2; this.options.granularity *= 2;
return this._drawTimes(); return this._drawTimes();
} }
}
// the hour rows // the hour rows
var show = { var show = {
@ -659,8 +682,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
} }
// Set heights in pixels for scrolling // Set heights in pixels for scrolling
this.scrolling $j('.calendar_calTimeLabels',this.scrolling)
.append('<div class="calendar_calTimeLabels">' + html + '</div>'); .empty()
.append(html);
this.days.css('height', (this.rowHeight*i)+'px'); this.days.css('height', (this.rowHeight*i)+'px');
// Scroll to start of day // Scroll to start of day
@ -797,18 +821,18 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
day.set_left((day_width * i) + 'px'); day.set_left((day_width * i) + 'px');
if(daily_owner) if(daily_owner)
{ {
day.set_id(this.day_list[0]+'-'+this.options.owner[i]);
day.set_date(this.day_list[0], false); day.set_date(this.day_list[0], false);
day.set_owner(this.options.owner[i]); day.set_owner(this.options.owner[i]);
day.set_id(this.day_list[0]+'-'+this.options.owner[i]);
day.set_label(this._get_owner_name(this.options.owner[i])); day.set_label(this._get_owner_name(this.options.owner[i]));
} }
else else
{ {
// Go back to self-calculated date // Go back to self-calculated date
day.set_label(''); day.set_label('');
day.set_id(this.day_list[i]);
day.set_date(this.day_list[i], this.value[this.day_list[i]] || false); day.set_date(this.day_list[i], this.value[this.day_list[i]] || false);
day.set_owner(this.options.owner); day.set_owner(this.options.owner);
day.set_id(this.day_list[i]);
} }
day.set_width(day_width + 'px'); day.set_width(day_width + 'px');
} }
@ -816,6 +840,11 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Don't hold on to value any longer, use the data cache for best info // Don't hold on to value any longer, use the data cache for best info
this.value = {}; this.value = {};
if(daily_owner)
{
this.set_label('');
}
// Adjust and scroll to start of day // Adjust and scroll to start of day
this._resizeTimes(); this._resizeTimes();
@ -1191,6 +1220,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
{ {
if(typeof events !== 'object') return false; if(typeof events !== 'object') return false;
this.loader.show();
var use_days_sent = true; var use_days_sent = true;
if(events.id) if(events.id)
@ -1198,11 +1228,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.set_id(events.id); this.set_id(events.id);
delete events.id; delete events.id;
} }
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
if(events.start_date) if(events.start_date)
{ {
this.set_start_date(events.start_date); this.set_start_date(events.start_date);
@ -1215,6 +1240,13 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
delete events.end_date; delete events.end_date;
use_days_sent = false; use_days_sent = false;
} }
// set_owner() wants start_date set to get the correct week number
// for the corner label
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
this.value = events || {}; this.value = events || {};
@ -1230,6 +1262,12 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Reset and calculate instead of just use the keys so we can get the weekend preference // Reset and calculate instead of just use the keys so we can get the weekend preference
this.day_list = []; this.day_list = [];
// None of the above changed anything, hide the loader
if(!this.update_timer)
{
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this),100);
}
}, },
/** /**
@ -1244,6 +1282,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
var old = this.options.owner || 0; var old = this.options.owner || 0;
this.owner.set_label(''); this.owner.set_label('');
this.div.removeClass('calendar_TimeGridNoLabel'); this.div.removeClass('calendar_TimeGridNoLabel');
this.options.owner = _owner;
if(typeof _owner == 'string' && isNaN(_owner)) if(typeof _owner == 'string' && isNaN(_owner))
{ {
@ -1262,7 +1301,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Label is empty, but give extra space for the owner name // Label is empty, but give extra space for the owner name
this.div.removeClass('calendar_TimeGridNoLabel'); this.div.removeClass('calendar_TimeGridNoLabel');
} }
else if (typeof _owner == 'object' && _owner.length) else if (!_owner || typeof _owner == 'object' && _owner.length)
{ {
// Don't show owners if more than one, show week number // Don't show owners if more than one, show week number
this.owner.set_value(''); this.owner.set_value('');
@ -1275,10 +1314,10 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
{ {
this.owner.options.application = 'home-accounts' this.owner.options.application = 'home-accounts'
this.owner.set_value(typeof _owner == "string" || typeof _owner == "number" ? _owner : jQuery.extend([],_owner)); this.owner.set_value(typeof _owner == "string" || typeof _owner == "number" ? _owner : jQuery.extend([],_owner));
this.set_label('');
$j(this.getDOMNode(this.owner)).prepend(this.owner.getDOMNode()); $j(this.getDOMNode(this.owner)).prepend(this.owner.getDOMNode());
} }
this.options.owner = _owner;//this.owner.getValue();
if(this.isAttached() && ( if(this.isAttached() && (
typeof old == "number" && typeof _owner == "number" && old !== this.options.owner || typeof old == "number" && typeof _owner == "number" && old !== this.options.owner ||
// Array of ids will not compare as equal // Array of ids will not compare as equal
@ -1304,7 +1343,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// If it's a short label (eg week number), don't give it an extra line // If it's a short label (eg week number), don't give it an extra line
// but is empty, but give extra space for a single owner name // but is empty, but give extra space for a single owner name
this.div.removeClass('calendar_TimeGridNoLabel');
this.div.toggleClass('calendar_TimeGridNoLabel', label.trim().length < 6 && typeof this.options.owner === 'object'); this.div.toggleClass('calendar_TimeGridNoLabel', label.trim().length < 6 && typeof this.options.owner === 'object');
}, },
@ -1318,11 +1356,15 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Avoid 0 or less // Avoid 0 or less
minutes = Math.max(1,minutes); minutes = Math.max(1,minutes);
if(this.options.granularity != minutes) if(this.options.granularity !== minutes)
{ {
this.options.granularity = minutes; this.options.granularity = minutes;
this._drawTimes(); this._drawTimes();
} }
else
{
this._resizeTimes();
}
}, },
/** /**
@ -1332,9 +1374,10 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
*/ */
set_show_weekend: function(weekends) set_show_weekend: function(weekends)
{ {
weekends = weekends ? true : false;
if(this.options.show_weekend !== weekends) if(this.options.show_weekend !== weekends)
{ {
this.options.show_weekend = weekends ? true : false; this.options.show_weekend = weekends;
if(this.isAttached()) if(this.isAttached())
{ {
this.invalidate(); this.invalidate();
@ -1430,7 +1473,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
result = this.onclick.apply(this, args); result = this.onclick.apply(this, args);
} }
if(event.id && result && !this.options.disabled && !this.options.readonly) if(event.id && result && !this.disabled && !this.options.readonly)
{ {
et2_calendar_event.recur_prompt(event); et2_calendar_event.recur_prompt(event);
@ -1539,33 +1582,35 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Resizable interface // Resizable interface
resize: function () resize: function ()
{ {
if(!this.div.is(':visible')) if(this.disabled || !this.div.is(':visible'))
{ {
return; return;
} }
// Set the max width to avoid animations screwing up the width
this.div.css('max-width',$j(this.getInstanceManager().DOMContainer).width());
// We expect the timegrid to be in a table with 0 or more other timegrids, // We expect the timegrid to be in a table with 0 or more other timegrids,
// 1 per row. We want each timegrid to be as large as possible, but space // 1 per row. We want each timegrid to be as large as possible, but space
// shared equally. Height can't be set to a percentage on the rows, because // shared equally. Height can't be set to a percentage on the rows, because
// that doesn't work. // that doesn't work.
// Find the table
var table = this.div.parentsUntil('table').parent();
// How many rows? // How many rows?
var rowCount = table.children('tr').length; var rowCount = 0;
this._parent.iterateOver(function(widget) {
if(!widget.disabled) rowCount++;
},this, et2_calendar_timegrid);
// Take the whole tab height // Take the whole tab height
this.options.height = Math.floor(Math.min($j(this.getInstanceManager().DOMContainer).height(),$j(this.getInstanceManager().DOMContainer).parent().innerHeight()) / rowCount); this.options.height = Math.floor(Math.min($j(this.getInstanceManager().DOMContainer).height(),$j(this.getInstanceManager().DOMContainer).parent().innerHeight()) / rowCount);
this.options.height = Math.floor((egw.getHiddenDimensions(this.getInstanceManager().DOMContainer).h ) / rowCount); this.options.height = Math.floor((egw.getHiddenDimensions(this.getInstanceManager().DOMContainer).h ) / rowCount);
this.options.height -= 2*((this.div.outerWidth(true) - this.div.innerWidth()) + parseInt(this.div.parent().css('padding-top'))); this.options.height -= 2*((this.div.outerWidth(true) - this.div.innerWidth()) + parseInt(this.div.parent().css('padding-top')));
if(this.options.height+"px" !== this.div.css('height'))
if(this.options.height+"px" != this.div.css('height'))
{ {
this.div.css('height', this.options.height); this.div.css('height', this.options.height);
// Re-do time grid // Re-do time grid
this._drawGrid(); this._drawTimes();
// Just re-did everything, no need to do more // Just re-did everything, no need to do more
return; return;
@ -1575,8 +1620,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
var total_width = ( $j(this.getInstanceManager().DOMContainer).width() - ( var total_width = ( $j(this.getInstanceManager().DOMContainer).width() - (
this.days.innerWidth() ? this.div.innerWidth() - this.days.innerWidth() : 0 this.days.innerWidth() ? this.div.innerWidth() - this.days.innerWidth() : 0
)); ));
// Set the max width to avoid animations screwing up the width
this.div.css('max-width',$j(this.getInstanceManager().DOMContainer).width());
var day_width = (total_width > 0 ? total_width : $j(this.getInstanceManager().DOMContainer).width())/this.day_widgets.length; var day_width = (total_width > 0 ? total_width : $j(this.getInstanceManager().DOMContainer).width())/this.day_widgets.length;
// update day widgets // update day widgets
for(var i = 0; i < this.day_widgets.length; i++) for(var i = 0; i < this.day_widgets.length; i++)

View File

@ -43,7 +43,7 @@ var et2_calendar_view = et2_valueWidget.extend(
/** /**
* Constructor * Constructor
* *
* @memberOf et2_calendar_planner * @memberOf et2_calendar_view
* @constructor * @constructor
*/ */
init: function init() { init: function init() {
@ -52,6 +52,8 @@ var et2_calendar_view = et2_valueWidget.extend(
// Used for its date calculations // Used for its date calculations
this.date_helper = et2_createWidget('date-time',{},null); this.date_helper = et2_createWidget('date-time',{},null);
this.date_helper.loadingFinished(); this.date_helper.loadingFinished();
this.loader = $j('<div class="egw-loading-prompt-container ui-front loading"></div>');
}, },
destroy: function destroy() { destroy: function destroy() {
@ -62,22 +64,53 @@ var et2_calendar_view = et2_valueWidget.extend(
this.date_helper = null; this.date_helper = null;
}, },
doLoadingFinished: function() {
this._super.apply(this, arguments);
this.loader.hide(0).prependTo(this.div);
},
/** /**
* Something changed, and the view need to be re-drawn. We wait a bit to * Something changed, and the view need to be re-drawn. We wait a bit to
* avoid re-drawing twice if start and end date both changed, then recreate * avoid re-drawing twice if start and end date both changed, then recreate
* as needed. * as needed.
* *
* @param {boolean} [trigger=false] Trigger an event once things are done. * @param {boolean} [trigger_event=false] Trigger an event once things are done.
* Waiting until invalidate completes prevents 2 updates when changing the date range. * Waiting until invalidate completes prevents 2 updates when changing the date range.
* @returns {undefined} * @returns {undefined}
*
* @memberOf et2_calendar_view
*/ */
invalidate: function invalidate(trigger) {}, invalidate: function invalidate(trigger_event) {},
/**
* Returns the current start date
*
* @returns {Date}
*
* @memberOf et2_calendar_view
*/
get_start_date: function get_start_date() {
return new Date(this.options.start_date);
},
/**
* Returns the current start date
*
* @returns {Date}
*
* @memberOf et2_calendar_view
*/
get_end_date: function get_end_date() {
return new Date(this.options.end_date);
},
/** /**
* Change the start date * Change the start date
* *
* @param {string|number|Date} new_date New starting date * @param {string|number|Date} new_date New starting date
* @returns {undefined} * @returns {undefined}
*
* @memberOf et2_calendar_view
*/ */
set_start_date: function set_start_date(new_date) set_start_date: function set_start_date(new_date)
{ {
@ -112,6 +145,8 @@ var et2_calendar_view = et2_valueWidget.extend(
* *
* @param {string|number|Date} new_date New end date * @param {string|number|Date} new_date New end date
* @returns {undefined} * @returns {undefined}
*
* @memberOf et2_calendar_view
*/ */
set_end_date: function set_end_date(new_date) set_end_date: function set_end_date(new_date)
{ {
@ -144,6 +179,8 @@ var et2_calendar_view = et2_valueWidget.extend(
* Set which users to display * Set which users to display
* *
* @param {number|number[]|string|string[]} _owner Account ID * @param {number|number[]|string|string[]} _owner Account ID
*
* @memberOf et2_calendar_view
*/ */
set_owner: function set_owner(_owner) set_owner: function set_owner(_owner)
{ {
@ -176,6 +213,8 @@ var et2_calendar_view = et2_valueWidget.extend(
* *
* @param {string} user * @param {string} user
* @returns {string} * @returns {string}
*
* @memberOf et2_calendar_view
*/ */
_get_owner_name: function _get_owner_name(user) { _get_owner_name: function _get_owner_name(user) {
if(parseInt(user) === 0) if(parseInt(user) === 0)

View File

@ -61,6 +61,9 @@
width: 100%; width: 100%;
transition: width 1s ease-in-out; transition: width 1s ease-in-out;
} }
#calendar-view_view td {
padding: 0px;
}
/* Header classes */ /* Header classes */
tr.dialogHeader td, tr.dialogHeader2 td, tr.dialogHeader3 td, tr.dialogHeader4 td, tr.dialogHeader td, tr.dialogHeader2 td, tr.dialogHeader3 td, tr.dialogHeader4 td,
tr.dialogOperators td,.dialogFooterToolbar { tr.dialogOperators td,.dialogFooterToolbar {
@ -171,6 +174,13 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
overflow-x: hidden; overflow-x: hidden;
} }
.calendar_calTimeGrid .loading,.calendar_plannerWidget .loading {
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
position: absolute;
}
/* single row in the time-line you dont need to set a bgcolor, but you can /* single row in the time-line you dont need to set a bgcolor, but you can
*/ */
.calendar_calTimeRow { .calendar_calTimeRow {
@ -624,7 +634,6 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 99.5%; width: 99.5%;
border: 1px solid gray;
padding-right: 3px; padding-right: 3px;
} }
.calendar_plannerWidget > div:not(.calendar_plannerHeader) { .calendar_plannerWidget > div:not(.calendar_plannerHeader) {
@ -723,14 +732,14 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
text-overflow: ellipsis; text-overflow: ellipsis;
white-space:nowrap; white-space:nowrap;
overflow:hidden; overflow:hidden;
margin-left: 20px; padding-left: 20px;
padding-right: 2px; padding-right: 2px;
} }
.calendar_plannerRowHeader:hover { .calendar_plannerRowHeader:hover {
width: initial !important; width: initial !important;
overflow:visible; overflow:visible;
z-index: 30; z-index: 30;
background-color: white; cursor: pointer;
} }
/* calendar_eventRows contain multiple eventRowWidgets /* calendar_eventRows contain multiple eventRowWidgets

View File

@ -22,6 +22,7 @@ Egroupware
<calendar-timegrid id="${row}" <calendar-timegrid id="${row}"
onchange="var state = {}; if(widget.options.start_date == widget.options.end_date) state.view = 'day'; app.calendar.update_state(state);" onchange="var state = {}; if(widget.options.start_date == widget.options.end_date) state.view = 'day'; app.calendar.update_state(state);"
onevent_change="app.calendar.event_change" onevent_change="app.calendar.event_change"
disabled="true"
> >
</calendar-timegrid> </calendar-timegrid>
</row> </row>