| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: comment.inc,v 1.156 2010/01/17 00:26:58 dww Exp $ 3 4 function project_issue_comment(&$arg, $op) { 5 // $arg can be a comment object, or a form or form_values. 6 if (is_object($arg)) { 7 $nid = $arg->nid; 8 } 9 elseif (is_array($arg)) { 10 $nid = is_array($arg['nid']) ? $arg['nid']['#value'] : $arg['nid']; 11 } 12 $node = node_load($nid); 13 if ($node->type != 'project_issue') { 14 return; 15 } 16 // Make a copy here so we have all the original metadata, since some 17 // of it can change below. 18 $original_node = drupal_clone($node); 19 $old_data = (object) $original_node->project_issue; 20 $old_data->title = $original_node->title; 21 22 // Maintain an array of project ids that are affected by this comment 23 // operation. We'll use this to invalidate the "Issue cockpit" block cache 24 // for any of these projects. 25 $affected_projects = array(); 26 27 switch ($op) { 28 case 'insert': 29 // Get a lock on the issue in order to generate the next comment ID. 30 $tries = 20; 31 $sleep_increment = 0; 32 while ($tries) { 33 $lock = db_query("UPDATE {project_issues} SET db_lock = 1 WHERE nid = %d AND db_lock = 0", $arg['nid']); 34 if (db_affected_rows()) { 35 $id = db_result(db_query("SELECT last_comment_id FROM {project_issues} WHERE nid = %d", $arg['nid'])) + 1; 36 db_query("UPDATE {project_issues} SET last_comment_id = %d, db_lock = 0 WHERE nid = %d", $id, $arg['nid']); 37 break; 38 } 39 40 // Wait a random and increasing amount of time before the next attempt. 41 $sleep = rand(10000, 1000000) + $sleep_increment; 42 usleep($sleep); 43 $sleep_increment += 50000; 44 $tries--; 45 } 46 47 if (isset($id)) { 48 $rid = isset($arg['project_info']['rid']) ? $arg['project_info']['rid'] : 0; 49 db_query("INSERT INTO {project_issue_comments} (nid, cid, pid, rid, component, category, priority, assigned, sid, title, timestamp, comment_number) VALUES (%d, %d, %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, %d)", $arg['nid'], $arg['cid'], $arg['project_info']['pid'], $rid, $arg['project_info']['component'], $arg['category'], $arg['priority'], $arg['project_info']['assigned'], $arg['sid'], $arg['title'], $arg['timestamp'], $id); 50 db_query("UPDATE {comments} SET subject = '%s' WHERE cid = %d", "#$id", $arg['cid']); 51 project_issue_update_by_comment($arg, 'insert'); 52 $affected_projects[$old_data->pid] = 1; 53 $affected_projects[$arg['project_info']['pid']] = 1; 54 } 55 else { 56 drupal_set_message(t('There was an error submitting your comment -- please try again. If the problem persists, contact the system administrator.'), 'error'); 57 watchdog('project_issue', 'Error obtaining lock for project issue %nid', array('%nid' => $arg['nid']), WATCHDOG_ERROR, 'node/'. $arg['nid']); 58 // This is a bit extreme, but we have to clean up the failed comment, 59 // or it will appear on the issue. 60 _comment_delete_thread((object) $arg); 61 _comment_update_node_statistics($arg['nid']); 62 cache_clear_all(); 63 // The hard redirect prevents any bogus data from being inserted for the failed comment. 64 drupal_goto('node/'. $arg['nid']); 65 } 66 break; 67 68 case 'update': 69 project_issue_update_by_comment($arg, 'update'); 70 // Updating a comment can't change anything relevant about the issue for 71 // the purposes of the issue blocks, so we don't need to touch 72 // $affected_projects here. 73 break; 74 75 case 'delete': 76 // Save the project that's specified in this comment so we can 77 // invalidate its issue block cache. 78 $deleted_comment_project_id = db_result(db_query("SELECT pid FROM {project_issue_comments} WHERE cid = %d", $arg->cid)); 79 $affected_projects[$deleted_comment_project_id] = 1; 80 // Actually delete the comment 81 db_query("DELETE FROM {project_issue_comments} WHERE cid = %d", $arg->cid); 82 $current_data = project_issue_update_by_comment($arg, 'delete'); 83 // We should also invalidate the block cache for whatever project is now 84 // used for this issue, since we might be deleting a comment that moved 85 // an issue from one project to another. 86 $affected_projects[$current_data->pid] = 1; 87 break; 88 89 case 'view': 90 if (isset($arg->cid)) { 91 $project_issue_table = project_issue_comment_view($original_node, $arg); 92 } 93 else { 94 // Previewing a comment. 95 $test = drupal_clone($arg); 96 $test->pid = $arg->project_info['pid']; 97 $test->component = $arg->project_info['component']; 98 $test->assigned = $arg->project_info['assigned']; 99 // Add a dummy rid if necessary -- prevents incorrect change data. 100 $test->rid = isset($arg->project_info['rid']) ? $arg->project_info['rid'] : 0; 101 $comment_changes = project_issue_metadata_changes($node, $old_data, $test, project_issue_field_labels('web')); 102 $project_issue_table = theme('project_issue_comment_table', $comment_changes); 103 } 104 if ($project_issue_table) { 105 $arg->comment = '<div class="project-issue"><div class="summary">'. $project_issue_table .'</div></div>' . $arg->comment; 106 } 107 break; 108 109 } 110 // If there are any affected projects, invalidate the block cache for those. 111 if (!empty($affected_projects)) { 112 foreach ($affected_projects as $pid => $value) { 113 $cid = 'project_issue_cockpit_block:'. $pid; 114 cache_clear_all($cid, 'cache'); 115 } 116 } 117 } 118 119 /** 120 * Add project issue metadata to the comment form. 121 * 122 * @param $form 123 * Reference to form structure. 124 * @param $form_state 125 * Current form state. 126 */ 127 function project_issue_form_comment_form_alter(&$form, &$form_state) { 128 $nid = $form['nid']['#value']; 129 $node = node_load($nid); 130 131 // Allows only project_issue 132 if ($node->type != 'project_issue') { 133 return; 134 } 135 136 // Comment body is not required since we validate that ourselves. 137 unset($form['comment_filter']['comment']['#required']); 138 139 // The 'your name' item just wastes screen estate. 140 unset($form['_author']); 141 142 // For existing comments, we want to preserve the comment subject, 143 // Even if the subject field is disabled. 144 if ($cid = $form['cid']['#value']) { 145 $subject = db_result(db_query('SELECT subject FROM {comments} WHERE cid = %d', $cid)); 146 } 147 // For new comments, show the expected next number for previews. 148 // This is only for show, the number will be generated when the comment 149 // is posted. 150 else { 151 $next_id = db_result(db_query('SELECT last_comment_id FROM {project_issues} WHERE nid = %d', $form['nid']['#value'])) + 1; 152 $subject = "#$next_id"; 153 // Clobber the comment signature for new followups if necessary. 154 // TODO: Revamp this for Drupal 6. 155 if (!variable_get('project_issue_show_comment_signatures', 0)) { 156 $form['comment_filter']['comment']['#default_value'] = ''; 157 } 158 } 159 $form['subject'] = array( 160 '#type' => 'value', 161 '#value' => $subject, 162 ); 163 164 // Any time we're on a reply page, show the full issue below the reply. 165 if (project_issue_is_comment_reply()) { 166 $form['#pre_render'][] = 'project_issue_comment_pre_render'; 167 } 168 169 // Make sure project is current here -- it may have changed when posted. 170 if (!empty($form_state['values']['project_info']['pid'])) { 171 $node->project_issue['pid'] = $form_state['values']['project_info']['pid']; 172 } 173 $project = node_load(array('nid' => $node->project_issue['pid'], 'type' => 'project_project')); 174 175 project_issue_set_breadcrumb($node, $project); 176 177 // Only allow metadata changes on new followups. 178 if (isset($form['cid']['#value'])) { 179 return; 180 } 181 182 // We have to set $form['#action'] to prevent AHAH nastiness. 183 if (!empty($form['pid']['#value'])) { 184 $form['#action'] = url('comment/reply/' . $nid . '/' . $form['pid']['#value']); 185 } 186 else { 187 $form['#action'] = url('comment/reply/' . $nid); 188 } 189 190 // We need to ask for almost the same metadata as project issue itself 191 // so let's reuse the form. 192 $form += project_issue_form($node, $form_state, TRUE); 193 194 // comment.module is basically still FAPI v1. It sets the preview button to 195 // #type 'button', so FAPI doesn't really consider that a form submission. 196 // However, we depend on the form being rebuilt on preview to do our magic. 197 // Thanks to a change in 6.14 core, form.inc will only rebuild the form if 198 // $form_state['submitted'] is TRUE. So, we set the preview button to 199 // actually be a 'submit' button so that the form is rebuilt on preview and 200 // our comment preview code can kick in. 201 $form['preview']['#type'] = 'submit'; 202 203 // We need this otherwise pid collides with comment. 204 $form['project_info']['#tree'] = TRUE; 205 $form['project_info']['#weight'] = -2; 206 207 // Remove the form item that displays the current project, and 208 // replace the static single project value with a select list 209 // of all projects to make swapping simpler. 210 unset($form['project_info']['project_display']); 211 $uris = NULL; 212 213 if (variable_get('project_issue_autocomplete', 0) == 1) { 214 $form['project_info']['project_title'] = array( 215 '#type' => 'textfield', 216 '#title' => t('Project'), 217 '#default_value' => $project->title, 218 '#required' => TRUE, 219 '#weight' => -1, 220 '#size' => 35, 221 '#autocomplete_path' => 'project/autocomplete/issue/project', 222 '#attributes' => array( 223 'onFocus' => 'project_issue_autocomplete_handler()', 224 ), 225 '#ahah' => array( 226 'progress' => array( 227 'type' => 'none', 228 ), 229 'path' => 'project/issues/update_project', 230 'wrapper' => 'project-info-wrapper', 231 ), 232 ); 233 } 234 else { 235 $projects = project_projects_select_options($uris); 236 $form['project_info']['pid'] = array( 237 '#type' => 'select', 238 '#title' => t('Project'), 239 '#default_value' => $project->nid, 240 '#options' => $projects, 241 '#required' => TRUE, 242 '#weight' => -1, 243 '#ahah' => array( 244 'path' => 'project/issues/update_project', 245 'wrapper' => 'project-info-wrapper', 246 'event' => 'change', 247 ), 248 ); 249 } 250 251 $form['issue_info']['#weight'] = -1; 252 $form['#prefix'] = '<div class="project-issue"><div class="node-form"><div class="standard">'; 253 $form['#suffix'] = '</div></div></div>'; 254 255 $form['original_issue'] = array( 256 '#type' => 'fieldset', 257 '#title' => t('Edit issue settings'), 258 '#description' => t('Note: changing any of these items will update the issue\'s overall values.'), 259 '#collapsible' => TRUE, 260 '#weight' => -10, 261 ); 262 263 $form['original_issue']['title'] = array( 264 '#type' => 'textfield', 265 '#title' => t('Issue title'), 266 '#maxlength' => 128, 267 '#default_value' => $node->title, 268 '#weight' => -30, 269 '#required' => TRUE, 270 ); 271 272 $form['project_info']['assigned'] = $form['issue_info']['assigned']; 273 unset($form['issue_info']['assigned']); 274 275 $form['project_info']['#prefix'] = '<div id="project-info-wrapper" class="inline-options">'; 276 $form['project_info']['#suffix'] = '</div>'; 277 278 // Remove the 'Project information' and 'Issue information' fieldsets, 279 // since we'll move everything inside the 'Edit issue settings' fieldset. 280 unset($form['project_info']['#type'], $form['project_info']['#title']); 281 unset($form['issue_info']['#type'], $form['issue_info']['#title']); 282 283 // Restructure the UI to de-emphasize the original project form inputs. 284 $form['original_issue']['project_info'] = $form['project_info']; 285 $form['original_issue']['issue_info'] = $form['issue_info']; 286 unset($form['project_info'], $form['issue_info']); 287 unset($form['issue_details'], $form['project_help']); 288 drupal_add_js(drupal_get_path('module', 'project_issue') .'/project_issue.js'); 289 } 290 291 /** 292 * Validate issue metadata on the comment form. 293 * 294 * @param $form 295 * The Drupal form structure. 296 * @param $form_state 297 * The current state of the form. 298 */ 299 function project_issue_form_comment_validate($form, &$form_state) { 300 if (empty($form['cid']['#value']) && variable_get('project_issue_autocomplete', 0) == 1) { 301 if (empty($form_state['values']['project_info']['project_title'])) { 302 form_set_error('project_title', t('You must enter a project to navigate to.')); 303 } 304 else { 305 $pid = db_result(db_query("SELECT nid FROM {node} WHERE title = '%s' AND type = '%s'", $form_state['values']['project_info']['project_title'], 'project_project')); 306 if (empty($pid)) { 307 form_set_error('project_info][project_title', t('The name you entered (%title) is not a valid project.', array('%title' => $form_state['values']['project_info']['project_title']))); 308 } 309 else { 310 $form_state['values']['project_info']['pid'] = $pid; 311 } 312 } 313 } 314 315 if (!empty($form_state['rebuild'])) { 316 return; 317 } 318 $values = $form_state['values']; 319 $project_info = $form_state['values']['project_info']; 320 $nid = $values['nid']; 321 $node = node_load($nid); 322 323 // Make a copy here so we have all the original metadata, since some 324 // of it can change below. 325 $original_node = drupal_clone($node); 326 $old_data = (object) $original_node->project_issue; 327 $old_data->title = $original_node->title; 328 329 // Adjust new file attachments to go to the issues directory. 330 // We have to do this during validate, otherwise we might miss 331 // adjusting the filename before comment upload saves it (module weighting) 332 // TODO: is this still true? 333 project_issue_change_comment_upload_path($values); 334 335 // Only validate metadata changes on new followups. 336 if (isset($values['cid'])) { 337 return; 338 } 339 340 // Make sure project is current here -- it may have changed when posted. 341 if (isset($project_info['pid'])) { 342 $node->project_issue['pid'] = $project_info['pid']; 343 } 344 $project = node_load($node->project_issue['pid']); 345 346 if (!empty($project) && $project->type == 'project_project') { 347 // Force all comments to be a child of the main issue, to match the 348 // flat display, and also to prevent accidentally deleting a thread. 349 $form_state['values']['pid'] = 0; 350 351 // Validate version. 352 if (module_exists('project_release') && isset($project_info['rid']) && ($releases = project_release_get_releases($project, 0, 'version', 'all', array($project_info['rid'])))) { 353 $rid = $project_info['rid']; 354 if ($rid && !in_array($rid, array_keys($releases))) { 355 $rid = 0; 356 } 357 // Check to make sure this release is not marked as an invalid 358 // release node for user selection. 359 $invalid_rids = variable_get('project_issue_invalid_releases', array()); 360 if (!empty($invalid_rids) && 361 ((empty($rid) && in_array($node->project_issue['rid'], $invalid_rids)) 362 || in_array($rid, $invalid_rids))) { 363 form_set_error('project_info][rid', t('%version is not a valid version, please select a different value.', array('%version' => $releases[$node->project_issue['rid']]))); 364 } 365 elseif (empty($rid)) { 366 form_set_error('project_info][rid', t('You have to specify a valid version.')); 367 } 368 } 369 // Add a dummy rid if necessary -- prevents incorrect change data. 370 else { 371 $rid = 0; 372 } 373 // Validate component. 374 $component = $project_info['component']; 375 if ($component && !in_array($component, $project->project_issue['components'])) { 376 $component = 0; 377 } 378 empty($component) && form_set_error('project_info][component', t('You have to specify a valid component.')); 379 } 380 else { 381 form_set_error('project_info][pid', t('You have to specify a valid project.')); 382 } 383 empty($values['category']) && form_set_error('category', t('You have to specify a valid category.')); 384 385 // Now, make sure the comment changes *something* about the issue. 386 // If the user uploaded a file, so long as it's not marked for removal, 387 // we consider that a valid change to the issue, too. 388 $has_file = FALSE; 389 $files = isset($values['files']) ? $values['files'] : array(); 390 foreach ($files as $number => $data) { 391 if (empty($data['remove'])) { 392 $has_file = TRUE; 393 break; 394 } 395 } 396 if (!$has_file && empty($values['comment'])) { 397 398 $comment = drupal_clone((object) $values); 399 $comment->pid = $project_info['pid']; 400 $comment->component = $component; 401 $comment->rid = $rid; 402 $comment->assigned = $project_info['assigned']; 403 $comment_changes = project_issue_metadata_changes($node, $old_data, $comment, project_issue_field_labels('web')); 404 // If the PID changed, rebuild the form 405 if (isset($comment_changes['pid']['new']) && $comment_changes['pid']['new'] === TRUE) { 406 $form_state['rebuild'] = TRUE; 407 } 408 $has_change = FALSE; 409 foreach ($comment_changes as $field => $changes) { 410 if (isset($changes['new'])) { 411 $has_change = TRUE; 412 break; 413 } 414 } 415 if (!$has_change) { 416 form_set_error('comment', t('You must either add a comment, upload a file, or change something about this issue.')); 417 } 418 } 419 } 420 421 /** 422 * Theme a project issue metadata table. 423 * 424 * @param $comment_changes 425 * Array containing metadata differences between comments 426 * as returned by project_issue_metadata_changes(). 427 * @return 428 * The themed metadata table. 429 */ 430 function theme_project_issue_comment_table($comment_changes) { 431 $rows = array(); 432 foreach ($comment_changes as $field => $change) { 433 if (!empty($change['label']) && isset($change['old']) && isset($change['new'])) { 434 $rows[] = theme('project_issue_comment_table_row', $field, $change); 435 } 436 } 437 return $rows ? theme('table', array(), $rows) : ''; 438 } 439 440 /** 441 * Theme a single row of the project issue metadata changes table. 442 * 443 * @param $field 444 * The name of the field to theme. 445 * @param $change 446 * A nested array containing changes to project issue metadata 447 * for the given issue or comment. 448 * @return 449 * An array representing one row of the table. 450 * 451 * NOTE: If you override this theme function, you *must* make sure 452 * that you sanitize all output from this function that is displayed 453 * to the user. No further escaping/filtering of the data in this 454 * table will take place after this function. In most cases 455 * this means that you need to run the $change['label'], $change['old'], 456 * and $change['new'] values through either the check_plain() or 457 * filter_xss() function to prevent XSS and other types 458 * of problems due to any malicious input in these 459 * field values. 460 */ 461 function theme_project_issue_comment_table_row($field, $change) { 462 // Allow anchor, emphasis, and strong tags in metadata tables. 463 $allowed_tags = array('a', 'em', 'strong'); 464 // Fields that should be rendered as plain text, not filtered HTML. 465 $plain_fields = array('title', 'pid', 'rid'); 466 467 if (is_array($change['old']) || is_array($change['new'])) { 468 $removed = array(); 469 if (is_array($change['old'])){ 470 foreach ($change['old'] as $item) { 471 $removed[] = '-'. $item; 472 } 473 } 474 elseif (!empty($change['old'])) { 475 $removed[] = '-'. $change['old']; 476 } 477 478 $added = array(); 479 if (is_array($change['new'])) { 480 foreach ($change['new'] as $item) { 481 $added[] = '+'. $item; 482 } 483 } 484 elseif (!empty($change['new'])) { 485 $added[] = '+'. $change['new']; 486 } 487 488 return array( 489 filter_xss($change['label'], $allowed_tags) .':', 490 filter_xss(implode(', ', $removed), $allowed_tags), 491 filter_xss(implode(', ', $added), $allowed_tags), 492 ); 493 } 494 elseif (in_array($field, $plain_fields)) { 495 return array( 496 filter_xss($change['label'], $allowed_tags) .':', 497 check_plain(project_issue_change_summary($field, $change['old'])), 498 '» '. check_plain(project_issue_change_summary($field, $change['new'])), 499 ); 500 } 501 else { 502 return array( 503 filter_xss($change['label'], $allowed_tags) .':', 504 filter_xss(project_issue_change_summary($field, $change['old']), $allowed_tags), 505 '» '. filter_xss(project_issue_change_summary($field, $change['new']), $allowed_tags), 506 ); 507 } 508 } 509 510 /** 511 * Returns the issue metadata table for a comment. 512 * 513 * @param $node 514 * The corresponding node. 515 * @param $comment 516 * The comment, if it's set then metadata will be returned. If it's not 517 * set then metadata will be precalculated. 518 * @return 519 * A themed table of issue metadata. 520 */ 521 function project_issue_comment_view(&$node, $comment = NULL) { 522 static $project_issue_tables; 523 524 if (isset($comment)) { 525 return isset($project_issue_tables[$comment->cid]) ? $project_issue_tables[$comment->cid] : ''; 526 } 527 if (!empty($node->comment_count)) { 528 $old = unserialize(db_result(db_query('SELECT original_issue_data FROM {project_issues} WHERE nid = %d', $node->nid))); 529 $labels = project_issue_field_labels('web'); 530 $result = db_query('SELECT p.cid, p.title, p.pid, p.rid, p.component, p.category, p.priority, p.assigned, p.sid FROM {project_issue_comments} p INNER JOIN {comments} c ON p.cid = c.cid WHERE p.nid = %d AND c.status = %d ORDER BY p.timestamp ASC', $node->nid, COMMENT_PUBLISHED); 531 while ($followup = db_fetch_object($result)) { 532 $followup_changes = project_issue_metadata_changes($node, $old, $followup, project_issue_field_labels('web')); 533 $project_issue_tables[$followup->cid] = theme('project_issue_comment_table', $followup_changes); 534 $old = $followup; 535 } 536 } 537 } 538 539 /** 540 * Updates the project issue based on the comment inserted/updated/deleted. 541 * 542 * @param $comment_data 543 * The comment data that's been submitted. 544 * @param $op 545 * The comment operation performed, 'insert', 'update', 'delete'. 546 * @return 547 * An object representing the comment data used to update the issue. 548 */ 549 function project_issue_update_by_comment($comment_data, $op) { 550 switch ($op) { 551 case 'insert': 552 // Massage the incoming data so the structure is consistent throughout the function. 553 $comment_data['component'] = $comment_data['project_info']['component']; 554 $comment_data['pid'] = $comment_data['project_info']['pid']; 555 $comment_data['rid'] = isset($comment_data['project_info']['rid']) ? $comment_data['project_info']['rid'] : 0; 556 unset ($comment_data['project_info']); 557 $comment_data = (object) $comment_data; 558 // Mark the node for email notification during hook_exit(), so all issue 559 // and file data is in a consistent state before we generate the email. 560 if (!isset($comment_data->followup_no_mail)) { // Temporary hack to get around sending of auto-close emails. 561 project_issue_set_mail_notify($comment_data->nid); 562 } 563 break; 564 case 'update': 565 $comment_data = (object) $comment_data; 566 break; 567 } 568 569 // In order to deal with deleted/unpublished comments, make sure that we're performing 570 // the updates to the issue with the latest available published comment. 571 $comment_data = project_issue_get_newest_comment($comment_data); 572 573 // Update the issue data to reflect the new final states. 574 db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, sid = %d WHERE nid = %d", $comment_data->pid, $comment_data->category, $comment_data->component, $comment_data->priority, $comment_data->rid, $comment_data->assigned, $comment_data->sid, $comment_data->nid); 575 576 // Update the issue title. 577 $node = node_load($comment_data->nid, NULL, TRUE); // Don't use cached since we changed data above. 578 $node->title = $comment_data->title; 579 580 // This also updates the changed date of the issue. 581 node_save($node); 582 583 // Return the object of comment data we used to update the issue. 584 return $comment_data; 585 } 586 587 /** 588 * Adjusts the filepath of issue followups so files are saved to 589 * the correct issues directory. 590 * 591 * @param $comment 592 * An array of the submitted comment values. 593 */ 594 function project_issue_change_comment_upload_path(&$comment) { 595 static $run = NULL; 596 597 // Only for new comments with attachments. 598 if (empty($comment['cid']) && isset($comment['files']) && !isset($run)) { 599 $run = TRUE; // Make sure this only gets run once. 600 project_issue_rewrite_issue_filepath($comment['files']); 601 } 602 } 603 604 /** 605 * Retrieves the newest published comment for an issue. 606 * 607 * @param $comment_data 608 * An object representing the current comment being edited 609 * @return 610 * An object representing the most recent published comment for the issue. 611 */ 612 function project_issue_get_newest_comment($comment_data) { 613 // Get the cid of the most recent comment. 614 $latest_cid = db_result(db_query_range('SELECT pic.cid FROM {project_issue_comments} pic INNER JOIN {comments} c ON c.cid = pic.cid WHERE c.nid = %d AND c.status = %d ORDER BY pic.timestamp DESC', $comment_data->nid, COMMENT_PUBLISHED, 0, 1)); 615 if ($latest_cid) { 616 $comment_data = db_fetch_object(db_query('SELECT * FROM {project_issue_comments} WHERE cid = %d', $latest_cid)); 617 } 618 // No more comments on the issue -- use the original issue metadata. 619 else { 620 // nid isn't stored in the original issue data, so capture it here and pass back 621 // into the object. 622 $nid = $comment_data->nid; 623 $comment_data = unserialize(db_result(db_query("SELECT original_issue_data FROM {project_issues} WHERE nid = %d", $comment_data->nid))); 624 $comment_data->nid = $nid; 625 } 626 return $comment_data; 627 } 628 629 /** 630 * Test to determine if the active page is the comment reply form. 631 * 632 * @return 633 * TRUE if the active page is the comment reply form, FALSE otherwise. 634 */ 635 function project_issue_is_comment_reply() { 636 return arg(0) == 'comment' && arg(1) == 'reply'; 637 } 638 639 /** 640 * Test to determine if the active page is the comment edit form. 641 * 642 * @return 643 * TRUE if the active page is the comment edit form, FALSE otherwise. 644 */ 645 function project_issue_is_comment_edit() { 646 return arg(0) == 'comment' && arg(1) == 'edit'; 647 } 648 649 /** 650 * Appends the comment thread to the comment reply form. 651 */ 652 function project_issue_comment_pre_render($form) { 653 // Force the correct formatting. 654 $_GET['mode'] = COMMENT_MODE_FLAT_EXPANDED; 655 $_GET['sort'] = COMMENT_ORDER_OLDEST_FIRST; 656 657 $suffix = empty($form['#suffix']) ? '' : $form['#suffix']; 658 $node = node_load($form['nid']['#value']); 659 660 // Unfortunately, the comment module blindly puts the node view 661 // after the comment form on preview, in the case where the comment 662 // parent is 0. If we want our issue previews to be consistent, this 663 // ugly hack is necessary. 664 if (isset($form['#parameters'][1]['values']['op']) && $form['#parameters'][1]['values']['op'] == t('Preview')) { 665 $preview = comment_render($node, 0); 666 } 667 else { 668 $preview = node_show($node, 0); 669 } 670 671 $form['#suffix'] = $suffix . $preview; 672 return $form; 673 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |