theme.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. <?php
  2. /**
  3. * @file
  4. * Theme functions for the Calendar module.
  5. */
  6. /**
  7. * Preprocess an RSS feed
  8. */
  9. function template_preprocess_calendar_style(&$vars) {
  10. global $base_url;
  11. global $language;
  12. }
  13. /**
  14. * Display a month view.
  15. */
  16. function template_preprocess_calendar_month(&$vars) {
  17. $view = $vars['view'];
  18. $rows = $vars['rows'];
  19. if (empty($rows)) {
  20. $rows = array();
  21. $day_names = array();
  22. }
  23. elseif (sizeof($rows) > 1) {
  24. $day_names = array_shift($rows);
  25. }
  26. else {
  27. $day_names = $rows;
  28. $rows = array();
  29. }
  30. $month_rows = $rows;
  31. foreach ($rows as $weekno => $row) {
  32. foreach ($row as $day => $data) {
  33. $cell = $data['data'];
  34. // If this cell is already rendered, like the weekno column,
  35. // move to the next item.
  36. if (!is_array($cell)) {
  37. $month_rows[$weekno][$day]['data'] = $cell;
  38. continue;
  39. }
  40. $data = $cell['datebox'];
  41. if ($cell['empty']) {
  42. $data .= $cell['empty'];
  43. }
  44. else {
  45. $data .= implode($cell['all_day']);
  46. foreach ($cell['items'] as $hour => $item) {
  47. $data .= implode($item);
  48. }
  49. $data .= $cell['link'];
  50. }
  51. if ($view->date_info->mini) {
  52. $month_rows[$weekno][$day]['data'] = $data;
  53. }
  54. else {
  55. $month_rows[$weekno][$day]['data'] = '<div class="inner">' . $data . '</div>';
  56. }
  57. }
  58. }
  59. $vars['rows'] = $month_rows;
  60. $vars['day_names'] = $day_names;
  61. $vars['display_type'] = $view->date_info->granularity;
  62. $vars['min_date_formatted'] = date_format($view->date_info->min_date, DATE_FORMAT_DATETIME);
  63. $vars['max_date_formatted'] = date_format($view->date_info->max_date, DATE_FORMAT_DATETIME);
  64. }
  65. /**
  66. * Display a mini month view.
  67. */
  68. function template_preprocess_calendar_mini(&$vars) {
  69. // Add in all the $vars added by the main calendar preprocessor.
  70. template_preprocess_calendar_month($vars);
  71. $view = $vars['view'];
  72. // Make sure that the calendar title links go to the month view,
  73. // not the year view (if this is embedded in a year display).
  74. $view->override_path = calendar_granularity_path($view, 'month');
  75. $view->date_info->show_title = !empty($view->date_info->show_title) ? $view->date_info->show_title : FALSE;
  76. $vars['show_title'] = $view->date_info->show_title;
  77. $vars['view'] = $view;
  78. }
  79. /**
  80. * Display a year view.
  81. */
  82. function template_preprocess_calendar_year(&$vars) {
  83. // Construct a calendar for each month, adjusting the $view passed
  84. // to the theme so it will produce the right results.
  85. $view = clone($vars['view']);
  86. $year = date_format($view->date_info->min_date, 'Y');
  87. $view->date_info->style_with_weekno = FALSE;
  88. $rows = $vars['rows'];
  89. $months = array();
  90. foreach ($rows as $month => $month_rows) {
  91. $view->date_info->month = $month;
  92. $view->date_info->granularity = 'month';
  93. $view->date_info->mini = TRUE;
  94. $view->date_info->hide_nav = TRUE;
  95. $view->date_info->show_title = TRUE;
  96. $view->date_info->url = date_pager_url($view, NULL, date_pad($year, 4) . '-' . date_pad($month));
  97. $view->date_info->min_date = new DateObject($view->date_info->year . '-' . date_pad($month) . '-01 00:00:00', date_default_timezone());
  98. $view->date_info->max_date = clone($view->date_info->min_date);
  99. date_modify($view->date_info->max_date, '+1 month');
  100. date_modify($view->date_info->max_date, '-1 second');
  101. $variables = array(
  102. 'view' => $view,
  103. 'options' => $vars['options'],
  104. 'rows' => $month_rows,
  105. );
  106. $months[$month] = theme('calendar_mini', $variables);
  107. }
  108. $view->date_info->mini = FALSE;
  109. $vars['months'] = $months;
  110. $vars['view']->date_info->hide_nav = FALSE;
  111. $vars['view']->date_info->granularity = 'year';
  112. $vars['mini'] = FALSE;
  113. }
  114. /**
  115. * Display a day overlap view.
  116. */
  117. function template_preprocess_calendar_day_overlap(&$vars) {
  118. template_preprocess_calendar_day($vars);
  119. }
  120. /**
  121. * Display a day view.
  122. */
  123. function template_preprocess_calendar_day(&$vars) {
  124. $vars['view']->style_with_weekno = FALSE;
  125. $view = $vars['view'];
  126. $rows = $vars['rows'];
  127. $item_count = 0;
  128. $by_hour_count = 0;
  129. $grouping_field = !empty($view->date_info->style_groupby_field) ? ($view->date_info->style_groupby_field - 1) : NULL;
  130. $display_overlap = !empty($view->date_info->style_theme_style) && !empty($view->date_info->style_groupby_times);
  131. $vars['scroll_content'] = !empty($view->date_info->style_theme_style) && $view->date_info->style_theme_style == 1;
  132. // Add optional css
  133. if ($display_overlap) {
  134. $overlapped_items = array();
  135. drupal_add_css(drupal_get_path('module', 'calendar') . '/css/calendar-overlap.css');
  136. if (empty($view->live_preview) && !empty($vars['scroll_content'])) {
  137. drupal_add_js(drupal_get_path('module', 'calendar') . '/js/calendar_overlap.js');
  138. }
  139. if (empty($vars['scroll_content'])) {
  140. drupal_add_css(drupal_get_path('module', 'calendar') . '/css/calendar-overlap-no-scroll.css');
  141. }
  142. }
  143. // If we're not grouping by time, move all items into the 'all day' array.
  144. if (empty($view->date_info->style_groupby_times)) {
  145. // Items are already grouped into times, so we need to process each time-group.
  146. foreach ($rows['items'] as $time => $items) {
  147. foreach ($items as $item) {
  148. $rows['all_day'][] = $item;
  149. }
  150. }
  151. $rows['items'] = array();
  152. }
  153. $columns = array();
  154. // Move all_day items into the right columns and render them.
  155. $grouped_items = array();
  156. foreach ($rows['all_day'] as $item) {
  157. if (!empty($item->rendered_fields[$grouping_field])) {
  158. $column = $item->rendered_fields[$grouping_field];
  159. unset($item->rendered_fields[$grouping_field]); // Remove the grouping field from the results.
  160. if (!in_array($column, $columns)) {
  161. $columns[] = $column;
  162. }
  163. }
  164. else {
  165. $column = t('Items');
  166. }
  167. $grouped_items[$column][] = theme('calendar_item', array('view' => $view, 'rendered_fields' => $item->rendered_fields, 'item' => $item));
  168. $item_count++;
  169. }
  170. $vars['rows']['all_day'] = $grouped_items;
  171. // Moved timed items into the right columns and render them.
  172. $start_times = $view->date_info->style_groupby_times;
  173. $show_empty_times = $view->date_info->style_show_empty_times;
  174. $end_start_time = '23:59:59';
  175. $start_time = array_shift($start_times);
  176. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  177. $grouped_items = array();
  178. foreach ($rows['items'] as &$items) {
  179. foreach ($items as &$item) {
  180. $time = date_format($item->calendar_start_date, 'H:i:s');
  181. if (!empty($item->rendered_fields[$grouping_field])) {
  182. $column = $item->rendered_fields[$grouping_field];
  183. unset($item->rendered_fields[$grouping_field]); // Remove the grouping field from the results.
  184. if (!in_array($column, $columns)) {
  185. $columns[] = $column;
  186. }
  187. }
  188. else {
  189. $column = t('Items');
  190. }
  191. // Find the next time slot and fill it. Populate the skipped
  192. // slots if the option to show empty times was chosen.
  193. while ($time >= $next_start_time && $time < $end_start_time) {
  194. if ((!empty($show_empty_times) || $display_overlap) && !array_key_exists($start_time, $grouped_items)) {
  195. $grouped_items[$start_time]['values'] = array();
  196. }
  197. $start_time = $next_start_time;
  198. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  199. }
  200. $grouped_items[$start_time]['values'][$column][] = $item;
  201. if ($display_overlap) {
  202. $time_end = date_format($item->calendar_end_date, 'H:i:s');
  203. $item->time_start = $time;
  204. $item->time_end = $time_end;
  205. _calc_indents($overlapped_items, $time, $time_end, $item);
  206. }
  207. $item_count++;
  208. $by_hour_count++;
  209. }
  210. }
  211. // Finish out the day's time values if we want to see empty times.
  212. if (!empty($show_empty_times) || $display_overlap) {
  213. while ($start_time < $end_start_time && (!empty($start_time) || $display_overlap)) {
  214. if (empty($start_time)) {
  215. $start_times = $view->date_info->style_groupby_times;
  216. $start_time = array_shift($start_times);
  217. $next_start_time = array_shift($start_times);
  218. }
  219. if (!array_key_exists($start_time, $grouped_items)) {
  220. $grouped_items[$start_time]['values'] = array();
  221. }
  222. $start_time = $next_start_time;
  223. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  224. }
  225. }
  226. // Do the headers last, once we know what the actual values are.
  227. $i = 0;
  228. $start_times = array_keys($grouped_items);
  229. foreach ($start_times as $start_time) {
  230. $next_start_time = array_key_exists($i + 1, $start_times) ? $start_times[$i + 1] : '23:59:59';
  231. $variables = array(
  232. 'start_time' => $start_time,
  233. 'next_start_time' => $next_start_time,
  234. 'curday_date' => $rows['date'],
  235. );
  236. $heading = theme('calendar_time_row_heading', $variables);
  237. $grouped_items[$start_time]['hour'] = $heading['hour'];
  238. $grouped_items[$start_time]['ampm'] = $heading['ampm'];
  239. foreach ($grouped_items[$start_time]['values'] as $column => &$items) {
  240. foreach ($items as $index => &$item) {
  241. if ($display_overlap) {
  242. if ($view->style_options['groupby_times'] == 'half'){
  243. $group_time = 30;
  244. $divisor = 7.5;
  245. }
  246. else if ($view->style_options['groupby_times'] == 'hour'){
  247. $group_time = 60;
  248. $divisor = 15;
  249. } else {
  250. $item->class = '';
  251. continue;
  252. }
  253. $start_minute = intval(substr($start_time, 3, 2));
  254. $offset = round((date_format($item->date_start, 'i') - $start_minute) / $divisor);
  255. $duration = round(($item->date_end->format('U') - $item->date_start->format('U')) / 60 / $divisor);
  256. $item->class = 'd_' . $duration . ' o_' . $offset . ' i_' . $item->indent . ' md_' . min($item->max_depth, 5);
  257. }
  258. $grouped_items[$start_time]['values'][$column][$index] = theme('calendar_item', array('view' => $view, 'rendered_fields' => $item->rendered_fields, 'item' => $item));
  259. }
  260. }
  261. $i++;
  262. }
  263. ksort($grouped_items);
  264. $vars['rows']['items'] = $grouped_items;
  265. if (empty($columns)) {
  266. $columns = array(t('Items'));
  267. }
  268. $vars['columns'] = $columns;
  269. $vars['agenda_hour_class'] = 'calendar-agenda-hour';
  270. $first_column_width = 10;
  271. if (empty($view->date_info->style_groupby_times)) {
  272. $vars['agenda_hour_class'] .= ' calendar-agenda-no-hours';
  273. $first_column_width = 1;
  274. }
  275. $vars['first_column_width'] = $first_column_width;
  276. if (count($columns)) {
  277. $vars['column_width'] = round((100 - $first_column_width)/count($columns));
  278. }
  279. else {
  280. $vars['column_width'] = (100 - $first_column_width);
  281. }
  282. $vars['item_count'] = $item_count;
  283. $vars['by_hour_count'] = $by_hour_count;
  284. $vars['start_times'] = $view->date_info->style_groupby_times;
  285. return;
  286. }
  287. /**
  288. * Display a week overlap view.
  289. */
  290. function template_preprocess_calendar_week_overlap(&$vars) {
  291. template_preprocess_calendar_week($vars);
  292. }
  293. /**
  294. * Display a week view.
  295. */
  296. function template_preprocess_calendar_week(&$vars) {
  297. $vars['view']->style_with_weekno = FALSE;
  298. $view = $vars['view'];
  299. $rows = $vars['rows'];
  300. $item_count = 0;
  301. $by_hour_count = 0;
  302. $start_time = NULL;
  303. $columns = array();
  304. if (sizeof($rows) > 1) {
  305. $day_names = array_shift($rows);
  306. }
  307. else {
  308. $day_names = $rows;
  309. $rows = array();
  310. }
  311. // Moved timed items into the right columns and render them.
  312. $show_empty_times = $view->date_info->style_show_empty_times;
  313. $end_start_time = '23:59:59';
  314. $grouped_items = array();
  315. // pass the multiday buckets
  316. $vars['all_day'] = $rows['multiday_buckets'];
  317. // Remove the count for singleday
  318. $vars['multiday_rows'] = max(0, $rows['total_rows'] - 1);
  319. $display_overlap = ($view->date_info->style_multiday_theme == '1' && !empty($view->date_info->style_theme_style));
  320. $vars['display_overlap'] = $display_overlap;
  321. $vars['scroll_content'] = !empty($view->date_info->style_theme_style) && $view->date_info->style_theme_style == 1;
  322. // Add optional css
  323. if ($display_overlap) {
  324. drupal_add_css(drupal_get_path('module', 'calendar') . '/css/calendar-overlap.css');
  325. if (empty($view->live_preview) && !empty($vars['scroll_content'])) {
  326. drupal_add_js(drupal_get_path('module', 'calendar') . '/js/calendar_overlap.js');
  327. }
  328. if (empty($vars['scroll_content'])) {
  329. drupal_add_css(drupal_get_path('module', 'calendar') . '/css/calendar-overlap-no-scroll.css');
  330. }
  331. $overlapped_items = array( array(), array(), array(), array(), array(), array(), array());
  332. // Locate the first item
  333. $first_time = '23:59:59';
  334. $first_time_index = -1;
  335. for ($i = 0; $i < 7; $i++) {
  336. if (count($rows['singleday_buckets'][$i]) > 0) {
  337. $time_slot = reset($rows['singleday_buckets'][$i]);
  338. $time = date_format($time_slot[0]['item']->date_start, 'H:i:s');
  339. if ($time < $first_time) {
  340. $first_time = $time;
  341. $first_time_index = $i;
  342. }
  343. }
  344. }
  345. if ($first_time_index > -1) {
  346. $rows['singleday_buckets'][$first_time_index][$first_time][0]['is_first'] = TRUE;
  347. }
  348. }
  349. // If we're not grouping by time, move all items into the 'all day' array.
  350. if (empty($view->date_info->style_groupby_times)) {
  351. $add_row = FALSE;
  352. foreach ($vars['all_day'] as $index => &$day ) {
  353. foreach ($rows['singleday_buckets'][$index] as $item) {
  354. foreach ($item as $event) {
  355. $day[] = $event;
  356. $add_row = TRUE;
  357. }
  358. }
  359. }
  360. if ( $add_row ) {
  361. $vars['multiday_rows']++;
  362. }
  363. }
  364. else {
  365. foreach ($rows['singleday_buckets'] as $wday => $singleday_row) {
  366. $columns[] = $wday;
  367. foreach ($singleday_row as &$row) {
  368. $start_times = $view->date_info->style_groupby_times;
  369. $start_time = array_shift($start_times);
  370. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  371. foreach ($row as &$item) {
  372. $time = date_format($item['item']->date_start, 'H:i:s');
  373. if ($item['item']->calendar_all_day) {
  374. $vars['all_day'][$item['wday']][] = $item;
  375. if ($vars['multiday_rows'] == 0) {
  376. $vars['multiday_rows']++;
  377. }
  378. }
  379. else {
  380. // Find the next time slot and fill it. Populate the skipped
  381. // slots if the option to show empty times was chosen.
  382. while ($time >= $next_start_time && $time < $end_start_time) {
  383. if (($show_empty_times || $display_overlap) && !array_key_exists($start_time, $grouped_items)) {
  384. $grouped_items[$start_time]['values'][$wday] = array();
  385. }
  386. $start_time = $next_start_time;
  387. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  388. }
  389. $grouped_items[$start_time]['values'][$wday][] = &$item;
  390. if ($display_overlap) {
  391. $date_end = date_format($item['item']->date_end, 'H:i:s');
  392. _calc_indents($overlapped_items[$wday], $time, $date_end, $item);
  393. }
  394. $item_count++;
  395. $by_hour_count++;
  396. }
  397. }
  398. }
  399. // Finish out the day's time values if we want to see empty times.
  400. if ($show_empty_times || $display_overlap) {
  401. while ($start_time < $end_start_time && ($start_time != NULL || $display_overlap)) {
  402. if ($start_time == NULL) {
  403. $start_times = $view->date_info->style_groupby_times;
  404. $start_time = array_shift($start_times);
  405. $next_start_time = array_shift($start_times);
  406. }
  407. if (!array_key_exists($start_time, $grouped_items)) {
  408. $grouped_items[$start_time]['values'][$wday] = array();
  409. }
  410. $start_time = $next_start_time;
  411. $next_start_time = count($start_times) ? array_shift($start_times) : $end_start_time;
  412. }
  413. }
  414. ksort($grouped_items);
  415. }
  416. }
  417. // Do the headers last, once we know what the actual values are.
  418. $i = 0;
  419. $start_times = array_keys($grouped_items);
  420. foreach ($start_times as $start_time) {
  421. $next_start_time = array_key_exists($i + 1, $start_times) ? $start_times[$i + 1] : '23:59:59';
  422. $variables = array(
  423. 'start_time' => $start_time,
  424. 'next_start_time' => $next_start_time,
  425. 'curday_date' => (isset($row['data'])) ? $row['data']['date'] : NULL,
  426. );
  427. $heading = theme('calendar_time_row_heading', $variables);
  428. $grouped_items[$start_time]['hour'] = $heading['hour'];
  429. $grouped_items[$start_time]['ampm'] = $heading['ampm'];
  430. $grouped_items[$start_time]['time'] = $start_time;
  431. if ($display_overlap) {
  432. foreach ($grouped_items[$start_time]['values'] as $wday => &$items) {
  433. foreach ($items as &$item) {
  434. if ($display_overlap) {
  435. if ($view->style_options['groupby_times'] == 'half'){
  436. $group_time = 30;
  437. $divisor = 7.5;
  438. }
  439. else if ($view->style_options['groupby_times'] == 'hour'){
  440. $group_time = 60;
  441. $divisor = 15;
  442. } else {
  443. $item['class'] = '';
  444. continue;
  445. }
  446. $start_minute = intval(substr($start_time, 3, 2));
  447. $offset = round((date_format($item['item']->date_start, 'i') - $start_minute) / $divisor);
  448. $duration = round(($item['item']->date_end->format('U') - $item['item']->date_start->format('U')) / 60 / $divisor);
  449. $item['class'] = 'd_' . $duration . ' o_' . $offset . ' i_' . $item['indent'] . ' md_' . min($item['max_depth'], 5);
  450. }
  451. }
  452. }
  453. }
  454. }
  455. $vars['items'] = $grouped_items;
  456. $vars['day_names'] = $day_names;
  457. $vars['columns'] = $columns;
  458. $vars['start_times'] = $view->date_info->style_groupby_times;
  459. $vars['first_time'] = !empty($first_time) ? $first_time : '';
  460. $vars['agenda_hour_class'] = 'calendar-agenda-hour';
  461. $first_column_width = 10;
  462. if (empty($view->date_info->style_groupby_times)) {
  463. $vars['agenda_hour_class'] .= ' calendar-agenda-no-hours';
  464. $first_column_width = 1;
  465. }
  466. $vars['item_count'] = $item_count;
  467. $vars['by_hour_count'] = $by_hour_count;
  468. return;
  469. }
  470. /**
  471. * Create the calendar date box.
  472. */
  473. function template_preprocess_calendar_datebox(&$vars) {
  474. $date = $vars['date'];
  475. $view = $vars['view'];
  476. $vars['day'] = intval(substr($date, 8, 2));
  477. $force_view_url = !empty($view->date_info->block) ? TRUE : FALSE;
  478. $month_path = calendar_granularity_path($view, 'month');
  479. $year_path = calendar_granularity_path($view, 'year');
  480. $day_path = calendar_granularity_path($view, 'day');
  481. $vars['url'] = str_replace(array($month_path, $year_path), $day_path, date_pager_url($view, NULL, $date, $force_view_url));
  482. $vars['link'] = !empty($day_path) ? l($vars['day'], $vars['url']) : $vars['day'];
  483. $vars['granularity'] = $view->date_info->granularity;
  484. $vars['mini'] = !empty($view->date_info->mini);
  485. if ($vars['mini']) {
  486. if (!empty($vars['selected'])) {
  487. $vars['class'] = 'mini-day-on';
  488. }
  489. else {
  490. $vars['class'] = 'mini-day-off';
  491. }
  492. }
  493. else {
  494. $vars['class'] = 'day';
  495. }
  496. }
  497. /**
  498. * Format an calendar month node for display.
  499. */
  500. function template_preprocess_calendar_month_multiple_entity(&$vars) {
  501. $view = $vars['view'];
  502. $curday = $vars['curday'];
  503. $count = $vars['count'];
  504. $ids = $vars['ids'];
  505. // get the year month and date
  506. $parts = explode('-', substr($curday, 0, 10));
  507. $year = $parts[0];
  508. $month = intval($parts[1]);
  509. $day = intval($parts[2]);
  510. // create the link to the day
  511. $month_path = calendar_granularity_path($view, 'month');
  512. $day_path = calendar_granularity_path($view, 'day');
  513. $vars['link'] = str_replace($month_path, $day_path, date_pager_url($view, NULL, date_pad($year, 4) . '-' . date_pad($month) . '-' . date_pad($day)));
  514. }
  515. /**
  516. * Theme function for rendering views fields as a calendar 'item'.
  517. *
  518. * $vars['rendered_fields'] = An array of the rendered display of each field in the View.
  519. * $vars['item'] = The source data for this item.
  520. * $vars['view'] = The view that this item is displayed on.
  521. *
  522. * @TODO We need some options about how to combine rendered fields.
  523. * Fields rendered in multiday containers need to be inline.
  524. */
  525. /**
  526. * Format the time row headings in the week and day view.
  527. */
  528. function theme_calendar_time_row_heading($vars) {
  529. $start_time = $vars['start_time'];
  530. $next_start_time = $vars['next_start_time'];
  531. $curday_date = $vars['curday_date'];
  532. static $format_hour, $format_ampm;
  533. if (empty($format_hour)) {
  534. $format = variable_get('date_format_short', 'm/d/Y - H:i');
  535. if (substr($start_time, -5) == '00:00' && substr($next_start_time, -5) == '00:00') {
  536. $limit = array('hour');
  537. }
  538. else {
  539. $limit = array('hour', 'minute');
  540. }
  541. $format_hour = str_replace(array('a', 'A'), '', date_limit_format($format, $limit));
  542. $format_ampm = strstr($format, 'a') ? 'a' : (strstr($format, 'A') ? 'A' : '');
  543. }
  544. if ($start_time == '00:00:00' && $next_start_time == '23:59:59') {
  545. $hour = t('All times');
  546. }
  547. elseif ($start_time == '00:00:00') {
  548. $date = date_create($curday_date . ' ' . $next_start_time);
  549. $hour = t('Before @time', array('@time' => date_format($date, $format_hour)));
  550. }
  551. else {
  552. $date = date_create($curday_date . ' ' . $start_time);
  553. $hour = date_format($date, $format_hour);
  554. }
  555. if (!empty($date)) {
  556. $ampm = date_format($date, $format_ampm);
  557. }
  558. else {
  559. $ampm = '';
  560. }
  561. return array('hour' => $hour, 'ampm' => $ampm);
  562. }
  563. /**
  564. * Format a node stripe legend
  565. */
  566. function theme_calendar_stripe_legend() {
  567. if (empty($GLOBALS['calendar_stripes'])) {
  568. return '';
  569. }
  570. $header = array(
  571. array('class' => 'calendar-legend', 'data' => t('Item')),
  572. array('class' => 'calendar-legend', 'data' => t('Key'))
  573. );
  574. $rows = array();
  575. $output = '';
  576. foreach ((array) $GLOBALS['calendar_stripes'] as $label => $stripe) {
  577. if ($stripe) {
  578. $rows[] = array($label, '<div style="background-color:' . $stripe . ';color:' . $stripe . '" class="stripe" title="Key: ' . $label . '">&nbsp;</div>');
  579. }
  580. }
  581. if (!empty($rows)) {
  582. $variables = array(
  583. 'header' => $header,
  584. 'rows' => $rows,
  585. 'attributes' => array('class' => array('mini', 'calendar-legend')),
  586. );
  587. $output .= theme('table', $variables);
  588. $output = '<div class="calendar legend">' . $output . '</div>';
  589. }
  590. return $output;
  591. }
  592. /**
  593. * Format item stripes
  594. */
  595. function theme_calendar_stripe_stripe($vars) {
  596. $item = $vars['item'];
  597. if (empty($item->stripe) || (!count($item->stripe))) {
  598. return;
  599. }
  600. $output = '';
  601. if (is_array($item->stripe_label)) {
  602. foreach ($item->stripe_label as $k => $stripe_label) {
  603. if (!empty($item->stripe[$k]) && !empty($stripe_label)) {
  604. $GLOBALS['calendar_stripes'][$stripe_label] = $item->stripe[$k];
  605. $output .= '<div style="background-color:' . $item->stripe[$k] . ';color:' . $item->stripe[$k] . '" class="stripe" title="Key: ' . $item->stripe_label[$k] . '">&nbsp;</div>' . "\n";
  606. }
  607. }
  608. }
  609. return $output;
  610. }
  611. /**
  612. * Format an empty day on a calendar
  613. *
  614. * @param day
  615. * The day to display.
  616. */
  617. function theme_calendar_empty_day($vars) {
  618. $curday = $vars['curday'];
  619. $view = $vars['view'];
  620. if ($view->date_info->calendar_type != 'day') {
  621. return '<div class="calendar-empty">&nbsp;</div>' . "\n";
  622. }
  623. else {
  624. return '<div class="calendar-dayview-empty">' . t('Empty day') . '</div>';
  625. }
  626. }
  627. /**
  628. * Indent items based off a nested tree structure of overlapping items
  629. *
  630. * @param array $overlapped_items
  631. * Tree of overlapped items
  632. * @param date $start
  633. * Start time of the event
  634. * @param date $end
  635. * End tiem of the event
  636. * @param array $item
  637. * The event to add to the tree
  638. * @param int $depth
  639. * Current depth of the tree
  640. * @return rc
  641. * Returns an array with the max depth of the branch and whether an overlap occurred
  642. */
  643. function _calc_indents(&$overlapped_items, $start, $end, &$item, $depth = 0) {
  644. // Are there any items at this depth?
  645. if (!empty($overlapped_items)) {
  646. // Iterate for each item as this depth and see if we overlap
  647. foreach ($overlapped_items as $index => &$entry) {
  648. // We search depth-first, so if there are children for this item, recurse into
  649. // each child tree looking for an overlap
  650. if (!empty($entry['children'])) {
  651. $rc = _calc_indents($entry['children'], $start, $end, $item, $depth + 1);
  652. // Was there an overlap in the child tree?
  653. if ($rc['overlap']) {
  654. if (is_object($entry['item'])) {
  655. $entry['item']->indent = _calc_indent($entry['depth'], $rc['max_depth']);
  656. $entry['item']->max_depth = $rc['max_depth'];
  657. }
  658. else {
  659. $entry['item']['indent'] = _calc_indent($entry['depth'], $rc['max_depth']);
  660. $entry['item']['max_depth'] = $rc['max_depth'];
  661. }
  662. // There was an overlap, pop out of this depth
  663. return $rc;
  664. }
  665. }
  666. // No, child overlap, so check if we overlap this item
  667. if ($start >= $entry['start'] && $start < $entry['end']) {
  668. // We overlap, create an overlapping entry
  669. $entry['children'][] = array('item' => &$item, 'depth' => $depth + 1, 'start' => $start, 'end' => $end, 'children' => array());
  670. if (is_object($entry['item'])) {
  671. $max_depth = max($entry['item']->max_depth, $depth + 1);
  672. $entry['item']->indent = _calc_indent($depth, $max_depth);
  673. $entry['item']->max_depth = $max_depth;
  674. }
  675. else {
  676. $max_depth = max($entry['item']['max_depth'], $depth + 1);
  677. $entry['item']['indent'] = _calc_indent($depth, $max_depth);
  678. $entry['item']['max_depth'] = $max_depth;
  679. }
  680. if (is_object($item)) {
  681. $item->indent = _calc_indent($depth + 1, $max_depth);
  682. $item->max_depth = $max_depth;
  683. }
  684. else {
  685. $item['indent'] = _calc_indent($depth + 1, $max_depth);
  686. $item['max_depth'] = $max_depth;
  687. }
  688. // We overlap, so pop out of this depth
  689. return array('overlap' => TRUE, 'max_depth' => $max_depth);
  690. }
  691. }
  692. // If there are items at this depth, but no overlap, then return no overlap and pop
  693. // out of this depth
  694. if ($depth > 0) {
  695. return array('overlap' => FALSE, 'max_depth' => 0);
  696. }
  697. }
  698. // No overlap at any depth, reset the array of overlaps
  699. if ($depth == 0) {
  700. reset($overlapped_items);
  701. $overlapped_items[0] = array('item' => &$item, 'depth' => $depth, 'start' => $start, 'end' => $end, 'children' => array());
  702. }
  703. else {
  704. $overlapped_items[] = array('item' => &$item, 'depth' => $depth, 'start' => $start, 'end' => $end, 'children' => array());
  705. }
  706. if (is_object($item)) {
  707. $item->indent = _calc_indent($depth, $depth);
  708. $item->max_depth = $depth;
  709. }
  710. else {
  711. $item['indent'] = _calc_indent($depth, $depth);
  712. $item['max_depth'] = $depth;
  713. }
  714. return array('overlap' => FALSE, 'max_depth' => $depth);
  715. }
  716. /**
  717. * Calculates the indent based of the current depth and the depth of this branch in the tree
  718. *
  719. * @param int $cur_depth
  720. * @param int $depth
  721. * @return number
  722. */
  723. function _calc_indent( $cur_depth, $depth ) {
  724. return round(10 * $cur_depth / ($depth + 1));
  725. }
  726. /** @} End of addtogroup themeable */