$view) { $items['admin/settings/calendar/'. $view_name .'/ical'] = array( 'title' => t('iCal'), 'description' => t('iCal setup.'), 'access arguments' => array('administer views'), 'callback' => 'drupal_get_form', 'callback arguments' => array('calendar_ical_setup_form', $view_name), 'type' => MENU_LOCAL_TASK, 'weight' => 6, ); } return $items; } function calendar_ical_theme() { return array( 'calendar_ical_feed' => array( 'arguments' => array('view', 'items', 'type'), ), 'calendar_ical_field' => array( 'arguments' => array('fieldname', 'fields', 'field', 'node', 'view', 'type'), ), 'calendar_ical_node' => array( 'arguments' => array('node', 'view'), ), ); } function calendar_ical_setup_form($view_name) { include_once(drupal_get_path('module', 'calendar') .'/calendar_ical_admin.inc'); return _calendar_ical_setup_form($view_name); } /** * Identify the cache where the ical feeds are stored. * * @return unknown */ function calendar_ical_cache() { return 'cache_views'; } /** * Implementation of hook_cron(). */ function calendar_ical_cron() { cache_clear_all('calendar_feeds_', calendar_ical_cache(), TRUE); } /** * Implementation of hook_calendar_add_items(). */ function calendar_ical_calendar_add_items($view) { include_once(drupal_get_path('module', 'date_api') .'/date_api_ical.inc'); $items = array(); $feeds = calendar_ical_add_feeds($view); foreach ($feeds as $feed) { if (is_object($feed->calendar_start_date) && is_object($feed->calendar_end_date)) { if (date_format($feed->calendar_start_date, DATE_FORMAT_DATETIME) >= date_format($view->min_date, DATE_FORMAT_DATETIME) && date_format($feed->calendar_end_date, DATE_FORMAT_DATETIME) <= date_format($view->max_date, DATE_FORMAT_DATETIME)) { $items[] = $feed; } } } return $items; } /** * Implementation of hook_calendar_add_types(). */ function calendar_ical_calendar_add_types($view) { return array('calendar_ical' => t('Calendar: iCal Feed')); } /** * Bring an ical feed into the calendar. * * @param $view - the view being manipulated * @param $refresh - whether or not to force a refresh of the feed * @return $nodes to add to calendar * @todo probably need to add more validation of the results in case the url doesn't work. */ function calendar_ical_add_feeds($view, $refresh = FALSE) { $nodes = array(); $feeds = variable_get('calendar_feeds_'. $view->name, array()); $expire = intval(variable_get('calendar_ical_expire_'. $view->name, 9676800) + time()); foreach ($feeds as $delta => $feed) { if ($view->build_type == 'page') { $GLOBALS['calendar_stripe_labels'][$feed['stripe']] = $feed['name']; } if (!$refresh && $cached = cache_get('calendar_feeds_'. $view->name .':'. $feed['url'], calendar_ical_cache())) { $nodes += (array) $cached->data; } else { $expire = intval(variable_get('calendar_ical_expire_'. $view->name, 9676800) + time()); include_once(drupal_get_path('module', 'date_api') .'/date_api_ical.inc'); switch ($feed['type']) { case 'ical': $filename = $feed['url']; $new_nodes = array(); $calendars = date_ical_import($filename); foreach ($calendars as $calendar) { foreach ($calendar['VEVENT'] as $key => $value) { if (empty($value['DTSTART'])) continue; $node = new stdClass(); $node->nid = $value['UID']; $node->title = $value['SUMMARY']; $node->label = $feed['name']; $node->teaser = $value['DESCRIPTION']; $node->calendar_start_date = date_ical_date($value['DTSTART'], $value['DTSTART']['tz']); $node->calendar_start = date_format_date($node->calendar_start_date, 'custom', DATE_FORMAT_DATETIME); $node->calendar_end_date = date_ical_date($value['DTEND'], $value['DTEND']['tz']); $node->calendar_end = date_format_date($node->calendar_end_date, 'custom', DATE_FORMAT_DATETIME); $show_tz = ' e'; $granularity = $value['DTSTART']['type'] == 'DATE' ? array('year', 'month', 'day') : array('year', 'month', 'day', 'hour', 'minute', 'second'); $node->format_time = variable_get('calendar_time_format_'. $view->name, 'H:i'); $node->format = date_limit_format(variable_get('date_format_short', 'm/d/Y - H:i'), $granularity) . $show_tz; $node->all_day = $value['DTSTART']['all_day']; $node->stripe = $feed['stripe']; $node->remote = TRUE; $node->uid = $value['uid'] ? $value['UID'] : (is_numeric($node->nid) ? url("node/$node->nid", NULL, NULL, 1) : $node->nid); $node->url = $value['URL'] ? $value['URL'] : (is_numeric($node->nid) ? url("node/$node->nid", NULL, NULL, 1) : $node->nid); $node->calendar_node_theme = 'calendar_ical_node'; $node->calendar_field_theme = 'calendar_ical_field'; $new_nodes[$value['UID']] = $node; } } //cache_set('calendar_feeds_'. $view->name .':'. $feed['url'], $new_nodes, calendar_ical_cache(), $expire); $nodes += (array) $new_nodes; break; } } } return $nodes; } /** * Provide views plugins for the feed types we support. */ function calendar_ical_views_style_plugins() { return array( 'calendar_ical' => array( 'name' => t('Calendar: iCal Feed'), 'theme' => 'calendar_ical_feed', 'needs_table_header' => TRUE, 'needs_fields' => TRUE, 'even_empty' => TRUE, ), ); } /** * While we support the global selector, some might want to allow * ONLY ical feeds so we support a stingy selector too */ function calendar_ical_views_arguments() { $arguments = array( 'calendar_ical' => array( 'name' => t('Calendar: iCal Feed'), 'handler' => 'views_handler_arg_ical', 'help' => t('Add this as the last argument to a calendar view to provide an iCal feed of the view.'), ), ); return $arguments; } /** * handler for our own ical argument; mimics the feed selector */ function views_handler_arg_ical($op, &$query, $argtype, $arg = '') { switch ($op) { case 'summary': case 'sort': case 'link': case 'title': break; case 'filter': // This is a clone of the default selector, but it just invokes ours // rather than calling all of them. calendar_ical_views_feed_argument('argument', $GLOBALS['current_view'], $arg, $argtype); } } /** * post view for our own op -- mimics the feed selector */ function calendar_ical_views_post_view($view, $items, $output) { foreach ($view->argument as $id => $argument) { if ($argument['type'] == 'calendar_ical') { $feed = $id; break; } } if ($feed !== NULL) { $query = NULL; return calendar_ical_views_feed_argument('post_view', $view, 'ical', $query); } } /** * feed argument hook that will convert us to ical or display an icon. * the 4th argument isn't part of the hook, but we use it to differentiate * when called as a hook or when called manually from calendar_ical_views_post_view */ function calendar_ical_views_feed_argument($op, &$view, $arg, $argtype = NULL) { if ($op == 'argument' && $arg == 'ical') { // Keep devel module from appending queries to ical export. $GLOBALS['devel_shutdown'] = FALSE; $view->page_type = 'calendar_ical'; // reset the 'real url' to the URL without the feed argument. $view_args = array(); $max = count($view->args); foreach ($view->args as $id => $view_arg) { ++$count; if ($view_arg == $arg && $view->argument[$id]['id'] == $argtype['id']) { if ($count != $max) { $view_args[] = $argtype['wildcard']; } } else { $view_args[] = $view_arg; } } $view->feed_url = views_get_url($view, $view_args); } else if ($op == 'post_view') { $args = calendar_ical_post_view_make_args($view, $arg, 'ical'); $url = views_get_url($view, $args); $title = views_get_title($view, 'page', $args); if ($view->used_filters) { $filters = drupal_query_string_encode($view->used_filters); } return implode(calendar_ical_add_ical(url($url, $filters), $title)); } } /** * helper function -- this function builds a URL for a given feed. * It defaults to the built in feed selector, but the 3rd arg can * be used to set it up for custom selectors too. */ function calendar_ical_post_view_make_args($view, $feed_id, $arg) { // assemble the URL $args = array(); foreach ($view->argument as $id => $argdata) { if (isset($view->args[$id])) { $args[] = $view->args[$id]; } else { if ($argdata['id'] == $feed_id && !in_array($arg, $args)) { $args[] = $arg; } else if ($argdata['argdefault'] != 1 && !in_array($arg, $args)) { $args[] = $arg; } } } return $args; } function calendar_ical_add_ical($url = NULL, $title = '') { if (!is_null($url)) { $stored_feed_links[$url] = theme('ical_icon', $url); drupal_add_link(array('rel' => 'alternate', 'type' => 'application/calendar', 'title' => $title, 'href' => $url)); } return $stored_feed_links; } function theme_ical_icon($url) { if ($image = theme('image', drupal_get_path('module', 'date_api') .'/images/ical16x16.gif', t('Add to calendar'), t('Add to calendar'))) { return '
'; } } /** * plugin that actually displays an ical feed */ function theme_calendar_ical_feed($view, $items, $type) { if ($type == 'block') { return; } drupal_set_header('Content-Type: text/calendar; charset=utf-8'); drupal_set_header('Content-Disposition: attachment; filename="calendar.ics"; '); $events = array(); include_once(drupal_get_path('module', 'date_api') .'/date_api_ical.inc'); $items = calendar_build_nodes($view, $items); foreach ($items as $node) { $event = array(); // Allow modules to affect item fields node_invoke_nodeapi($node, 'ical item'); $event['start'] = $node->calendar_start_date; $event['end'] = $node->calendar_end_date; $event['location'] = $node->calendar_location; $event['summary'] = $node->title; $event['description'] = $node->teaser; $event['uid'] = $node->uid ? $node->uid : (is_numeric($node->nid) ? url("node/$node->nid", array('absolute' => TRUE)) : $node->nid); $event['url'] = $node->url ? $node->url : (is_numeric($node->nid) ? url("node/$node->nid", array('absolute' => TRUE)) : $node->nid); $events[] = $event; } $description = $headertitle . ($title ? ' | '. $title : ''); print date_ical_export($events, $description); module_invoke_all('exit'); exit; } /** * Theme for an entire ical node. */ function theme_calendar_ical_node($node, $view) { // Check plain may leave html entities in the title. $node->title = html_entity_decode(check_plain($node->title), ENT-QUOTES); $node->teaser = check_markup($node->teaser); if ($view->calendar_display == 'calendar') { // Remote nodes may come in with lengthy descriptions that won't fit // in small boxes of year, month, and week calendars. if ($view->calendar_type != 'day') { $node->teaser = ''; } $theme = 'calendar_node_'. $view->calendar_type; return theme($theme, $node, $view); } else { // Create a pseudo node view for this item. $output = '