Projet

Général

Profil

Paste
Télécharger (42,4 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / advanced_forum / advanced_forum.module @ 87dbc3bf

1
<?php
2

    
3
/**
4
 * @file
5
 * Enables the look and feel of other popular forum software.
6
 */
7
// DRUPAL HOOKS **************************************************************/
8

    
9
/**
10
 * Implementation of hook_perm().
11
 */
12
function advanced_forum_permission() {
13
  return array(
14
    'administer advanced forum' => array(
15
      'title' => t('Administer Advanced Forum')
16
    ),
17
    'view forum statistics' => array(
18
      'title' => t('View Advanced Forum statistics')
19
    ),
20
    'view last edited notice' => array(
21
      'title' => t('View last edited notice')
22
    )
23
  );
24
}
25

    
26
/**
27
 * Implementation of hook_menu().
28
 */
29
function advanced_forum_menu() {
30
  $items['admin/config/content/advanced-forum'] = array(
31
    'access arguments' => array('administer advanced forum'),
32
    'description' => 'Configure Advanced Forum with these settings.',
33
    'page arguments' => array('advanced_forum_settings_page'),
34
    'page callback' => 'drupal_get_form',
35
    'title' => 'Advanced Forum',
36
    'file' => 'includes/settings.inc'
37
  );
38

    
39
  $items['forum/markasread'] = array(
40
    'access callback' => 'advanced_forum_markasread_access',
41
    'page callback' => 'advanced_forum_markasread',
42
    'type' => MENU_CALLBACK,
43
  );
44

    
45
  if (variable_get('advanced_forum_add_local_task', TRUE)) {
46
    $items['forum/view'] = array(
47
      'title' => 'View Forums',
48
      'page callback' => 'advanced_forum_page',
49
      'type' => MENU_DEFAULT_LOCAL_TASK,
50
      'weight' => -100,
51
    );
52
  }
53

    
54
  return $items;
55
}
56

    
57
/**
58
 * Implementation of hook_cron().
59
 */
60
function advanced_forum_cron() {
61
  // ensure the reply stats are up-to-date
62
  advanced_forum_statistics_replies(NULL, TRUE);
63
}
64

    
65
/**
66
 * Implementation of hook_menu_alter().
67
 */
68
function advanced_forum_menu_alter(&$items) {
69
  // Take over the forum page creation so we can add more information.
70
  $items['forum']['page callback'] = 'advanced_forum_page';
71
  $items['forum']['module'] = 'advanced_forum';
72
  unset($items['forum']['file']);
73

    
74

    
75
  // Take over forum/%forum_forum page because we want advanced_forum_forum_load
76
  // is called instead of core forum_forum_load
77
  $items['forum/%advanced_forum_forum'] = $items['forum/%forum_forum'];
78
  $items['forum/%advanced_forum_forum']['page callback'] = 'advanced_forum_page';
79
  $items['forum/%advanced_forum_forum']['module'] = 'advanced_forum';
80
  unset($items['forum/%advanced_forum_forum']['file']);
81
  unset($items['forum/%forum_forum']);
82
}
83

    
84
/**
85
 * Implements hook_menu_local_tasks_alter().
86
 *
87
 * Unset all items set in core forum_menu_local_tasks_alter
88
 */
89
function advanced_forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
90
  if ($root_path == 'forum' || $root_path == 'forum/%') {
91
    $data['actions']['output'] = array();
92
  }
93
}
94

    
95
/**
96
 * Implementation of hook_module_implements_alter().
97
 *
98
 * We don't want forum_menu_local_tasks_alter() to be called and mess with our links.
99
 *
100
 */
101
function advanced_forum_module_implements_alter(&$implementations, $hook) {
102
  if ($hook == 'menu_local_tasks_alter') {
103
    unset($implementations['forum']);
104
  }
105
}
106

    
107
/**
108
 * Implementation of hook_theme().
109
 */
110
function advanced_forum_theme() {
111
  advanced_forum_load_style_includes();
112

    
113
  // Bulk read all available (active) style templates
114
  $existing_items = advanced_forum_find_style_templates();
115

    
116
  $items['advanced_forum_l'] = array(
117
    'variables' => array(
118
      'text' => NULL,
119
      'path' => NULL,
120
      'options' => array(),
121
      'button_class' => NULL,
122
    )
123
  );
124

    
125
  $items['advanced_forum_topic_header'] = array(
126
    'variables' => array(
127
      'node' => NULL,
128
      'comment_count' => NULL,
129
    )
130
  );
131

    
132
  $items['advanced_forum_active_poster'] = array(
133
    'variables' => array(
134
      'forum' => NULL,
135
      'account' => NULL,
136
      'posts' => NULL,
137
      'topics' => NULL,
138
      'last_post' => NULL,
139
    )
140
  );
141

    
142
  $items['advanced_forum_user_picture'] = array(
143
    'variables' => array(
144
      'account' => NULL,
145
    )
146
  );
147

    
148
  $items['advanced_forum_reply_link'] = array(
149
    'variables' => array(
150
      'node' => NULL,
151
    )
152
  );
153

    
154
  $items['advanced_forum_topic_pager'] = array(
155
    'variables' => array(
156
      'pagecount' => NULL,
157
      'topic' => NULL,
158
    )
159
  );
160

    
161
  $items['advanced_forum_shadow_topic'] = array(
162
    'variables' => array(
163
      'title' => NULL,
164
      'nid' => NULL,
165
      'new_forum' => NULL,
166
    )
167
  );
168

    
169
  $items['advanced_forum_subforum_list'] = array(
170
    'variables' => array(
171
      'subforum_list' => NULL,
172
    )
173
  );
174

    
175
  $items['advanced_forum_subcontainer_list'] = array(
176
    'variables' => array(
177
      'subcontainer_list' => NULL,
178
    )
179
  );
180

    
181
  $items['advanced_forum_simple_author_pane'] = array(
182
    'variables' => array(
183
      'context' => NULL,
184
    )
185
  );
186

    
187
  $items['advanced_forum_post_edited'] = array(
188
    'variables' => array(
189
      'who' => NULL,
190
      'when' => NULL,
191
      'why' => NULL,
192
    )
193
  );
194

    
195
  $items['advanced_forum_node_type_create_list'] = array(
196
    'variables' => array(
197
      'forum_id' => NULL,
198
    )
199
  );
200
  /*
201
    // Templates for features added by Views
202

    
203
    // style
204
    $items['views_view_forum_topic_list__advanced_forum_topic_list'] = array(
205
    'variables' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
206
    'template' => 'advanced-forum-topic-list-view',
207
    //'base hook' => 'views_view_forum_topic_list',
208
    );
209
   */
210
  //display
211
  $items['views_view__advanced_forum_topic_list'] = array(
212
    'variables' => array('view' => NULL),
213
    'template' => 'advanced-forum-topic-list-outer-view',
214
      //'base hook' => 'views_view',
215
  );
216

    
217
  //display group
218
  $items['views_view__advanced_forum_group_topic_list'] = array(
219
    'variables' => array('view' => NULL),
220
    'template' => 'advanced-forum-group-topic-list-outer-view',
221
      //'base hook' => 'views_view',
222
  );
223

    
224
  // Return merged items found in style folder with new ones
225
  // array_merge_recursive doesn't work as desired
226
  foreach ($items as $key => $item) {
227
    if (array_key_exists($key, $existing_items)) {
228
      $existing_items[$key] += $item;
229
    }
230
    else {
231
      $existing_items[$key] = $item;
232
    }
233
  }
234

    
235
  return $existing_items;
236
}
237

    
238
/**
239
 * Implementation of hook_theme_registry_alter().
240
 */
