Calendar et2 conversion work in progress.

- Start of planner view
- Scroll moved to app.js so month works better
This commit is contained in:
Nathan Gray 2015-06-25 17:44:28 +00:00
parent 558589c1eb
commit 4648f91bb7
12 changed files with 2067 additions and 55 deletions

View File

@ -710,17 +710,17 @@ class calendar_ui
), ),
array( array(
'text' => lang('planner by category'), 'text' => lang('planner by category'),
'value' => '{"view":"planner", "menuaction":"calendar.calendar_uiviews.planner","sortby":"category"}', 'value' => '{"view":"planner", "sortby":"category"}',
'selected' => $this->view == 'planner' && $this->sortby != 'user', 'selected' => $this->view == 'planner' && $this->sortby != 'user',
), ),
array( array(
'text' => lang('planner by user'), 'text' => lang('planner by user'),
'value' => '{"view":"planner", "menuaction":"calendar.calendar_uiviews.planner","sortby":"user"}', 'value' => '{"view":"planner","sortby":"user"}',
'selected' => $this->view == 'planner' && $this->sortby == 'user', 'selected' => $this->view == 'planner' && $this->sortby == 'user',
), ),
array( array(
'text' => lang('yearly planner'), 'text' => lang('yearly planner'),
'value' => '{"view":"planner", "menuaction":"calendar.calendar_uiviews.planner","sortby":"month"}', 'value' => '{"view":"planner","sortby":"month"}',
'selected' => $this->view == 'planner' && $this->sortby == 'month', 'selected' => $this->view == 'planner' && $this->sortby == 'month',
), ),
array( array(

View File

@ -211,8 +211,24 @@ class calendar_uiviews extends calendar_ui
/** /**
* Show the last view or the default one, if no last * Show the last view or the default one, if no last
*/ */
function index() function index($content)
{ {
if($content['merge'])
{
// View from sidebox is JSON encoded
$this->manage_states(array_merge($content,json_decode($content['view'],true)));
if($content['first'])
{
$this->first = egw_time::to($content['first'],'ts');
}
if($content['last'])
{
$this->last = egw_time::to($content['last'],'ts');
}
$_GET['merge'] = $content['merge'];
$this->merge();
return;
}
if (!$this->view) $this->view = 'week'; if (!$this->view) $this->view = 'week';
// handle views in other files // handle views in other files
@ -240,6 +256,11 @@ class calendar_uiviews extends calendar_ui
// Actually, this takes care of most of it... // Actually, this takes care of most of it...
$this->week(); $this->week();
$tmpl = new etemplate_new('calendar.planner');
// Get the actions
$tmpl->setElementAttribute('planner','actions',$this->get_actions());
$tmpl->exec('calendar_uiviews::index',array());
// List view in a separate file // List view in a separate file
$list_ui = new calendar_uilist(); $list_ui = new calendar_uilist();

View File

@ -12,6 +12,7 @@
/*egw:uses /*egw:uses
/etemplate/js/etemplate2.js; /etemplate/js/etemplate2.js;
/calendar/js/et2_widget_timegrid.js; /calendar/js/et2_widget_timegrid.js;
/calendar/js/et2_widget_planner.js;
*/ */
/** /**
@ -119,6 +120,10 @@ app.classes.calendar = AppJS.extend(
set_start_date: function(state) { set_start_date: function(state) {
var d = state.date ? new Date(state.date) : new Date(); var d = state.date ? new Date(state.date) : new Date();
d.setUTCDate(1); d.setUTCDate(1);
d.setUTCHours(0);
d.setUTCMinutes(0);
d.setUTCSeconds(0);
state.date = d.toJSON();
return app.calendar.date.start_of_week(d); return app.calendar.date.start_of_week(d);
}, },
set_end_date: function(state) { set_end_date: function(state) {
@ -130,7 +135,76 @@ app.classes.calendar = AppJS.extend(
return week_start; return week_start;
}, },
}, },
listview: {etemplates: ['calendar.list']}
planner: {
etemplates: ['calendar.planner'],
set_group_by: function(state) {
return state.cat_id? state.cat_id : (state.sortby ? state.sortby : 0);
},
set_start_date: function(state) {
var d = state.date ? new Date(state.date) : new Date();
if(state.sortby && state.sortby === 'month')
{
d.setUTCDate(1);
}
else if (!state.planner_days)
{
if(d.getUTCDate() < 15)
{
d.setUTCDate(1);
return app.calendar.date.start_of_week(d);
}
else
{
return app.calendar.date.start_of_week(d);
}
}
return d;
},
set_end_date: function(state) {
var d = state.date ? new Date(state.date) : new Date();
if(state.sortby && state.sortby === 'month')
{
d.setUTCDate(0);
d.setUTCFullYear(d.getUTCFullYear() + 1);
}
else if (state.planner_days)
{
d.setUTCDate(d.getUTCDate() + parseInt(state.planner_days)-1);
}
else if (app.calendar.state.last)
{
d = new Date(app.calendar.state.last);
}
else if (!state.planner_days)
{
if (d.getUTCDate() < 15)
{
d.setUTCDate(0);
d.setUTCMonth(d.getUTCMonth()+1);
d = app.calendar.date.end_of_week(d);
}
else
{
d.setUTCMonth(d.getUTCMonth()+1);
d = app.calendar.date.end_of_week(d);
}
}
return d;
},
set_owner: function(state) {
return state.owner || 0;
}
},
listview: {
etemplates: ['calendar.list'],
set_start_date: function(state)
{
var d = state.date ? new Date(state.date) : new Date();
return d;
}
}
}, },
/** /**
@ -162,6 +236,9 @@ app.classes.calendar = AppJS.extend(
//Drag_n_Drop (need to wait for DOM ready to init dnd) //Drag_n_Drop (need to wait for DOM ready to init dnd)
jQuery(jQuery.proxy(this.drag_n_drop,this)); jQuery(jQuery.proxy(this.drag_n_drop,this));
// Scroll
jQuery(jQuery.proxy(this._scroll,this));
}, },
/** /**
@ -177,6 +254,7 @@ app.classes.calendar = AppJS.extend(
{ {
delete window.top.app.calendar; delete window.top.app.calendar;
} }
jQuery(egw_getFramework().applications.calendar.tab.contentDiv).off();
}, },
/** /**
@ -543,6 +621,55 @@ app.classes.calendar = AppJS.extend(
} }
}, },
/**
* Bind scroll event
* When the user scrolls, we'll move enddate - startdate days
*/
_scroll: function() {
// Bind only once, to the whole tab
jQuery(egw_getFramework().applications.calendar.tab.contentDiv)
.on('wheel','.et2_container:not(#calendar-list)',
function(e)
{
e.preventDefault();
var direction = e.originalEvent.deltaY > 0 ? 1 : -1;
var delta = 1;
var start = new Date(app.calendar.state.date);
var end = null;
// Get the view to calculate
if (app.calendar.views && app.calendar.state.view && app.calendar.views[app.calendar.state.view].set_end_date)
{
if(direction > 0)
{
start = app.calendar.views[app.calendar.state.view].set_end_date({date:start});
}
else
{
start = app.calendar.views[app.calendar.state.view].set_start_date({date:start});
}
start.setUTCDate(start.getUTCDate()+direction);
end = app.calendar.views[app.calendar.state.view].set_end_date({date:start});
}
// Calculate the current difference, and move
else if(app.calendar.state.first && app.calendar.state.last)
{
start = new Date(app.calendar.state.first);
end = new Date(app.calendar.state.last);
// Get the number of days
delta = (Math.round(Math.max(1,end - start)/(24*3600*1000)))*24*3600*1000
// Adjust
start = new Date(start.valueOf() + (delta * direction ));
end = new Date(end.valueOf() + (delta * direction));
}
app.calendar.update_state({date: start});
return false;
}
);
},
/** /**
* Function to help calendar resizable event, to fetch the right droppable cell * Function to help calendar resizable event, to fetch the right droppable cell
* *
@ -1390,8 +1517,8 @@ app.classes.calendar = AppJS.extend(
// Show the correct number of grids // Show the correct number of grids
var grid_count = state.state.view == 'weekN' ? parseInt(this.egw.preference('multiple_weeks','calendar')) || 3 : var grid_count = state.state.view === 'weekN' ? parseInt(this.egw.preference('multiple_weeks','calendar')) || 3 :
state.state.view == 'month' ? 0 : // Calculate based on weeks in the month state.state.view === 'month' ? 0 : // Calculate based on weeks in the month
state.state.owner.length > (this.egw.config('calview_no_consolidate','phpgwapi') || 5) ? 1 : state.state.owner.length; state.state.owner.length > (this.egw.config('calview_no_consolidate','phpgwapi') || 5) ? 1 : state.state.owner.length;
var grid = this.views[this.state.view] ? this.views[this.state.view].etemplates[0].widgetContainer.getWidgetById('view') : false; var grid = this.views[this.state.view] ? this.views[this.state.view].etemplates[0].widgetContainer.getWidgetById('view') : false;
@ -1401,11 +1528,13 @@ app.classes.calendar = AppJS.extend(
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(state.state.view !== 'listview' && (!grid || grid_count != grid._children.length || grid_count > 1)) if(grid && (grid_count !== grid._children.length || grid_count > 1))
{ {
// Need to redo the number of grids // Need to redo the number of grids
var value = []; var value = [];
var date = state.state.first = view.set_start_date(state.state); state.state.first = view.set_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
switch(state.state.view) switch(state.state.view)
@ -1427,7 +1556,7 @@ app.classes.calendar = AppJS.extend(
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.toJSON();
break; break;
default: default:
var end = state.state.last = view.set_end_date(state.state); var end = state.state.last = view.set_end_date(state.state);
@ -1442,16 +1571,16 @@ app.classes.calendar = AppJS.extend(
} }
break; break;
} }
if(view.etemplates[0].widgetContainer.getWidgetById('view')) if(grid)
{ {
view.etemplates[0].widgetContainer.getWidgetById('view').set_value( grid.set_value(
{content: value} {content: value}
); );
} }
} }
else else
{ {
// Simple, easy case - just one timegrid. // Simple, easy case - just one widget for the selected time span.
// 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)
{ {
@ -1658,8 +1787,18 @@ app.classes.calendar = AppJS.extend(
if(_selected[i].iface.getWidget() && _selected[i].iface.getWidget().instanceOf(et2_calendar_event)) if(_selected[i].iface.getWidget() && _selected[i].iface.getWidget().instanceOf(et2_calendar_event))
{ {
is_widget = true; is_widget = true;
break;
} }
// Also check classes, usually indicating permission
if(_action.data && _action.data.enableClass)
{
is_widget = is_widget && ($j( _selected[i].iface.getDOMNode()).hasClass(_action.data.enableClass))
}
if(_action.data && _action.data.disableClass)
{
is_widget = is_widget && !($j( _selected[i].iface.getDOMNode()).hasClass(_action.data.disableClass))
}
} }
return is_widget; return is_widget;
}, },

View File

@ -207,7 +207,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
this.div.attr("data-date", this.options.date); this.div.attr("data-date", this.options.date);
// Set holiday and today classes // Set holiday and today classes
this._day_class_holiday(); this.day_class_holiday();
// Update all the little boxes // Update all the little boxes
this._draw(); this._draw();
@ -228,7 +228,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
/** /**
* Applies class for today, and any holidays for current day * Applies class for today, and any holidays for current day
*/ */
_day_class_holiday: function() { day_class_holiday: function() {
// Remove all classes // Remove all classes
this.title.removeClass() this.title.removeClass()
// Except this one... // Except this one...
@ -243,7 +243,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
); );
// Holidays and birthdays // Holidays and birthdays
var holidays = et2_calendar_daycol.get_holidays(this); var holidays = et2_calendar_daycol.get_holidays(this,this.options.date.substring(0,4));
var holiday_list = []; var holiday_list = [];
if(holidays && holidays[this.options.date]) if(holidays && holidays[this.options.date])
{ {
@ -295,7 +295,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
var events = _events || this.getArrayMgr('content').getEntry(this.options.date) || []; var events = _events || this.getArrayMgr('content').getEntry(this.options.date) || [];
// Sort events into minimally-overlapping columns // Sort events into minimally-overlapping columns
var columns = this._event_columns(events); var columns = this._spread_events(events);
for(var c = 0; c < columns.length; c++) for(var c = 0; c < columns.length; c++)
{ {
@ -352,7 +352,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
* @param {Object[]} events * @param {Object[]} events
* @returns {Array[]} Events sorted into columns * @returns {Array[]} Events sorted into columns
*/ */
_event_columns: function(events) _spread_events: function(events)
{ {
var day_start = this.date.valueOf() / 1000; var day_start = this.date.valueOf() / 1000;
var dst_check = new Date(this.date); var dst_check = new Date(this.date);
@ -633,36 +633,36 @@ jQuery.extend(et2_calendar_daycol,
* Fetch and cache a list of the year's holidays * Fetch and cache a list of the year's holidays
* *
* @param {et2_calendar_timegrid} widget * @param {et2_calendar_timegrid} widget
* @param {string|numeric} year
* @returns {Array} * @returns {Array}
*/ */
get_holidays: function(widget) get_holidays: function(widget,year)
{ {
// Loaded in an iframe or something // Loaded in an iframe or something
if(!egw.window.et2_calendar_daycol) return {}; if(!egw.window.et2_calendar_daycol) return {};
var cache_id = widget.options.date.substring(0,4); var cache = egw.window.et2_calendar_daycol.holiday_cache[year];
var cache = egw.window.et2_calendar_daycol.holiday_cache[cache_id];
if (typeof cache == 'undefined') if (typeof cache == 'undefined')
{ {
// Fetch with json instead of jsonq because there may be more than // Fetch with json instead of jsonq because there may be more than
// one widget listening for the response by the time it gets back, // one widget listening for the response by the time it gets back,
// and we can't do that when it's queued. // and we can't do that when it's queued.
egw.window.et2_calendar_daycol.holiday_cache[cache_id] = egw.json( egw.window.et2_calendar_daycol.holiday_cache[year] = egw.json(
'calendar_timegrid_etemplate_widget::ajax_get_holidays', 'calendar_timegrid_etemplate_widget::ajax_get_holidays',
[cache_id] [year]
).sendRequest(); ).sendRequest();
} }
cache = egw.window.et2_calendar_daycol.holiday_cache[cache_id]; cache = egw.window.et2_calendar_daycol.holiday_cache[year];
if(typeof cache.done == 'function') if(typeof cache.done == 'function')
{ {
// pending, wait for it // pending, wait for it
cache.done(jQuery.proxy(function(response) { cache.done(jQuery.proxy(function(response) {
egw.window.et2_calendar_daycol.holiday_cache[this.cache_id] = response.response[0].data||undefined; egw.window.et2_calendar_daycol.holiday_cache[this.year] = response.response[0].data||undefined;
egw.window.setTimeout(jQuery.proxy(function() { egw.window.setTimeout(jQuery.proxy(function() {
this.widget._day_class_holiday(); this.widget.day_class_holiday();
},this),1); },this),1);
},{widget:widget,cache_id:cache_id})); },{widget:widget,year:year}));
return {}; return {};
} }
else else

View File

@ -43,6 +43,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Main container // Main container
this.div = $j(document.createElement("div")) this.div = $j(document.createElement("div"))
.addClass("calendar_calEvent") .addClass("calendar_calEvent")
.addClass(this.options.class)
.css('width',this.options.width); .css('width',this.options.width);
this.title = $j(document.createElement('div')) this.title = $j(document.createElement('div'))
.addClass("calendar_calEventHeader") .addClass("calendar_calEventHeader")
@ -95,7 +96,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
event = jQuery.extend({},event); event = jQuery.extend({},event);
var list = [event]; var list = [event];
// Let parent format any missing data // Let parent format any missing data
this._parent._event_columns(list); this._parent._spread_events(list);
// Calculate vertical positioning // Calculate vertical positioning
// TODO: Maybe move this somewhere common between here & parent? // TODO: Maybe move this somewhere common between here & parent?
@ -176,8 +177,12 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Header // Header
var title = !event.is_private ? event['title'] : egw.lang('private'); var title = !event.is_private ? event['title'] : egw.lang('private');
var small_height = event['end_m']-event['start_m'] < 2*this._parent.display_settings.granularity || var small_height = true;
event['end_m'] <= this._parent.display_settings.wd_start || event['start_m'] >= this._parent.display_settings.wd_end; if(this._parent.display_settings)
{
small_height = event['end_m']-event['start_m'] < 2*this._parent.display_settings.granularity ||
event['end_m'] <= this._parent.display_settings.wd_start || event['start_m'] >= this._parent.display_settings.wd_end;
}
this.div.attr('data-title', title); this.div.attr('data-title', title);
this.title.text(small_height ? title : this._get_timespan(event)) this.title.text(small_height ? title : this._get_timespan(event))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,391 @@
/*
* Egroupware
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package
* @subpackage
* @link http://www.egroupware.org
* @author Nathan Gray
* @version $Id$
*/
/**
* Class for one row of a planner
*
* This widget is responsible for the label on the side
*
* @augments et2_valueWidget
*/
var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM],
{
attributes: {
start_date: {
name: "Start date",
type: "any"
},
end_date: {
name: "End date",
type: "any"
},
value: {
type: "any"
}
},
/**
* Constructor
*
* @memberOf et2_calendar_daycol
*/
init: function() {
this._super.apply(this, arguments);
// Main container
this.div = $j(document.createElement("div"))
.addClass("calendar_plannerRowWidget")
.css('width',this.options.width);
this.title = $j(document.createElement('div'))
.addClass("calendar_plannerRowHeader")
.css('width', '15%')
.appendTo(this.div);
this.rows = $j(document.createElement('div'))
.addClass("calendar_eventRows")
.appendTo(this.div);
this.setDOMNode(this.div[0]);
// Used for its date calculations
this.date_helper = et2_createWidget('date-time',{},null);
this.date_helper.loadingFinished();
},
doLoadingFinished: function() {
this._super.apply(this, arguments);
this.set_label(this.options.label);
this._draw();
return true;
},
destroy: function() {
this._super.apply(this, arguments);
// date_helper has no parent, so we must explicitly remove it
this.date_helper.destroy();
this.date_helper = null;
},
getDOMNode: function(_sender)
{
if(_sender === this || !_sender)
{
return this.div[0];
}
if(_sender._parent === this)
{
return this.rows[0];
}
},
/**
* Draw the individual divs for weekends and events
*/
_draw: function() {
// Remove any existing
this.rows.empty().nextAll().remove();
var days = 31;
var width = 85;
if (this._parent.options.group_by === 'month')
{
days = new Date(this.options.end_date.getUTCFullYear(),this.options.end_date.getUTCMonth()+1,0).getUTCDate();
if(days < 31)
{
width = 85*days/31;
this.rows.css('width',width+'%');
}
}
// mark weekends and other special days in yearly planner
if (this._parent.options.group_by == 'month')
{
this.rows.append(this._yearlyPlannerMarkDays(this.options.start_date, days));
}
if (this._parent.options.group_by === 'month' && days < 31)
{
// add a filler for non existing days in that month
this.rows.after('<div class="calendar_eventRowsFiller"'+
' style="left:'+(15+width)+'%; width:'+(85-width)+'%;" ></div>');
}
},
set_label: function(label)
{
this.options.label = label;
this.title.text(label);
if(this._parent.options.group_by === 'month')
{
this.title.attr('data-date', this.options.start_date.toJSON());
this.title.addClass('et2_clickable');
}
else
{
this.title.attr('data-date','');
this.title.removeClass('et2_clickable');
}
},
/**
* Mark special days (birthdays, holidays) on the planner
*
* @param {Date} start Start of the month
* @param {number} days How many days in the month
*/
_yearlyPlannerMarkDays: function(start,days)
{
var day_width = 100/days;
var t = new Date(start);
var content = '';
for(var left = 0,i = 0; i < days;left += day_width,++i)
{
var holidays = [];
// TODO: implement this, pull / copy data from et2_widget_timegrid
var day_class = this._parent.day_class_holiday(t,holidays);
if (day_class) // no regular weekday
{
content += '<div class="calendar_eventRowsMarkedDay '+day_class+
'" style="left: '+left+'%; width:'+day_width+'%;"'+
(holidays ? ' title="'+holidays.join(',')+'"' : '')+
' ></div>';
}
t.setUTCDate(t.getUTCDate()+1)
}
return content;
},
/**
* Load the event data for this day and create event widgets for each.
*
* If event information is not provided, it will be pulled from the content array.
*
* @param {Object[]} [_events] Array of event information, one per event.
*/
_update_events: function(_events)
{
// Remove all events
while(this._children.length)
{
this._children[this._children.length-1].free();
this.removeChild(this._children[this._children.length-1]);
}
var rows = this._spread_events(_events);
var row = $j('<div class="calendar_plannerEventRowWidget"></div>').appendTo(this.rows);
var height = rows.length * (parseInt(window.getComputedStyle(row[0]).getPropertyValue("height")) || 20);
row.remove();
for(var c = 0; c < rows.length; c++)
{
// Calculate vertical positioning
var top = c * (100.0 / rows.length);
for(var i = 0; i < rows[c].length; i++)
{
// Calculate horizontal positioning
var left = this._time_to_position(rows[c][i].start);
var width = this._time_to_position(rows[c][i].end)-left;
// Create event
var event = et2_createWidget('calendar-event',{
id:rows[c][i].app_id||rows[c][i].id,
class: 'calendar_plannerEvent'
},this);
if(this.isInTree())
{
event.doLoadingFinished();
}
event.set_value(rows[c][i]);
// TODO
event._link_actions(this._parent.options.actions||{});
// Position the event
event.div.css('top', top+'%');
event.div.css('height', (100/rows.length)+'%');
event.div.css('left', left.toFixed(1)+'%');
event.div.css('width', width.toFixed(1)+'%');
}
}
if(height)
{
this.div.height(height+'px');
}
},
/**
* Sort a day's events into non-overlapping rows
*
* @param {Object[]} events
* @returns {Array[]} Events sorted into rows
*/
_spread_events: function(events)
{
// sorting the events in non-overlapping rows
var rows = [];
var row_end = [0];
var start = this.options.start_date;
var end = this.options.end_date;
for(var n = 0; n < events.length; n++)
{
var event = events[n];
if(typeof event.start !== 'object')
{
this.date_helper.set_value(event.start);
event.start = new Date(this.date_helper.getValue());
}
if(typeof event.end !== 'object')
{
this.date_helper.set_value(event.end);
event.end = new Date(this.date_helper.getValue());
}
if(typeof event['start_m'] === 'undefined')
{
var day_start = event.start.valueOf() / 1000;
var dst_check = new Date(event.start);
dst_check.setUTCHours(12);
// if daylight saving is switched on or off, correct $day_start
// gives correct times after 2am, times between 0am and 2am are wrong
var daylight_diff = day_start + 12*60*60 - (dst_check.valueOf()/1000);
if(daylight_diff)
{
day_start -= daylight_diff;
}
event['start_m'] = parseInt((event.start.valueOf()/1000 - day_start) / 60);
if (event['start_m'] < 0)
{
event['start_m'] = 0;
event['multiday'] = true;
}
event['end_m'] = parseInt((event.end.valueOf()/1000 - day_start) / 60);
if (event['end_m'] >= 24*60)
{
event['end_m'] = 24*60-1;
event['multiday'] = true;
}
}
var event_start = new Date(events[n].start).valueOf();
for(var row = 0; row_end[row] > event_start; ++row); // find a "free" row (no other event)
if(typeof rows[row] === 'undefined') rows[row] = [];
rows[row].push(events[n]);
row_end[row] = new Date(events[n]['end']).valueOf();
}
return rows;
},
/**
* Calculates the horizontal position based on the time given, as a percentage
* between the start and end times
*
* @param {int|Date|string} time in minutes from midnight, or a Date in string or object form
* @param {int|Date|string} start Earliest possible time (0%)
* @param {int|Date|string} end Latest possible time (100%)
* @return {float} position in percent
*/
_time_to_position: function(time, start, end)
{
var pos = 0.0;
// Handle the different value types
start = this.options.start_date;
end = this.options.end_date;
if(typeof start === 'string')
{
start = new Date(start);
end = new Date(end);
}
var wd_start = 60 * (parseInt(egw.preference('workdaystarts','calendar')) || 9);
var wd_end = 60 * (parseInt(egw.preference('workdayends','calendar')) || 17);
var t = time;
if(typeof time === 'number' && time < 3600)
{
t = new Date(start.valueOf() + wd_start * 3600*1000);
}
else
{
t = new Date(time);
}
// Limits
if(t <= start) return 0; // We are left of our scale
if(t >= end) return 100; // We are right of our scale
// Basic scaling, doesn't consider working times
pos = (t - start) / (end - start);
// Month view
if(this._parent.options.group_by !== 'month')
{
// Daywise scaling
var start_date = new Date(start.getUTCFullYear(), start.getUTCMonth(),start.getUTCDate());
var end_date = new Date(end.getUTCFullYear(), end.getUTCMonth(),end.getUTCDate());
var t_date = new Date(t.getUTCFullYear(), t.getUTCMonth(),t.getUTCDate());
var days = Math.round((end_date - start_date) / (24 * 3600 * 1000))+1;
pos = 1 / days * Math.round((t_date - start_date) / (24*3600 * 1000));
var time_of_day = typeof t === 'object' ? 60 * t.getUTCHours() + t.getUTCMinutes() : t;
if (time_of_day >= wd_start)
{
var day_percentage = 0.1;
if (time_of_day > wd_end)
{
day_percentage = 1;
}
else
{
var wd_length = wd_end - wd_start;
if (wd_length <= 0) wd_length = 24*60;
day_percentage = (time_of_day-wd_start) / wd_length; // between 0 and 1
}
pos += day_percentage / days;
}
}
pos = 100 * pos;
return pos;
},
/**
* Code for implementing et2_IDetachedDOM
*
* @param {array} _attrs array to add further attributes to
*/
getDetachedAttributes: function(_attrs) {
},
getDetachedNodes: function() {
return [this.getDOMNode()];
},
setDetachedAttributes: function(_nodes, _values) {
},
});
et2_register_widget(et2_calendar_planner_row, ["calendar-planner_row"]);

View File

@ -331,28 +331,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz
this.dropEnd = drag_helper.call($j('.calendar_calEventHeader',ui.helper)[0],event,ui.helper[0],0); this.dropEnd = drag_helper.call($j('.calendar_calEventHeader',ui.helper)[0],event,ui.helper[0],0);
$j('.calendar_timeDemo',ui.helper).css('bottom','auto'); $j('.calendar_timeDemo',ui.helper).css('bottom','auto');
}); });
// Bind scroll event
// When the user scrolls, we'll move enddate - startdate days
this.div.on('wheel',jQuery.proxy(function(e) {
var direction = e.originalEvent.deltaY > 0 ? 1 : -1;
this.date_helper.set_value(this.options.end_date || this.options.start_date);
var end = this.date_helper.get_time();
this.date_helper.set_value(this.options.start_date);
var start = this.date_helper.get_time();
var delta = 1000 * 60 * 60 * 24 + Math.max(0,end - start);
// TODO - actually fetch new data
this.set_start_date(new Date(start + (delta * direction )));
this.set_end_date(new Date(end + (delta * direction)));
e.preventDefault();
return false;
},this));
return true; return true;
}, },

View File

@ -473,6 +473,12 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
border: 1px solid gray; border: 1px solid gray;
padding-right: 3px; padding-right: 3px;
} }
.calendar_plannerWidget:nth-child(odd) {
background-color: #ffffff;
}
.calendar_plannerWidget:nth-child(even) {
background-color: #f2f2f2;
}
/* calendar_plannerHeader contains a calendar_plannerHeaderTitle and multiple calendar_plannerHeaderRows /* calendar_plannerHeader contains a calendar_plannerHeaderTitle and multiple calendar_plannerHeaderRows
*/ */
@ -481,6 +487,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 100%; width: 100%;
background-color: #e0e0e0;
} }
/* calendar_plannerRowWidget contains a calendar_plannerRowHeader and multiple eventRowWidgets in an calendar_eventRows /* calendar_plannerRowWidget contains a calendar_plannerRowHeader and multiple eventRowWidgets in an calendar_eventRows
@ -490,6 +497,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 100%; width: 100%;
min-height: 20px;
} }
/* calendar_plannerScale represents a scale-row of the calendar_plannerHeader, containing multiple planner{Day|Week|Month}Scales /* calendar_plannerScale represents a scale-row of the calendar_plannerHeader, containing multiple planner{Day|Week|Month}Scales
@ -553,6 +561,8 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 15%; /* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */ left: 15%; /* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */
width: 85%; width: 85%;
min-height: 20px;
height: 100%;
} }
/** /**
@ -576,6 +586,9 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
height: 100%; height: 100%;
z-index: 10; z-index: 10;
} }
.calendar_eventRowsMarkedDay.calendar_weekend {
background-color: #e0e0e0;
}
/* calendar_eventRowWidget contains non-overlapping events /* calendar_eventRowWidget contains non-overlapping events
*/ */

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Egroupware
@license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
@package
@subpackage
@link http://www.egroupware.org
@author Nathan Gray
@version $Id$
-->
<!DOCTYPE overlay PUBLIC '-//Stylite AG//eTemplate 2//EN' 'http://www.egroupware.org/etemplate2.dtd'>
<overlay>
<template id="calendar.planner">
<calendar-planner id="planner"
onchange="app.calendar.update_state(ev.data);"
onevent_change="app.calendar.event_change"
>
</calendar-planner>
</template>
</overlay>

