? calendar-multi-day.patch Index: calendar.css =================================================================== RCS file: calendar/calendar.css,v retrieving revision 1.30.2.23 diff -u -p -r1.30.2.23 calendar.css --- calendar.css 14 Feb 2009 20:07:59 -0000 1.30.2.23 +++ calendar.css 4 Oct 2010 05:33:43 -0000 @@ -230,10 +230,9 @@ table.calendar-legend tr.even .stripe { /* formatting for the full day view */ .calendar-calendar td.calendar-agenda-hour { - font-family:serif; text-align:right; border:none; - border-top:1px #333 dotted; + border-top:1px solid #CCCCCC; padding-top:.25em; width:1%; } @@ -248,7 +247,7 @@ table.calendar-legend tr.even .stripe { font-size:1em; } .calendar-calendar td.calendar-agenda-items { - border:1px #333 dotted; + border:1px solid #CCCCCC; text-align:left; } .calendar-calendar td.calendar-agenda-items div.calendar { @@ -333,7 +332,7 @@ table.calendar-legend tr.even .stripe { .calendar-calendar td .inner div.calendar div a { border:none; background:#ffc; - padding:0 2px; + padding:0; } .calendar-calendar td .inner div.calendar div.calendar-more, .calendar-calendar td .inner div.calendar div.calendar-more a { @@ -362,11 +361,467 @@ table.calendar-legend tr.even .stripe { background-color:#C3D6E4; } .calendar-calendar td .inner div.calendar div div.view-data-node-data-field-date-field-date-value { - border-bottom:1px solid #ccc; } /* The following are not used by default but are available for themes */ .calendar-calendar td.past {} .calendar-calendar td.future {} .calendar-calendar td.has-events {} -.calendar-calendar td.has-no-events {} \ No newline at end of file +.calendar-calendar td.has-no-events {} + +/* Multi day styles */ +.calendar-calendar tbody { + border-top : none; +} + +.calendar-calendar .month-view .full .inner, +.calendar-calendar .week-view .full .multi-day .inner { + height : auto; + min-height : auto; +} + +.calendar-calendar .week-view .full .calendar-agenda-hour { + width : 9%; +} + +.calendar-calendar .week-view .full .days { + width : 13%; +} + +.calendar-calendar .month-view .full div.calendar, +.calendar-calendar .week-view .full div.calendar, +.calendar-calendar .day-view div.calendar { + width : auto; +} + +.calendar-calendar .month-view .full td, +.calendar-calendar .week-view .full td, +.calendar-calendar .day-view td { + vertical-align: top; + padding :1px 2px 0 2px +} + +.calendar-calendar .month-view .full td.date-box { + height : 1%; + border-bottom: 0px; + padding-bottom : 2px; +} + + +.calendar-calendar .month-view .full .week { + font-size : inherit; +} + +.calendar-calendar .month-view .full .week a, +.calendar-calendar .week-view .full .week a { + color:#4b85ac; +} + +.calendar-calendar .month-view .full td .inner div.day, +.calendar-calendar .month-view .full td .inner div.day a { + border :none; + background : none; + margin-bottom: 0px; +} + +.calendar-calendar .month-view .full td.date-box .inner, +.calendar-calendar .week-view .full td.date-box .inner { + min-height : inherit; +} + +.calendar-calendar .month-view .full td.multi-day, +.calendar-calendar .week-view .full td.multi-day { + height : 1%; + border-top: 0px; + border-bottom: 0px; +} + +.calendar-calendar .week-view .full .first td.multi-day { + border-top : 1px solid #CCCCCC; +} + +.calendar-calendar .month-view .full td.single-day { + height : 98%; + border-top: 0px; +} + +.calendar-calendar .month-view .full td.multi-day .inner, +.calendar-calendar .week-view .full td.multi-day .inner, +.calendar-calendar .day-view .calendar .inner { + min-height : inherit; + width : auto; + overflow : hidden; + position : relative; +} + +.calendar-calendar .month-view .full td.single-day .inner, +.calendar-calendar .week-view .full td.single-day .inner { + min-height : 4em; + height : 98% !important; + height : 4em; + width : auto; + position : relative; +} + +.calendar-calendar .month-view .full td.multi-day.no-entry { + min-height : 0px; +} + +.calendar-calendar .month-view .full td.single-day.no-entry, +.calendar-calendar .month-view .full td.single-day .calendar-empty { + height : 100%; + line-height : 100%; + font-size : 1px; + min-height : 5em; +} + +.calendar-calendar .month-view .full td.single-day .calendar-empty, +.calendar-calendar .month-view .full td.single-day.empty, +.calendar-calendar .month-view .full td.date-box.empty { + background : #F4F4F4; +} + +.calendar-calendar .month-view .full td.single-day .inner div, +.calendar-calendar .month-view .full td.single-day .inner div a , +.calendar-calendar .month-view .full td.multi-day .inner div, +.calendar-calendar .month-view .full td.multi-day .inner div a , +.calendar-calendar .month-view .full td .inner div.calendar.monthview div, +.calendar-calendar .month-view .full td .inner div.calendar.monthview div a, +.calendar-calendar .week-view .full td.single-day .inner div, +.calendar-calendar .week-view .full td.single-day .inner div a , +.calendar-calendar .week-view .full td.multi-day .inner div, +.calendar-calendar .week-view .full td.multi-day .inner div a , +.calendar-calendar .week-view .full td .inner div.calendar.weekview div, +.calendar-calendar .week-view .full td .inner div.calendar.weekview div a, +.calendar-calendar .day-view td .inner div.calendar div, +.calendar-calendar .day-view td .inner div.calendar div a { + background : none; +} + +.calendar-calendar .day-view td .inner div.calendar div, +.calendar-calendar .day-view td .inner div.calendar div a { + margin : 0px 3px; +} + +.calendar-calendar .day-view td .inner div.calendar div.stripe { + margin : 0px; +} + +.calendar-calendar .month-view .full tr td.today, +.calendar-calendar .month-view .full tr.odd td.today, +.calendar-calendar .month-view .full tr.even td.today { + background: none; + border-left :2px solid #7C7F12; + border-right :2px solid #7C7F12; +} + +.calendar-calendar .month-view .full td.date-box.today { + border-width : 2px 2px 0px 2px; + border-style: solid; + border-color : #7C7F12; +} + +.calendar-calendar .month-view .full tr td.single-day.today { + border-bottom :2px solid #7C7F12; +} + +.calendar-calendar .month-view .full tr td.multi-day.starts-today { + border-left :2px solid #7C7F12; +} + +.calendar-calendar .month-view .full tr td.multi-day.ends-today { + border-right :2px solid #7C7F12; +} + +.calendar-calendar .month-view .full tr td.single-day { + border-top : 0px; +} + +.calendar-calendar .month-view .full tr td.date-box { + border-bottom : 0px; +} + +.calendar-calendar .month-view .full .inner .monthview, +.calendar-calendar .week-view .full .inner .weekview, +.calendar-calendar .day-view .inner .dayview { + -moz-border-radius : 5px; + border-radius : 5px; + height : 100%; + width : 100%; + float : none; + display : block; + margin : .25em auto; +} + + +.calendar-calendar .month-view .full td.single-day div.monthview, +.calendar-calendar .week-view .full td.single-day div.weekview, +.calendar-calendar .day-view td div.dayview { + background : #FFD8C0; + width : auto; + padding : 0px 3px; +} + +.calendar-calendar .month-view .full td.single-day .calendar-more div.monthview { + background : none; +} + +.calendar-calendar .day-view td div.dayview { + padding : 0px; +} + +.calendar-calendar .month-view .full td.multi-day div.monthview, +.calendar-calendar .week-view .full td.multi-day div.weekview { + background : #74a5d7; + height : 1.9em; + overflow : hidden; + margin : 0px auto; + color : #ffffff; + position : relative; +} + +.calendar-calendar .week-view .full td.multi-day div.weekview { + height : 3.5em; +} + +.calendar-calendar .month-view .full td.multi-day .inner .view-field, +.calendar-calendar .month-view .full td.multi-day .inner .view-field a, +.calendar-calendar .week-view .full td.multi-day .inner .view-field, +.calendar-calendar .week-view .full td.multi-day .inner .view-field a { + color : #ffffff; +} + +.calendar-calendar .full td.multi-day .calendar .view-field, +.calendar-calendar .full td.single-day .calendar .view-field { +} + +.calendar-calendar .month-view .full td.multi-day .calendar.monthview .view-field { + white-space: nowrap; + float : left; + margin-right : 3px; +} + +.calendar-calendar .week-view .full td.multi-day .calendar.weekview .view-field { + white-space: nowrap; + display : inline; + margin-right : 3px; +} + +.calendar-calendar .week-view .full td.multi-day .calendar.weekview .view-field { + display : block; +} + +.calendar-calendar .month-view .full td.multi-day .calendar.monthview .contents, +.calendar-calendar .week-view .full td.multi-day .calendar.weekview .contents { + position : absolute; + width : 3000px; + left: 5px; +} + +.calendar-calendar .day-view td .stripe, +.calendar-calendar .month-view .full td .stripe, +.calendar-calendar .week-view .full td .stripe { + -moz-border-radius : 5px 5px 0px 0px; + border-radius : 5px 5px 0px 0px; + left:0; + position:absolute; + width : 100%; + height :3px; + z-index : 2; +} + +.calendar-calendar .full td.single-day .continuation, +.calendar-calendar .full td.single-day .continues, +.calendar-calendar .full td.single-day .cutoff { + display : none; +} + +.calendar-calendar .month-view .full td.multi-day .inner .monthview .continuation, +.calendar-calendar .week-view .full td.multi-day .inner .weekview .continuation { + float :left; + margin-right : 3px; + height : 1.9em; +} + +.calendar-calendar .week-view .full td.multi-day .inner .weekview .continuation { + height : 2.75em; + padding-top: 0.75em; + margin-right : 8px; +} + +.calendar-calendar .month-view .full td.multi-day .inner .monthview .continues, +.calendar-calendar .month-view .full td.multi-day .inner .monthview .cutoff, +.calendar-calendar .week-view .full td.multi-day .inner .weekview .continues, +.calendar-calendar .week-view .full td.multi-day .inner .weekview .cutoff { + position:absolute; + right : 0px !important; + right : -1px; + width : 10px; + text-align: left; + background : #74a5d7; + -moz-border-radius : 0px 5px 5px 0px; + border-radius : 0px 5px 5px 0px; + height : 1.9em; + padding-left: 6px; + z-index : 1; +} + +.calendar-calendar .week-view .full td.multi-day .inner .weekview .continues, +.calendar-calendar .week-view .full td.multi-day .inner .weekview .cutoff { + height : 2.75em; + padding-top: 0.75em; +} + +.calendar-calendar .month-view .full td.multi-day .inner .monthview .cutoff, +.calendar-calendar .week-view .full td.multi-day .inner .weekview .cutoff { + width : 8px; + padding-left: 0px; +} + +.calendar-calendar .week-view .full td.multi-day { + padding : 2px; +} + +.calendar-calendar .week-view td.single-day div.calendar { + width : 100%; + padding-left:0px; + padding-right : 0px; +} + +.calendar-calendar .week-view .full tr.last td.multi-day { + border-bottom:1px solid #CCCCCC; +} + +/* Restyle Header */ +.view-content .calendar-calendar { + position : relative; + margin-top : 5px; + float:left; + width: 100%; +} + +.view-content .calendar-calendar .links { + display : block; +} + +.view-content .calendar-calendar ul.links { + margin-bottom: 3px; +} + +.view-content .calendar-calendar ul { + position : absolute; + width : 210px; + top : 8px ; + line-height : inherit; + z-index : 1; +} + +.view-content .calendar-calendar li { + float : left; + line-height : inherit ; + margin-left : 10px ; +} + +.view-content .calendar-calendar li a { + text-decoration : underline ; + line-height : inherit ; +} + +.view-content .calendar-calendar .date-nav { + background-color : transparent ; + border : 0px ; + height : 30px; + height : auto ; + min-height : 30px; +} + +.view-content .calendar-calendar .date-nav a { + text-decoration : none ; + color : inherit ; +} + +.view-content .calendar-calendar .date-nav a:hover { + text-decoration : underline ; +} + +.view-content .calendar-calendar .date-prev { + -moz-border-radius:5px 0 0 5px; + border-radius:5px 0 0 5px; + background:none repeat scroll 0 0 #dfdfdf; + float:none; + padding:5px 0; + position:absolute; + right:60px; + text-align:right; + top:0px; + width:auto; + z-index : 1; + font-size : 12px; +} + +.view-content .calendar-calendar .date-prev span { + margin-left : 10px; + font-style : bold; +} + +.view-content .calendar-calendar .date-heading { + position : relative; + width : 100%; + top : 0px; + text-align : center; + z-index : 0; + float : none; +} + +.view-content .calendar-calendar .date-heading h3 { + line-height : 30px ; + font-size : 1.7em ; +} + +.view-content .calendar-calendar .date-next { + -moz-border-radius:0px 5px 5px 0px; + border-radius:0px 5px 5px 0px; + background:none repeat scroll 0 0 #dfdfdf; + float:none; + padding:5px 0; + position:absolute; + right:0px; + text-align:right; + top:0px; + width:auto; + z-index : 1; + font-size : 12px; +} + +.view-content .calendar-calendar .date-next span { + margin-right : 10px; + font-style : bold; +} + +.view-content:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.attachment .calendar-calendar { + margin-top : 20px ; + clear : both; +} + +.attachment .calendar-calendar th { + background-color : transparent ; + border : 0px ; +} + +.attachment .calendar-calendar th.calendar-agenda-hour { + color : #777777; + font-weight : bold; + text-align : right; +} + +.view-calendar .feed-icon { + margin-top : 5px; +} \ No newline at end of file Index: calendar.module =================================================================== RCS file: calendar/calendar.module,v retrieving revision 1.121.2.38 diff -u -p -r1.121.2.38 calendar.module --- calendar.module 17 Mar 2009 18:03:36 -0000 1.121.2.38 +++ calendar.module 4 Oct 2010 05:33:43 -0000 @@ -92,8 +92,16 @@ function calendar_theme() { ), 'calendar_time_row_heading' => $base + array( 'arguments' => array('start_time', 'next_start_time', 'curday_date'), + ), + 'calendar_month_col' => $base + array( + 'template' => 'calendar-month-col', + 'arguments' => array('item' => NULL), ), - ); + 'calendar_month_row' => $base + array( + 'template' => 'calendar-month-row', + 'arguments' => array('inner' => NULL), + ), + ); } /** Index: includes/calendar.inc =================================================================== RCS file: calendar/includes/calendar.inc,v retrieving revision 1.1.2.40 diff -u -p -r1.1.2.40 calendar.inc --- includes/calendar.inc 11 May 2009 22:24:27 -0000 1.1.2.40 +++ includes/calendar.inc 4 Oct 2010 05:33:44 -0000 @@ -18,7 +18,7 @@ function calendar_build_calendar($view, $item_end = date_format($item->calendar_end_date, DATE_FORMAT_DATE); if (($item_start >= $view->date_info->min_date_date && $item_start <= $view->date_info->max_date_date) || ($item_end >= $view->date_info->min_date_date && $item_end <= $view->date_info->max_date_date)) { - $values[$item_start][date_format($item->calendar_start_date, 'H:i:s')][] = $item; + $values[$item_start][date_format($item->date_start, 'H:i:s')][] = $item; } } $items = $values; @@ -32,13 +32,13 @@ function calendar_build_calendar($view, $rows = array(); $view->date_info->mini = TRUE; for ($i = 1; $i <= 12; $i++) { - $rows[$i] = calendar_build_month($curday, $view, $items); + $rows[$i] = calendar_build_mini_month($curday, $view, $items); } $view->date_info->mini = FALSE; break; case 'month': - $rows = calendar_build_month($curday, $view, $items); + $rows = ($view->date_info->mini) ? calendar_build_mini_month($curday, $view, $items) : calendar_build_month($curday, $view, $items); break; case 'day': @@ -59,13 +59,13 @@ function calendar_build_calendar($view, /** * Build one month. */ -function calendar_build_month(&$curday, $view, $items) { +function calendar_build_mini_month(&$curday, $view, $items) { $month = date_format($curday, 'n'); date_modify($curday, '-' . strval(date_format($curday, 'j')-1) . ' days'); $rows = array(); do { - $rows = array_merge($rows, calendar_build_week($curday, $view, $items, TRUE)); + $rows = array_merge($rows, calendar_build_mini_week($curday, $view, $items, TRUE)); $curday_date = date_format($curday, DATE_FORMAT_DATE); $curday_month = date_format($curday, 'n'); } while ($curday_month == $month && $curday_date <= $view->date_info->max_date_date); @@ -76,9 +76,190 @@ function calendar_build_month(&$curday, } /** + * Build one month. + */ +function calendar_build_month(&$curday, $view, $items) { + $month = date_format($curday, 'n'); + date_modify($curday, '-' . strval(date_format($curday, 'j')-1) . ' days'); + + $rows = array(); + do { + $init_day = clone($curday); + $today = date_format(date_now(date_default_timezone_name()), DATE_FORMAT_DATE); + $month = date_format($curday, 'n'); + $week = date_week($curday_date); + $first_day = variable_get('date_first_day', 0); + $week_rows = calendar_build_week($curday, $view, $items, TRUE); + $multiday_buckets = $week_rows['multiday_buckets']; + $singleday_buckets = $week_rows['singleday_buckets']; + $total_rows = $week_rows['total_rows']; + + // Theme each row + $output = ""; + $final_day = clone($curday); + + // Add a row for the day numbers + for ($i = 0; $i < $total_rows + 1; $i++) { + $inner = ""; + + // If we're displaying the week number, add it as the + // first cell in the week. + if ($i == 0 && !empty($view->date_info->style_with_weekno) && !in_array($view->date_info->granularity, array('day', 'week'))) { + $url = $view->get_path() .'/'. $view->date_info->year .'-W'. $week; + if (!empty($view->date_info->display_types['week'])) { + $weekno = l($week, $url, array('query' => !empty($view->date_info->append) ? $view->date_info->append : '')); + } + else { + // Do not link week numbers, if Week views are disabled. + $weekno = $week; + } + $item = array( + 'entry' => $weekno, + 'colspan' => 1, + 'rowspan' => $total_rows + 1, + 'id' => $view->name . '-weekno-' . $curday_date, + 'class' => 'week' + ); + $inner .= theme('calendar_month_col', $item); + } + + $curday = clone($init_day); + + // move backwards to the first day of the week + $day_wday = date_format($curday, 'w'); + date_modify($curday, '-' . strval((7 + $day_wday - $first_day) % 7) . ' days'); + + for ( $wday = 0; $wday < 7; $wday++) { + + $curday_date = date_format($curday, DATE_FORMAT_DATE); + $class = strtolower($weekdays[$wday]); + $item = NULL; + $in_month = !($curday_date < $view->date_info->min_date_date || $curday_date > $view->date_info->max_date_date || date_format($curday, 'n') != $month); + + // Add the datebox + if ($i == 0) { + $item = array( + 'entry' => theme('calendar_datebox', $curday_date, $view), + 'colspan' => 1, + 'rowspan' => 1, + 'class' => 'date-box', + 'id' => $view->name . '-' . $curday_date . '-date-box' + ); + $item['class'] .= ($curday_date == $today && $in_month ? ' today' : '') . + ($curday_date < $today ? ' past' : '') . + ($curday_date > $today ? ' future' : ''); + } + else { + $index = $i - 1; + $multi_count = count($multiday_buckets[$wday]); + + // Process multiday buckets first. If there is a multiday-bucket item in this row... + if ($index < $multi_count) { + + // If this item is filled with either a blank or an entry... + if ($multiday_buckets[$wday][$index]['filled']) { + + // Add item and add class + $item = $multiday_buckets[$wday][$index]; + $item['class'] = 'multi-day'; + + // Is this an entry? + if (!$multiday_buckets[$wday][$index]['avail']) { + + // If the item either starts or ends on today, + // then add tags so we can style the borders + if ($curday_date == $today && $in_month) { + $item['class'] .= ' starts-today'; + } + + // Calculate on which day of this week this item ends on.. + $end_day = clone($curday); + $span = $item['colspan'] - 1; + date_modify($end_day, '+' . $span .' day'); + $endday_date = date_format($end_day, DATE_FORMAT_DATE); + + // If it ends today, add class + if ($endday_date == $today && $in_month) { + $item['class'] .= ' ends-today'; + } + } + } + + // If this is an acutal entry, add classes regarding the state of the + // item + if ($multiday_buckets[$wday][$index]['avail']) { + $item['class'] .= ' ' . $wday . ' ' . $index . ' no-entry ' . ($curday_date == $today && $in_month ? ' today' : '') . + ($curday_date < $today ? ' past' : '') . + ($curday_date > $today ? ' future' : ''); + } + + // Else, process the single day bucket - we only do this once per day + } + elseif ($index == $multi_count) { + + // If it's empty, add class + if (count($singleday_buckets[$wday]) == 0 && $multi_count == 0) { + $single_days = " "; + $class = 'single-day no-entry'; + } + else { + $single_days = ""; + foreach ($singleday_buckets[$wday] as $day) { + foreach ($day as $event) { + $single_days .= ($event['more_link']) ? '
' . $event['entry'] . '
' : $event['entry']; + } + } + $class = 'single-day'; + } + + // Add item... + $item = array( + 'entry' => $single_days, + 'colspan' => 1, + 'rowspan' => $total_rows - $index, + 'class' => $class, + 'id' => $view->name . '-' . $curday_date + ); + $item['class'] .= ($curday_date == $today && $in_month ? ' today' : '') . + ($curday_date < $today ? ' past' : '') . + ($curday_date > $today ? ' future' : ''); + } + } + + // If there isn't an item, then add empty class + if ($item != NULL) { + if (!$in_month) { + $item['class'] .= ' empty'; + } + + // Style this entry - it will be a . + $inner .= theme('calendar_month_col', $item); + } + + date_modify($curday, '+1 day'); + } + + // Style all the columns into a row + $output .= theme('calendar_month_row', $inner); + } + $curday = $final_day; + + // Add the row into the row array.... + $rows[] = array('data' => $output); + + $curday_date = date_format($curday, DATE_FORMAT_DATE); + $curday_month = date_format($curday, 'n'); + } while ($curday_month == $month && $curday_date <= $view->date_info->max_date_date); + + // Merge the day names in as the first row. + $rows = array_merge(array(calendar_week_header($view)), $rows); + return $rows; +} + +/** * Build one week row. */ -function calendar_build_week(&$curday, $view, $items, $check_month = FALSE) { +function calendar_build_mini_week(&$curday, $view, $items, $check_month = FALSE) { $curday_date = date_format($curday, DATE_FORMAT_DATE); $weekdays = calendar_untranslated_days($items, $view); $today = date_format(date_now(date_default_timezone_name()), DATE_FORMAT_DATE); @@ -109,8 +290,7 @@ function calendar_build_week(&$curday, $ } for ($i = 0; $i < 7; $i++) { $curday_date = date_format($curday, DATE_FORMAT_DATE); - $class = strtolower($weekdays[$i] . - ($view->date_info->mini ? ' mini' : '')); + $class = strtolower($weekdays[$i] . ' mini'); if ($check_month && ($curday_date < $view->date_info->min_date_date || $curday_date > $view->date_info->max_date_date || date_format($curday, 'n') != $month)) { $class .= ' empty'; $content = array( @@ -139,6 +319,217 @@ function calendar_build_week(&$curday, $ } /** + * Build one week row. + */ +function calendar_build_week(&$curday, $view, $items, $check_month = FALSE) { + $curday_date = date_format($curday, DATE_FORMAT_DATE); + $weekdays = calendar_untranslated_days($items, $view); + $month = date_format($curday, 'n'); + $first_day = variable_get('date_first_day', 0); + + // Set up buckets + $total_rows = 0; + $multiday_buckets = array( array(), array(), array(), array(), array(), array(), array()); + $singleday_buckets = array( array(), array(), array(), array(), array(), array(), array()); + + // move backwards to the first day of the week + $day_wday = date_format($curday, 'w'); + date_modify($curday, '-' . strval((7 + $day_wday - $first_day) % 7) . ' days'); + $curday_date = date_format($curday, DATE_FORMAT_DATE); + + for ($i = 0; $i < 7; $i++) { + if ($check_month && ($curday_date < $view->date_info->min_date_date || $curday_date > $view->date_info->max_date_date || date_format($curday, 'n') != $month)) { + $class = strtolower($weekdays[$i]) .' empty'; + $singleday_buckets[$i][][] = array( + 'entry' => theme('calendar_empty_day', $curday_date, $view), + 'item' => NULL + ); + } + else { + calendar_build_week_day($curday, $view, $items, $i, $multiday_buckets, $singleday_buckets); + } + $total_rows = max(count($multiday_buckets[$i]) + 1, $total_rows); + date_modify($curday, '+1 day'); + $curday_date = date_format($curday, DATE_FORMAT_DATE); + } + + $rows = array( + 'multiday_buckets' => $multiday_buckets, + 'singleday_buckets' => $singleday_buckets, + 'total_rows' => $total_rows); + return $rows; +} + +/** + * Build the contents of a single day for the $rows results. + */ +function calendar_build_week_day($curday, $view, $items, $wday, &$multiday_buckets, &$singleday_buckets) { + $curday_date = date_format($curday, DATE_FORMAT_DATE); + $max_events = !empty($view->date_info->style_max_items) ? $view->date_info->style_max_items : 0; + $hide = !empty($view->date_info->style_max_items_behavior) ? ($view->date_info->style_max_items_behavior == 'hide') : FALSE; + $multiday_theme = $view->date_info->style_multiday_theme != '0'; + $cur_cnt = 0; + $total_cnt = 0; + $types = array(); + + // If we are hiding, count before processing further + if ($max_events != CALENDAR_SHOW_ALL) { + foreach ($items as $date => $day) { + if ($date == $curday_date) { + foreach ($day as $time => $hour) { + foreach ($hour as $key => $item) { + $total_cnt++; + $types[$item->type] = $item; + } + } + } + } + } + + // If we haven't already exceeded the max or we'll showing all, then process the items + if ($max_events == CALENDAR_SHOW_ALL || !$hide || $total_cnt <= $max_events) { + + // Count currently filled items + foreach ($multiday_buckets[$wday] as $bucket) { + if (!$bucket['avail']) { + $cur_cnt++; + } + } + + foreach ($items as $date => $day) { + if ($date == $curday_date) { + $count = 0; + ksort($day); + foreach ($day as $time => $hour) { + foreach ($hour as $key => $item) { + $count++; + + // Can we add an item? + if ($max_events == CALENDAR_SHOW_ALL || $cur_cnt <= $max_events) { + $all_day = $item->calendar_start_date == $item->calendar_end_date; + $theme = isset($item->calendar_node_theme) ? $item->calendar_node_theme : 'calendar_'. $view->date_info->granularity .'_node'; + + // Parse out date part + $start_ydate = date_format($item->date_start, DATE_FORMAT_DATE); + $end_ydate = date_format($item->date_end, DATE_FORMAT_DATE); + $cur_ydate = date_format($curday, DATE_FORMAT_DATE); + + $is_multi_day = ($start_ydate < $cur_ydate || $end_ydate > $cur_ydate || $all_day); + + // Does this event span multi-days? + if ($multiday_theme && $is_multi_day) { + + // If this the first day of the week, or is the start date of the multi-day event, + // then record this item, otherwise skip over + $day_no = date_format($curday, 'd'); + if ($wday == 0 || $start_ydate == $cur_ydate || ($view->date_info->granularity == 'month' && $day_no == 1) || $all_day) { + $cur_cnt++; + + // Calculate the colspan for this event + $start = date_make_date($cur_ydate); + $end = date_make_date($end_ydate); + $curday_obj = date_make_date($curday_date); + + // Calculate end of month + $last_day = date_make_date($view->date_info->max_date_date); + + // If the last day of this event exceeds the end of the current month or week, + // truncate the remaining days + $remaining_days = min(6, date_difference($last_day, $curday_obj, 'days')); + $remaining_days = ($view->date_info->granularity == 'month') ? $remaining_days - $wday : $remaining_days; + + // The bucket_cnt defines the colspan. colspan = bucket_cnt + 1 + $days = date_difference($start, $end, 'days'); + $bucket_cnt = max(0, min($days, $remaining_days)); + + // See if there is an avaiable slot to add an event. This will allow + // an event to precede a row filled up by a previous day event + $avail = FALSE; + $bucket_index = count($multiday_buckets[$wday]); + for ($i = 0; $i < $bucket_index; $i++) { + if ($multiday_buckets[$wday][$i]['avail']) { + $bucket_index = $i; + break; + } + } + + // Add continuation attributes + $start_date = date_make_date($start_ydate); + $item->continuation = ($start_date < $curday_obj); + $item->continues = ( $days > $bucket_cnt ); + + // Assign the item to the available bucket + $multiday_buckets[$wday][$bucket_index] = array( + 'colspan' => $bucket_cnt + 1, + 'rowspan' => 1, + 'filled' => TRUE, + 'avail' => FALSE, + 'all_day' => $all_day, + 'item' => $item, + 'wday' => $wday, + 'entry' => theme($theme, $item, $view) + ); + + // Block out empty buckets for the next days in this event for this week + for ($i = 0; $i < $bucket_cnt; $i++) { + $bucket = &$multiday_buckets[$i + $wday + 1]; + $bucket_row_count = count($bucket); + $row_diff = $bucket_index - $bucket_row_count; + + // Fill up the preceding buckets - these are available for future + // events + for ( $j = 0; $j < $row_diff; $j++) { + $bucket[($bucket_row_count + $j) ] = array( + 'entry' => ' ', + 'colspan' => 1, + 'rowspan' => 1, + 'filled' => TRUE, + 'avail' => TRUE, + 'wday' => $wday, + 'item' => NULL + ); + } + $bucket[$bucket_index] = array( + 'filled' => FALSE, + 'avail' => FALSE + ); + } + } + } + else { + $cur_cnt++; + // Assign to single day bucket + $singleday_buckets[$wday][$time][] = array( + 'entry' => theme($theme, $item, $view), + 'item' => $item, + 'colspan' => 1, + 'rowspan' => 1, + 'filled' => TRUE, + 'avail' => FALSE, + 'wday' => $wday, + ); + } + } + else { + break; // exceeded count + } + } + } + } + } + } + + // Add a more link if necessary + if ($max_events != CALENDAR_SHOW_ALL && $total_cnt > 0 && $cur_cnt < $total_cnt) { + $singleday_buckets[$wday][][] = array( + 'entry' => theme('calendar_'. $view->date_info->calendar_type .'_multiple_node', $curday_date, $total_cnt, $view, $types), + 'more_link' => TRUE, + 'item' => NULL + ); + } +} + +/** * Build the contents of a single day for the $rows results. */ function calendar_build_day($curday, $view, $items) { @@ -169,7 +560,7 @@ function calendar_build_day($curday, $vi $all_day[] = in_array($view->date_info->calendar_type, array('day', 'week')) ? $item : theme($theme, $item, $view); } else { - $key = date_format($item->calendar_start_date, 'H:i:s'); + $key = date_format($item->date_start, 'H:i:s'); $inner[$key][] = in_array($view->date_info->calendar_type, array('day', 'week')) ? $item : theme($theme, $item, $view); } } @@ -514,12 +905,14 @@ function calendar_build_nodes(&$view, &$ $node->calendar_start = $values[0] < $start ? $start : $values[0]; $node->calendar_end = !empty($values[1]) ? ($values[1] > $end ? $end : $values[1]) : $node->calendar_start; } - + $node->date_start = date_create($values[0], timezone_open($to_zone)); + $node->date_end = date_create(!empty($values[1]) ? $values[1] : $values[0], timezone_open($to_zone));; + // Make date objects $node->calendar_start_date = date_create($node->calendar_start, timezone_open($to_zone)); $node->calendar_end_date = date_create($node->calendar_end, timezone_open($to_zone)); - if (date_format($node->calendar_start_date, 'H:i:s') == '00:00:00' && - date_format($node->calendar_end_date, 'H:i:s') == '23:59:59') { + if (date_format($node->date_end, 'H:i:s') == '00:00:00' && + date_format($node->date_start, 'H:i:s') == '23:59:59') { $node->calendar_all_day = TRUE; } else { Index: includes/calendar.views_default.inc =================================================================== RCS file: calendar/includes/calendar.views_default.inc,v retrieving revision 1.1.2.21 diff -u -p -r1.1.2.21 calendar.views_default.inc --- includes/calendar.views_default.inc 21 Feb 2009 16:33:15 -0000 1.1.2.21 +++ includes/calendar.views_default.inc 4 Oct 2010 05:33:45 -0000 @@ -365,6 +365,7 @@ $handler->override_option('style_options 'display_type' => 'month', 'name_size' => '99', 'with_weekno' => '1', + 'multiday_theme' => '1', 'date_fields' => NULL, 'max_items' => 0, )); @@ -406,6 +407,7 @@ $handler->override_option('style_plugin' $handler->override_option('style_options', array( 'name_size' => '99', 'with_weekno' => 0, + 'multiday_theme' => '1', 'max_items' => 0, 'max_items_behavior' => 'more', 'groupby_times' => 'hour', Index: includes/calendar_view_plugin_style.inc =================================================================== RCS file: calendar/includes/calendar_view_plugin_style.inc,v retrieving revision 1.1.2.19 diff -u -p -r1.1.2.19 calendar_view_plugin_style.inc --- includes/calendar_view_plugin_style.inc 17 Feb 2009 18:09:35 -0000 1.1.2.19 +++ includes/calendar_view_plugin_style.inc 4 Oct 2010 05:33:46 -0000 @@ -15,6 +15,7 @@ class calendar_view_plugin_style extends $calendar_type = $this->display->handler->get_option('calendar_type'); $view->date_info->style_name_size = $this->options['name_size']; $view->date_info->style_with_weekno = $this->options['with_weekno']; + $view->date_info->style_multiday_theme = $this->options['multiday_theme']; $view->date_info->style_max_items = $this->options['max_items']; $view->date_info->style_max_items_behavior = $this->options['max_items_behavior']; if (!empty($this->options['groupby_times_custom'])) { @@ -39,6 +40,7 @@ class calendar_view_plugin_style extends function options(&$options) { $options['name_size'] = 3; $options['with_weekno'] = 0; + $options['multiday_theme'] = 1; $options['max_items'] = 0; $options['max_items_behavior'] = 'more'; $options['groupby_times'] = 'hour'; @@ -58,6 +60,13 @@ class calendar_view_plugin_style extends '#options' => array(1 => t('First letter of name'), 2 => t('First two letters of name'), 3 => t('Abbreviated name'), 99 => t('Full name')), '#description' => t('The way day of week names should be displayed in a calendar.'), ); + $form['multiday_theme'] = array( + '#title' => t('Theme multi day events with a multi-column row'), + '#default_value' => $this->options['multiday_theme'], + '#type' => in_array($calendar_type, array('month','week')) ? 'radios' : 'value', + '#options' => array(0 => t('No'), 1 => t('Yes')), + '#description' => t('If selected, events which span multiple days will displayed as a multi-column row. If not selected, the event will be displayed as individual items for each day.'), + ); $form['with_weekno'] = array( '#title' => t('Show week numbers'), '#default_value' => $this->options['with_weekno'], Index: theme/calendar-month-col.tpl.php =================================================================== RCS file: theme/calendar-month-col.tpl.php diff -N theme/calendar-month-col.tpl.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ theme/calendar-month-col.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -0,0 +1,14 @@ + + +
+ +
+ Index: theme/calendar-month-node.tpl.php =================================================================== RCS file: calendar/theme/calendar-month-node.tpl.php,v retrieving revision 1.2.2.5 diff -u -p -r1.2.2.5 calendar-month-node.tpl.php --- theme/calendar-month-node.tpl.php 19 Nov 2008 12:35:40 -0000 1.2.2.5 +++ theme/calendar-month-node.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -37,17 +37,28 @@ * * @see template_preprocess_calendar_month_node. */ +$index = 0; ?>
-
+
- -
- -
- - -
- +
+ + continuation) : ?> +
«
+ +
+ +
+ + +
+ +
+ continues) : ?> +
»
+ +
 
+
Index: theme/calendar-month-row.tpl.php =================================================================== RCS file: theme/calendar-month-row.tpl.php diff -N theme/calendar-month-row.tpl.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ theme/calendar-month-row.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -0,0 +1,12 @@ + + + + Index: theme/calendar-month.tpl.php =================================================================== RCS file: calendar/theme/calendar-month.tpl.php,v retrieving revision 1.6.2.3 diff -u -p -r1.6.2.3 calendar-month.tpl.php --- theme/calendar-month.tpl.php 19 Jun 2008 22:55:56 -0000 1.6.2.3 +++ theme/calendar-month.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -21,7 +21,7 @@ //dsm('Display: '. $display_type .': '. $min_date_formatted .' to '. $max_date_formatted); ?>
- +
@@ -32,15 +32,10 @@ - - - - - - - +
- -
\ No newline at end of file Index: theme/calendar-week-node.tpl.php =================================================================== RCS file: calendar/theme/calendar-week-node.tpl.php,v retrieving revision 1.2.2.2 diff -u -p -r1.2.2.2 calendar-week-node.tpl.php --- theme/calendar-week-node.tpl.php 20 Jun 2008 11:19:30 -0000 1.2.2.2 +++ theme/calendar-week-node.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -39,9 +39,13 @@ */ ?>
-
+
+
+ continuation) : ?> +
«
+
@@ -49,5 +53,11 @@
+
+ continues) : ?> +
»
+ +
 