241
function advanced_forum_theme_registry_alter(&$theme_registry) {
242
  advanced_forum_load_style_includes();
243

    
244
  // Don't let core do its basic preprocess for forums, as we want to do
245
  // other stuff now.
246
  if (isset($theme_registry['forums']['preprocess functions'])) {
247
    foreach ($theme_registry['forums']['preprocess functions'] as $key => $value) {
248
      if ($value == 'template_preprocess_forums') {
249
        unset($theme_registry['forums']['preprocess functions'][$key]);
250
      }
251
    }
252
  }
253

    
254
  // We duplicate all of core's forum list preprocessing so no need to run
255
  // it twice. Running twice also causes problems with & in forum name.
256
  if (isset($theme_registry['forum_list']['preprocess functions'])) {
257
    foreach ($theme_registry['forum_list']['preprocess functions'] as $key => $value) {
258
      if ($value == 'template_preprocess_forum_list') {
259
        unset($theme_registry['forum_list']['preprocess functions'][$key]);
260
      }
261
    }
262
  }
263

    
264
  // Views handles the topic list pages so remove the core template preprocess.
265
  if (isset($theme_registry['forum_topic_list']['preprocess functions'])) {
266
    foreach ($theme_registry['forum_topic_list']['preprocess functions'] as $key => $value) {
267
      if ($value == 'template_preprocess_forum_topic_list') {
268
        unset($theme_registry['forum_topic_list']['preprocess functions'][$key]);
269
      }
270
    }
271
  }
272

    
273
  // --- The following section manipulates the theme registry so the .tpl files
274
  // --- for the given templates can be found first in the (sub)theme directory
275
  // --- then in ancestor themes, if any, then in the active style directory
276
  // --- for advanced forum or any ancestor styles.
277
  // Affected templates
278
  $templates = array(
279
    'node',
280
    'comment',
281
    'comment_wrapper',
282
    'forums',
283
    'forum_list',
284
    'forum_topic_list',
285
    'forum_icon',
286
    'forum_submitted',
287
    'author_pane',
288
      /*
289
        'advanced_forum_statistics',
290
        'advanced_forum_topic_list_view',
291
        'advanced_forum_topic_legend',
292
        'advanced_forum_forum_legend',
293
        'advanced_forum_topic_header',
294
        'advanced_forum_active_poster', */
295
  );
296

    
297
  // Get the sequence of styles to look in for templates
298
  $lineage = advanced_forum_style_lineage();
299

    
300
  if (!array_key_exists('naked', $lineage)) {
301
    // Add naked in at the end of the line to prevent problems if a style
302
    // doesn't include all needed templates.
303
    $lineage['naked'] = drupal_get_path('module', 'advanced_forum') . '/styles/naked';
304
  }
305

    
306
  // Get theme engine extension
307
  global $theme_engine;
308
  $extension = '.tpl.php';
309
  if (isset($theme_engine)) {
310
    $extension_function = $theme_engine . '_extension';
311
    if (function_exists($extension_function)) {
312
      $extension = $extension_function();
313
    }
314
  }
315

    
316
  foreach ($templates as $template) {
317
    // Sanity check in case the template is not being used.
318
    if (!empty($theme_registry[$template])) {
319
      // There are preprocess functions to add, so figure out where we want to add
320
      // them.
321
      if (!empty($preprocess)) {
322
        $position = 0;
323
        foreach ($theme_registry[$template]['preprocess functions'] as $function) {
324
          $position++;
325
          // If we see either of these items, that means we can place our
326
          // preprocess functions after this.
327
          if (substr($function, 0, 25) == 'advanced_forum_preprocess' || substr($function, 0, 34) == 'template_preprocess_advanced_forum') {
328
            break;
329
          }
330
        }
331
        // Add in our new preprocess functions:
332
        if (isset($theme_registry[$template]['preprocess functions'])) {
333
          array_splice($theme_registry[$template]['preprocess functions'], $position, 0, $preprocess);
334
        }
335
      }
336
    }
337
  }
338

    
339

    
340
  // temp workaround
341
  if (isset($theme_registry['views_view__advanced_forum_topic_list']['preprocess functions'])) {
342
    array_splice($theme_registry['views_view__advanced_forum_topic_list']['preprocess functions'], 1, 0, 'template_preprocess_views_view');
343
  }
344
  if (isset($theme_registry['views_view__advanced_forum_group_topic_list']['preprocess functions'])) {
345
    array_splice($theme_registry['views_view__advanced_forum_group_topic_list']['preprocess functions'], 1, 0, 'template_preprocess_views_view');
346
  }
347
  //array_splice($theme_registry['views_view_forum_topic_list__advanced_forum_topic_list']['preprocess functions'], 1, 0, 'template_preprocess_views_view_forum_topic_list');
348
}
349

    
350
/**
351
 * Own link alteration implementaion because there are no
352
 * hook_link nor hook_link_alter in D7
353
 *
354
 * Name changed intentionally to avoid confusion with hook_link_alter!
355
 */
