'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;
}
?>