+
Index: theme/calendar-week.tpl.php =================================================================== RCS file: calendar/theme/calendar-week.tpl.php,v retrieving revision 1.5.2.6 diff -u -p -r1.5.2.6 calendar-week.tpl.php --- theme/calendar-week.tpl.php 16 Feb 2009 23:46:22 -0000 1.5.2.6 +++ theme/calendar-week.tpl.php 4 Oct 2010 05:33:46 -0000 @@ -27,13 +27,16 @@ //dsm('Display: '. $display_type .': '. $min_date_formatted .' to '. $max_date_formatted); //dsm($rows); //dsm($items); +$index = 0; ?>
- +
- + 0 || !empty($start_times)) :?> + + - - - - - + + + + 0 || !empty($start_times))) :?> + + + + + + + + + + + + + + + + - - + - - + + + + + + -
0 ? t('Time') : ''; ?> @@ -42,39 +45,80 @@
- 0 ? date_t('All day', 'datetime') : ''; ?> - - -
-
- -
-
-
+ +
 
+
+ +
+
 
+
- + + + $column): ?> + + + +
+
 
+
+
- + + + + +
+
+
 
+
+
\ No newline at end of file Index: theme/theme.inc =================================================================== RCS file: calendar/theme/theme.inc,v retrieving revision 1.10.2.72 diff -u -p -r1.10.2.72 theme.inc --- theme/theme.inc 2 Jul 2009 14:42:08 -0000 1.10.2.72 +++ theme/theme.inc 4 Oct 2010 05:33:46 -0000 @@ -282,7 +282,7 @@ function template_preprocess_calendar_da if (empty($view->date_info->style_groupby_times)) { // Items are already grouped into times, so we need to process each time-group. foreach ($rows['items'] as $time => $items) { - foreach($items as $item) { + foreach ($items as $item) { $rows['all_day'][] = $item; } } @@ -318,8 +318,9 @@ function template_preprocess_calendar_da $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; $grouped_items = array(); - foreach ($rows['items'] as $time => $items) { + foreach ($rows['items'] as $items) { foreach ($items as $item) { + $time = date_format($item->date_start, 'H:i:s'); if (isset($item->{$grouping_field})) { $column = $item->{$grouping_field}; $item->{$grouping_field} = ''; // Remove the grouping field from the results. @@ -421,57 +422,74 @@ function template_preprocess_calendar_we $end_start_time = '23:59:59'; $grouped_items = array(); - $vars['rows'] = $rows[0]; - foreach ($rows[0] as $weekno => $row) { - $vars['rows'][$weekno] = $row['data']; - - // If we're not grouping by time, move all items into the 'all day' array. - if (empty($view->date_info->style_groupby_times)) { - foreach ($row['data']['items'] as $item) { - $row['data']['all_day'] += $item; - } - $row['data']['items'] = array(); - } - - $columns[] = $weekno; - $start_times = $view->date_info->style_groupby_times; - $start_time = array_shift($start_times); - $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; - foreach ($row['data']['all_day'] as $key => $item) { - $theme = isset($item->calendar_node_theme) ? $item->calendar_node_theme : 'calendar_'. $view->date_info->granularity .'_node'; - $vars['rows'][$weekno]['all_day'][$key] = theme($theme, $item, $view); - $item_count++; + + // pass the multiday buckets + $vars['all_day'] = $rows['multiday_buckets']; + + // Remove the count for singleday + $vars['multiday_rows'] = max(0, $rows['total_rows'] - 1); + + // If we're not grouping by time, move all items into the 'all day' array. + if (empty($view->date_info->style_groupby_times)) { + $add_row = FALSE; + foreach ($vars['all_day'] as $index => &$day ) { + foreach ($rows['singleday_buckets'][$index] as $item) { + foreach ($item as $event) { + $day[] = $event; + $add_row = TRUE; + } + } } - foreach ($row['data']['items'] as $time => $items) { - foreach ($items as $item) { - // Find the next time slot and fill it. Populate the skipped - // slots if the option to show empty times was chosen. - while ($time >= $next_start_time && $time < $end_start_time) { - if (($show_empty_times) && !array_key_exists($start_time, $grouped_items)) { - $grouped_items[$start_time]['values'][$weekno] = array(); + if ( $add_row ) { + $vars['multiday_rows']++; + } + } + else { + + foreach ($rows['singleday_buckets'] as $weekno => $singleday_row) { + $columns[] = $weekno; + foreach ($singleday_row as $row) { + + $start_times = $view->date_info->style_groupby_times; + $start_time = array_shift($start_times); + $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; + foreach ($row as $item) { + $time = date_format($item['item']->date_start, 'H:i:s'); + if ($item['item']->calendar_all_day || ($item['item']->date_start == $item['item']->date_end)) { + $vars['all_day'][$item['wday']][] = $item; + if ($vars['multiday_rows'] == 0) { + $vars['multiday_rows']++; + } + } + else { + // Find the next time slot and fill it. Populate the skipped + // slots if the option to show empty times was chosen. + while ($time >= $next_start_time && $time < $end_start_time) { + if (($show_empty_times) && !array_key_exists($start_time, $grouped_items)) { + $grouped_items[$start_time]['values'][$weekno] = array(); + } + $start_time = $next_start_time; + $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; + } + $grouped_items[$start_time]['values'][$weekno][] = $item; + $item_count++; + $by_hour_count++; } - $start_time = $next_start_time; - $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; } - $theme = isset($item->calendar_node_theme) ? $item->calendar_node_theme : 'calendar_'. $view->date_info->granularity .'_node'; - $grouped_items[$start_time]['values'][$weekno][] = theme($theme, $item, $view); - $item_count++; - $by_hour_count++; } - } - - // Finish out the day's time values if we want to see empty times. - if ($show_empty_times) { - while ($start_time < $end_start_time) { - if (!array_key_exists($start_time, $grouped_items)) { - $grouped_items[$start_time]['values'][$weekno] = array(); + // Finish out the day's time values if we want to see empty times. + if ($show_empty_times) { + while ($start_time < $end_start_time && $start_time != NULL) { + if (!array_key_exists($start_time, $grouped_items)) { + $grouped_items[$start_time]['values'][$weekno] = array(); + } + $start_time = $next_start_time; + $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; } - $start_time = $next_start_time; - $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time; } + ksort($grouped_items); } } - ksort($grouped_items); // Do the headers last, once we know what the actual values are. $i = 0;