356
function advanced_forum_links_alter(&$object, $view_mode, $object_type = 'node') {
357
  // Don't alter anything if in preview mode
358
  if (!empty($object->in_preview)) {
359
    return;
360
  }
361

    
362
  if (!advanced_forum_is_styled($object, ($view_mode == 'teaser'), $object_type)) {
363
    return;
364
  }
365

    
366
  if (!empty($object->content['links']['comment'])) {
367
    $comment_links = $object->content['links']['comment'];
368
    $links = empty($comment_links['#links']) ? array() : $comment_links['#links'];
369
  }
370
  else {
371
    $comment_links = array();
372
    $links = array();
373
  }
374

    
375
  if ($object_type == 'node') {
376

    
377
    $node = $object;
378
    // Add edit / delete links to the node links to match replies.
379
    if (node_access('update', $node)) {
380
      $links['post-edit'] = array(
381
        'title' => t('edit'),
382
        'href' => 'node/' . $node->nid . '/edit',
383
        'query' => drupal_get_destination(),
384
      );
385
    }
386

    
387
    if (node_access('delete', $node)) {
388
      $links['post-delete'] = array(
389
        'title' => t('delete'),
390
        'href' => 'node/' . $node->nid . '/delete',
391
      );
392
    }
393
  }
394

    
395
  // Change first post from "add comment" to "reply" if it isn't already.
396
  if (!empty($links['comment-add'])) {
397
    $links['comment-add']['title'] = t('reply');
398
    $links['comment-add']['href'] = "comment/reply/$node->nid";
399
  }
400

    
401

    
402
  // List the keys we are interested in.
403
  $affected_keys = array('post-edit', 'comment-edit', 'post-delete', 'comment-delete', 'quote', 'comment-add', 'comment-reply');
404

    
405
  // Add extra span tags for image replacement.
406
  foreach ($links AS $key => $link) {
407
    if (in_array($key, $affected_keys)) {
408
      $links[$key]['attributes']['class'][] = "af-button-small";
409
      $links[$key]['title'] = '<span>' . $links[$key]['title'] . '</span>';
410
      $links[$key]['html'] = TRUE;
411
    }
412
  }
413

    
414
  // Put the links in a consistent order.
415
  foreach ($affected_keys as $key) {
416
    if (isset($links[$key])) {
417
      $temp = $links[$key];
418
      unset($links[$key]);
419
      $links[$key] = $temp;
420
    }
421
  }
422

    
423
  // we want to put comment links last
424
  unset($object->content['links']['comment']);
425
  $object->content['links']['comment'] = $comment_links;
426

    
427
  // put links back
428
  $object->content['links']['comment']['#links'] = $links;
429
}
430

    
431
/**
432
 * Implementation of hook_node_view().
433
 *
434
 * hook_link() and hook_link_alter() functionalty implemented here
435
 */
436
function advanced_forum_node_view($node, $view_mode, $langcode) {
437
  advanced_forum_links_alter($node, $view_mode, 'node');
438
}
439

    
440
/**
441
 * Implementation of hook_comment_view().
442
 */
443
function advanced_forum_comment_view($comment, $view_mode, $langcode) {
444
  advanced_forum_links_alter($comment, $view_mode, 'comment');
445
}
446

    
447
/**
448
 * Implementation of hook_comment_delete().
449
 */
450
function advanced_forum_comment_delete($comment) {
451
  if (!empty($comment->node_type) && ($comment->node_type == "comment_node_forum")) {
452
    advanced_forum_statistics_replies(-1);
453
  }
454
}
455

    
456
/**
457
 * Implementation of hook_comment_update().
458
 */
459
function advanced_forum_comment_update($comment) {
460
  if (!empty($comment->node_type) && ($comment->node_type == "comment_node_forum")) {
461
    // comment unpublished?
462
    if (!$comment->status) {
463
      advanced_forum_statistics_replies(-1);
464
    }
465
  }
466
}
467

    
468
/**
469
 * Implementation of hook_comment_publish().
470
 */
471
function advanced_forum_comment_publish($comment) {
472
  if (!empty($comment->node_type) && ($comment->node_type == "comment_node_forum")) {
473
    advanced_forum_statistics_replies(1);
474
  }
475
}
476

    
477
/**
478
 * Implementation of hook_form_alter().
479
 */
480
function advanced_forum_form_alter(&$form, &$form_state, $form_id) {
481
  if (!empty($form['#node']->type) && advanced_forum_type_is_in_forum($form['#node']) && isset($form['body_field']) && isset($form['body_field']['#after_build'])) {
482
    // Remove the teaser splitter.
483
    $teaser_js_build = array_search('node_teaser_js', $form['body_field']['#after_build']);
484
    unset($form['body_field']['#after_build'][$teaser_js_build]);
485
    $form['body_field']['teaser_js']['#access'] = FALSE;
486
    $form['body_field']['teaser_include']['#access'] = FALSE;
487
  }
488

    
489
  // Add our OG view as a potential RON for organic groups.
490
  if (!empty($form['og_settings']['group_details']['og_home_page_view'])) {
491
    $form['og_settings']['group_details']['og_home_page_view']['#options']['advanced_forum_group_topic_list'] = 'advanced_forum_group_topic_list';
492
  }
493
}
494

    
495
// MAKE VIEWS BITS WORK *****************************************************/
496
function advanced_forum_views_api() {
497
  return array(
498
    'api' => '3.0-alpha1',
499
    'path' => drupal_get_path('module', 'advanced_forum') . '/includes/views',
500
  );
501
}
502

    
503
// MAKE CTOOLS BITS WORK *****************************************************/
504
/**
505
 * Tell CTools about what plugins we support.
506
 */
507
function advanced_forum_ctools_plugin_directory($module, $plugin) {
508
  if ($module == 'advanced_forum') {
509
    return 'styles';
510
  }
511

    
512
  if ($module == 'page_manager' || $module == 'ctools') {
513
    return 'plugins/' . $plugin;
514
  }
515
}
516

    
517
function advanced_forum_ctools_plugin_api($module, $api) {
518
  if ($module == 'page_manager' && $api = 'pages_default') {
519
    return array(
520
      'version' => 1,
521
      'path' => drupal_get_path('module', 'advanced_forum') . '/includes/panels',
522
    );
523
  }
524
}
525

    
526
// THEME FUNCTIONS AND TEMPLATE PREPROCESSES **********************************/
527
module_load_include('inc', 'advanced_forum', 'includes/theme');
528

    
529
// STYLE RELATED FUNCTIONS ****************************************************/
530
module_load_include('inc', 'advanced_forum', 'includes/style');
531

    
532
// CORE FORUM PAGE OVERRIDES **************************************************/
533
module_load_include('inc', 'advanced_forum', 'includes/core-overrides');
534

    
535
// MARK AS READ ***************************************************************/
536
module_load_include('inc', 'advanced_forum', 'includes/mark-read');
537

    
538
// VIEWS RELATED GOODIES ******************************************************/
539

    
540
/**
541
 * Post render a view and replace any advanced forum tokens.
542
 */
