diff --git a/calendar/inc/class.calendar_hooks.inc.php b/calendar/inc/class.calendar_hooks.inc.php
index 83970b3aa1..2111e382bd 100644
--- a/calendar/inc/class.calendar_hooks.inc.php
+++ b/calendar/inc/class.calendar_hooks.inc.php
@@ -153,6 +153,7 @@ class calendar_hooks
'week' => lang('Weekview'),
'weekN' => lang('Multiple week view'),
'month' => lang('Monthview'),
+ 'year' => lang('yearview'),
'planner_cat' => lang('Planner by category'),
'planner_user' => lang('Planner by user'),
'listview' => lang('Listview'),
diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php
index a0f854a9d0..60a04cd28f 100644
--- a/calendar/inc/class.calendar_ui.inc.php
+++ b/calendar/inc/class.calendar_ui.inc.php
@@ -545,6 +545,7 @@ class calendar_ui
'week' => array('icon'=>'week','text'=>'Weekview','menuaction' => 'calendar.calendar_uiviews.week'),
'weekN' => array('icon'=>'multiweek','text'=>'Multiple week view','menuaction' => 'calendar.calendar_uiviews.weekN'),
'month' => array('icon'=>'month','text'=>'Monthview','menuaction' => 'calendar.calendar_uiviews.month'),
+ //'year' => array('icon'=>'year','text'=>'yearview','menuaction' => 'calendar.calendar_uiviews.year'),
'planner' => array('icon'=>'planner','text'=>'Group planner','menuaction' => 'calendar.calendar_uiviews.planner','sortby' => $this->sortby),
'list' => array('icon'=>'list','text'=>'Listview','menuaction'=>'calendar.calendar_uilist.listview'),
) as $view => $data)
@@ -610,6 +611,11 @@ class calendar_ui
'value' => 'menuaction=calendar.calendar_uiviews.month',
'selected' => $this->view == 'month',
),
+ array(
+ 'text' => lang('yearview'),
+ 'value' => 'menuaction=calendar.calendar_uiviews.year',
+ 'selected' => $this->view == 'year',
+ ),
array(
'text' => lang('planner by category'),
'value' => 'menuaction=calendar.calendar_uiviews.planner&sortby=category'.
diff --git a/calendar/inc/class.calendar_uiviews.inc.php b/calendar/inc/class.calendar_uiviews.inc.php
index 3736afdafe..e6721ab775 100644
--- a/calendar/inc/class.calendar_uiviews.inc.php
+++ b/calendar/inc/class.calendar_uiviews.inc.php
@@ -32,6 +32,7 @@ class calendar_uiviews extends calendar_ui
'week' => True,
'weekN' => True,
'month' => True,
+ 'year' => True,
'planner' => True,
'index' => True,
);
@@ -67,14 +68,14 @@ class calendar_uiviews extends calendar_ui
var $timeRow_width = 40;
/**
- * how many rows per day get displayed, gets set be the timeGridWidget
+ * how many rows per day get displayed, gets set by the timeGridWidget
*
* @var int
*/
var $rowsToDisplay;
/**
- * height in percent of one row, gets set be the timeGridWidget
+ * height in percent of one row, gets set by the timeGridWidget
*
* @var int
*/
@@ -137,6 +138,7 @@ class calendar_uiviews extends calendar_ui
'4day' => lang('Four days view'),
'week' => lang('Weekview'),
'month' => lang('Monthview'),
+ 'year' => lang('yearview'),
'planner' => lang('Group planner'),
);
$GLOBALS['egw_info']['flags']['app_header'] = $GLOBALS['egw_info']['apps']['calendar']['title'].
@@ -217,6 +219,9 @@ class calendar_uiviews extends calendar_ui
case 'planner':
return $group_warning.$this->planner(true);
+ case 'year':
+ return $group_warning.$this->year(true);
+
case 'month':
return $group_warning.$this->month(0,true);
@@ -320,6 +325,230 @@ class calendar_uiviews extends calendar_ui
return $this->month($num,$home);
}
+ /** Month column width (usually 3 or 4) in year view */
+ const YEARVIEW_COLS = 3;
+
+ /**
+ * Displays a year view
+ *
+ * @param boolean $home=false if true return content suitable for home-page
+ */
+ function &year($home=false)
+ {
+ if ($this->debug > 0) $this->bo->debug_message('uiviews::year date=%2',True,$this->date);
+
+ $content = $this->edit_series();
+
+ $this->_month_align_year($this->first,$this->last);
+
+ $GLOBALS['egw_info']['flags']['app_header'] .= ': '.$this->year;
+
+ $days =& $this->bo->search(array(
+ 'start' => $this->first,
+ 'end' => $this->last,
+ ) + $this->search_params);
+
+ /* Loop through the week-aligned months. */
+ for ($month = 1; $month <= 12; $month++)
+ {
+ // The first date entry in the view may be in the last month.
+ if (($month - 1) % self::YEARVIEW_COLS == 0)
+ {
+ $content .= '
'."\n";
+ $content .= "\t".'
'."\n";
+ }
+
+ $month_start = $this->datetime->get_weekday_start($this->year,$month,1);
+ // Beginning of the last week in the month
+ $month_end = $this->datetime->get_weekday_start(
+ $this->year,
+ $month,
+ $this->datetime->days_in_month($month,$this->year));
+ // End of the last week in month
+ $month_end = strtotime("+6 days",$month_end);
+
+ $content .= "\t\t".'
'."\n";
+
+ // Year Header
+ $content .= "\t\t\t".''."\n";
+
+ $content .= "\t\t\t".'
'."\n";
+ $content .= "\t\t\t\t".'
'.lang('Wk').'
'."\n";
+ // Day Columns, Legend
+ for ($i = 0; $i <= 6; $i++)
+ {
+ $day_date = ($i ? strtotime("+$i days",$month_start) : $month_start);
+ if (adodb_date('w',$day_date) % 6 == 0)
+ {
+ $style = 'cal_year_legend_weekend';
+ }
+ else
+ {
+ $style = 'cal_year_legend';
+ }
+
+ $content .= "\t\t\t\t".'
'.
+ lang(adodb_date('D',$day_date)).'
'."\n";
+ }
+ $content .= "\t\t\t".'
'."\n";
+
+ // Week rows in month
+ $week_start = $month_start;
+ for ($week_in_month = 1; $week_in_month <= 6; $week_in_month ++)
+ {
+ $content .= "\t\t\t".'
'."\n";
+
+ $content .= "\t\t\t\t".'
'."\n";
+ // Day columns in week row
+ for ($i = 0; $i <= 6; $i++)
+ {
+ $day_date = $i ? strtotime("+$i days",$week_start) : $week_start;
+ $day_ymd = $this->bo->date2string($day_date);
+ $eventcount = count($days[$day_ymd]);
+ $in_month = true;
+ $css_class = "";
+ $this->_day_class_holiday($day_ymd,$class,$holidays,false,false);
+ if (adodb_date('n',$day_date) != $month)
+ {
+ $css_class .= 'cal_year_legend';
+ $in_month = false;
+ }
+ else
+ {
+ $css_class .= 'calEvent calEventAllAccepted';
+ if (adodb_date('w',$day_date) % 6 == 0)
+ {
+ $css_class .= ' cal_year_weekend';
+ }
+ else
+ {
+ if ($holidays)
+ {
+ $css_class .= ' calHoliday';
+ }
+ else
+ {
+ $css_class .= ' cal_year_free';
+ }
+ }
+
+ if ($day_ymd == $this->bo->date2string($this->bo->now_su))
+ {
+ $css_class .= ' cal_year_today';
+ }
+ }
+ $content .= "\t\t\t\t".''."\n";
+ $content .= "\t\t\t\t".'
'."\n";
+
+
+ if (($in_month) && (count($days[$day_ymd])))
+ {
+ $eventCols = $this->getEventCols($day_ymd,$days[$day_ymd]);
+ // displaying all event columns of the day
+ $row_height = 100 / count($eventCols);
+ $space_left = 4; //%
+ $space_right = 1; //%
+ $row_width = 11.5 - $space_left - $space_right;
+ // settings for time2pos
+ $this->scroll_to_wdstart = false;
+ $this->wd_start = 0;
+ $this->wd_end = 24*60;
+ $this->granularity_m = 24 * 60;
+ $this->extraRows = -1;
+ $this->rowHeight = $row_width;
+ foreach($eventCols as $n => $eventCol)
+ {
+ foreach ($eventCol as $event)
+ {
+ $indent = "\t\t\t\t";
+ // some fields set by the dayColWidget for the other views
+ unset($event['whole_day_on_top']);
+ $data = $this->eventWidget($event,25,$indent,$this->owner,true,'planner_event');
+
+ $left = ((($i + 1) * 12.5) + 0.5 + $space_left + $this->time2pos($event['start_m']));
+ $width = $this->time2pos($event['end_m'] - $event['start_m']);
+ $color = $data['color'] ? $data['color'] : 'gray';
+
+ $content .= $indent.'
0,'Padding'=>0)).
+ '>'."\n".$data['html'].$indent."
\n";
+ }
+ }
+ }
+ }
+ $week_start = strtotime("+1 week",$week_start);
+ $content .= "\t\t\t".'
'."\n";
+ }
+ $content .= "\t\t".'
'."\n";
+
+ if (($month) % self::YEARVIEW_COLS == 0)
+ {
+ $content .= "\t
\n";
+ $content .= "
\n";
+ }
+ }
+
+ if (!$home)
+ {
+ $this->do_header();
+
+ echo $content;
+ }
+
+ return $content;
+ }
+
/**
* Displays the monthview or a multiple week-view
*
@@ -414,6 +643,27 @@ class calendar_uiviews extends calendar_ui
$last = $this->bo->date2ts($last);
}
+ /**
+ * Get start and end of a year aligned to full months
+ *
+ * @param int &$first timestamp 0h of first day of week containing the first of the current year
+ * @param int &$last timestamp 23:59:59 of last day of week containg the last day of the current year
+ */
+ function _month_align_year(&$first,&$last)
+ {
+ $first = $this->datetime->get_weekday_start($this->year,$this->month=1,$this->day=1);
+ $last = $this->datetime->get_weekday_start($this->year,$this->month+12,
+ $this->datetime->days_in_month($this->month+12,$this->year));
+ // now we need to calculate the end of the last day of that week
+ // as simple $last += WEEK_s - 1; does NOT work, if daylight saving changes in that week!!!
+ $last = $this->bo->date2array($last);
+ $last['day'] += 6;
+ $last['hour'] = 23;
+ $last['min'] = $last['sec'] = 59;
+ unset($last['raw']); // otherwise date2ts does not calc raw new, but uses it
+ $last = $this->bo->date2ts($last);
+ }
+
/**
* Four days view, everythings done by the week-view code ...
*
@@ -763,7 +1013,7 @@ function open_edit(series)
}
/**
- * Calculates the height of a differenc between 2 times
+ * Calculates the height of a difference between 2 times
*
* workday start- and end-time, is taken into account, as well as timeGrids px_m - minutes per pixel param
*
@@ -927,23 +1177,14 @@ function open_edit(series)
}
/**
- * Creates (if necessary multiple) columns for the events of a day
- *
- * Uses the eventColWidget to display each column.
+ * Sorts the events of a day into columns with non-overlapping events, the events
+ * are already sorted by start-time
*
* @param string/int $day_ymd date as Ymd
- * @param array $events of events to show
- * @param int $left start of the widget
- * @param int $width width of the widget
- * @param string $indent string for correct indention
- * @param boolean/string $short_title=True should we add a label (weekday, day) with link to the day-view above each day or string with title
- * @param boolean $on_off=false start with row_on or row_off, default false=row_off
- * @param int $owner=0 if != 0 owner to add to the add-event link
+ * @param array &$events events to split into non-overlapping groups
*/
- function dayColWidget($day_ymd,$events,$left,$width,$indent,$short_title=True,$on_off=False,$owner=0)
+ function getEventCols($day_ymd, &$events)
{
- if ($this->debug > 1 || $this->debug==='dayColWidget') $this->bo->debug_message('uiviews::dayColWidget(%1,%2,left=%3,width=%4,)',False,$day_ymd,$events,$left,$width);
-
$day_start = $this->bo->date2ts((string)$day_ymd);
// if daylight saving is switched on or off, correct $day_start
@@ -952,7 +1193,7 @@ function open_edit(series)
{
$day_start -= $daylight_diff;
}
- // sorting the event into columns with none-overlapping events, the events are already sorted by start-time
+
$eventCols = $col_ends = array();
foreach($events as $event)
{
@@ -980,6 +1221,26 @@ function open_edit(series)
}
$eventCols[$c][] = $event;
}
+ return $eventCols;
+ }
+
+ /**
+ * Creates (if necessary multiple) columns for the events of a day
+ *
+ * Uses the eventColWidget to display each column.
+ *
+ * @param string/int $day_ymd date as Ymd
+ * @param array $events of events to show
+ * @param int $left start of the widget
+ * @param int $width width of the widget
+ * @param string $indent string for correct indention
+ * @param boolean/string $short_title=True should we add a label (weekday, day) with link to the day-view above each day or string with title
+ * @param boolean $on_off=false start with row_on or row_off, default false=row_off
+ * @param int $owner=0 if != 0 owner to add to the add-event link
+ */
+ function dayColWidget($day_ymd,$events,$left,$width,$indent,$short_title=True,$on_off=False,$owner=0)
+ {
+ if ($this->debug > 1 || $this->debug==='dayColWidget') $this->bo->debug_message('uiviews::dayColWidget(%1,%2,left=%3,width=%4,)',False,$day_ymd,$events,$left,$width);
$html = $indent.'
'."\n";
@@ -995,7 +1256,7 @@ function open_edit(series)
);
$this->_day_class_holiday($day_ymd,$class,$holidays);
// the weekday and date
- if (!$short_title && $holidays) $title .= ': '.$holidays;
+ if (!$short_title && $holidays) $title .= html::htmlspecialchars(': '.$holidays);
if ($short_title === true)
{
@@ -1027,8 +1288,10 @@ function open_edit(series)
$title .= ' '.$day_view;
}
}
- $html .= $indent."\t".'\n";
+ if (is_bool($short_title) || ($short_title != "")) {
+ $html .= $indent."\t".'\n";
+ }
if ($this->use_time_grid)
{
@@ -1045,7 +1308,7 @@ function open_edit(series)
}
}
// adding divs to click on for each row / time-span
- for($t = $this->scroll_to_wdstart ? 0 : $this->wd_start,$i = 1+$this->extraRows;
+ for($t = $this->scroll_to_wdstart ? 0 : $this->wd_start,$i = 1 + $this->extraRows;
$t <= $this->wd_end || $this->scroll_to_wdstart && $t < 24*60;
$t += $this->granularity_m,++$i)
{
@@ -1079,6 +1342,8 @@ function open_edit(series)
}
}
}
+
+ $eventCols = $this->getEventCols($day_ymd,$events);
// displaying all event columns of the day
foreach($eventCols as $n => $eventCol)
{
@@ -1098,26 +1363,35 @@ function open_edit(series)
* @param string &$class class to use
* @param string &$holidays commaseparted holidays or empty if none
* @param boolean $only_weekend=false show only the weekend in header-color, otherwise every second days is shown too
+ * @param boolean $show_bdays=true If available, also show birthdays (or hide Bdays)
+ * Note that this is not the place to disable a preference.
+ * If the preferences allow birthdays to be displayed, they are cached within the holidays structure.
+ * This setting just suppressing the available data in the view.
*/
- function _day_class_holiday($day_ymd,&$class,&$holidays,$only_weekend=false)
+ function _day_class_holiday($day_ymd,&$class,&$holidays,$only_weekend=false,$show_bdays=true)
{
$class = $holidays = '';
$bday = false;
if (isset($this->holidays[$day_ymd]))
{
+ $h = array();
foreach($this->holidays[$day_ymd] as $holiday)
{
if (isset($holiday['birthyear']))
{
- $bday = true;
+ if ($show_bdays)
+ {
+ $bday = true;
+ $h[] = $holiday['name'];
+ }
}
else
{
$class = 'calHoliday';
+ $h[] = $holiday['name'];
}
- $holidays[] = $holiday['name'];
}
- $holidays = implode(', ',$holidays);
+ $holidays = implode(', ',$h);
}
if (!$class)
{
@@ -1243,7 +1517,10 @@ function open_edit(series)
$small_trigger_width = 120 + 20*count($icons);
$corner_radius=$width > $small_trigger_width ? 10 : 5;
$header_height=$width > $small_trigger_width ? 19 : 12; // multi_3 icon has a height of 19=16+2*1padding+1border !
- if (!$return_array) $height = $this->times2height($event['start_m'],$event['end_m'],$header_height);
+ if (!$return_array)
+ {
+ $height = $this->times2height($event['start_m'],$event['end_m'],$header_height);
+ }
//$body_height = max(0,$height - $header_height - $corner_radius);
$border=1;
$headerbgcolor = $color ? $color : '#808080';
diff --git a/calendar/templates/default/app.css b/calendar/templates/default/app.css
index 6bf013edc9..a81101a260 100644
--- a/calendar/templates/default/app.css
+++ b/calendar/templates/default/app.css
@@ -483,6 +483,27 @@ e.g. the div with class calTimeGrid is generated by the timeGridWidget method of
.plannerEvent:hover{
cursor: pointer;
}
+
+/* Special colors for the year view */
+.cal_year_legend_weekend {
+ background-color: #CCCCCC;
+}
+.cal_year_legend {
+ background-color: #EFEFEF;
+}
+.cal_year_free {
+ background-color: #FFFFCC;
+ z-index: 0;
+}
+.cal_year_weekend {
+ background-color: #F9F9CC;
+ z-index: 0;
+}
+.cal_year_today {
+ border-color: #EE0000;
+ border-width: 2px;
+}
+
/**
* edit series or exception popup used in eventWidget and
* delete series and exceptions popup used in edit event