title)); return drupal_get_form('project_issue_project_edit_form', $node); } /** * Theme function to render the issue subtab form. */ function theme_project_issue_project_edit_form($form) { drupal_add_tabledrag('project-issue-edit-project-components-table', 'order', 'self', 'project-issue-component-weight'); $header = array( array('data' => t('Name')), array('data' => t('Weight')), array('data' => t('Operations')) ); // List the existing components. foreach (element_children($form['component']) as $key) { $rows[] = array( 'class' => 'draggable', 'data' => array( drupal_render($form['component'][$key]['name']), drupal_render($form['component'][$key]['weight']), drupal_render($form['component'][$key]['delete']), ), ); } // Add a row to add a new component. $rows[] = array( 'class' => 'draggable', 'data' => array( drupal_render($form['component_add']['name']), drupal_render($form['component_add']['weight']), NULL, ), ); $output = drupal_render($form['issue']); $output .= drupal_render($form['email']); $output .= '

' . t('Issue components') . '

'; $output .= '
' . theme('table', $header, $rows, array('id' => 'project-issue-edit-project-components-table')) . '
'; $output .= drupal_render($form); return $output; } /** * Form builder for the issues subtab on the edit tab for project nodes. */ function project_issue_project_edit_form(&$form_state, $node) { /* Issue properties */ $form['issue'] = array( '#type' => 'fieldset', '#title' => t('Issue information'), '#collapsible' => TRUE, ); $form['issue']['issue'] = array( '#type' => 'item', '#title' => t('Issue tracker'), ); $form['issue']['issues'] = array( '#type' => 'checkbox', '#title' => t('Enable issue tracker'), '#return_value' => 1, '#default_value' => isset($node->project_issue['issues']) ? $node->project_issue['issues'] : 1, '#description' => t('Let users submit bug requests, patches, feature requests, support requests, etc.'), ); $form['issue']['help'] = array( '#type' => 'textarea', '#title' => t('Submission guidelines'), '#default_value' => isset($node->project_issue['help']) ? $node->project_issue['help'] : NULL, '#cols' => 20, '#rows' => 5, ); $weight = 0; $default_component_options[0] = t(' (user must select)'); $form['component']['#tree'] = TRUE; $number_components = count($node->project_issue['components']); $delta = max(20, $number_components + 10); foreach ($node->project_issue['components'] as $component) { $default_component_options[$component] = $component; $form['component'][$component]['name'] = array( '#type' => 'textfield', '#default_value' => $component, '#size' => 20, ); $form['component'][$component]['weight'] = array( '#type' => 'weight', '#default_value' => $weight, '#delta' => $delta, '#attributes' => array('class' => 'project-issue-component-weight'), ); // For the delete links, we just need the offset of the component as // currently stored in the DB or node. So, we can just use the $weight. // Using an integer offset avoids problems with urlencoding for component // names that have '/' in them. $del_link = ($component != $node->project_issue['default_component']) ? l(t('Delete'), 'node/'. $node->nid .'/edit/component/delete/'. $weight) : ''; $form['component'][$component]['delete'] = array( '#type' => 'markup', '#value' => $del_link, ); $weight++; } $form['component_add']['#tree'] = TRUE; $form['component_add']['name'] = array( '#type' => 'textfield', '#size' => 20, ); $form['component_add']['weight'] = array( '#type' => 'weight', '#default_value' => $weight, '#delta' => $delta, '#attributes' => array('class' => 'project-issue-component-weight'), ); $form['default_component'] = array( '#type' => 'select', '#title' => t('Default component for new issues'), '#options' => $default_component_options, '#default_value' => !empty($node->project_issue['default_component']) ? $node->project_issue['default_component'] : 0, ); /* E-mail options */ $form['email'] = array( '#type' => 'fieldset', '#title' => t('Issue e-mail options'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['email']['mail_digest'] = array( '#type' => 'textfield', '#title' => t('Weekly critical issues report'), '#default_value' => isset($node->project_issue['mail_digest']) ? $node->project_issue['mail_digest'] : NULL, '#size' => 20, '#maxlength' => 255, '#description' => t('To get a weekly digest of critical issues specify an e-mail address.'), ); $form['email']['mail_copy'] = array( '#type' => 'textfield', '#title' => t('Issues e-mail address'), '#default_value' => isset($node->project_issue['mail_copy']) ? $node->project_issue['mail_copy'] : NULL, '#size' => 20, '#maxlength' => 255, '#description' => t('If you wish to receive a copy of all the issues to a central location specify an address here. Note: the copy will contain links to file attachments.'), ); $options = project_issue_category(); $form['email']['categories'] = array( '#type' => 'item', '#title' => t('Categories'), '#description' => t('Which issue categories to e-mail. If none is checked all categories will be posted.'), ); $form['email']['mail_copy_filter']['#tree'] = TRUE; foreach ($options as $key => $choice) { $form['email']['mail_copy_filter'][$key] = array( '#type' => 'checkbox', '#title' => $choice, '#return_value' => $key, '#default_value' => isset($node->project_issue['mail_copy_filter'][$key]) ? $node->project_issue['mail_copy_filter'][$key] : NULL, ); } $options = project_issue_state(); $form['email']['states'] = array( '#type' => 'item', '#title' => t('States'), '#description' => t('Which issue states to e-mail. If none is checked all states will be posted.'), ); $form['email']['mail_copy_filter_state']['#tree'] = TRUE; foreach ($options as $key => $choice) { $form['email']['mail_copy_filter_state'][$key] = array( '#type' => 'checkbox', '#title' => check_plain($choice), '#return_value' => $key, '#default_value' => isset($node->project_issue['mail_copy_filter_state'][$key]) ? $node->project_issue['mail_copy_filter_state'][$key] : NULL, ); } if (user_access('administer projects')) { $form['email']['reminder'] = array( '#type' => 'item', '#title' => t('Monthly reminder'), ); $form['email']['mail_reminder'] = array( '#type' => 'checkbox', '#title' => t('Send monthly reminders to users'), '#return_value' => 1, '#default_value' => isset($node->project_issue['mail_reminder']) ? $node->project_issue['mail_reminder'] : NULL, '#description' => t('Enabling this will send a monthly reminder to users that have open issues registered.'), ); } $form['nid'] = array('#type' => 'value', '#value' => $node->nid); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 45, ); return $form; } /** * Validation handler when project admins use the issues subtab. * @see project_issue_project_edit_issues */ function project_issue_project_edit_form_validate($form, &$form_state) { if (!empty($form_state['values']['mail_digest']) && ($data = user_validate_mail($form_state['values']['mail_digest']))) { form_set_error('mail_digest', $data); } if (!empty($form_state['values']['mail_copy']) && ($data = user_validate_mail($form_state['values']['mail_copy']))) { form_set_error('mail_copy', $data); } } /** * Submit handler when project admins use the issues subtab. * @see project_issue_project_edit_issues */ function project_issue_project_edit_form_submit($form, &$form_state) { $components = array(); if (!empty($form_state['values']['component_add']['name'])) { $components[trim($form_state['values']['component_add']['name'])] = $form_state['values']['component_add']['weight']; } if (!empty($form_state['values']['component'])) { foreach ($form_state['values']['component'] as $component) { $components[trim($component['name'])] = $component['weight']; } } asort($components); $components = serialize(array_keys($components)); $default_component = !empty($form_state['values']['default_component']) ? $form_state['values']['default_component'] : ''; $mail_copy_filter = serialize($form_state['values']['mail_copy_filter']); $mail_copy_filter_state = serialize($form_state['values']['mail_copy_filter_state']); db_query("UPDATE {project_issue_projects} SET issues = %d, components = '%s',default_component = '%s', mail_digest = '%s', mail_reminder = %d, mail_copy = '%s', mail_copy_filter = '%s', mail_copy_filter_state = '%s', help = '%s' WHERE nid = %d", $form_state['values']['issues'], $components, $default_component, $form_state['values']['mail_digest'], $form_state['values']['mail_reminder'], $form_state['values']['mail_copy'], $mail_copy_filter, $mail_copy_filter_state, $form_state['values']['help'], $form_state['values']['nid']); db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $form_state['values']['nid']); drupal_set_message(t('Issue settings have been saved.')); } function project_issue_component_delete_form($form_state, $project, $component_offset) { $component = $project->project_issue['components'][$component_offset]; $form['component'] = array( '#type' => 'value', '#value' => $component, ); $form['project'] = array( '#type' => 'value', '#value' => $project, ); return confirm_form( $form, t('Are you sure you want to delete the component %component?', array('%component' => $component)), 'node/' . $project->nid . '/edit/issues', t('This action cannot be undone.'), t('Delete'), t('Cancel') ); } function project_issue_component_delete_form_submit($form, &$form_state) { $project = $form_state['values']['project']; $component = $form_state['values']['component']; project_issue_delete_component($project, $component); drupal_set_message(t('Issue component %component deleted.', array('%component' => $component))); $form_state['redirect'] = 'node/' . $project->nid . '/edit/issues'; } /** * Remove a component from a given project. * * @param $project * The project to remove the component from. * @param $component * The component to remove. */ function project_issue_delete_component($project, $component) { $components = array_diff($project->project_issue['components'], array($component)); db_query("UPDATE {project_issue_projects} SET components = '%s' WHERE nid = %d", serialize($components), $project->nid); db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $project->nid); }