543
function advanced_forum_views_post_render(&$view, &$output) {
544
  if (empty($view->style_plugin) || !$view->style_plugin->uses_row_plugin()) {
545
    return;
546
  }
547

    
548
  $plugin = $view->display_handler->get_option('row_plugin');
549
  if ($plugin == 'node') {
550
    // Look for token matches in the output:
551
    $matches = array();
552
    $tokens = array();
553

    
554
    // We want to change the look of the 'new' marker from the default, slightly:
555
    $tokens['<span class="new">' . t('new') . '</span>'] = '<span class="new">(' . t('new') . ')</span>';
556

    
557
    // Replace the Author Pane token with the actual Author Pane.
558
    if (preg_match_all('/<!--post:author-pane-([\d]+)-->/us', $output, $matches)) {
559
      foreach ($matches[1] as $match => $uid) {
560
        $token = $matches[0][$match]; // This is the exact string that matched.
561
        if (!isset($tokens[$token])) {
562
          $account = user_load($uid);
563
          $tokens[$token] = theme('author_pane', array(
564
            'account' => $account,
565
            'caller' => 'advanced_forum',
566
            'picture_preset' => variable_get('advanced_forum_user_picture_preset', ''),
567
            'context' => NULL,
568
            'disable_css' => TRUE,
569
            'join_date_type' => variable_get('advanced_forum_author_pane_join_date_type', 'short'),
570
          ));
571
        }
572
      }
573
    }
574

    
575
    // Replace the Post edited token.
576
    if (preg_match_all('/<!--post:post-edited-([\d]+)-->/us', $output, $matches)) {
577
      foreach ($matches[1] as $match => $nid) {
578
        $token = $matches[0][$match]; // This is the exact string that matched.
579
        if (!isset($tokens[$token])) {
580
          if (user_access('view last edited notice')) {
581
            $sql = 'SELECT uid, log, timestamp FROM {node_revision} WHERE nid = %d ORDER BY timestamp DESC';
582
            $row = db_fetch_object(db_query($sql, $nid));
583
            $tokens[$token] = theme('advanced_forum_post_edited', array(
584
              'who' => $row->uid,
585
              'when' => $row->timestamp,
586
              'why' => $row->log
587
            ));
588
          }
589
          else {
590
            // No access; remove token.
591
            $tokens[$token] = '';
592
          }
593
        }
594
      }
595
    }
596

    
597
    // Replace the core Signature token.
598
    if (preg_match_all('/<!--post:signature-core-([\d]+)-->/us', $output, $matches)) {
599
      foreach ($matches[1] as $match => $uid) {
600
        $token = $matches[0][$match]; // This is the exact string that matched.
601
        if (!isset($tokens[$token])) {
602
          $account = user_load($uid);
603
          if ($account->signature) {
604
            $tokens[$token] = check_markup($account->signature, $account->signature_format, FALSE);
605
          }
606
        }
607
      }
608
    }
609

    
610
    // Perform replacements.
611
    $output = strtr($output, $tokens);
612
  }
613
}
614

    
615
/**
616
 * Display the "sort" widget. This is a specially hacked widget that only
617
 * works with tablesorting. Tablesorting MUST be on for these widgets
618
 * to appear.
619
 */
620
function advanced_forum_forum_topic_list_sort() {
621
  $form_state = array(
622
    'method' => 'get',
623
    'no_redirect' => TRUE,
624
    'rerender' => TRUE,
625
    'input' => $_GET,
626
    'drop tokens' => TRUE,
627
  );
628

    
629
  $form = drupal_build_form('advanced_forum_forum_topic_list_sort_form', $form_state);
630
  return drupal_render($form);
631
}
632

    
633
function advanced_forum_forum_topic_list_sort_form($form_state) {
634
  $view = views_get_view('advanced_forum_topic_list');
635
  $view->set_display('default');
636
  $view->init_handlers();
637
  $view->init_style();
638

    
639
  // Work up a list of possible fields.
640
  $handler = &$view->style_plugin;
641
  $fields = &$view->field;
642
  $columns = $handler->sanitize_columns($handler->options['columns'], $fields);
643

    
644
  $options = array();
645
  foreach ($columns as $field => $column) {
646
    if ($field == $column && empty($fields[$field]->options['exclude'])) {
647
      if (empty($handler->options['info'][$field]['sortable']) || !$fields[$field]->click_sortable()) {
648
        continue;
649
      }
650
      $label = check_plain(!empty($fields[$field]) ? $fields[$field]->label() : '');
651
      $options[$field] = $label;
652
    }
653
  }
654

    
655
  $form['inline'] = array(
656
    '#prefix' => '<div class="container-inline">',
657
    '#suffix' => '</div>',
658
  );
659
  $form['inline']['order'] = array(
660
    '#type' => 'select',
661
    '#title' => t('Order by'),
662
    '#title_display' => 'invisible',
663
    '#options' => $options,
664
    '#default_value' => $handler->options['default'],
665
  );
666

    
667
  $form['inline']['sort'] = array(
668
    '#type' => 'select',
669
    '#title' => t('Sort'),
670
    '#title_display' => 'invisible',
671
    '#options' => array(
672
      'asc' => t('Up'),
673
      'desc' => t('Down'),
674
    ),
675
    '#default_value' => 'desc',
676
  );
677

    
678
  $form['inline']['submit'] = array(
679
    '#id' => 'sort-topic-submit',
680
    '#name' => '',
681
    '#type' => 'submit',
682
    '#value' => t('Sort'),
683
  );
684

    
685
  if (isset($_GET['page'])) {
686
    $form['page'] = array(
687
      '#type' => 'hidden',
688
      '#default_value' => $_GET['page'],
689
    );
690
  }
691

    
692
  if (!variable_get('clean_url', FALSE)) {
693
    $form['q'] = array(
694
      '#type' => 'hidden',
695
      '#value' => $_GET['q'],
696
    );
697
  }
698

    
699
  $view->destroy();
700
  return $form;
701
}
702

    
703
// STATISTICS *****************************************************************/
704

    
705
/**
706
 * Count total amount of forum threads.
707
 */
