'timeline/load_xml', 'title' => '', 'callback' => 'timeline_create_event_xml', 'access' => user_access('access content'), 'type' => MENU_CALLBACK); $items[] = array('path' => 'timeline/load_test_xml', 'title' => '', 'callback' => 'timeline_load_test_xml', 'access' => user_access('access content'), 'type' => MENU_CALLBACK); return $items; } } /** * Implementation of hook_perm. * */ function timeline_perm() { return array('administer timelines'); } /** * * Returns the html required to insert a timeline. * * @param $timeline * An associative array with the following variables set: * * id - the id of the timeline element * width - width of the map * height - height of the map * class - CSS class of the div enclosing the timeline (default 'tline') * align - left right or center (default '') * orientation - HORIZONTAL or VERTICAL * start_date - the start date of the timeline * timezone - the timezone represented by # of hours difference from GMT * view_name - the name of the Drupal view to render in the timeline * view_args - an array of view arguments * * @return * A string containing the timeline HTML. * */ function timeline_draw_timeline($timeline) { global $base_url; _timeline_doheader(); $timeline_starttime = strtotime($timeline['start_date']); //print_r($timeline); if (!isset($timeline['class'])) $timeline['class']='timeline_default'; if (!isset($timeline['width'])) $timeline['width']=TIMELINE_WIDTH; if (!isset($timeline['height'])) $timeline['height']=TIMELINE_HEIGHT; if (!isset($timeline['align'])) $timeline['align']=''; if (!isset($timeline['id'])) $timeline['id']='tline'; if (!isset($timeline['orientation'])) $timeline['orientation']=TIMELINE_ORIENTATION; if (!isset($timeline['start_date'])) $timeline['start_date']=date("D M d Y G:i:s") . ' GMT' . date('O'); if (!isset($timeline['timezone'])) $timeline['timezone'] = date("O"); $style='width: '.timeline_todim($timeline['width']).'; height: '.timeline_todim($timeline['height']).';'; switch (strtolower($timeline['align'])) { case 'left': $style .= ' float: left;'; break; case 'right': $style .= ' float: right;'; break; case 'center': case 'centre': $style .= ' margin-left: auto; margin-right: auto;'; } $outtext.='
'; $timeline_querystring = 'view=' . $timeline['view_name']; if ($timeline['view_args']) { $timeline_querystring .= '&args=' . urlencode(serialize($timeline['view_args'])); //$timeline_querystring .= '&args=' . http_build_query($timeline['view_args']); } $timeline_load_url = url('timeline/load_xml', $timeline_querystring, null, true); $addjs = " EOD; $outtext = $outtext . $addjs; return $outtext; } /** * Render the XML which is to be loaded by the timeline generated by * function timeline_draw_timeline() */ function timeline_create_event_xml() { $view_name = $_REQUEST['view']; $view_args = array(); if (isset($_REQUEST['args']) && $_REQUEST['args']) { $view_args = unserialize($_REQUEST['args']); } //var_export($view_args); //get the view, passing any arguments $view = views_get_view($view_name); if (!$view) return; //$view->timeline_get_xml = true; drupal_set_header("Content-type: text/xml"); $items = views_build_view('items', $view, $view_args, false, $view->nodes_per_page); print timeline_get_event_xml($view, $items['items'], NULL); //print $xml; } /** * This generates an XML page for loading events via JS + XML REST interface. * It determines what will be the field specifying the start time for the * timeline entries, by looking at the view's first field. * It determines what will be the field specifying the end time for the timeline * entries, by looking at the view's second field (if persent). */ function timeline_get_event_xml($view, $nodes, $type, $teasers = false, $links = true) { //var_export($view); $fieldinfo = $view->field; //use the view's first field as the start time for timeline entries if (isset($fieldinfo[0]['field']) && $fieldinfo[0]['field']) { $start_field = $fieldinfo[0]['field']; } //use the view's second field (if present) as the end time for timeline entries if (isset($fieldinfo[1]['field']) && $fieldinfo[1]['field']) { $end_field = $fieldinfo[1]['field']; } $xml = ''; foreach ($nodes as $view_node) { $node = node_load($view_node->nid); $start_value = $node->$start_field; if (! is_numeric($start_value)) { $start_value = strtotime($start_value); } $event_start = date("D M d Y G:i:s", $start_value) . ' GMT' . date('O', $start_value); $event_end = ""; if ($end_field) { $end_value = $node->$end_field; if (! is_numeric($end_value)) { $end_value = strtotime($end_value); } $event_end = date("D M d Y G:i:s", $end_value) . ' GMT' . date('O', $end_value); } $event_title = str_replace ( array ( '&', '"', "'", '<', '>', '?' ), array ( '&' , '"', ''' , '<' , '>', ''' ), $node->title ); $event_teaser = str_replace ( array ( '&', '"', "'", '<', '>', '?' ), array ( '&' , '"', ''' , '<' , '>', ''' ), $node->teaser ); $event_link = url($node->path); // if ($event_end) { $xml .= << $event_teaser EOD; } else { $xml .= << $event_teaser EOD; } } $xml .= ''; return $xml; } /** * * Lifted from gmap.module; thanks to webgeer * Cleans the timeline variables to * prevent javascript interjection * * @param $timeline * A timeline variable * * @return * A timeline variable with any dangerous text removed. * * This is not currently being used. */ function timeline_sanitize(&$timeline){ //sanitizes the timeline variables to reduce the possibility of javascript inserts foreach ($timeline as $key=>$value) { if ($key=='id') { $out = array(); preg_match('([a-zA-Z1-9_-]*)', $value, $out); if (strlen($out[0])==0) { $out[0]='map'; } $timeline[$key]=$out[0]; } else { $timeline[$key]=str_replace(';','',$value); } } } /** * Use this function to add JS to header. Currently timeline JS library is * loaded from simile.mit.edu each request. */ function _timeline_doheader(){ static $timeline_initialized = FALSE; if ($timeline_initialized) { return; } theme_add_style(drupal_get_path('module','timeline'). '/timeline.css'); $js = ''; //$js .= ''; drupal_set_html_head($js); //drupal_add_js(drupal_get_path('module','timeline'). '/timeline.js'); $timeline_initialized = TRUE; } /** * Lifted from gmap.module; thanks to webgeer; not used */ function timeline_todim($instring) { if (strpos($instring,'px')) { return intval($instring).'px'; } elseif (strpos($instring,'%')) { return intval($instring).'%'; } else { return intval($instring).'px'; } } /** * Add configuration settings */ function timeline_settings() { $form['timeline_default_width']=array( '#type'=>'textfield', '#title'=>t('Default width'), '#default_value'=>TIMELINE_WIDTH, '#size'=>25, '#maxlength'=>6, '#description'=>t('The default width of a timeline. E.g. 400px'), ); $form['timeline_default_height']=array( '#type'=>'textfield', '#title'=>t('Default height'), '#default_value'=>TIMELINE_HEIGHT, '#size'=>25, '#maxlength'=>6, '#description'=>t('The default height of a timeline. E.g. 400px'), ); return $form; } /** * Implementation of hook_views_style_plugins(); * Adds view types to views UI interface */ function timeline_views_style_plugins() { return array( 'timeline_vertical' => array( 'name' => t('Timeline Vertical'), 'theme' => 'views_view_timeline_vertical', 'needs_fields' => true, //'validate' => 'views_ui_plugin_validate_list', ), 'timeline_horizontal' => array( 'name' => t('Timeline Horizontal'), 'theme' => 'views_view_timeline_horizontal', 'needs_fields' => true, //'validate' => 'views_ui_plugin_validate_list', ), ); } /** * Display a Drupal view in a Timeline, VERTICAL mode */ function theme_views_view_timeline_vertical($view, $nodes) { return theme('views_view_timeline', $view, $nodes, 'VERTICAL'); } /** * Display a Drupal view in a Timeline, HORIZONTAL mode */ function theme_views_view_timeline_horizontal($view, $nodes) { return theme('views_view_timeline', $view, $nodes, 'HORIZONTAL'); } /** * Display a Drupal view in a Timeline */ function theme_views_view_timeline($view, $nodes, $orientation='VERTICAL') { $output = ''; //print '

theme_views_view_timeline

'; //var_export($view); $fields = _views_get_fields(); $timeline = array(); $timeline['view_name'] = $view->name; $timeline['view_args'] = $view->args; $timeline['orientation'] = $orientation; //the start date for a timeline is the start date of the first event (i.e., assume view is sorted by event start date ascending $first_node = node_load($nodes[0]->nid); //add start date and timezone //use the view's first field as the start time for timeline entries $fieldinfo = $view->field; if (isset($fieldinfo[0]['field']) && $fieldinfo[0]['field']) { $start_field = $fieldinfo[0]['field']; } $start_value = $first_node->$start_field; if (! is_numeric($start_value)) { $start_value = strtotime($start_value); } $timeline['start_date'] = date("D M d Y G:i:s", $start_value) . ' GMT' . date('O', $start_value); $timeline['timezone'] = date("Z", $start_value) / 3600; $output .= timeline_draw_timeline($timeline); return $output; } /** * Not using this yet. Call this to create an array of events if needed, * e.g. from function theme_views_view_timeline() */ function timeline_get_events_array($nodes, $fields) { $events = array(); foreach ($nodes as $node) { $event = array(); $node_data = node_load(array("nid"=>$node->nid)); //$event['title'] = views_theme_field('views_handle_field', 'title', $fields, $view->field['title'], $node); $event['title'] = $node_data->title; $event['label'] = ''; foreach ($view->field as $field) { $event['label'] .= "

" . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node) . "

"; }//loop back to next field //$event['start'] = date("D M d Y G:i:s", $node_data->event_start) . ' GMT' . date('O', $node_data->event_start); $event['start'] = date("D M d Y G:i:s e", $node_data->event_start); //$event['end'] = date("D M d Y G:i:s", $node_data->event_end) . ' GMT' . date('O', $node_data->event_end); $event['end'] = date("D M d Y G:i:s e", $node_data->event_end); $events[] = $event; }//loop back to next node $timeline['events'] = $events; $last_node = $node; $timeline['end_date'] = date("D M d Y G:i:s", $last_node->event_end) . ' GMT' . date('O', $last_node->event_end); } /** * Not used. Can be used to generate JS to load events at the time of building * the timeline, instead of separate loading of XML */ function timeline_get_events_js($events) { $addjs = <<name = 'timeline_nodes'; $view->description = 'example timeline of nodes; accepts YYYY/MM args'; $view->access = array ( 0 => '1', 1 => '2', ); $view->view_args_php = ''; $view->page = TRUE; $view->page_title = 'Timeline of Content'; $view->page_header = ''; $view->page_header_format = '1'; $view->page_footer = ''; $view->page_footer_format = '1'; $view->page_empty = ''; $view->page_empty_format = '1'; $view->page_type = 'timeline_horizontal'; $view->url = 'timeline_nodes'; $view->use_pager = FALSE; $view->nodes_per_page = '50'; $view->sort = array ( array ( 'tablename' => 'node', 'field' => 'created', 'sortorder' => 'ASC', 'options' => '', ), ); $view->argument = array ( array ( 'type' => 'year', 'argdefault' => '2', 'title' => '', 'options' => '', 'wildcard' => '', 'wildcard_substitution' => '', ), array ( 'type' => 'month', 'argdefault' => '2', 'title' => '', 'options' => '', 'wildcard' => '', 'wildcard_substitution' => '', ), ); $view->field = array ( array ( 'tablename' => 'node', 'field' => 'created', 'label' => 'timeline_start', 'handler' => 'views_handler_field_date_small', ), ); $view->filter = array ( array ( 'tablename' => 'node', 'field' => 'status', 'operator' => '=', 'options' => '', 'value' => '1', ), ); $view->exposed_filter = array ( ); $view->requires = array(node); $views[$view->name] = $view; //add timeline_events view $view = new stdClass(); $view->name = 'timeline_events'; $view->description = 'example timeline of events; accepts YYYY/MM/DD args'; $view->access = array ( 0 => '1', 1 => '2', ); $view->view_args_php = ''; $view->page = TRUE; $view->page_title = 'Timeline of Events'; $view->page_header = ''; $view->page_header_format = '1'; $view->page_footer = ''; $view->page_footer_format = '1'; $view->page_empty = ''; $view->page_empty_format = '1'; $view->page_type = 'timeline_horizontal'; $view->url = 'timeline_events'; $view->use_pager = FALSE; $view->nodes_per_page = '50'; $view->sort = array ( array ( 'tablename' => 'event', 'field' => 'event_start', 'sortorder' => 'ASC', 'options' => '', ), ); $view->argument = array ( array ( 'type' => 'event_year', 'argdefault' => '2', 'title' => '', 'options' => 'event.event_start', 'wildcard' => '', 'wildcard_substitution' => '', ), array ( 'type' => 'event_month', 'argdefault' => '2', 'title' => '', 'options' => 'event.event_start', 'wildcard' => '', 'wildcard_substitution' => '', ), array ( 'type' => 'event_day', 'argdefault' => '2', 'title' => '', 'options' => 'event.event_start', 'wildcard' => '', 'wildcard_substitution' => '', ), ); $view->field = array ( array ( 'tablename' => 'event', 'field' => 'event_start', 'label' => '', 'handler' => 'views_handler_field_date_small', ), array ( 'tablename' => 'event', 'field' => 'event_end', 'label' => '', 'handler' => 'views_handler_field_date_small', ), ); $view->filter = array ( array ( 'tablename' => 'node', 'field' => 'status', 'operator' => '=', 'options' => '', 'value' => '1', ), array ( 'tablename' => 'event', 'field' => 'event_start', 'operator' => '>', 'options' => '', 'value' => '1970-08-02 11:01:18', ), ); $view->exposed_filter = array ( ); $view->requires = array(event, node); $views[$view->name] = $view; return $views; } ?>