forked from extern/egroupware
Calendar et2 conversion work in progress.
- Start of planner view - Scroll moved to app.js so month works better
This commit is contained in:
parent
558589c1eb
commit
4648f91bb7
@ -710,17 +710,17 @@ class calendar_ui
|
||||
),
|
||||
array(
|
||||
'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',
|
||||
),
|
||||
array(
|
||||
'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',
|
||||
),
|
||||
array(
|
||||
'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',
|
||||
),
|
||||
array(
|
||||
|
@ -211,8 +211,24 @@ class calendar_uiviews extends calendar_ui
|
||||
/**
|
||||
* 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';
|
||||
|
||||
// handle views in other files
|
||||
@ -240,6 +256,11 @@ class calendar_uiviews extends calendar_ui
|
||||
|
||||
// Actually, this takes care of most of it...
|
||||
$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_ui = new calendar_uilist();
|
||||
|
@ -12,6 +12,7 @@
|
||||
/*egw:uses
|
||||
/etemplate/js/etemplate2.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) {
|
||||
var d = state.date ? new Date(state.date) : new Date();
|
||||
d.setUTCDate(1);
|
||||
d.setUTCHours(0);
|
||||
d.setUTCMinutes(0);
|
||||
d.setUTCSeconds(0);
|
||||
state.date = d.toJSON();
|
||||
return app.calendar.date.start_of_week(d);
|
||||
},
|
||||
set_end_date: function(state) {
|
||||
@ -130,7 +135,76 @@ app.classes.calendar = AppJS.extend(
|
||||
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)
|
||||
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;
|
||||
}
|
||||
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
|
||||
*
|
||||
@ -1390,8 +1517,8 @@ app.classes.calendar = AppJS.extend(
|
||||
|
||||
|
||||
// Show the correct number of grids
|
||||
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
|
||||
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.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;
|
||||
@ -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
|
||||
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
|
||||
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
|
||||
switch(state.state.view)
|
||||
@ -1427,7 +1556,7 @@ app.classes.calendar = AppJS.extend(
|
||||
value.push(val);
|
||||
date.setUTCHours(24*7);
|
||||
}
|
||||
state.state.last=val.end_date;
|
||||
state.state.last=val.end_date.toJSON();
|
||||
break;
|
||||
default:
|
||||
var end = state.state.last = view.set_end_date(state.state);
|
||||
@ -1442,16 +1571,16 @@ app.classes.calendar = AppJS.extend(
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(view.etemplates[0].widgetContainer.getWidgetById('view'))
|
||||
if(grid)
|
||||
{
|
||||
view.etemplates[0].widgetContainer.getWidgetById('view').set_value(
|
||||
grid.set_value(
|
||||
{content: value}
|
||||
);
|
||||
}
|
||||
}
|
||||
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
|
||||
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))
|
||||
{
|
||||
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;
|
||||
},
|
||||
|
@ -207,7 +207,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
this.div.attr("data-date", this.options.date);
|
||||
|
||||
// Set holiday and today classes
|
||||
this._day_class_holiday();
|
||||
this.day_class_holiday();
|
||||
|
||||
// Update all the little boxes
|
||||
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
|
||||
*/
|
||||
_day_class_holiday: function() {
|
||||
day_class_holiday: function() {
|
||||
// Remove all classes
|
||||
this.title.removeClass()
|
||||
// Except this one...
|
||||
@ -243,7 +243,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
);
|
||||
|
||||
// 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 = [];
|
||||
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) || [];
|
||||
|
||||
// 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++)
|
||||
{
|
||||
@ -352,7 +352,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
* @param {Object[]} events
|
||||
* @returns {Array[]} Events sorted into columns
|
||||
*/
|
||||
_event_columns: function(events)
|
||||
_spread_events: function(events)
|
||||
{
|
||||
var day_start = this.date.valueOf() / 1000;
|
||||
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
|
||||
*
|
||||
* @param {et2_calendar_timegrid} widget
|
||||
* @param {string|numeric} year
|
||||
* @returns {Array}
|
||||
*/
|
||||
get_holidays: function(widget)
|
||||
get_holidays: function(widget,year)
|
||||
{
|
||||
// Loaded in an iframe or something
|
||||
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[cache_id];
|
||||
var cache = egw.window.et2_calendar_daycol.holiday_cache[year];
|
||||
if (typeof cache == 'undefined')
|
||||
{
|
||||
// Fetch with json instead of jsonq because there may be more than
|
||||
// one widget listening for the response by the time it gets back,
|
||||
// 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',
|
||||
[cache_id]
|
||||
[year]
|
||||
).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')
|
||||
{
|
||||
// pending, wait for it
|
||||
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() {
|
||||
this.widget._day_class_holiday();
|
||||
this.widget.day_class_holiday();
|
||||
},this),1);
|
||||
},{widget:widget,cache_id:cache_id}));
|
||||
},{widget:widget,year:year}));
|
||||
return {};
|
||||
}
|
||||
else
|
||||
|
@ -43,6 +43,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
// Main container
|
||||
this.div = $j(document.createElement("div"))
|
||||
.addClass("calendar_calEvent")
|
||||
.addClass(this.options.class)
|
||||
.css('width',this.options.width);
|
||||
this.title = $j(document.createElement('div'))
|
||||
.addClass("calendar_calEventHeader")
|
||||
@ -95,7 +96,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
event = jQuery.extend({},event);
|
||||
var list = [event];
|
||||
// Let parent format any missing data
|
||||
this._parent._event_columns(list);
|
||||
this._parent._spread_events(list);
|
||||
|
||||
// Calculate vertical positioning
|
||||
// TODO: Maybe move this somewhere common between here & parent?
|
||||
@ -176,8 +177,12 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
|
||||
|
||||
// Header
|
||||
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 ||
|
||||
event['end_m'] <= this._parent.display_settings.wd_start || event['start_m'] >= this._parent.display_settings.wd_end;
|
||||
var small_height = true;
|
||||
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.title.text(small_height ? title : this._get_timespan(event))
|
||||
|
1430
calendar/js/et2_widget_planner.js
Normal file
1430
calendar/js/et2_widget_planner.js
Normal file
File diff suppressed because it is too large
Load Diff
391
calendar/js/et2_widget_planner_row.js
Normal file
391
calendar/js/et2_widget_planner_row.js
Normal 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"]);
|
@ -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);
|
||||
$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;
|
||||
},
|
||||
|
||||
|
@ -473,6 +473,12 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
||||
border: 1px solid gray;
|
||||
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
|
||||
*/
|
||||
@ -481,6 +487,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
left: 15%; /* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */
|
||||
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%;
|
||||
z-index: 10;
|
||||
}
|
||||
.calendar_eventRowsMarkedDay.calendar_weekend {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
/* calendar_eventRowWidget contains non-overlapping events
|
||||
*/
|
||||
|
22
calendar/templates/default/planner.xet
Normal file
22
calendar/templates/default/planner.xet
Normal 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>
|
@ -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="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="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'});"/>
|
||||
</row>
|
||||
</rows>
|
||||
|
@ -11,7 +11,7 @@
|
||||
* @package calendar
|
||||
* @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 {
|
||||
.th td,
|
||||
@ -473,6 +473,12 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
||||
border: 1px solid gray;
|
||||
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 {
|
||||
@ -480,6 +486,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
/* 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;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
min-height: 20px;
|
||||
}
|
||||
/* 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%;
|
||||
/* need to be identical for calendar_eventRows and calendar_plannerHeaderRows and match width of calendar_plannerRowHeader/calendar_plannerHeaderTitle */
|
||||
width: 85%;
|
||||
min-height: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
/**
|
||||
* 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%;
|
||||
z-index: 10;
|
||||
}
|
||||
.calendar_eventRowsMarkedDay.calendar_weekend {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
/* calendar_eventRowWidget contains non-overlapping events
|
||||
*/
|
||||
.calendar_eventRowWidget {
|
||||
|
Loading…
Reference in New Issue
Block a user