708
function advanced_forum_statistics_topics() {
709
  return db_query('SELECT COUNT(DISTINCT(nid)) FROM {forum}')->fetchField();
710
}
711

    
712
/**
713
 * Counts total amount of replies. Initial posts are added to this total
714
 * in the calling function.
715
 *
716
 * @param $delta
717
 *   if not NULL, a numerical delta which should be applied to the count
718
 * @param $refresh
719
 * @param $refresh
720
 *   TRUE if the stored count should be updated.
721
 * @return
722
 *   Total number of replies in the forum.
723
 */
724
function advanced_forum_statistics_replies($delta = NULL, $refresh = FALSE) {
725

    
726
  if ($refresh || !($cache = cache_get('advanced_forum_stats_replies'))) {
727
    $total_replies = db_query('SELECT SUM(comment_count) FROM {forum_index}')->fetchField();
728
    cache_set('advanced_forum_stats_replies', $total_replies);
729
  }
730
  else {
731
    $total_replies = $cache->data;
732
  }
733

    
734

    
735
  if (!empty($delta) && is_numeric($delta)) {
736
    $total_replies += $delta;
737
    cache_set('advanced_forum_stats_replies', $total_replies);
738
  }
739

    
740
  return $total_replies;
741
}
742

    
743
/**
744
 * Count total amount of active users.
745
 */
746
function advanced_forum_statistics_users() {
747
  return db_query('SELECT COUNT(uid) FROM {users} WHERE status = 1')->fetchField();
748
}
749

    
750
/**
751
 * Return the newest X active (not blocked) users, linked to their profiles.
752
 */
753
function advanced_forum_statistics_latest_users() {
754
  $number_to_fetch = 5; // @TODO: Make this a setting.
755

    
756
  $query = db_select("users", "u")
757
      ->fields("u", array("uid", "name"))
758
      ->condition("status", 0, "<>")
759
      ->condition("access", 0, "<>")
760
      ->orderBy("created", "DESC");
761

    
762
  $latest_users = $query->range(NULL, $number_to_fetch)->execute();
763
  while ($account = $latest_users->fetchObject()) {
764
    $list[] = theme('username', array('account' => $account));
765
  }
766

    
767
  return $list;
768
}
769

    
770
function advanced_forum_session_count($anonymous = TRUE) {
771

    
772
  $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
773

    
774
  $query = db_select("sessions", "s")
775
      ->fields("s", array("uid"))
776
      ->distinct()
777
      ->condition('s.timestamp', $interval, '>=')
778
      ->condition('s.uid', 0, $anonymous ? '=' : '>')
779
      ->countQuery();
780

    
781
  return $query->execute()->fetchField();
782
}
783

    
784
/**
785
 * Return an array of online usernames, linked to their profiles.
786
 */
787
function advanced_forum_statistics_online_users() {
788
  $list = array();
789

    
790
  $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
791

    
792
  $query = db_select("users", "u")->distinct()->fields("u", array("uid", "name"));
793
  $s_alias = $query->join("sessions", "s", "u.uid = s.uid");
794

    
795
  $query->addExpression("MAX({$s_alias}.timestamp)", "maxtime");
796
  $query
797
      ->condition("{$s_alias}.timestamp", $interval, ">=")
798
      ->condition("{$s_alias}.uid", "0", ">")
799
      ->groupBy("u.uid, u.name")
800
      ->orderBy("maxtime", "DESC");
801

    
802
  $authenticated_users = $query->execute();
803

    
804
  while ($account = $authenticated_users->fetchObject()) {
805
    $list[] = theme('username', array('account' => $account));
806
  }
807

    
808
  return $list;
809
}
810

    
811
// CALCULATING LINKS - New, Last, Etc *****************************************/
812

    
813
function advanced_forum_get_reply_link($node) {
814
  $reply_link = array();
815

    
816
  $comment_setting = $node->comment;
817
  $fragment = 'comment-form';
818

    
819
  if ($comment_setting == COMMENT_NODE_OPEN) {
820

    
821
    $allowed = FALSE;
822
    if (module_exists('forum_access')) {
823
      // get tid
824
      if (!empty($node->taxonomy_forums)) {
825
        reset($node->taxonomy_forums);
826
        $langcode = key($node->taxonomy_forums);
827
        if (!empty($node->taxonomy_forums[$langcode])) {
828
          $tid = $node->taxonomy_forums[$langcode][0]['tid'];
829
          if (forum_access_access('create', $tid)) {
830
            $allowed = TRUE;
831
          }
832
        }
833
      }
834
    }
835
    else {
836
      $allowed = user_access('post comments');
837
    }
838

    
839
    if ($allowed) {
840
      if (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_SEPARATE_PAGE) {
841
        // Reply form is on separate page. Grab the href from the node links
842
        // so it's automatically corrected for Node Comments if needed.
843
        $reply_link['href'] = "comment/reply/$node->nid";
844
        $reply_link['options']['fragment'] = $fragment;
845

    
846
        $reply_link['class'] = 'reply-allowed';
847
        $reply_link['title'] = t('Post reply');
848

    
849
        return $reply_link;
850
      }
851
      else {
852
        // Reply form is on same page. The reply button should jump down to it
853
        // rather than going to a new page.
854
        $reply_link['href'] = $_GET['q'];
855
        $reply_link['options']['fragment'] = $fragment;
856
        $current_page = isset($_GET['page']) ? $_GET['page'] : 0;
857
        if ($current_page)
858
          $reply_link['options']['query'] = array('page' => $current_page);
859

    
860
        $reply_link['class'] = 'reply-allowed';
861
        $reply_link['title'] = t('Quick reply');
862

    
863
        return $reply_link;
864
      }
865
    }
866
    else {
867
      // User does not have access to post replies on this node.
868
      return 'reply-forbidden';
869
    }
870
  }
871
  else {
872
    // Topic is locked.
873
    return 'reply-locked';
874
  }
875
}
876

    
877
/**
878
 * Get a link to the last post in a topic.
879
 *
880
 * @param $node
881
 *   Node object
882
 * @return
883
 *   Text linking to the last post in a topic.
884
 */
