5.x-2.x branch
Adds ical functionality to Calendar.
| Name | Description |
|---|---|
| calendar_ical_add_feeds | |
| calendar_ical_add_ical | |
| calendar_ical_cache | Identify the cache where the ical feeds are stored. |
| calendar_ical_calendar_add_items | Implementation of hook_calendar_add_items(). |
| calendar_ical_calendar_add_types | Implementation of hook_calendar_add_types(). |
| calendar_ical_cron | Implementation of hook_cron(). |
| calendar_ical_menu | Implementation of hook_menu(). |
| calendar_ical_post_view_make_args | 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. |
| calendar_ical_setup_form | |
| calendar_ical_views_arguments | While we support the global selector, some might want to allow ONLY ical feeds so we support a stingy selector too |
| calendar_ical_views_feed_argument | 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 |
| calendar_ical_views_post_view | post view for our own op -- mimics the feed selector |
| calendar_ical_views_style_plugins | Provide views plugins for the feed types we support. |
| theme_calendar_ical_feed | plugin that actually displays an ical feed |
| theme_calendar_ical_field | Views field theme for an ical field. |
| theme_calendar_ical_node | Theme for an entire ical node. |
| theme_ical_icon | |
| views_handler_arg_ical | handler for our own ical argument; mimics the feed selector |
- <?php
-
- /**
- * @file
- * Adds ical functionality to Calendar.
- */
-
- /**
- * Implementation of hook_menu().
- */
- function calendar_ical_menu($may_cache) {
- $items = array();
- if (!$may_cache) {
- drupal_add_css(drupal_get_path('module', 'calendar') .'/calendar.css');
- require_once('./'. drupal_get_path('module', 'calendar') .'/calendar.module');
- foreach (calendar_info() as $view_name => $view) {
- $items[] = array(
- 'path' => 'admin/settings/calendar/'. $view_name .'/ical',
- 'title' => t('iCal'),
- 'description' => t('iCal setup.'),
- 'access' => user_access('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_setup_form($view_name) {
- require_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) {
- require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
-
- $items = array();
- $feeds = calendar_ical_add_feeds($view);
-
- $min = date_format($view->min_date, DATE_FORMAT_DATETIME);
- $max = date_format($view->max_date, DATE_FORMAT_DATETIME);
-
- foreach ($feeds as $feed) {
- if (!empty($feed->calendar_start) && !empty($feed->calendar_end)) {
- if ($feed->calendar_start >= date_format($view->min_date, DATE_FORMAT_DATETIME) && $feed->calendar_end <= date_format($view->max_date, DATE_FORMAT_DATETIME)) {
- if (($feed->calendar_start >= $min && $feed->calendar_end <= $max) || ($feed->calendar_start >= $min && $feed->all_day == 1)){
- // We have to add a calendar start and end object to the feed,
- // the cached date objects will not work correctly.
- $feed->calendar_start_date = date_make_date($feed->calendar_start, $feed->timezone);
- $feed->calendar_end_date = date_make_date($feed->calendar_end, $feed->timezone);
- $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) unserialize($cached->data);
- }
- else {
- $expire = intval(variable_get('calendar_ical_expire_'. $view->name, 9676800) + time());
- require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
-
- switch ($feed['type']) {
- case 'ical':
- $filename = $feed['url'];
- $default = $feed['link'];
- $new_nodes = array();
- $calendars = date_ical_import($filename);
- if (empty($calendars)) {
- continue;
- }
- foreach ($calendars as $calendar) {
- if (empty($calendar) || empty($calendar['VEVENT'])) {
- continue;
- }
- 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->timezone = $value['DTSTART']['tz'];
- $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['all_day'];
- $node->location = $value['LOCATION'];
- $node->stripe = $feed['stripe'];
- $node->stripe_label = $feed['name'];
- $node->remote = TRUE;
- $node->uid = $value['uid'] ? $value['UID'] : calendar_get_node_link($node, $default);
- $node->url = $value['URL'] ? $value['URL'] : calendar_get_node_link($node, $default);
- $node->calendar_node_theme = 'calendar_ical_node';
- $node->calendar_field_theme = 'calendar_ical_field';
- $new_nodes[$value['UID']] = $node;
- }
- }
- if (!empty($new_nodes)) {
- cache_set('calendar_feeds_'. $view->name .':'. $feed['url'], calendar_ical_cache(), serialize($new_nodes), $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;
- }
- }
- $url = calendar_get_url($view, $args, FALSE);
- $view->feed_url = $url;
- }
- else if ($op == 'post_view') {
- $args = calendar_ical_post_view_make_args($view, $arg, 'ical');
- $url = calendar_get_url($view, $args, FALSE);
- $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 '<div style="text-align:right"><a href="'. check_url($url) .'" class="ical-icon" title="ical">'. $image .'</a></div>';
- }
- }
-
-
- /**
- * 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"; ');
- $display_formats = variable_get('calendar_display_format_'. $view->name, array('year' => 'calendar', 'month' => 'calendar', 'week' => 'calendar', 'day' => 'calendar', 'block' => 'calendar'));
- $events = array();
- include_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
- include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.inc');
- $items = calendar_build_nodes($view, $items, $display_formats[$view->calendar_type]);
- foreach ($items as $time) {
- foreach ($time as $node) {
- $event = array();
- // Allow modules to affect item fields
- node_invoke_nodeapi($node, 'ical item');
- if (!$node->remote) {
- $real_node = node_load($node->nid);
- $node->teaser = $real_node->teaser;
- }
- $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['url'] = $node->url ? $node->url : calendar_get_node_link($node);
- $event['uid'] = !empty($node->date_id) ? $node->date_id : $event['url'];
- $events[] = $event;
- }
- }
-
- $headertitle = filter_xss_admin(views_get_title($view, 'page'));
- $title = variable_get('site_name', 'Drupal');
- $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.
- $field = array();
- $output = '<div class="node">';
- $output .= '<h2>'. l($node->title, $node->url) .'</h2>';
- $output .= '<div>'. theme('calendar_date_combo', $field, $node, $node->format, t('Dates'), $view) .'</div>';
- $output .= '<div class="content">'. $node->teaser .'</div>';
- $output .= '</div>';
- return $output;
- }
- }
-
- /**
- * Views field theme for an ical field.
- *
- * Used for table and list views.
- *
- * For non-calendar views that use fields, the field needs a value from the
- * imported node that matches the kind of field in the view. Most possible
- * Views fields make no sense here and will return nothing.
- */
- function theme_calendar_ical_field($fieldname, $fields, $field, $node, $view, $type) {
- static $datefield;
-
- // Find the first date field in the view to attach the ical date to.
- // There may be more than one date field in the view and we only
- // want to put the ical field in one place.
- if (empty($datefield)) {
- $calendar_fields = calendar_fields();
- foreach ($view->field as $viewfield) {
- if (in_array($viewfield['field'], array_keys($calendar_fields))) {
- $datefield = $viewfield['queryname'];
- break;
- }
- }
- }
-
- // 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);
-
- // Fix some common html entities that may not get decoded correctly.
- // You can add more of them in this array.
- $replace = array(
- ''' => "'",
- );
- foreach (array('title', 'teaser') as $key) {
- $node->$key = strtr($node->$key, $replace);
- }
-
- if ($fieldname == $datefield) {
- return theme('calendar_date_combo', $field, $node, '', $view);
- }
-
- switch ($field['fullname']) {
- case 'node.title':
- return l($node->title, $node->url);
-
- case 'node.teaser':
- case 'node.body':
- return $node->teaser;
-
- case 'node.type':
- return $node->label;
- }
- return;
-
- }