array( 'name' => t('Task'), 'module' => 'tasks', 'description' => t('A task to keep track of.'), ), ); } // Implementation of hook_perm(). function tasks_perm() { return array('create tasks', 'edit own tasks', 'edit all tasks', 'access tasks main page'); } // Implementation of hook_access(). function tasks_access($op, $node, $account) { if ($op == 'create') { return user_access('create tasks'); } if ($op == 'update' || $op == 'delete') { if (user_access('edit all tasks') || (user_access('edit own tasks') && ($account->uid == $node->uid))) { return TRUE; } } } // Implementation of hook_menu(). function tasks_menu() { $items['tasks'] = array( 'title' => 'Tasks', 'page callback' => '_tasks_main', 'access arguments' => array('access tasks main page'), 'type' => MENU_CALLBACK ); return $items; } // Implementation of hook_user(). function tasks_user($op, &$edit, &$user, $category = NULL) { if ($op == "form" && $category == 'account' && user_access( 'access tasks main page')) { $form['tasklist'] = array( '#type' => 'fieldset', '#title' => t('Tasklist'), '#collapsible' => TRUE, '#weight' => 4 ); $form['tasklist']['tasks_colour'] = array( '#type' => 'textfield', '#title' => t('Colour'), '#default_value' => $edit['tasks_colour'], '#description' => t('This will be the colour this user\'s tasks will appear in. Hexdecimal or recognized colour name (e.g. #eee or just \'blue\')') ); return $form; } } // Implementation of hook_form(). function tasks_form(&$node) { drupal_add_js(drupal_get_path('module', 'tasks') .'/tasks.js'); drupal_add_css(drupal_get_path('module', 'tasks') .'/tasks.css'); $bc = drupal_get_breadcrumb(); $bc[] = l(t('Tasks'), 'tasks'); drupal_set_breadcrumb($bc); $form = array(); // Get a list of tasklists to choose a parent tasklist if (!isset($node->task_parent) || $node->task_parent != 0) { $result = db_query("SELECT n.*, t.* FROM {node} n INNER JOIN {tasks} t ON n.nid = t.nid WHERE n.type='tasks' AND t.completed = '0000-00-00' ORDER BY IF(t.task_parent = 0,0,1), n.title ASC"); while ($tasklist = db_fetch_object($result)) { if ($tasklist->task_parent == 0) { $tasklist->title = t('-- MASTER TASKLIST --'); } $tasklists[$tasklist->nid] = $tasklist->title; $not_master = 1; } if (!$not_master) $tasklists[0] = t('NO PARENT - THIS IS THE MASTER TASKLIST'); if (isset($_GET['edit']['task_parent'])) { $node->task_parent = $_GET['edit']['task_parent']; } $form['task_parent'] = array( '#type' => 'select', '#title' => t('Parent Tasklist'), '#default_value' => $node->task_parent, '#options' => $tasklists, '#weight' => -10 ); } else { // parent tasklist $form['task_parent'] = array( '#type' => 'value', '#value' => 0 ); } $form['title'] = array( '#type' => 'textfield', '#title' => t('Task Name'), '#required' => TRUE, '#default_value' => $node->title ); $form['body'] = array( '#type' => 'textarea', '#title' => t('About this task'), '#default_value' => $node->body, '#rows' => 10 ); $form['format'] = filter_form($node->format); $sql = 'SELECT u.uid, u.name, u.status, u.created, u.access FROM {users} u WHERE uid <> 0 ORDER BY u.name'; $result = db_query($sql); $users[0] = t('-- Unassigned --'); while ($account = db_fetch_object($result)) { $users[$account->uid] = $account->name; } $form['assigned_to'] = array( '#type' => 'select', '#title' => t('Assign to user'), '#default_value' => $node->assigned_to, '#options' => $users ); $form['completed'] = array( '#type' => 'checkbox', '#title' => t('Completed?'), '#default_value' => ($node->completed > 0)?1:0, '#attributes' => array("onclick" => "toggletasks();") ); $form['completed_date'] = array( '#type' => 'date', '#title' => t('Date Completed'), '#prefix' => '
', '#suffix' => '
' ); if ($node->completed != '0000-00-00') $form['completed_date']['#default_value'] = $node->completed_date; $form['from'] = array( '#type' => 'hidden', '#value' => arg(3) ); if ($node->task_parent) { $result = db_query("SELECT n.*, t.* FROM {node} n, {tasks} t WHERE n.type='tasks' AND t.nid = n.nid AND t.completed = '0000-00-00' AND t.task_parent = %d ORDER BY t.order_by ASC", $node->task_parent); while ($tasklist = db_fetch_object($result)) { if ($tasklist->nid == $node->nid) { $tasks[$tasklist->order_by] = t('*************** NO CHANGE ***************'); } else { $tasks[$tasklist->order_by] = $tasklist->title; } } $tasks['10000'] = t('*** bottom of list ***'); $form['order_by'] = array( '#type' => 'select', '#title' => t('Place in tasklist above'), '#default_value' => $node->order_by, '#options' => $tasks, '#prefix' => '
', '#suffix' => '
' ); } else { $form['order_by'] = array( '#type' => 'hidden', '#value' => 1, '#prefix' => '
', '#suffix' => '
' ); } return $form; } // Implementation of hooks_forms_alter so we don't see preview or delete buttons for tasks function tasks_form_alter(&$form, &$form_state, $form_id) { global $user; if ($form_id == 'tasks_node_form') { // Putting preview button back due to popular demand where people had preview as required and hence saw no button at all! //unset($form['preview']); //unset($form['delete']); } } function tasks_link($type, $node = NULL, $teaser = FALSE) { $links = array(); if ($type == 'node' && $node->type == 'tasks' && user_access('create tasks')) { if (!$teaser) { $links['tasks_add_subtask'] = array( 'title' => t('Add new sub-task'), 'href' => 'node/add/tasks', 'attributes' => array('title' => t('Add a new task to this task list')), 'query' => 'edit[task_parent]='. $node->nid, ); } } return $links; } // Implementation of hook_insert(). function tasks_insert($node) { $node->order_by -= 0.1; if (!$node->completed) { $node->completed_date['year'] = "0000"; $node->completed_date['month'] = "00"; $node->completed_date['day'] = "00"; } db_query("INSERT INTO {tasks} (nid, task_parent, assigned_to, order_by, completed) VALUES (%d, %d, %d, '%s', '%s')", $node->nid, $node->task_parent, $node->assigned_to, $node->order_by, $node->completed_date['year'] .'-'. $node->completed_date['month'] .'-'. $node->completed_date['day']); _tasks_order_by($node); } // Implementation of hook_update(). function tasks_update($node) { $node->order_by -= 0.1; if (!$node->completed) { $node->completed_date['year'] = "0000"; $node->completed_date['month'] = "00"; $node->completed_date['day'] = "00"; } db_query("UPDATE {tasks} SET task_parent = %d, assigned_to = %d, order_by = '%s', completed = '%s' WHERE nid = %d", $node->task_parent, $node->assigned_to, $node->order_by, $node->completed_date['year'] .'-'. $node->completed_date['month'] .'-'. $node->completed_date['day'], $node->nid); _tasks_order_by($node); // Redirect to the tasks home page? if ($node->from) { $_REQUEST['destination'] = 'tasks'; } } // Implementation of hook_delete(). function tasks_delete($node) { db_query('DELETE FROM {tasks} WHERE nid = %d', $node->nid); } // Implementation of hook_load(). function tasks_load($node) { $additions = db_fetch_object(db_query('SELECT task_parent, assigned_to, order_by, completed FROM {tasks} WHERE nid = %d', $node->nid)); $additions->completed_date['year'] = substr($additions->completed, 0, 4); $additions->completed_date['month'] = substr($additions->completed, 5, 2); $additions->completed_date['day'] = substr($additions->completed, 8, 2); return $additions; } /* Implementation of hook_view(). We want to view the task, and list any sub tasks */ function tasks_view(&$node, $teaser = FALSE, $page = FALSE) { drupal_add_js(drupal_get_path('module', 'tasks') .'/tasks_view.js'); drupal_add_css(drupal_get_path('module', 'tasks') .'/tasks.css'); if ($page) { // The page should show the task and any subtasks $bc = drupal_get_breadcrumb(); $bc[1] = l(t('Tasks'), 'tasks'); if ($node->task_parent) { $parent_node = node_load($node->task_parent); if ($parent_node->task_parent != 0) { $bc[2] = l($parent_node->title, 'node/'. $parent_node->nid); } } drupal_set_breadcrumb($bc); // Look to see if we need to change node order in this list if (($action = $_GET['action']) && ($tid = $_GET['task'])) { $task = node_load(array('nid' => $tid)); if ($action == 'up') { $task->order_by -= 1.3; drupal_set_message(t('Task %task has been moved up the tasklist.', array('%task' => $task->title))); } elseif ($action == 'down') { $task->order_by += 1.3; drupal_set_message(t('Task %task has been moved down the tasklist.', array('%task' => $task->title))); } node_save($task); drupal_goto("node/$node->nid", NULL, 'task'. $task->nid); } $node = node_prepare($node, $teaser); // Now show subtasks if there are any // Filter the tasks shown if ($_POST['filter'] == 0) { // incomplete tasks $complete = 'AND t.completed = 0'; $order_by = 't.order_by'; } elseif ($_POST['filter'] == 1) { // complete tasks $complete = 'AND t.completed > 0'; $order_by = 't.completed DESC'; } else { // all tasks $order_by = 'IF(t.completed = 0, 0, 1), t.completed DESC, t.order_by'; } // Get the list of tasks to display //$result = db_query("SELECT n.*, t.*, u.name AS assigned_name, u.data FROM {node} n INNER JOIN {tasks} t ON t.nid = n.nid LEFT JOIN {users} u ON u.uid = t.assigned_to WHERE n.status = 1 AND n.type='tasks' AND t.task_parent = %d %s ORDER BY %s", $node->nid, $complete, $order_by); $result = db_query("SELECT n.nid, u.name AS assigned_name, u.data FROM {node} n INNER JOIN {tasks} t ON t.nid = n.nid LEFT JOIN {users} u ON u.uid = t.assigned_to WHERE n.status = 1 AND n.type='tasks' AND t.task_parent = '%d' '%s' ORDER BY '%s'", $node->nid, $complete, $order_by); $num_rows = db_result(db_query("SELECT COUNT(*) FROM {node} n INNER JOIN {tasks} t ON t.nid = n.nid LEFT JOIN {users} u ON u.uid = t.assigned_to WHERE n.status = 1 AND n.type='tasks' AND t.task_parent = '%d' '%s' ORDER BY '%s'", $node->nid, $complete, $order_by)); // Add filtering to the the tasklist $node->content['tasks_filter'] = array( '#value' => drupal_get_form('tasks_view_filter_form', $num_rows, $node->nid), '#weight' => 1, ); if ($num_rows) { while ($task = db_fetch_object($result)) { $assigned_name = $task->assigned_name; //$tasks_colour = drupal_unpack($task)->tasks_colour; $extra = drupal_unpack($task); // Only color codes or color names are accepted. preg_match('/#?[a-zA-Z0-9]*/', $extra->tasks_colour, $matches); $tasks_colour = isset($matches[0]) ? $matches[0] : NULL; $task = node_load(array('nid' => $task->nid)); $rows[] = array( 'data' => array( array('data' => l($assigned_name, "user/". $task->assigned_to), 'style' => "width:25px;". ($tasks_colour ? "background:$tasks_colour;":'')), array('data' => l($task->title, "node/$task->nid", array('name' => 'task'. $task->nid)), 'style' => ($task->completed>0)?'text-decoration: line-through;':''), array('data' => ($task->completed>0) ? $task->completed : t('No')), array('data' => "nid');\">". t('Expand') ." ". l("", "node/$task->nid/edit", array('html' => TRUE), NULL, NULL, FALSE, TRUE) .' '. l("", "node/$node->nid", array('html' => TRUE), "action=up&task=$task->nid", NULL, FALSE, TRUE) .' '. l("", "node/$node->nid", array('html' => TRUE), "action=down&task=$task->nid", NULL, FALSE, TRUE)), ), 'class' => ($task->completed>0) ? 'completed' : '' ); $task = node_prepare($task); $rows[] = array( 'data' => array( array('data' => $task->body, 'colspan' => '4'), ), 'class' => 'task-expand', 'id' => "row-$task->nid", 'style' => 'display:none;' ); } $header = array(t('Assigned'), t('Task'), t('Complete?'), t('Edit')); $node->content['tasks_table'] = array( '#value' => theme('table', $header, $rows, array("id" => "task-list")), '#weight' => 2, ); } } return $node; } /** * Filtering for tasklist */ function tasks_view_filter_form($num_rows, $nid) { // Enable the list of tasks to be filtered $form['filter'] = array( '#type' => 'select', '#title' => t('Showing %num_rows tasks. Filter', array('%num_rows' => $num_rows)), '#default_value' => 0, '#options' => array(0 => t('Incomplete Tasks'), 1 => t('Complete Tasks'), -1 => t('All Tasks')), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Filter') ); $form['#redirect'] = FALSE; return $form; } // PRIVATE FUNCTIONS /* FUNCTION tasks_main() This function redirects to the master tasklist if one exists, or creates one if it doesn't */ function _tasks_main() { // Get the list of tasks to display $result = db_query("SELECT COUNT(*) FROM {tasks} t WHERE t.task_parent = 0"); if ($num_rows = db_result($result)) { if ($num_rows != 1) { drupal_set_message(t('WARNING: more than one master tasklists. Please delete all but one nodes of type tasks where task_parent = 0')); print theme('page', ''); } else { while ($node = db_fetch_object($result)) { drupal_goto('node/'. $node->nid); } } } else { // There are no tasks. Create the master task(list) drupal_set_message(t('

There are no tasks yet, so creating a top-level tasklist.

')); $node->title = t('Tasklist'); $node->uid = 1; $node->filter = variable_get('filter_default_format', 1); $node->status = 1; $node->type = 'tasks'; node_save($node); drupal_goto('node/'. $node->nid); } } function _tasks_order_by($node) { // done either on insert or update of a task. we want to make order by values into integers to get in the updated one and remain consistent $result = db_query("SELECT n.*, t.* FROM {node} n, {tasks} t WHERE n.type='tasks' AND t.nid = n.nid AND t.order_by <> 0 AND t.task_parent = %d ORDER BY t.order_by ASC", $node->task_parent); $i = 1; while ($task = db_fetch_object($result)) { if ($task->completed != '0000-00-00') $task->order_by = 0; else { $task->order_by = $i; $i++; } db_query("UPDATE {tasks} SET order_by = %d WHERE nid = %d", $task->order_by, $task->nid); } }