885
function advanced_forum_last_post_link($node) {
886
  $last_comment_id = advanced_forum_last_post_in_topic($node->nid);
887
  // Return empty link if post doesn't have comments.
888
  if (empty($last_comment_id))
889
    return '';
890

    
891
  $last_page = advanced_forum_get_last_page($node);
892

    
893
  if ($last_page > 0)
894
    $query = array('page' => $last_page);
895

    
896
  $options = array(
897
    'html' => TRUE,
898
    'query' => empty($query) ? array() : $query,
899
    'fragment' => "comment-$last_comment_id",
900
  );
901

    
902
  return theme('advanced_forum_l', array(
903
    'text' => t('Last post'),
904
    'path' => "node/$node->nid",
905
    'options' => $options,
906
    'button_class' => 'large'
907
  ));
908
}
909

    
910
/**
911
 * Returns a link directly to the first new post in a topic.
912
 *
913
 * @param $node
914
 *   Node object
915
 * @param $comment_count
916
 *   Number of comments on passed node.
917
 * @return
918
 *   Link to the first unread post.
919
 */
920
function advanced_forum_first_new_post_link($node, $comment_count) {
921
  $nid = $node->nid;
922

    
923
  $current_page = isset($_GET['page']) ? $_GET['page'] : 0;
924
  $number_new_comments = advanced_forum_reply_num_new($nid);
925

    
926
  if ($number_new_comments > 0) {
927
    $page_of_first_new = advanced_forum_page_first_new($comment_count, $number_new_comments, $node);
928

    
929
    // Note that we are linking to the cid anchor rather than "new" because
930
    // the new links will be gone if we go to another page.
931
    $cid_of_first_new = advanced_forum_first_new_comment($nid);
932

    
933
    $number_new = t("(!new new)", array('!new' => $number_new_comments));
934

    
935
    $options = array(
936
      'html' => TRUE,
937
      'query' => $page_of_first_new,
938
      'fragment' => "comment-$cid_of_first_new"
939
    );
940

    
941
    return theme('advanced_forum_l', array(
942
      'text' => t('First unread'),
943
      'path' => "node/$nid",
944
      'options' => $options,
945
      'button_class' => 'large'
946
    ));
947
  }
948
}
949

    
950
/**
951
 * Get the page number with the first new post.
952
 */
953
function advanced_forum_page_first_new($comment_count, $new_replies, $node) {
954
  return comment_new_page_count($comment_count, $new_replies, $node);
955
}
956

    
957
/**
958
 * Get the number of new posts on a topic.
959
 */
960
function advanced_forum_reply_num_new($nid, $timestamp = 0) {
961
  // Make a static cache because this function is called twice from the topic
962
  // header. Once to display the number and once to make the link to first new.
963
  static $number_new_for_node = array();
964

    
965
  // $nid is empty if new topic in preview.
966
  if (empty($nid))
967
    return 0;
968

    
969
  if (empty($number_new_for_node[$nid])) {
970
    global $user;
971

    
972
    $node = node_load($nid);
973

    
974
    // We must also check the forum post itself to see if we have viewed it
975
    $viewed = 0; // If not told otherwise, it has been viewed before
976
    if ($user->uid) {
977
      $viewed = node_last_viewed($nid);
978
      // Set it to 1 if it has not been viewed before.
979
      $viewed = ($viewed == 0 ? 1 : 0);
980
    }
981

    
982
    $number_new_for_node[$nid] = comment_num_new($nid, $timestamp) + $viewed;
983
  }
984

    
985
  return $number_new_for_node[$nid];
986
}
987

    
988
/**
989
 * Get the comment id of the last post in a topic.
990
 *
991
 * @param $node
992
 *   Node object
993
 * @return
994
 *   cid of last post.
995
 */
996
function advanced_forum_last_post_in_topic($nid) {
997
  // $nid is empty if new topic in preview.
998
  if (empty($nid))
999
    return NULL;
1000

    
1001
  $node = node_load($nid);
1002

    
1003
  // Comment module version
1004
  $query = 'SELECT c.cid
1005
            FROM {comment} c
1006
            WHERE c.nid = :nid AND c.status = :status
1007
            ORDER BY c.cid DESC';
1008
  $result = db_query_range($query, 0, 1, array(':nid' => $nid, ':status' => COMMENT_PUBLISHED))->fetchField();
1009

    
1010
  return $result;
1011
}
1012

    
1013
/**
1014
 * Returns the page number of the last page starting at 0 like the pager does.
1015
 */
1016
function advanced_forum_get_last_page($node) {
1017
  $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50);
1018
  $comment_count = isset($node->comment_count) ? $node->comment_count : 0;
1019
  $last_page = ceil($comment_count / $comments_per_page) - 1;
1020
  return $last_page;
1021
}
1022

    
1023
/**
1024
 * Returns the ID of the first unread comment.
1025
 *
1026
 * @param $nid
1027
 *   Node ID
1028
 * @param $timestamp
1029
 *   Date/time used to override when the user last viewed the node.
1030
 * @return
1031
 *   Comment ID
1032
 */
1033
function advanced_forum_first_new_comment($nid, $timestamp = 0) {
1034
  global $user;
1035

    
1036
  if ($user->uid) {
1037
    // Retrieve the timestamp at which the current user last viewed the
1038
    // specified node.
1039
    if (!$timestamp) {
1040
      $timestamp = node_last_viewed($nid);
1041
    }
1042

    
1043
    // Set the timestamp to the limit if the node was last read past the cutoff
1044
    $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT);
1045

    
1046
    // Use the timestamp to retrieve the oldest new comment.
1047
    $query = db_select('comment', 'c')
1048
        ->fields('c', array('cid'))
1049
        ->condition('nid', $nid)
1050
        ->condition('changed', $timestamp, '>')
1051
        ->condition('status', COMMENT_PUBLISHED)
1052
        ->range(0, 1)
1053
        ->execute();
1054
    return $query->fetchField();
1055
  }
1056
  else {
1057
    return 0;
1058
  }
1059
}
1060

    
1061
// GENERAL UTILITY FUNCTIONS *************************************************/
1062

    
1063
/**
1064
 * Return an array of node types allowed in a given vocabulary or term ID.
1065
 */
1066
function advanced_forum_allowed_node_types($tid = 0) {
1067
  if (module_exists('forum_access')) {
1068
    // Check with forum access to see if this forum allows node creation.
1069
    // If it doesn't, send back an empty list.
1070
    if (!forum_access_access('create', $tid)) {
1071
      return array();
1072
    }
1073
  }
1074

    
1075
  $field = field_info_field('taxonomy_forums');
1076
  if (!empty($field['bundles']['node'])) {
1077
    return $field['bundles']['node'];
1078
  }
1079
  else {
1080
    return array();
1081
  }
1082
}
1083

    
1084
/**
1085
 * Return whether a given node type is allowed in the whole forum or given forum.
1086
 */
