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');
}
// 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['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;';
}
// 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
foreach(array('start','end') as $time)
{

View File

@ -661,20 +661,36 @@ class calendar_uiviews extends calendar_ui
$content = array('view' => array());
// 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);
if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row
if(!$home)
{
$content['view'][] = (array)$this->tagWholeDayOnTop($this->bo->search($search_params)) +
array('owner' => $users);
// 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
{
foreach($this->_get_planner_users(false) as $uid => $label)
// 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);
if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row
{
$search_params['users'] = $uid;
$content['view'][] = $this->tagWholeDayOnTop($this->bo->search($search_params))
+ array('owner' => $uid);
$content['view'][] = (array)$this->tagWholeDayOnTop($this->bo->search($search_params)) +
array('owner' => $users);
}
else
{
foreach($this->_get_planner_users(false) as $uid => $label)
{
$search_params['users'] = $uid;
$content['view'][] = $this->tagWholeDayOnTop($this->bo->search($search_params))
+ array('owner' => $uid);
}
}
}
$tmpl = $home ? $home :new etemplate_new('calendar.view');

View File

@ -1594,7 +1594,7 @@ app.classes.calendar = AppJS.extend(
*
* @param {Object} _set New settings
*/
update_state: function(_set)
update_state: function update_state(_set)
{
// Make sure we're running in top window
if(window !== window.top)
@ -1632,7 +1632,7 @@ app.classes.calendar = AppJS.extend(
*
* @return {object} description
*/
getState: function()
getState: function getState()
{
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
*/
setState: function(state)
setState: function setState(state)
{
// State should be an object, not a string, but we'll parse
if(typeof state == "string")
@ -1730,7 +1730,7 @@ app.classes.calendar = AppJS.extend(
}
// 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)));
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');
/*
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
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 = [];
state.state.first = view.start_date(state.state).toJSON();
// We'll modify this one, so it needs to be a new object
var date = new Date(state.state.first);
// Determine the different end date
// Determine the different end date & varying values
switch(state.state.view)
{
case 'month':
@ -1861,59 +1860,147 @@ app.classes.calendar = AppJS.extend(
for(var week = 0; week < grid_count; week++)
{
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(),
end_date: new Date(date.toJSON()),
owner: state.state.owner
};
val.end_date.setUTCHours(24*7-1);
val.end_date.setUTCMinutes(59);
val.end_date.setUTCSeconds(59);
val.end_date = val.end_date.toJSON();
value.push(val);
date.setUTCHours(24*7);
}
state.state.last=val.end_date;
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:
var end = state.state.last = view.end_date(state.state).toJSON();
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({
id: ""+date.getUTCFullYear() + sprintf("%02d",date.getUTCMonth()) + sprintf("%02d",date.getUTCDate()),
id: app.classes.calendar._daywise_cache_id(date,_owner),
start_date: date,
end_date: end,
owner: grid_count > 1 ? state.state.owner[owner] || 0 : state.state.owner
owner: _owner
});
}
break;
}
// If we have cached data for the timespan, pass it along
this._need_data(value,state.state);
if(grid)
var row_index = 0;
// Find any matching, existing rows - they can be kept
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)
{
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);
grid.iterateOver(function(widget) {
if(widget.set_granularity)
{
widget.set_granularity(view.granularity(state.state));
}
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')))
{
grid.set_value(
{content: value}
);
// Weekend needs to be done seperately
grid.iterateOver(function(widget) {
if(widget.set_show_weekend)
{
widget.set_show_weekend(view.show_weekend(state.state));
}
},this, et2_calendar_view);
// Granularity needs to be done seperately
grid.iterateOver(function(widget) {
if(widget.set_granularity)
{
widget.set_granularity(view.granularity(state.state));
}
},this, et2_calendar_view);
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
{
// 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
for(var updater in view)
{
@ -1929,26 +2016,13 @@ app.classes.calendar = AppJS.extend(
view.etemplates[i].widgetContainer.iterateOver(function(widget) {
if(typeof widget['set_'+updater] === 'function')
{
widget['set_'+updater](value);
widget['set_'+updater](value);
}
}, this, et2_calendar_view);
}
}
}
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);
}
// 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},
query,
this.id,
function(data) {
function calendar_handleResponse(data) {
console.log(data);
// Look for any updated select options
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
d.setUTCHours(24*7-1);
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({

View File

@ -93,6 +93,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
// Percentage; not yet available
titleHeight: 2.0
}
this.registeredUID = null;
},
doLoadingFinished: function() {
@ -122,7 +124,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
this.date_helper.destroy();
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;
}
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
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
var cache_id = app.classes.calendar._daywise_cache_id(new_date,this.options.owner);
egw.dataRegisterUID(cache_id, this._data_callback,this,this.getInstanceManager().execId,this.id);
if(events) {
this._update_events(events);
if(this.registeredUID !== cache_id)
{
this.registeredUID = cache_id;
egw.dataRegisterUID(this.registeredUID, this._data_callback,this,this.getInstanceManager().execId,this.id);
}
},
@ -295,17 +298,22 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
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.title
.attr("data-owner", this.options.owner);
// Register for updates on events for this day
egw.dataRegisterUID(
app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),
this._data_callback,this,this.getInstanceManager().execId,this.id
);
if(this.registeredUID !== cache_id)
{
this.registeredUID = cache_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
var event = et2_createWidget('calendar-event',{
id:events[c].id,
id:'event_'+events[c].id,
value: events[c]
},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
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

View File

@ -97,6 +97,16 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
this.options.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() {
@ -131,47 +141,60 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Un-register for updates
if(this.options.value)
{
var old_app_id = this.options.value.app_id;
egw.dataUnregisterUID('calendar::'+old_app_id,false,this);
var old_id = this.options.value.row_id;
if(!_value || !_value.row_id || old_id !== _value.row_id)
{
egw.dataUnregisterUID('calendar::'+old_id,false,this);
}
}
this.options.value = _value;
// Register for updates
var app_id = this.options.value.app_id;
egw.dataRegisterUID('calendar::'+app_id, function _UID_callback(event) {
// Make sure id is a string
this._values_check(event);
// Check for changing days in the grid view
if(!this._sameday_check(event))
{
// This should now cease to exist, as new events have been created
this.free();
return;
}
// Copy to avoid changes, which may cause nm problems
this.options.value = jQuery.extend({},event);
if(this._parent.options.date)
{
this.options.value.date = this._parent.options.date;
}
// Let parent position
this._parent.position_event(this);
// Parent may remove this if the date isn't the same
if(this._parent)
{
this._update(this.options.value);
}
},this,this.getInstanceManager().execId,this.id);
if(_value && !egw.dataHasUID('calendar::'+app_id))
var id = this.options.value.row_id;
if(!old_id || old_id !== id)
{
egw.dataStoreUID('calendar::'+app_id, _value);
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
this._values_check(event);
// Check for changing days in the grid view
if(!this._sameday_check(event))
{
// This should now cease to exist, as new events have been created
this.free();
return;
}
// Copy to avoid changes, which may cause nm problems
this.options.value = jQuery.extend({},event);
if(this._parent.options.date)
{
this.options.value.date = this._parent.options.date;
}
// Let parent position
this._parent.position_event(this);
// Parent may remove this if the date isn't the same
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);
}
},
@ -180,15 +203,19 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Copy new information
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);
var formatted_start = this._parent.date_helper.getValue();
this.set_id('event_' + event.app_id);
this.set_id('event_' + id);
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
// Fake it to use the cache / call - if already there, these will return
// 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
.attr('data-id', event.id)
.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-owner', event.owner)
.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);
}
this.update_timer = window.setTimeout(jQuery.proxy(function() {
this.doInvalidate = false;
this.widget.value = this.widget._fetch_data();
this.widget.doInvalidate = false;
// Show AJAX loader
framework.applications.calendar.sidemenuEntry.showAjaxLoader();
this.widget.loader.show();
this.widget.value = this.widget._fetch_data();
this.widget._drawGrid();
// 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)
{
this.widget.change();
}
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);
},

View File

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

View File

@ -96,7 +96,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Contains times / rows
this.scrolling = $j(document.createElement('div'))
.addClass("calendar_calTimeGridScroll")
.appendTo(this.div);
.appendTo(this.div)
.append('<div class="calendar_calTimeLabels"></div>');
// Contains days / columns
this.days = $j(document.createElement("div"))
@ -500,25 +501,31 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.day_list = [];
// Wait a bit to see if anything else changes, then re-draw the days
if(this.update_timer === null)
if(this.update_timer)
{
this.update_timer = window.setTimeout(jQuery.proxy(function() {
this.widget.update_timer = null;
// Update actions
if(this.widget._actionManager)
{
this.widget._link_actions(this.widget._actionManager.children);
}
this.widget._drawDays();
this.widget._resizeTimes();
if(this.trigger)
{
this.widget.change();
}
},{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT);
window.clearTimeout(this.update_timer);
}
this.update_timer = window.setTimeout(jQuery.proxy(function() {
this.widget.update_timer = null;
this.widget.loader.hide().show();
// Update actions
if(this.widget._actionManager)
{
this.widget._link_actions(this.widget._actionManager.children);
}
this.widget._drawDays();
// 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)
{
this.widget.change();
}
// Hide loader
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this.widget),100);
},{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT);
},
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
*/
@ -569,6 +584,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.div.css('height', this.options.height)
.empty();
this.loader.prependTo(this.div).show();
// Draw in the horizontal - the times
this._drawTimes();
@ -605,7 +621,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.scrolling
.css('height', (this.div.innerHeight() - header_height)+'px')
.appendTo(this.div)
.empty()
.off().on('scroll', jQuery.proxy(this._scroll, this));
// Percent
@ -616,8 +631,16 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// We need a reasonable bottom limit here...
if(this.rowHeight < 5 && this.div.is(':visible'))
{
this.options.granularity *= 2;
return this._drawTimes();
if(this.rowHeight === 0)
{
// Something is not right...
this.rowHeight = 5;
}
else
{
this.options.granularity *= 2;
return this._drawTimes();
}
}
// the hour rows
@ -659,8 +682,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
}
// Set heights in pixels for scrolling
this.scrolling
.append('<div class="calendar_calTimeLabels">' + html + '</div>');
$j('.calendar_calTimeLabels',this.scrolling)
.empty()
.append(html);
this.days.css('height', (this.rowHeight*i)+'px');
// Scroll to start of day
@ -797,25 +821,30 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
day.set_left((day_width * i) + 'px');
if(daily_owner)
{
day.set_id(this.day_list[0]+'-'+this.options.owner[i]);
day.set_date(this.day_list[0], false);
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]));
}
else
{
// Go back to self-calculated date
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_owner(this.options.owner);
day.set_id(this.day_list[i]);
}
day.set_width(day_width + 'px');
}
// Don't hold on to value any longer, use the data cache for best info
this.value = {};
if(daily_owner)
{
this.set_label('');
}
// Adjust and scroll to start of day
this._resizeTimes();
@ -1190,7 +1219,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
set_value: function(events)
{
if(typeof events !== 'object') return false;
this.loader.show();
var use_days_sent = true;
if(events.id)
@ -1198,11 +1228,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.set_id(events.id);
delete events.id;
}
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
if(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;
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 || {};
@ -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
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;
this.owner.set_label('');
this.div.removeClass('calendar_TimeGridNoLabel');
this.options.owner = _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
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
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.set_value(typeof _owner == "string" || typeof _owner == "number" ? _owner : jQuery.extend([],_owner));
this.set_label('');
$j(this.getDOMNode(this.owner)).prepend(this.owner.getDOMNode());
}
this.options.owner = _owner;//this.owner.getValue();
if(this.isAttached() && (
typeof old == "number" && typeof _owner == "number" && old !== this.options.owner ||
// 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
// 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');
},
@ -1318,11 +1356,15 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Avoid 0 or less
minutes = Math.max(1,minutes);
if(this.options.granularity != minutes)
if(this.options.granularity !== minutes)
{
this.options.granularity = minutes;
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)
{
weekends = weekends ? true : false;
if(this.options.show_weekend !== weekends)
{
this.options.show_weekend = weekends ? true : false;
this.options.show_weekend = weekends;
if(this.isAttached())
{
this.invalidate();
@ -1430,7 +1473,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
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);
@ -1539,33 +1582,35 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
// Resizable interface
resize: function ()
{
if(!this.div.is(':visible'))
if(this.disabled || !this.div.is(':visible'))
{
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,
// 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
// that doesn't work.
// Find the table
var table = this.div.parentsUntil('table').parent();
// 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
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 -= 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);
// Re-do time grid
this._drawGrid();
this._drawTimes();
// Just re-did everything, no need to do more
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() - (
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;
// update day widgets
for(var i = 0; i < this.day_widgets.length; i++)

View File

@ -43,7 +43,7 @@ var et2_calendar_view = et2_valueWidget.extend(
/**
* Constructor
*
* @memberOf et2_calendar_planner
* @memberOf et2_calendar_view
* @constructor
*/
init: function init() {
@ -52,6 +52,8 @@ var et2_calendar_view = et2_valueWidget.extend(
// Used for its date calculations
this.date_helper = et2_createWidget('date-time',{},null);
this.date_helper.loadingFinished();
this.loader = $j('<div class="egw-loading-prompt-container ui-front loading"></div>');
},
destroy: function destroy() {
@ -62,22 +64,53 @@ var et2_calendar_view = et2_valueWidget.extend(
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
* avoid re-drawing twice if start and end date both changed, then recreate
* 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.
* @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
*
* @param {string|number|Date} new_date New starting date
* @returns {undefined}
*
* @memberOf et2_calendar_view
*/
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
* @returns {undefined}
*
* @memberOf et2_calendar_view
*/
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
*
* @param {number|number[]|string|string[]} _owner Account ID
*
* @memberOf et2_calendar_view
*/
set_owner: function set_owner(_owner)
{
@ -176,6 +213,8 @@ var et2_calendar_view = et2_valueWidget.extend(
*
* @param {string} user
* @returns {string}
*
* @memberOf et2_calendar_view
*/
_get_owner_name: function _get_owner_name(user) {
if(parseInt(user) === 0)

View File

@ -61,6 +61,9 @@
width: 100%;
transition: width 1s ease-in-out;
}
#calendar-view_view td {
padding: 0px;
}
/* Header classes */
tr.dialogHeader td, tr.dialogHeader2 td, tr.dialogHeader3 td, tr.dialogHeader4 td,
tr.dialogOperators td,.dialogFooterToolbar {
@ -171,6 +174,13 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
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
*/
.calendar_calTimeRow {
@ -624,7 +634,6 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px;
left: 0px;
width: 99.5%;
border: 1px solid gray;
padding-right: 3px;
}
.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;
white-space:nowrap;
overflow:hidden;
margin-left: 20px;
padding-left: 20px;
padding-right: 2px;
}
.calendar_plannerRowHeader:hover {
width: initial !important;
overflow:visible;
z-index: 30;
background-color: white;
cursor: pointer;
}
/* calendar_eventRows contain multiple eventRowWidgets

View File

@ -22,6 +22,7 @@ Egroupware
<calendar-timegrid id="${row}"
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"
disabled="true"
>
</calendar-timegrid>
</row>