View File

@ -31,7 +31,7 @@ Egroupware
<buttononly align="center" class="sideboxstar" id="week" image="week" label="Weekview" onclick="app.calendar.update_state({view:'week'});"/> <buttononly align="center" class="sideboxstar" id="week" image="week" label="Weekview" onclick="app.calendar.update_state({view:'week'});"/>
<buttononly align="center" class="sideboxstar" id="weekN" image="multiweek" label="Multiple week view" onclick="app.calendar.update_state({view:'weekN'});"/> <buttononly align="center" class="sideboxstar" id="weekN" image="multiweek" label="Multiple week view" onclick="app.calendar.update_state({view:'weekN'});"/>
<buttononly align="center" class="sideboxstar" id="month" image="month" label="Multiple week view" onclick="app.calendar.update_state({view:'month'});"/> <buttononly align="center" class="sideboxstar" id="month" image="month" label="Multiple week view" onclick="app.calendar.update_state({view:'month'});"/>
<buttononly align="center" class="sideboxstar" id="planner" image="planner" label="Group planner" onclick="app.calendar.update_state({view:'planner'});"/> <buttononly align="center" class="sideboxstar" id="planner" image="planner" label="Group planner" onclick="app.calendar.update_state({view:'planner',planner_days:0});"/>
<buttononly align="center" class="sideboxstar" id="listview" image="list" label="Listview" onclick="app.calendar.update_state({view:'listview'});"/> <buttononly align="center" class="sideboxstar" id="listview" image="list" label="Listview" onclick="app.calendar.update_state({view:'listview'});"/>
</row> </row>
</rows> </rows>

