Index: tasks.module =================================================================== --- tasks.module (revision 1) +++ tasks.module (working copy) @@ -20,7 +20,11 @@ // Implementation of hook_perm(). function tasks_perm() { - return array('create task', 'edit own task', 'edit all tasks', 'access tasks main page'); + if(variable_get("tasks_use_timer", 0)>0) { + return array('create task', 'edit own task', 'edit all tasks', 'access tasks main page', 'edit times', 'edit own times', 'add times'); + } else { + return array('create task', 'edit own task', 'edit all tasks', 'access tasks main page'); + } } // Implementation of hook_access(). @@ -155,6 +159,14 @@ '#options' => $users ); + if(variable_get('tasks_use_timer', 0)) { + $form['time'] = array( + '#type' => 'fieldset', + '#title' => t('Timer') + ); + $form['time']['timer'] = _tasks_timer_form($node); + } + $form['completed'] = array( '#type' => 'checkbox', '#title' => t('Completed?'), @@ -211,7 +223,7 @@ // Implementation of hooks_forms_alter so we don't see preview or delete buttons for tasks function tasks_form_alter($form_id, &$form) { global $user; - + if ($form_id == 'tasks_node_form') { unset($form['preview']); //unset($form['delete']); @@ -240,8 +252,9 @@ $node->completed_date['month'] = "00"; $node->completed_date['day'] = "00"; } - - db_query("INSERT INTO {tasks} (nid, parent, assigned_to, order_by, completed) VALUES (%d, %d, %d, '%s', '%s')", $node->nid, $node->parent, $node->assigned_to, $node->order_by, $node->completed_date['year'].'-'.$node->completed_date['month'].'-'.$node->completed_date['day']); + $node->start = '0'; + $node->stop = '0'; + db_query("INSERT INTO {tasks} (nid, parent, assigned_to, order_by, completed, start, stop) VALUES (%d, %d, %d, '%s', '%s','%s','%s')", $node->nid, $node->parent, $node->assigned_to, $node->order_by, $node->completed_date['year'].'-'.$node->completed_date['month'].'-'.$node->completed_date['day'],$node->start,$node->stop); _tasks_order_by($node); } @@ -255,8 +268,33 @@ $node->completed_date['month'] = "00"; $node->completed_date['day'] = "00"; } - - db_query("UPDATE {tasks} SET parent = %d, assigned_to = %d, order_by = '%s', completed = '%s' WHERE nid = %d", $node->parent, $node->assigned_to, $node->order_by, $node->completed_date['year'].'-'.$node->completed_date['month'].'-'.$node->completed_date['day'], $node->nid); + if(variable_get("tasks_use_timer", 0) > 0) { + $startNum = $node->timer['tasks_start_num']; + $stopNum = $node->timer['tasks_stop_num']; + $node->start = ''; + $node->stop = ''; + //print_r($node->timer); + if($node->timer[0]['start_date'] != 'Task not started' && $node->timer[0]['stop_date'] != 'Task not started') { + for($i = 0; $i < $startNum; $i++) { + if($node->timer[$i]['delete'] == 0) { + $node->start .= strtotime($node->timer[$i]['start_date']).','; + if($node->timer[$i]['stop_date'] != 'Running...') { + $node->stop .= strtotime($node->timer[$i]['stop_date']).','; + } + } + } + $node->start = rtrim($node->start,','); + $node->stop = rtrim($node->stop,','); + if($startNum - $stopNum == 0 && $node->completed != '0000-00-00') { + $node->stop = $node->stop.','._tasks_hours($node->start,$node->stop,$node->completed); + } + } + if($node->start == '' && $node->stop == '') { + $node->start = '0'; + $node->stop = '0'; + } + } + db_query("UPDATE {tasks} SET parent = %d, assigned_to = %d, order_by = '%s', completed = '%s', start = '%s', stop = '%s' WHERE nid = %d", $node->parent, $node->assigned_to, $node->order_by, $node->completed_date['year'].'-'.$node->completed_date['month'].'-'.$node->completed_date['day'],$node->start,$node->stop,$node->nid); _tasks_order_by($node); // Redirect to the tasks home page? @@ -313,7 +351,28 @@ } $node = node_prepare($node, $teaser); - + + //Get Task hours + if(variable_get("tasks_use_timer", 0)>0) { + $task = db_fetch_object(db_query("SELECT t.start, t.stop, t.completed FROM {tasks} t WHERE t.nid = %s", $node->nid)); + if($_POST['edit']['tasks_stop_watch'] == 'start') { + if($task->start == 0) { + $task->start = time(); + } else { + $task->start .= ','.time(); + } + db_query("UPDATE {tasks} SET start = '%s' WHERE nid = %d",$task->start,$node->nid); + } else if($_POST['edit']['tasks_stop_watch'] == 'stop') { + if($task->stop == 0) { + $task->stop = time(); + } else { + $task->stop .= ','.time(); + } + db_query("UPDATE {tasks} SET stop = '%s' WHERE nid = %d",$task->stop,$node->nid); + } + $node->body .= _tasks_formated_time($task->start,$task->stop,$task->completed,1); + $node->body .= drupal_get_form('tasks_timer_clocker',_tasks_timer_stopwatch($task->start,$task->stop,$task->completed)); + } $output = ''; @@ -361,37 +420,78 @@ //$tasks_colour = drupal_unpack($task)->tasks_colour; $extra = drupal_unpack($task); $tasks_colour = $extra->tasks_colour; + $hours = 0; $task = node_load(array('nid'=>$task->nid)); $rows[] = array( 'data' => array( array('data' => $assigned_name, '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:'No'), - array('data' => "nid');\">Expand ".l("", "node/$task->nid/edit/home",array(),null,null,false,true).' '.l('Up',"node/$node->nid",array(),"action=up&task=$task->nid").' '.l('Down',"node/$node->nid",array(),"action=down&task=$task->nid")), + array('data' => l($task->title, "node/$task->nid", array('name'=>'task'.$task->nid)), 'style'=>($task->completed>0)?'text-decoration: line-through;':'') ) ); + // Add new row for hours + if(variable_get("tasks_use_timer", 0)>0) { + $hours = _tasks_hours($task->start,$task->stop,$task->completed); + if($hours > 0) { + $hours = "nid');\">".$hours.""; + } + $rows[count($rows)-1]['data'][] = array('data' => $hours); + } + $rows[count($rows)-1]['data'][] = array('data' => ($task->completed>0)?$task->completed:'No'); + $rows[count($rows)-1]['data'][] = array('data' => "nid');\">Expand ".l("", "node/$task->nid/edit/home",array(),null,null,false,true).' '.l('Up',"node/$node->nid",array(),"action=up&task=$task->nid").' '.l('Down',"node/$node->nid",array(),"action=down&task=$task->nid")); + $task = node_prepare($task); - $rows[] = array( - 'data' => array( - array('data' => $task->body, 'colspan' => '4'), - ), - 'class' => 'task-expand', 'id' => "row-$task->nid", 'style' => 'display:none;' - ); + if(variable_get("tasks_use_timer", 0)>0) { + // change last column span to 5 + $rows[] = array( + 'data' => array( + array('data' => $task->body, 'colspan' => '5'), + ), + 'class' => 'task-expand', 'id' => "row-$task->nid", 'style' => 'display:none;' + ); + // add new row for timer details if necessary + if($hours > 0) { + $rows[] = array( + 'data' => array( + array('data' => _tasks_formated_time($task->start,$task->stop,$task->completed), 'colspan' => '5'), + ), + 'class' => 'task-expand', 'id' => "row-timer-$task->nid", 'style' => 'display:none;' + ); + } + $header = array(t('Assigned'),t('Task'),t('Hours'),t('Complete?'), t('Edit')); + } else { + $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')); + } } - $header = array(t('Assigned'),t('Task'), t('Complete?'), t('Edit')); - $output .= theme('table', $header, $rows, array("id"=>"task-list")); } - + $output .= theme('table', $header, $rows, array("id"=>"task-list")); $node->body .= $output; } } +function tasks_settings() { + //record time spent on a task + $options = array('1' => t('Enabled'), '0' => t('Disabled')); + $form['tasks_use_timer'] = array( + '#type' => 'radios', + '#title' => t('Enable time spent'), + '#default_value' => variable_get('tasks_use_timer', 0), + '#options' => $options, + '#description' => t('Allows for time logging of a task') + ); + + return $form; +} - // PRIVATE FUNCTIONS @@ -449,4 +549,299 @@ db_query("UPDATE {tasks} SET order_by = %d WHERE nid = %d", $task->order_by, $task->nid); } -} \ No newline at end of file +} + + +/* + FUNCTION _tasks_hours() + + This function returns total hours worked on task + + +*/ + +function _tasks_hours($start, $stop,$complete = '0000-00-00') { + $startTimes = explode(',',$start); + $stopTimes = explode(',',$stop); + if($start == 0) { + $startNum = 0; + } else { + $startNum = count($startTimes); + } + if($stop == 0) { + $stopNum = 0; + } else { + $stopNum = count($stopTimes); + } + $totalTime = 0; + // For a complete task final stop time is total in unix time stamp + if($complete != '0000-00-00' && $stopNum - $startNum == 1) { + return $stopTimes[$stopNum-1]; + // if there is at least on start time set the current hours + } else { + if($stopNum > 0) { + for($i=0;$i<$startNum-1;$i++) { + $totalTime = $totalTime+$stopTimes[$i]-$startTimes[$i]; + } + } + if($startNum - $stopNum == 1) { + // If the last stop sign is not set, then use the current time for hours. + $totalTime = $totalTime+time()-$startTimes[$startNum-1]; + } else if($startNum == $stopNum) { + $totalTime = $totalTime+$stopTimes[$stopNum-1]-$startTimes[$startNum-1]; + } + // return hours + if($totalTime > 0) { + $totalTime = round((($totalTime/60)/60),2); + } + } + return $totalTime; +} + + +/* + FUNCTION _tasks_formated_time() + + This function returns a table of Start and Stop times + + +*/ + +function _tasks_formated_time($start, $stop,$complete = '0000-00-00',$showTotal = 0) { + $startTimes = explode(',',$start); + $stopTimes = explode(',',$stop); + if($start == 0) { + $startNum = 0; + } else { + $startNum = count($startTimes); + } + if($stop == 0) { + $stopNum = 0; + } else { + $stopNum = count($stopTimes); + } + + if($startNum > 0 && $startTimes[$startNum-1] != 0) { + if($stopNum > 0) { + for($i=0;$i<$startNum-1;$i++) { + $rows[] = array( + 'data' => array( + array('data' => _tasks_date('g:ia n/j/y',$startTimes[$i]), 'style' => "width:25px"), + array('data' => _tasks_date('g:ia n/j/y',$stopTimes[$i]), 'style' => "width:25px"), + ) + ); + } + } + if($startNum > $stopNum) { + $rows[] = array( + 'data' => array( + array('data' => _tasks_date('g:ia n/j/y',$startTimes[$startNum-1]), 'style' => "width:25px"), + array('data' => 'Still Running', 'style' => "width:25px"), + ) + ); + } else if($startNum < $stopNum && $complete) { + $rows[] = array( + 'data' => array( + array('data' => _tasks_date('g:ia n/j/y',$startTimes[$startNum-1]), 'style' => "width:25px"), + array('data' => _tasks_date('g:ia n/j/y',$stopTimes[$stopNum-2]), 'style' => "width:25px"), + ) + ); + } else if ($startNum == $stopNum) { + $rows[] = array( + 'data' => array( + array('data' => _tasks_date('g:ia n/j/y',$startTimes[$startNum-1]), 'style' => "width:25px"), + array('data' => _tasks_date('g:ia n/j/y',$stopTimes[$stopNum-1]), 'style' => "width:25px"), + ) + ); + } + if($showTotal > 0) { + $rows[] = array( + 'data' => array( + array('data' => 'Total Time (hrs)', 'style' => "width:25px"), + array('data' => _tasks_hours($start,$stop,$complete), 'style' => "width:25px"), + ) + ); + } + $header = array(t('Start'),t('Stop')); + return theme('table', $header, $rows, array("id"=>"time-list")); + } +} + +function _tasks_timer_stopwatch($start, $stop,$complete = '0000-00-00') { + if (user_access('add times')) { + $startTimes = explode(',',$start); + $stopTimes = explode(',',$stop); + if($start == 0) { + $startNum = 0; + } else { + $startNum = count($startTimes); + } + if($stop == 0) { + $stopNum = 0; + } else { + $stopNum = count($stopTimes); + } + + if($complete == '0000-00-00') { + if($startNum > $stopNum) { + $form['tasks_stop_watch'] = array( + '#type' => 'hidden', + '#value' => 'stop' + ); + $form['timer'] = array( + '#type' => 'submit', + '#value' => t('Stop Timer') + ); + } else { + $form['tasks_stop_watch'] = array( + '#type' => 'hidden', + '#value' => 'start' + ); + $form['timer'] = array( + '#type' => 'submit', + '#value' => t('Start Timer'.$node->start) + ); + } + //$form['#action'] = "node/$node->nid"; + return $form; + } + } +} + +function _tasks_timer_form($node) { + global $user; + $form['#type'] = 'item'; + $form['#tree'] = TRUE; + $form['#theme'] = 'tasks_timer_form'; + $editable = FALSE; + + if ((user_access('edit own times') && ($user->uid == $node->uid)) || user_access('edit times')) { + $editable = TRUE; + } + + if($editable && $node->nid) { + $form['#description'] = t('Edit Start and Stop Times (HH:MM MM/DD/YYYY) or remove entries'); + } else { + $form['#description'] = t('Start and Stop Times'); + } + if($node->nid) { + $task = db_fetch_object(db_query("SELECT t.start, t.stop, t.completed FROM {tasks} t WHERE t.nid = %s", $node->nid)); + } else { + $task = array('start' => 0,'stop' => 0,'completed' => 0); + } + $startTimes = explode(',',$task->start); + $stopTimes = explode(',',$task->stop); + if($task->start == 0) { + $startNum = 0; + } else { + $startNum = count($startTimes); + } + if($task->stop == 0) { + $stopNum = 0; + } else { + $stopNum = count($stopTimes); + } + + if($startNum > 0) { + for($i=0;$i<$startNum;$i++) { + $form[$i]['start_date'] = array( + '#type' => 'textfield', + '#default_value' => _tasks_date('H:i n/j/y',$startTimes[$i]), + '#size' => 19, + '#maxlength' => 19, + ); + $form[$i]['stop_date'] = array( + '#type' => 'textfield', + '#size' => 19, + '#maxlength' => 19 + ); + $form[$i]['delete'] = array( + '#type' => 'checkbox', + '#default_value' => 0 + ); + if(!$editable) { + $form[$i]['start_date']['#attributes'] = array('disabled' => 'disabled'); + $form[$i]['stop_date']['#attributes'] = array('disabled' => 'disabled'); + $form[$i]['delete']['#attributes'] = array('disabled' => 'disabled'); + } + + if($i == $startNum-1 && $startNum > $stopNum) { + $form[$i]['stop_date']['#default_value'] = 'Running...'; + $form[$i]['stop_date']['#attributes'] = array('disabled' => 'disabled'); + } else { + $form[$i]['stop_date']['#default_value'] = _tasks_date('H:i n/j/y',$stopTimes[$i]); + } + } + } else { + $form[0]['start_date'] = array( + '#type' => 'textfield', + '#default_value' => 'Task not started', + '#attributes' => array('disabled' => 'disabled'), + '#size' => 19, + '#maxlength' => 19, + ); + $form[0]['stop_date'] = array( + '#type' => 'textfield', + '#default_value' => 'Task not started', + '#attributes' => array('disabled' => 'disabled'), + '#size' => 19, + '#maxlength' => 19, + ); + } + $form['tasks_start_num'] = array( + '#type' => 'hidden', + '#value' => $startNum + ); + $form['tasks_stop_num'] = array( + '#type' => 'hidden', + '#value' => $stopNum + ); + return $form; +} + +function theme_tasks_timer_form(&$form) { + $header = array(t('Start'), t('Stop'), t('Delete')); + foreach (element_children($form) as $key) { + $row = array(); + $row[] = form_render($form[$key]['start_date']); + $row[] = form_render($form[$key]['stop_date']); + $row[] = form_render($form[$key]['delete']); + $rows[]['data'] = $row; + } + $output = theme('table', $header, $rows); + $output .= form_render($form); + + return $output; +} + +/* + FUNCTION _tasks_date() + + This function returns a formated time with timezone + + +*/ + +function _tasks_date($format, $timestamp, $offset = null) { + global $user; + + if (isset($offset)) { + $timestamp += $offset; + } + elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { + $timestamp += $user->timezone; + } + else { + $timestamp += variable_get('date_default_timezone', 0); + } + + // make sure we apply the site first day of the week setting for dow requests + if ($format == 'w') { + $result = _event_day_of_week($timestamp); + } + else { + $result = gmdate($format, $timestamp); + } + return $result; +} +