1087
function advanced_forum_type_is_in_forum($node, $tid = 0) {
1088
  $vid = (empty($vid)) ? variable_get('forum_nav_vocabulary', 0) : $vid;
1089
  if (!empty($node->taxonomy_forums)) {
1090
    // Check for language used
1091
    if (!isset($node->taxonomy_forums[$node->language])) {
1092
      $langcode = LANGUAGE_NONE;
1093
    }
1094
    else {
1095
      $langcode = $node->language;
1096
    }
1097

    
1098
    foreach ($node->taxonomy_forums[$langcode] as $tforum) {
1099
      if (!isset($tforum['taxonomy_term'])) {
1100
        continue;
1101
      }
1102
      if (($tforum['taxonomy_term']->vid == $vid) || ($tforum['taxonomy_term']->tid == $tid))
1103
        return TRUE;
1104
    }
1105
  }
1106
  return FALSE;
1107
}
1108

    
1109
/**
1110
 * Generate a list of node creation links for a forum.
1111
 *
1112
 * This is used on the forum list, allowing us to have direct
1113
 * links to create new nodes in the forum.
1114
 */
1115
function advanced_forum_node_type_create_list($tid) {
1116
  $allowed_types = advanced_forum_allowed_node_types($tid);
1117

    
1118
  // Ensure "new topic" is first.
1119
  if (isset($allowed_types['forum'])) {
1120
    unset($allowed_types['forum']);
1121
    array_unshift($allowed_types, 'forum');
1122
  }
1123
  // Loop through all node types allowed in this forum.
1124
  foreach ($allowed_types as $type) {
1125
    // Check if this node type can be created by current user.
1126
    if (node_access('create', $type)) {
1127
      // Fetch the "General" name of the content type.
1128
      $node_type = t(node_type_get_name($type));
1129

    
1130
      // Remove the word "Forum" out of "Forum topic" to shorten it.
1131
      // @TODO: this is a little dodgy and may not work right with
1132
      // translations. Should be replaced if there's a better way.
1133
      $node_type = str_replace('Forum', '', $node_type);
1134

    
1135
      // Push the link with title and url to the array.
1136
      $forum_types[$type] = array(
1137
        'name' => $node_type,
1138
        'href' => 'node/add/' . str_replace('_', '-', $type) . '/' . $tid,
1139
      );
1140
    }
1141
  }
1142

    
1143
  if (empty($forum_types)) {
1144
    // The user is logged-in; but denied access to create any new forum content type.
1145
    global $user;
1146
    if ($user->uid) {
1147
      return t('You are not allowed to post new content in the forum.');
1148
    }
1149
    // The user is not logged-in; and denied access to create any new forum content type.
1150
    else {
1151
      return t('<a href="@login">Log in</a> to post new content in the forum.', array(
1152
        '@login' => url('user/login', array('query' => drupal_get_destination())),
1153
      ));
1154
    }
1155
  }
1156
  else {
1157
    return $forum_types;
1158
  }
1159
}
1160

    
1161
/**
1162
 * Create a drop down list of forum actions.
1163
 */
1164
function advanced_forum_forum_tools($tid = 0) {
1165
  global $user;
1166
  $options = array();
1167

    
1168
  ctools_include('jump-menu');
1169
  if ($tid > 0) {
1170
    $select[url("forum/active", array('query' => array('forum[]' => $tid)))] = t("View active posts in this forum");
1171
    $select[url("forum/unanswered", array('query' => array('forum[]' => $tid)))] = t("View unanswered posts in this forum");
1172

    
1173
    if ($user->uid) {
1174
      $select[url("forum/new", array('query' => array('forum[]' => $tid)))] = t("View new posts in this forum");
1175
    }
1176
  }
1177
  else {
1178
    $select[url("forum/active")] = t("View active forum posts");
1179
    $select[url("forum/unanswered")] = t("View unanswered forum posts");
1180

    
1181
    if ($user->uid) {
1182
      $select[url("forum/new")] = t("View new forum posts");
1183
    }
1184
  }
1185

    
1186
  // Add mark as read to the jump list.
1187
  // This code is a little odd and needs explaining. The return value of
1188
  // the mark_as_read function is already formed HTML and so is unsuitable
1189
  // for the jump list. The function already has built in the ability
1190
  // to add to an existing $links array, which has the URL and title text
1191
  // separated. Rather than add a third method just for the jump menu, I
1192
  // reused that functionality here.
1193
  $mark_as_read = array();
1194
  advanced_forum_get_mark_read_link($tid, $mark_as_read);
1195
  if (!empty($mark_as_read['mark-read']['href'])) {
1196
    $select[url($mark_as_read['mark-read']['href'])] = $mark_as_read['mark-read']['title'];
1197
  }
1198

    
1199
  $options['choose'] = t("- Forum Tools -");
1200

    
1201
  // Create and return the jump menu.
1202
  $form = drupal_get_form('ctools_jump_menu', $select, $options);
1203
  return drupal_render($form);
1204
}
1205

    
1206
/**
1207
 * Creates a pager to place on each multi-page topic of the topic listing page.
1208
 *
1209
 * @param $max_pages_to_display
1210
 *   Number of pages to include on the pager.
1211
 * @param $topic
1212
 *   Topic object to create a pager for.
1213
 * @return
1214
 *   Object containing the linked pages ready assembly by the theme function.
1215
 */
