array('administer advanced forum'), 'description' => 'Configure Advanced Forum with these settings.', 'page arguments' => array('advanced_forum_settings_page'), 'page callback' => 'drupal_get_form', 'title' => 'Advanced Forum', 'file' => 'includes/settings.inc' ); $items['forum/markasread'] = array( 'access callback' => 'advanced_forum_markasread_access', 'page callback' => 'advanced_forum_markasread', 'type' => MENU_CALLBACK, ); if (variable_get('advanced_forum_add_local_task', TRUE)) { $items['forum/view'] = array( 'title' => t('View Forums'), 'page callback' => 'advanced_forum_page', 'access arguments' => array('access content'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -100, ); } return $items; } /** * Implementation of hook_menu_alter(). */ function advanced_forum_menu_alter(&$callbacks) { // Take over the forum page creation so we can add more information. $callbacks['forum']['page callback'] = 'advanced_forum_page'; // Turn 'forum' into a normal menu item so it appears in navigation. $callbacks['forum']['type'] = MENU_NORMAL_ITEM; } /** * Implementation of hook_theme(). */ function advanced_forum_theme() { $items['advanced_forum_l'] = array( 'arguments' => array( 'text' => NULL, 'path' => NULL, 'options' => array(), 'button_class' => NULL, ) ); $items['advanced_forum_statistics'] = array( 'template' => 'advanced_forum-statistics', ); $items['advanced_forum_topic_legend'] = array( 'template' => 'advanced_forum-topic-legend', ); $items['advanced_forum_topic_header'] = array( 'template' => 'advanced_forum-topic-header', 'arguments' => array( 'node' => NULL, 'comment_count' => NULL, ) ); $items['advanced_forum_active_poster'] = array( 'template' => 'advanced_forum-active-poster', 'arguments' => array( 'forum' => NULL, 'account' => NULL, 'posts' => NULL, 'topics' => NULL, 'last_post' => NULL, ) ); $items['advanced_forum_forum_legend'] = array( 'template' => 'advanced_forum-forum-legend', ); $items['advanced_forum_user_picture'] = array( 'arguments' => array( 'account' => NULL, ) ); $items['advanced_forum_reply_link'] = array( 'arguments' => array( 'node' => NULL, ) ); $items['advanced_forum_topic_pager'] = array( 'arguments' => array( 'pagecount' => NULL, 'topic' => NULL, ) ); $items['advanced_forum_shadow_topic'] = array( 'arguments' => array( 'title' => NULL, 'nid' => NULL, 'new_forum' => NULL, ) ); $items['advanced_forum_subforum_list'] = array( 'arguments' => array( 'subforum_list' => NULL, ) ); $items['advanced_forum_simple_author_pane'] = array( 'arguments' => array( 'context' => NULL, ) ); $items['advanced_forum_post_edited'] = array( 'arguments' => array( 'who' => NULL, 'when' => NULL, 'why' => NULL, ) ); $items['advanced_forum_node_type_create_list'] = array( 'arguments' => array( 'forum_id' => NULL, ) ); // These only exist if nodecomment is on. if (module_exists('nodecomment')) { $items['advanced_forum_search_forum'] = array( 'arguments' => array('tid' => NULL), 'template' => 'advanced_forum-search-forum', ); $items['advanced_forum_search_topic'] = array( 'arguments' => array('node' => NULL), 'template' => 'advanced_forum-search-topic', ); $items['views_view_fields__advanced_forum_search'] = array( 'arguments' => array('view' => NULL, 'options' => NULL, 'row' => NULL), 'template' => 'advanced_forum_search_result', 'original hook' => 'views_view_fields', ); $items['views_view_fields__advanced_forum_search_topic'] = array( 'arguments' => array('view' => NULL, 'options' => NULL, 'row' => NULL), 'template' => 'advanced_forum_search_result', 'original hook' => 'views_view_fields', ); } // Templates for features added by Views $items['views_view_forum_topic_list__advanced_forum_topic_list'] = array( 'arguments' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL), 'template' => 'advanced_forum-topic-list-view', 'original hook' => 'views_view_forum_topic_list', ); $items['views_view__advanced_forum_topic_list'] = array( 'arguments' => array('view' => NULL), 'template' => 'advanced_forum-topic-list-outer-view', 'original hook' => 'views_view', ); $items['views_view__advanced_forum_group_topic_list'] = array( 'arguments' => array('view' => NULL), 'template' => 'advanced_forum-group-topic-list-outer-view', 'original hook' => 'views_view', ); return $items; } /** * Implementation of hook_theme_registry_alter(). */ function advanced_forum_theme_registry_alter(&$theme_registry) { advanced_forum_load_style_includes(); // Garland's phptemplate_comment_wrapper really sucks. Chances are, a theme // does NOT want to control this on forum nodes anyway, so we're going to take // it over: if (isset($theme_registry['comment_wrapper']['function']) && $theme_registry['comment_wrapper']['function'] == 'phptemplate_comment_wrapper') { $theme_registry['comment_wrapper']['function'] = 'advanced_forum_comment_wrapper'; } // Optionally kill the next/previous forum topic navigation links because // it is a nasty query that can slow down the forums. if (!variable_get('advanced_forum_use_topic_navigation', FALSE)) { foreach ($theme_registry['forum_topic_navigation']['preprocess functions'] as $key => $value) { if ($value == 'template_preprocess_forum_topic_navigation') { unset($theme_registry['forum_topic_navigation']['preprocess functions'][$key]); } } } // Don't let core do its basic preprocess for forums, as we want to do // other stuff now. foreach ($theme_registry['forums']['preprocess functions'] as $key => $value) { if ($value == 'template_preprocess_forums') { unset($theme_registry['forums']['preprocess functions'][$key]); } } // We duplicate all of core's forum list preprocessing so no need to run // it twice. Running twice also causes problems with & in forum name. foreach ($theme_registry['forum_list']['preprocess functions'] as $key => $value) { if ($value == 'template_preprocess_forum_list') { unset($theme_registry['forum_list']['preprocess functions'][$key]); } } // Views handles the topic list pages so remove the core template preprocess. foreach ($theme_registry['forum_topic_list']['preprocess functions'] as $key => $value) { if ($value == 'template_preprocess_forum_topic_list') { unset($theme_registry['forum_topic_list']['preprocess functions'][$key]); } } // --- The following section manipulates the theme registry so the .tpl files // --- for the given templates can be found first in the (sub)theme directory // --- then in ancestor themes, if any, then in the active style directory // --- for advanced forum or any ancestor styles. // Affected templates $templates = array('node', 'comment', 'comment_wrapper', 'forums', 'forum_list', 'forum_topic_list', 'forum_icon', 'forum_submitted', 'forum_topic_navigation', 'author_pane', 'advanced_forum_statistics', 'advanced_forum_search_forum', 'advanced_forum_search_topic', 'advanced_forum_search_result', 'advanced_forum_topic_list_view', 'views_view_fields__advanced_forum_search', 'views_view_fields__advanced_forum_search_topic', 'views_view_forum_topic_list__advanced_forum_topic_list', 'views_view_forum_topic_list__advanced_forum_group_topic_list', 'views_view__advanced_forum_topic_list', 'views_view__advanced_forum_group_topic_list', 'advanced_forum_topic_legend', 'advanced_forum_forum_legend', 'advanced_forum_topic_header', 'advanced_forum_active_poster', ); // Find all our ancestor themes and put them in an array. global $theme; $themes = list_themes(); $ancestor_paths = array(); $ancestor = $theme; while ($ancestor && isset($themes[$ancestor]->base_theme)) { array_unshift($ancestor_paths, dirname($themes[$themes[$ancestor]->base_theme]->filename)); $ancestor = $themes[$ancestor]->base_theme; } // Get the sequence of styles to look in for templates $lineage = advanced_forum_style_lineage(); if (!array_key_exists('naked', $lineage)) { // Add naked in at the end of the line to prevent problems if a style // doesn't include all needed templates. $lineage['naked'] = drupal_get_path('module', 'advanced_forum') . '/styles/naked'; } foreach ($templates as $template) { // Sanity check in case the template is not being used. if (!empty($theme_registry[$template])) { // If there was a path in there, store it. $existing_path = array_shift($theme_registry[$template]['theme paths']); // Add paths for our style and ancestors before the existing path, if any. foreach ($lineage AS $style => $style_path) { array_unshift($theme_registry[$template]['theme paths'], $existing_path, $style_path); $existing_path = array_shift($theme_registry[$template]['theme paths']); } // If there are any ancestor paths (ie: we are in a subtheme, add those) foreach ($ancestor_paths as $ancestor_path) { $theme_registry[$template]['theme paths'][] = $ancestor_path; } // Put the active theme's path last since that takes precidence. $theme_registry[$template]['theme paths'][] = advanced_forum_path_to_theme(); // Add preprocess functions if our style has them. $preprocess = array(); foreach ($lineage as $key => $path) { if (function_exists('advanced_forum_' . $key . '_preprocess_' . $template)) { $preprocess[] = 'advanced_forum_' . $key . '_preprocess_' . $template; } } // There are preprocess functions to add, so figure out where we want to add // them. if ($preprocess) { $position = 0; foreach ($theme_registry[$template]['preprocess functions'] as $function) { $position++; // If we see either of these items, that means we can place our // preprocess functions after this. if (substr($function, 0, 25) == 'advanced_forum_preprocess' || substr($function, 0, 34) == 'template_preprocess_advanced_forum') { break; } } // Add in our new preprocess functions: array_splice($theme_registry[$template]['preprocess functions'], $position, 0, $preprocess); } } } } /** * Implementation of hook_nodeapi(). */ function advanced_forum_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { if ($op == 'update' || $op == 'insert' || $op == 'delete') { // Update the cached statistics. advanced_forum_statistics_replies(TRUE); } if ($op == 'view' && !empty($node->content['forum_navigation'])) { if (!empty($node->content['forum_navigation'])) { // Move the forum navigation to a seperate variable so it doesn't // get lumped in with the content. $node->advanced_forum_navigation = $node->content['forum_navigation']['#value']; $node->content['forum_navigation'] = NULL; } } } /** * Implementation of hook_comment(). */ function advanced_forum_comment(&$a1, $op) { if ($op == 'update' || $op == 'insert' || $op == 'delete') { // Update the cached statistics. advanced_forum_statistics_replies(TRUE); } } /** * Implementation of hook_link(). */ function advanced_forum_link($type, $node = NULL, $teaser = FALSE) { $links = array(); if (advanced_forum_is_styled($node, $teaser, $type)) { if ($type == 'node' && (!isset($node->comment_target_nid))) { // Add edit / delete links to the node links to match replies. if (node_access('update', $node)) { $links['post_edit'] = array( 'title' => t('edit'), 'href' => 'node/'. $node->nid .'/edit', 'query' => drupal_get_destination(), ); } if (node_access('delete', $node)) { $links['post_delete'] = array( 'title' => t('delete'), 'href' => 'node/'. $node->nid .'/delete', ); } // Core only adds the link if the comment form is on a separate page // but we want the link there regardless for consistancy. // Nodecomment already handles this so only run if that's not enabled. if (!module_exists('nodecomment')) { if ($node->comment == COMMENT_NODE_READ_WRITE) { if (user_access('post comments')) { if (variable_get('comment_form_location_'. $node->type, COMMENT_FORM_SEPARATE_PAGE) != COMMENT_FORM_SEPARATE_PAGE) { $links['comment_add'] = array( 'title' => t('Add new comment'), 'href' => "comment/reply/$node->nid", 'attributes' => array('title' => t('Reply to this topic.')), 'fragment' => 'comment-form' ); } } } } } } return $links; } /** * Implementation of hook_link_alter(). */ function advanced_forum_link_alter(&$links, $node, $comment = NULL) { if (empty($comment)) { $object = $node; $object_type = 'node'; } else { $object = $comment; $object_type = 'comment'; } // Check if we are altering links on a node that is displayed in a teaser. // @TODO: Find out if there's a better way to tell if this is a teaser. $teaser = !(arg(0) == 'node' && arg(1) > 0); if (advanced_forum_is_styled($object, $teaser, $object_type)) { // Change first post from "add comment" to "reply" if it isn't already. if (!empty($links['comment_add'])) { $links['comment_add']['title'] = t('reply'); } // List the keys we are interested in. $affected_keys = array('post_edit', 'comment_edit', 'post_delete', 'comment_delete', 'quote', 'comment_add', 'comment_reply', 'comment_mover_node_prune', 'comment_mover_comment_prune'); // Add extra span tags for image replacement. foreach ($links AS $key => $link) { if (in_array($key, $affected_keys)) { $current_classes = (empty($links[$key]['attributes']['class'])) ? '' : $links[$key]['attributes']['class']; $links[$key]['attributes']['class'] = "$current_classes af-button-small"; $links[$key]['title'] = '' . $links[$key]['title'] . ''; $links[$key]['html'] = TRUE; } } // Put the links in a consistent order. foreach ($affected_keys as $key) { if (isset($links[$key])) { $temp = $links[$key]; unset($links[$key]); $links[$key] = $temp; } } } } /** * Implementation of hook_form_alter(). */ function advanced_forum_form_alter(&$form, &$form_state, $form_id) { if (!empty($form['#node']->type) && advanced_forum_type_is_in_forum($form['#node']->type) && isset($form['body_field']) && isset($form['body_field']['#after_build'])) { // Remove the teaser splitter. $teaser_js_build = array_search('node_teaser_js', $form['body_field']['#after_build']); unset($form['body_field']['#after_build'][$teaser_js_build]); $form['body_field']['teaser_js']['#access'] = FALSE; $form['body_field']['teaser_include']['#access'] = FALSE; } // Add our OG view as a potential RON for organic groups. if (!empty($form['og_settings']['group_details']['og_home_page_view'])) { $form['og_settings']['group_details']['og_home_page_view']['#options']['advanced_forum_group_topic_list'] = 'advanced_forum_group_topic_list'; } } // MAKE VIEWS BITS WORK *****************************************************/ function advanced_forum_views_api() { return array( 'api' => 2, 'path' => drupal_get_path('module', 'advanced_forum') . '/includes/views', 'file' => 'views.inc', ); } // MAKE CTOOLS BITS WORK *****************************************************/ /** * Tell CTools about what plugins we support. */ function advanced_forum_ctools_plugin_directory($module, $plugin) { if ($module == 'advanced_forum') { return 'styles'; } if ($module == 'page_manager' || $module == 'ctools') { return 'plugins/' . $plugin; } } function advanced_forum_ctools_plugin_api($module, $api) { if ($module == 'page_manager' && $api = 'pages_default') { return array( 'version' => 1, 'path' => drupal_get_path('module', 'advanced_forum') . '/includes/panels', ); } } // THEME FUNCTIONS AND TEMPLATE PREPROCESSES **********************************/ include_once drupal_get_path('module', 'advanced_forum') . '/includes/theme.inc'; // STYLE RELATED FUNCTIONS ****************************************************/ include_once drupal_get_path('module', 'advanced_forum') . '/includes/style.inc'; // CORE FORUM PAGE OVERRIDES **************************************************/ include_once drupal_get_path('module', 'advanced_forum') . '/includes/core-overrides.inc'; // MARK AS READ ***************************************************************/ include_once drupal_get_path('module', 'advanced_forum') . '/includes/mark-read.inc'; // VIEWS RELATED GOODIES ******************************************************/ /** * Post render a view and replace any advanced forum tokens. */ function advanced_forum_views_post_render(&$view, &$output) { if (!$view->style_plugin->uses_row_plugin()) { return; } $plugin = $view->display_handler->get_option('row_plugin'); if ($plugin == 'node' || $plugin == 'nodecomment_threaded') { // Look for token matches in the output: $matches = array(); $tokens = array(); // We want to change the look of the 'new' marker from the default, slightly: $tokens['' . t('new') . ''] = '(' . t('new') . ')'; // Replace the Author Pane token with the actual Author Pane. // Note that this token will only exist if Author Pane is enabled. if (preg_match_all('//us', $output, $matches)) { foreach ($matches[1] as $match => $uid) { $token = $matches[0][$match]; // This is the exact string that matched. if (!isset($tokens[$token])) { $account = user_load($uid); $tokens[$token] = theme('author_pane', $account, 'advanced_forum', variable_get('advanced_forum_user_picture_preset', ''), NULL, TRUE); } } } // Replace the Post edited token. if (preg_match_all('//us', $output, $matches)) { foreach ($matches[1] as $match => $nid) { $token = $matches[0][$match]; // This is the exact string that matched. if (!isset($tokens[$token])) { if (user_access('view last edited notice')) { $sql = 'SELECT uid, log, timestamp FROM {node_revisions} WHERE nid = %d ORDER BY timestamp DESC'; $row = db_fetch_object(db_query($sql, $nid)); $tokens[$token] = theme('advanced_forum_post_edited', $row->uid, $row->timestamp, $row->log); } else { // No access; remove token. $tokens[$token] = ''; } } } } // Replace the core Signature token. if (preg_match_all('//us', $output, $matches)) { foreach ($matches[1] as $match => $uid) { $token = $matches[0][$match]; // This is the exact string that matched. if (!isset($tokens[$token])) { $account = user_load($uid); if ($account->signature) { $tokens[$token] = check_markup($account->signature, $account->signature_format, FALSE); } } } } // Replace the posted by viewer tokens with class if appropriate. if (preg_match_all('//us', $output, $matches)) { foreach ($matches[1] as $match => $uid) { $token = $matches[0][$match]; // This is the exact string that matched. if (!isset($tokens[$token])) { global $user; if ($user->uid > 0 && $uid == $user->uid) { // This post is by current user. $tokens[$token] = " post-by-viewer"; } else { $tokens[$token] = ""; } } } } // Perform replacements. $output = strtr($output, $tokens); } } /** * Display the "sort" widget. This is a specially hacked widget that only * works with tablesorting. Tablesorting MUST be on for these widgets * to appear. */ function advanced_forum_forum_topic_list_sort() { $form_state = array( 'method' => 'get', 'no_redirect' => TRUE, 'rerender' => TRUE, 'input' => $_GET, 'drop tokens' => TRUE, ); ctools_include('form'); return ctools_build_form('advanced_forum_forum_topic_list_sort_form', $form_state); } function advanced_forum_forum_topic_list_sort_form(&$form_state) { $view = views_get_view('advanced_forum_topic_list'); $view->set_display('default'); $view->init_handlers(); $view->init_style(); // Work up a list of possible fields. $handler = &$view->style_plugin; $fields = &$view->field; $columns = $handler->sanitize_columns($handler->options['columns'], $fields); $options = array(); foreach ($columns as $field => $column) { if ($field == $column && empty($fields[$field]->options['exclude'])) { if (empty($handler->options['info'][$field]['sortable']) || !$fields[$field]->click_sortable()) { continue; } $label = check_plain(!empty($fields[$field]) ? $fields[$field]->label() : ''); $options[$field] = $label; } } $form['inline'] = array( '#prefix' => '