View File

@ -11,7 +11,7 @@
* @package calendar * @package calendar
* @version $Id$ * @version $Id$
*/ */
/* $Id: app.css 52977 2015-06-23 12:32:55Z hnategh $ */ /* $Id: app.css 52979 2015-06-23 14:17:18Z hnategh $ */
/*Media print classes*/ /*Media print classes*/
@media print { @media print {
.th td, .th td,
@ -473,6 +473,12 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
border: 1px solid gray; border: 1px solid gray;
padding-right: 3px; padding-right: 3px;
} }
.calendar_plannerWidget:nth-child(odd) {
background-color: #ffffff;
}
.calendar_plannerWidget:nth-child(even) {
background-color: #f2f2f2;
}
/* calendar_plannerHeader contains a calendar_plannerHeaderTitle and multiple calendar_plannerHeaderRows /* calendar_plannerHeader contains a calendar_plannerHeaderTitle and multiple calendar_plannerHeaderRows
*/ */
.calendar_plannerHeader { .calendar_plannerHeader {
@ -480,6 +486,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 100%; width: 100%;
background-color: #e0e0e0;
} }
/* calendar_plannerRowWidget contains a calendar_plannerRowHeader and multiple eventRowWidgets in an calendar_eventRows /* calendar_plannerRowWidget contains a calendar_plannerRowHeader and multiple eventRowWidgets in an calendar_eventRows
*/ */
@ -488,6 +495,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 100%; width: 100%;
min-height: 20px;
} }
/* calendar_plannerScale represents a scale-row of the calendar_plannerHeader, containing multiple planner{Day|Week|Month}Scales /* calendar_plannerScale represents a scale-row of the calendar_plannerHeader, containing multiple planner{Day|Week|Month}Scales
*/ */
@ -560,6 +568,8 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
left: 15%; left: 15%;
/* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */ /* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */
width: 85%; width: 85%;
min-height: 20px;
height: 100%;
} }
/** /**
* Filler for month with less then 31 days in yearly planner * Filler for month with less then 31 days in yearly planner
@ -581,6 +591,9 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
height: 100%; height: 100%;
z-index: 10; z-index: 10;
} }
.calendar_eventRowsMarkedDay.calendar_weekend {
background-color: #e0e0e0;
}
/* calendar_eventRowWidget contains non-overlapping events /* calendar_eventRowWidget contains non-overlapping events
*/ */
.calendar_eventRowWidget { .calendar_eventRowWidget {