1216
function advanced_forum_create_topic_pager($max_pages_to_display, $topic) {
1217
  // Find the number of comments per page for the node type of the topic.
1218
  $comments_per_page = variable_get('comment_default_per_page_' . $topic->type, 50);
1219

    
1220
  if ($max_pages_to_display > 0 && $topic->comment_count > $comments_per_page) {
1221
    // Topic has more than one page and a pager is wanted. Start off the
1222
    // first page because that doesn't have a query.
1223
    $pager_array = array();
1224
    $current_display_page = 1;
1225
    $pager_array[0] = l('1', "node/$topic->nid");
1226

    
1227
    // Find the ending point. The pager URL is always 1 less than
1228
    // the number being displayed because the first page is 0.
1229
    $last_display_page = ceil($topic->comment_count / $comments_per_page);
1230
    $last_pager_page = $last_display_page - 1;
1231

    
1232
    // Add pages until we run out or until we hit the max to show.
1233
    while (($current_display_page < $last_display_page) && ($current_display_page < $max_pages_to_display)) {
1234
      // Move to the next page
1235
      $current_display_page++;
1236

    
1237
      // The page number we link to is 1 less than what's displayed
1238
      $link_to_page = $current_display_page - 1;
1239

    
1240
      // Add the link to the array
1241
      $pager_array[$link_to_page] = l($current_display_page, "node/$topic->nid", array('query' => array('page' => $link_to_page)));
1242
    }
1243

    
1244
    // Move to the next page
1245
    $current_display_page++;
1246

    
1247
    if ($current_display_page == $last_display_page) {
1248
      // We are one past the max to display, but it's the last page,
1249
      // so putting the ...last is silly. Just display it normally.
1250
      $link_to_page = $current_display_page - 1;
1251
      $pager_array[$link_to_page] = l($current_display_page, "node/$topic->nid", array('query' => array('page' => $link_to_page)));
1252
    }
1253

    
1254
    if ($current_display_page < $last_display_page) {
1255
      // We are one past the max to display and still aren't
1256
      // on the last page, so put in ... Last Page(N)
1257
      $text = t('Last Page');
1258
      $pager_last_text = l($text, "node/$topic->nid", array('query' => array('page' => $last_pager_page)));
1259
      $pager_last_number = l($last_display_page, "node/$topic->nid", array('query' => array('page' => $last_pager_page)));
1260
      // Create last page array to enable more customization for themers.
1261
      $pager_last = array(
1262
        'number' => $last_display_page,
1263
        'link' => "node/$topic->nid",
1264
        'options' => array('query' => array('page' => $last_pager_page)),
1265
      );
1266
    }
1267

    
1268
    $topic_pager = new stdClass();
1269
    $topic_pager->initial_pages = (empty($pager_array)) ? array() : $pager_array;
1270
    $topic_pager->last_page_text = (empty($pager_last_text)) ? '' : $pager_last_text;
1271
    $topic_pager->last_page_number = (empty($pager_last_number)) ? '' : $pager_last_number;
1272
    $topic_pager->last_page = (empty($pager_last)) ? array() : $pager_last;
1273

    
1274
    return $topic_pager;
1275
  }
1276
}
1277

    
1278
/**
1279
 * Create a drop down list of forum hierarchy
1280
 */
1281
function advanced_forum_forum_jump($tid = 0) {
1282
  global $user;
1283
  ctools_include('jump-menu');
1284
  $select = array();
1285
  $options = array();
1286
  $vid = variable_get('forum_nav_vocabulary', 0);
1287
  if ($tid > 0) {
1288
    $forum_tree = taxonomy_get_tree($vid);
1289
    foreach ($forum_tree as $forum) {
1290
      $select[url("forum/" . $forum->tid)] = str_repeat("-", $forum->depth) . $forum->name;
1291
    }
1292
  }
1293
  else {
1294
    // nothing
1295
  }
1296

    
1297
  $options['choose'] = t("- Select a forum -");
1298

    
1299
  // Create and return the jump menu.
1300
  $form = drupal_get_form('ctools_jump_menu', $select, $options);
1301
  return drupal_render($form);
1302
}
1303

    
1304
/**
1305
 * Calculates the number of unread replies for each forum and returns the
1306
 * count for the requested forum.
1307
 */
1308
function advanced_forum_unread_replies_in_forum($tid, $uid) {
1309
  static $result_cache = NULL;
1310

    
1311
  if (is_null($result_cache)) {
1312
    $result_cache = array();
1313

    
1314
    $query = db_select("comment", "c");
1315
    $f_alias = $query->join("forum", "f", "c.nid = f.nid");
1316
    //$n_alias = $query->join("node", "n", "f.vid = n.vid");
1317
    $h_alias = $query->leftJoin("history", "h", "c.nid = h.nid AND h.uid = :uid", array(":uid" => $uid));
1318
    $query->addExpression("COUNT(DISTINCT(c.cid))", "count");
1319
    $query->addField($f_alias, "tid");
1320

    
1321
    $query->condition("c.status", COMMENT_PUBLISHED)
1322
        ->condition("c.changed", NODE_NEW_LIMIT, ">")
1323
        ->condition(db_or()->where("c.changed > {$h_alias}.timestamp")->isNull("h.timestamp"))
1324
        ->groupBy("{$f_alias}.tid")
1325
        ->addTag("node_access");
1326

    
1327
    $result = $query->execute();
1328
    foreach ($result as $row) {
1329
      $result_cache[$row->tid] = $row->count;
1330
    }
1331
  }
1332

    
1333
  return (isset($result_cache[$tid])) ? $result_cache[$tid] : 0;
1334
}
1335

    
1336
/**
1337
 * Returns the display position of a given reply post ID on a given node.
1338
 */
1339
function advanced_forum_post_position($node, $comment) {
1340
  static $post_order = array();
1341

    
1342
  if (empty($node) || empty($comment)) {
1343
    return 0;
1344
  }
1345

    
1346
  $node_id = $node->nid;
1347
  $post_id = $comment->cid;
1348

    
1349
  if (!isset($post_order[$node_id])) {
1350
    // Initialize the spot for this node's list.
1351
    $post_order[$node_id] = array();
1352

    
1353
    $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
1354

    
1355
    // Get the list of CIDs from the database in order of oldest first.
1356
    // We are going to make that assumption for now for simplicity but may
1357
    // revisit in the future if there are requests for newest first.
1358
    $query = db_select('comment', 'c')
1359
        ->fields('c', array('cid'))
1360
        ->condition('c.nid', $node_id)
1361
        ->addTag('node_access')
1362
        ->addTag('comment_filter');
1363

    
1364
    if ($mode === COMMENT_MODE_FLAT) {
1365
      $query->orderBy('c.cid', 'ASC');
1366
    }
1367
    else {
1368
      $query->addExpression('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'torder');
1369
      $query->orderBy('torder', 'ASC');
1370
    }
1371

    
1372
    $query = $query->execute();
1373
    // Cycle through the results and fill in the array.
1374
    while ($post = $query->fetchAssoc()) {
1375
      $post_order[$node_id][] = reset($post);
1376
    }
1377
  }
1378

    
1379
  // Find the position of the passed in post ID.
1380
  $post_position = 0;
1381
  if (is_array($post_order[$node_id])) {
1382
    if (($index = array_search($post_id, $post_order[$node_id])) !== FALSE) {
1383
      $post_position = $index;
1384

    
1385
      // We need to add 2 because the array starts at 0 and also because the topic
1386
      // node is post #1 on display but is not included in the index.
1387
      $post_position = $post_position + 2;
1388
    }
1389
  }
1390

    
1391
  return $post_position;
1392
}