views_gantt.module in Views Gantt 7.2
Same filename and directory in other branches
Module file for Views Gantt
File
views_gantt.moduleView source
<?php
/**
* @file
* Module file for Views Gantt
*/
/**
* Implements hook_views_api().
*/
function views_gantt_views_api() {
return array(
'api' => 3,
);
}
/**
* Implements hook_libraries_info().
*/
function views_gantt_libraries_info() {
$libraries['dhtmlxgantt'] = array(
'name' => 'dhtmlxgantt',
'vendor url' => 'http://dhtmlx.com/docs/products/dhtmlxGantt/index.shtml',
'download url' => 'http://dhtmlx.com/docs/products/dhtmlxGantt/index.shtml',
'version' => '2.0',
'files' => array(
'js' => array(
'codebase/dhtmlxgantt.js',
),
'css' => array(
'codebase/dhtmlxgantt.css',
),
),
);
return $libraries;
}
/**
* Implements hook_menu().
*/
function views_gantt_menu() {
$items = array();
$items['views_gantt/data.json'] = array(
'type' => MENU_CALLBACK,
'page callback' => 'views_gantt_data_json',
'access arguments' => array(
'access content',
),
);
// @todo Add permission to update tasks from Gantt chart?
$items['views_gantt/update'] = array(
'type' => MENU_CALLBACK,
'page callback' => 'views_gantt_update',
'access arguments' => array(
'access content',
),
);
$items['gantt/redirect/%/%'] = array(
'page callback' => 'views_gantt_redirect_page',
'page arguments' => array(
2,
3,
),
'access callback' => 'views_gantt_redirect_access',
'access arguments' => array(
2,
3,
),
);
return $items;
}
function views_gantt_data_json() {
$data = array();
$links = array();
if (!isset($_SESSION['views_gantt']) && isset($_GET['view'], $_GET['display'], $_GET['project'])) {
_views_gantt_load_view($_GET['view'], $_GET['display'], $_GET['project']);
}
if (isset($_SESSION['views_gantt'])) {
$project_id = $_SESSION['views_gantt']['project']['id'];
foreach ($_SESSION['views_gantt']['tasks'] as $id => $task) {
if (!$task['parent_id'] && $id != $project_id) {
$task['parent_id'] = $project_id;
}
$row = array(
'id' => $id,
'text' => $task['name'],
'start_date' => $task['est'],
'duration' => $task['duration'] / 8,
'progress' => $task['percentcompleted'] / 100,
'parent' => $task['parent_id'],
'open' => TRUE,
'type' => $id == $project_id ? 'project' : 'task',
);
if (!empty($task['columns'])) {
foreach ($task['columns'] as $col_key => $col_val) {
if (!array_key_exists($col_key, $row)) {
$row[$col_key] = $col_val;
}
}
}
$data[] = $row;
if ($task['predecessortasks']) {
$links[] = array(
'id' => $task['predecessortasks'] . '_' . $id,
'source' => $task['predecessortasks'],
'target' => $id,
'type' => 0,
);
}
}
}
drupal_json_output(array(
'data' => $data,
'links' => $links,
));
}
function _views_gantt_load_view($view_name, $display, $project_id) {
$view = views_get_view($view_name);
$exposed_filters = array();
foreach ($_GET as $key => $value) {
if (isset($view->exposed_data[$key])) {
$exposed_filters[$key] = $value;
}
}
if (isset($view->exposed_input)) {
$view->exposed_input = array_merge($exposed_filters, (array) $view->exposed_input);
}
if (isset($view->exposed_raw_input)) {
$view->exposed_raw_input = array_merge($exposed_filters, (array) $view->exposed_raw_input);
}
if (isset($view->exposed_data)) {
$view->exposed_data = array_merge($exposed_filters, (array) $view->exposed_data);
}
$view
->preview($display, $project_id);
}
/**
* Callback for task/project update when we change it in Gantt chart.
*/
function views_gantt_update($account = NULL) {
$view_name = variable_get('views_gantt_view_name', NULL);
// Show empty page in browser if request incorrect.
if (!$view_name || empty($_POST['ids'])) {
return NULL;
}
$data = $_POST;
$id = $data['ids'];
$style_options = views_gantt_get_style_options($view_name);
switch ($_GET['gantt_mode']) {
case 'tasks':
if (isset($data[$id . '_start_date'])) {
$fields = array(
'date_field' => $data[$id . '_start_date'],
'end_date_field' => $data[$id . '_end_date'],
'progress_field' => $data[$id . '_progress'] * 100,
);
$node = node_load($id);
}
break;
case 'links':
if ($data[$id . '_!nativeeditor_status'] != 'deleted') {
$source = $data[$id . '_source'];
$target = $data[$id . '_target'];
}
else {
list($source, $target) = explode('_', $id);
$source = NULL;
}
$fields = array(
'predecessor_id_field' => $source,
);
$node = node_load($target);
break;
}
if (!empty($node) && views_gantt_update_access($node, $account)) {
views_gantt_update_node($node, $fields, $style_options);
$response_type = 'updated';
}
else {
$response_type = 'error';
}
$xml = new SimpleXMLElement("<data><action type='{$response_type}' sid='{$id}' tid='{$id}' /></data>");
drupal_add_http_header('Content-Type', 'text/xml');
print $xml
->asXML();
drupal_exit();
}
/**
* Access callback for task/project updating.
*/
function views_gantt_update_access($node, $account = NULL) {
if (empty($account)) {
$account = $GLOBALS['user'];
}
// Check access to update node by default
$access = node_access('update', $node, $account);
// Allow other modules to add another access rules.
drupal_alter('views_gantt_update_access', $access, $node, $account);
return $access;
}
/**
* Updates node if there are changes in it's fields.
*
* @param object $node
* Node object
* @param array $data
* Array of option names (from style plugin options) => values to update
* @param array $style_options
* Array of all style plugin option names
*/
function views_gantt_update_node($node, $data, $style_options) {
$changed = FALSE;
$lang = LANGUAGE_NONE;
// For now we support only simple fields that
// storing their values in array with 'value' key,
// and datetime fields (form Date module).
// Maybe we don't need to add another field types,
// because we update only dates and duration.
foreach ($data as $option_name => $option_value) {
if (isset($style_options[$option_name])) {
$field_name = $style_options[$option_name];
if (isset($node->{$field_name})) {
if (is_array($node->{$field_name})) {
// Get field info.
$field_info = field_info_field($field_name);
// If field is translatable, we check if it has
// an index equals to node language.
$is_translatable = field_is_translatable('node', $field_info);
if ($is_translatable && isset($node->{$field_name}[$node->language])) {
$lang = $node->language;
}
$index = key($field_info['columns']);
if ($option_name == 'end_date_field' && isset($field_info['columns']['value2'])) {
$index = 'value2';
}
// If field type = datetime, modify new value before storing.
if (isset($field_info['columns'][$index]) && $field_info['columns'][$index]['type'] == 'datetime') {
views_gantt_normalize_date_field($option_value, 'Y-m-d H:i:s');
}
if ($option_value) {
$node->{$field_name}[$lang][0][$index] = $option_value;
}
else {
$node->{$field_name} = array();
}
}
else {
$node->{$field_name} = $option_value;
}
$changed = TRUE;
}
}
}
// If we have some changes, we need to save node.
// Also if node saved, we remove cached gantt data from session.
if ($changed) {
node_save($node);
unset($_SESSION['views_gantt']);
}
}
/**
* Formats date for Gantt Chart.
*/
function views_gantt_normalize_date_field(&$field, $format = 'Y-m-d H:i') {
if (!is_numeric($field)) {
$field = strtotime($field);
}
$field = format_date($field, 'custom', $format);
}
/**
* Get style plugin options.
*/
function views_gantt_get_style_options($view_name) {
$view = views_get_view($view_name);
// Get style plugin options.
// Some fields in $this->options can have incorrect names (e.g. field_date_1),
// so we should check the real field name.
$style_options = array();
foreach ($view->display as $display) {
$display_options = $display->display_options;
if (isset($display_options['style_plugin']) && $display_options['style_plugin'] == 'gantt') {
$style_options = $display->display_options['style_options'];
foreach ($style_options as $key => &$value) {
if (!empty($value) && !is_array($value) && isset($display->display_options['fields'][$value])) {
$value = $display->display_options['fields'][$value]['field'];
}
}
break;
}
}
return $style_options;
}
/**
* Implements hook_theme().
*/
function views_gantt_theme() {
return array(
'views_gantt_page' => array(
'render element' => 'page',
'template' => 'views-gantt-page',
),
);
}
/**
* Process variables for references_dialog_page.
*/
function template_process_views_gantt_page(&$variables) {
// Generate messages last in order to capture as many as possible for the
// current page.
if (!isset($variables['messages'])) {
$variables['messages'] = $variables['page']['#show_messages'] ? theme('status_messages') : '';
}
}
/**
* Implements hook_entity_insert().
*/
function views_gantt_entity_insert($entity, $entity_type) {
if (views_gantt_in_dialog() && views_gantt_close_on_submit()) {
views_gantt_close_on_redirect($entity, $entity_type);
}
}
/**
* Implements hook_entity_update().
*/
function views_gantt_entity_update($entity, $entity_type) {
if (views_gantt_in_dialog() && views_gantt_close_on_submit()) {
views_gantt_close_on_redirect($entity, $entity_type);
}
}
/**
* Sets our destination parameter so that the dialog will close itself after
* redirect is completed.
*/
function views_gantt_close_on_redirect($entity, $entity_type) {
$entity_info = entity_get_info($entity_type);
$_GET['destination'] = 'gantt/redirect/' . $entity->{$entity_info['entity keys']['id']} . '/' . $entity_type . '?gantt-dialog-close=1&render=gantt-dialog';
}
/**
* Implements hook_page_alter().
*/
function views_gantt_page_alter(&$page) {
if (views_gantt_in_dialog()) {
unset($page['page_top']);
unset($page['page_bottom']);
$page['#theme'] = 'views_gantt_page';
}
}
/**
* Check if we are in a gantt dialog.
* @return boolean if we are in a dialog.
*/
function views_gantt_in_dialog() {
return isset($_GET['render']) && $_GET['render'] == 'gantt-dialog';
}
/**
* Check if we should close the dialog upon submition.
*/
function views_gantt_close_on_submit() {
return !isset($_GET['closeonsubmit']) || $_GET['closeonsubmit'];
}
function views_gantt_redirect_access() {
return TRUE;
}
/**
* Page callback for our redirect page.
*/
function views_gantt_redirect_page($entity_id, $entity_type) {
// Get some information about the entity.
$entity = entity_load($entity_type, array(
$entity_id,
));
$entity = reset($entity);
$entity_info = entity_get_info($entity_type);
$entity_id = $entity->{$entity_info['entity keys']['id']};
$entity_title = entity_label($entity_type, $entity);
// Add appropriate javascript that will be used by the parent page to
// fill in the required data.
if (isset($entity_id) && views_gantt_in_dialog() && isset($_GET['gantt-dialog-close'])) {
drupal_add_js(drupal_get_path('module', 'views_gantt') . '/js/gantt-dialog-child.js');
drupal_add_js(array(
'GanttDialog' => array(
'entity_id' => $entity_id,
'title' => $entity_title,
'entity_type' => $entity_type,
),
), 'setting');
}
return '';
}
/**
* Implements hook_form_alter().
*/
function views_gantt_form_alter(&$form, &$form_state, $form_id) {
if (isset($_GET['render']) && $_GET['render'] == 'gantt-dialog') {
// Prepopulate parent and project fields in add task form.
if (!empty($_SESSION['views_gantt']['project_field'])) {
views_gantt_prepopulate_field($_SESSION['views_gantt']['project_field'], $_GET['project'], $form, $form_state);
}
if (!empty($_SESSION['views_gantt']['parent_field']) && $_GET['parent'] != $_GET['project']) {
views_gantt_prepopulate_field($_SESSION['views_gantt']['parent_field'], $_GET['parent'], $form, $form_state);
}
}
}
/**
* Helper function for prepopulation fields on add form.
*/
function views_gantt_prepopulate_field($field_name, $value, &$form, $form_state) {
if (!isset($form[$field_name])) {
return FALSE;
}
if (isset($form[$field_name]['#language']) && !empty($form[$field_name]['#language'])) {
$language = $form[$field_name]['#language'];
}
else {
$language = LANGUAGE_NONE;
}
$widget = isset($form_state['field'][$field_name][$language]['instance']['widget']['type']) ? $form_state['field'][$field_name][$language]['instance']['widget']['type'] : '';
if (empty($widget)) {
return FALSE;
}
switch ($widget) {
case 'options_select':
$form[$field_name][$language]['#default_value'][0] = $value;
break;
case 'options_buttons':
$form[$field_name][$language]['#default_value'] = $value;
break;
case 'node_reference_autocomplete':
$form[$field_name][$language][0]['nid']['#default_value'] = $value;
break;
case 'entityreference_autocomplete':
$node = node_load($value);
$form[$field_name][$language][0]['target_id']['#default_value'] = $node->title . ' (' . $value . ')';
break;
case 'entityreference_autocomplete_tags':
$node = node_load($value);
$form[$field_name][$language]['#default_value'] = $node->title . ' (' . $value . ')';
break;
}
}
Functions
Name | Description |
---|---|
template_process_views_gantt_page | Process variables for references_dialog_page. |
views_gantt_close_on_redirect | Sets our destination parameter so that the dialog will close itself after redirect is completed. |
views_gantt_close_on_submit | Check if we should close the dialog upon submition. |
views_gantt_data_json | |
views_gantt_entity_insert | Implements hook_entity_insert(). |
views_gantt_entity_update | Implements hook_entity_update(). |
views_gantt_form_alter | Implements hook_form_alter(). |
views_gantt_get_style_options | Get style plugin options. |
views_gantt_in_dialog | Check if we are in a gantt dialog. |
views_gantt_libraries_info | Implements hook_libraries_info(). |
views_gantt_menu | Implements hook_menu(). |
views_gantt_normalize_date_field | Formats date for Gantt Chart. |
views_gantt_page_alter | Implements hook_page_alter(). |
views_gantt_prepopulate_field | Helper function for prepopulation fields on add form. |
views_gantt_redirect_access | |
views_gantt_redirect_page | Page callback for our redirect page. |
views_gantt_theme | Implements hook_theme(). |
views_gantt_update | Callback for task/project update when we change it in Gantt chart. |
views_gantt_update_access | Access callback for task/project updating. |
views_gantt_update_node | Updates node if there are changes in it's fields. |
views_gantt_views_api | Implements hook_views_api(). |
_views_gantt_load_view |