# This patch file was generated by NetBeans IDE # This patch can be applied using context Tools: Apply Diff Patch action on respective folder. # It uses platform neutral UTF-8 encoding. # Above lines and this line are ignored by the patching process. Index: contributions/modules/article/article with taxonomy links changed.module --- contributions/modules/article/article with taxonomy links changed.module No Base Revision +++ contributions/modules/article/article with taxonomy links changed.module Locally New @@ -0,0 +1,575 @@ + array( + 'arguments' => array( + 'name' => NULL, 'index_list' => NULL + ) + ), + + 'article_list' => array( + 'arguments' => array('output' => NULL) + ), + + 'article_index_item' => array( + 'arguments' => array('term' => NULL) + ), + + 'article_more_info' => array( + 'arguments' => array('content' => NULL) + ), + ); +} + +/** + * implementation of hook_block() + */ +function article_block($op = 'list', $delta = 0, $edit = array()) { + switch ($op) { + case 'list': + return array(array('info' => t('Latest Articles'))); + + case 'view': + $content = module_invoke('node', 'title_list', article_get_latest(variable_get('article_recent_block', '5'))); + $content .= theme('article_more_info', l(t('more'), 'article', array('title' => t('Read more articles.')))); + return array('subject' => t(variable_get('article_block_title', 'Latest Articles')), + 'content' => $content); + + case 'configure': + return _article_block_configure(); + + case 'save': + variable_set('article_recent_block', $edit['article_recent_block']); + variable_set('article_block_title', $edit['article_block_title']); + break; + } +} + +/** + * implementation of hook_help() + */ +function article_help($section) { + switch ($section) { + case 'admin/help#article': + return t('Allow users to view nodes of multiple types in a central location.'); + } +} + +/** + * implementation of hook_menu() + */ +function article_menu() { + $items = array(); + + $items['article'] = array( + 'title' => t(variable_get('article_title', 'Articles')), + 'page callback' => 'article_page', + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + ); + $items['admin/settings/article'] = array( + 'title' => t('Article'), + 'description' => t('Administer settings for Article'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('article_admin_settings'), + 'access callback' => 'user_access', + 'access arguments' => array('administer site configuration'), + ); + return $items; +} + +/** + * admin settings for the article module. + */ +function article_admin_settings() { + $select = array(); + + $vocabularies = taxonomy_get_vocabularies(); + if (is_array($vocabularies) && count($vocabularies) > 0) { + foreach ($vocabularies as $vocabulary) { + $select[$vocabulary->vid] = $vocabulary->name; + } + } + + $form['article_vocab'] = array( + '#type' => 'select', + '#title' => t('Article Vocabularies'), + '#size' => min(9, count($select)), + '#options' => $select, + '#multiple' => TRUE, + '#required' => TRUE, + '#default_value' => variable_get('article_vocab', ''), + '#description' => t('Select the vocabularies which contain the Article categories. All the vocabularies you select here will show up on the Article index. You must select at least one value.'), + ); + $form['article_title'] = array( + '#type' => 'textfield', + '#title' => t('Overview Title'), + '#default_value' => t(variable_get('article_title', 'Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Articles page.') + ); + $form['article_index_depth'] = array( + '#type' => 'select', + '#title' => t('Index Depth'), + '#options' => array('all' => 'All Terms', 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6), + '#default_value' => variable_get('article_index_depth', 'all'), + '#description' => t('Defines how many levels of terms should be displayed on any given article index page. For example, if you select 1 then only one level of the Article index tree will be displayed at a time.'), + ); + + $form['article_categories_title'] = array( + '#type' => 'textfield', + '#title' => t('Categories Title'), + '#default_value' => t(variable_get('article_categories_title', 'Article Categories')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title displayed before the list of categories.') + ); + + $form['recent_group'] = array('#type' => 'fieldset', + '#title' => t('Article Page Settings'), + '#collapsible' => TRUE, + ); + $form['recent_group']['article_recent_box_enable'] = array( + '#type' => 'radios', + '#title' => t('Recent Articles Box'), + '#options' => array(t('Disabled'), t('Enabled')), + '#default_value' => variable_get('article_recent_box_enable', 1), + '#description' => t('Enables or Disables the recent articles box on the article index page.'), + ); + $form['recent_group']['article_recent_box_title'] = array( + '#type' => 'textfield', + '#title' => t('Box Title'), + '#default_value' => t(variable_get('article_recent_box_title', 'Latest Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Recent Articles Box on the Article index page.') + ); + $form['recent_group']['article_recent_display'] = array( + '#type' => 'select', + '#options' => drupal_map_assoc(array(5, 10, 15)), + '#default_value' => variable_get('article_recent_display', '5'), + '#title' => t('Articles to Display'), + '#description' => t('Sets the number of recent articles that will be displayed in the Recent Articles box. (0 = not displayed).'), + ); + $form['article_pathauto'] = array( + '#type' => 'checkbox', + '#title' => t('Enable pathauto integration'), + '#default_value' => variable_get('article_pathauto', false), + '#description' => t('Use the pathauto module to create links to article categories.') +); + $form['article_replace_taxonomy_links'] = array( + '#type' => 'checkbox', + '#title' => t('Replace taxonomy links to point to article based path'), + '#default_value' => variable_get('article_replace_taxonomy_links', false), + '#description' => t('When viewing a node, the category link will link back to taxonomy. Mark this checkbox if you want to the links to point to article again.') +); + + return system_settings_form($form); +} + +/** + * displays the main article page. + */ +function article_page() { + if (arg(1) == 'feed') { + // TODO: Should we set a channel title and URL here ? + $nids = array(); + $obj = taxonomy_select_nodes(article_get_article_terms(), 'or', variable_get('article_index_depth', 'all'), FALSE); + while ($node = db_fetch_object($obj)) { + $nids[] = $node->nid; + } + node_feed($nids); + return; + } + + if (arg(1) && is_numeric(arg(1))) { + $term = article_build_breadcrumbs(arg(1)); + + if ($term) { + $article_index_output = article_index($term->tid); + $output = $article_index_output ? theme('box', t('%term_name - Sub Categories', + array('%term_name' => $term->name)), + $article_index_output) : ''; + $output .= taxonomy_render_nodes(taxonomy_select_nodes(array($term->tid), 'or', variable_get('article_index_depth', 'all'))); + return $output; + } + else { + drupal_set_message(t('The category you requested can not be found.')); + return ''; + } + } + else if (arg(1)) { + drupal_goto('article'); + } + else { + if (variable_get('article_recent_box_enable', 1)) { + $feed = drupal_add_feed(url('article/feed'), t('Articles')); + $body = theme('box', t(variable_get('article_recent_box_title', 'Latest Articles')), + node_title_list(article_get_latest(variable_get('article_recent_display', '5'))). + theme('article_more_info', $feed['article/feed'])); + } + $content = article_index(); + return $body.theme('box', t(variable_get('article_categories_title', 'Article Categories')), $content); + } +} + +/** + * Constructs the article index page (Article categories), using theme functions. + * + * @return a string containing the output ready for display. + */ +function article_index($tid = 0) { + $output = ''; + $max_depth = variable_get('article_index_depth', 'all'); + $max_depth = is_numeric($max_depth) ? $max_depth : NULL; + $vocabularies = article_get_vocabularies(); + foreach ($vocabularies as $vocab) { + $vocab_tree = taxonomy_get_tree($vocab->vid, $tid, -1, $max_depth); + $content = ''; + + while (current($vocab_tree)) { + $content .= article_build_index($vocab_tree); + } + + if ($content) { + $output .= theme('article_index', $vocab->name, $content); + } + } + + return $output; +} + + +/** + * Recursivly traverses the term tree to construct the index. + * + * @param &$tree A reference to a taxonomy tree. + * @return string the output for this tree. + */ +function article_build_index(&$tree) { + $output = ''; + + if ($tree == array()) { + return ''; + } + + do { + $cur = current($tree); + $nex = next($tree); + if ($nex === false) { + $next_depth = -1; + } + else { + $next_depth = $nex->depth; + } + + $cur->link = 'article/' . $cur->tid; + + $cur->children = ''; + if ($next_depth > $cur->depth) { + $cur->children = article_build_index($tree); + + // sync $next_depth, because 'next item' may be shoved forward + // Thanks for the patch Roderik. + $nex = current($tree); + if ($nex === false) { + $next_depth = -1; + } + else { + $next_depth = $nex->depth; + } + } + + $cur->count = taxonomy_term_count_nodes($cur->tid); + + $output .= theme('article_index_item', $cur); + } while ($cur->depth == $next_depth); + + return theme('article_list', $output); +} + + +/** + * Gets all the vocabularies that are associated with the article module. + * + * @return array the vocabularies. + */ +function article_get_vocabularies() { + $allvocabularies = module_invoke('taxonomy', 'get_vocabularies'); + $article_vocabs = variable_get('article_vocab', array()); + $vocabularies = array(); + foreach ($article_vocabs as $vocab) { + $vocabularies[] = $allvocabularies[$vocab]; + } + return $vocabularies; +} + + +/** + * Get all the terms associated with Articles. + * + * @return an array of unique term ids. + */ +function article_get_article_terms() { + $vocabs = article_get_vocabularies(); + $tids = array(); + foreach ($vocabs as $vocab) { + $tids = array_merge($tids, article_tax_get_terms($vocab->vid)); + } + return array_unique($tids); +} + + +/** + * Get all the terms in a given vocabulary. + * + * @return an array of unique term ids. + */ +function article_tax_get_terms($vid) { + $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid); + $tids = array(); + while ($term = db_fetch_array($result)) { + $tids[] = $term['tid']; + } + return array_unique($tids); +} + + +/** + Get the latest articles + + @return a database query result. +**/ +function article_get_latest($count = 0) { + $tids = article_get_article_terms(); + return article_select_nodes($tids, 'or', 'all', $count); +} + +/** + * Finds all nodes that match selected taxonomy conditions. + * This is just a copy of taxonomy_select_nodes() but it gets a $count argument. + * I also removed some not needed parameters. + * + * @param $tids + * An array of term IDs to match. + * @param $operator + * How to interpret multiple IDs in the array. Can be "or" or "and". + * @param $depth + * How many levels deep to traverse the taxonomy tree. Can be a nonnegative + * integer or "all". + * @return + * A resource identifier pointing to the query results. + */ +function article_select_nodes($tids = array(), $operator = 'or', $depth = 0, $count = 0, $order = 'n.sticky DESC, n.created DESC') { + if (count($tids) > 0) { + // For each term ID, generate an array of descendant term IDs to the right depth. + $descendant_tids = array(); + if ($depth === 'all') { + $depth = NULL; + } + foreach ($tids as $index => $tid) { + $term = taxonomy_get_term($tid); + $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth); + $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree)); + } + + if ($operator == 'or') { + $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids)); + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1'; + } + else { + $joins = ''; + $wheres = ''; + foreach ($descendant_tids as $index => $tids) { + $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid'; + $wheres .= ' AND tn'. $index .'.tid IN ('. implode(',', $tids) .')'; + } + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 ' . $wheres; + } + $sql = db_rewrite_sql($sql); + $sql_count = db_rewrite_sql($sql_count); + $result = db_query_range($sql, 0, $count); + } + + return $result; +} + +/** + * Builds a breadcrumb list. + * + * @param $tid the term ID we want to build the breadcrumb for. + * @return a term object for the term ID passed as an argument. + */ +function article_build_breadcrumbs($tid) { + $parents = taxonomy_get_parents_all($tid); + //Home doesn't need to be / (issue: http://drupal.org/node/234209) + $breadcrumb[] = l(drupal_ucfirst(t('home')), ''); + $breadcrumb[] = l(drupal_ucfirst(t(variable_get('article_title', 'Article'))), 'article/'); + + $parents = array_reverse($parents); + + foreach ($parents as $term) { + $breadcrumb[] = l(drupal_ucfirst($term->name), 'article/'.$term->tid); + } + drupal_set_breadcrumb($breadcrumb); + return $term; +} + +/** + * Implementation of hook_link(); + * Replace current taxonomy link with article path + */ +function article_link_alter(&$links, $node) { + //Only process if the option is enabled + if (!variable_get('article_replace_taxonomy_links', false)) { + return; + } + //Get current article terms + $terms = article_get_article_terms(); + foreach ($links as $module => $link) { + if (strstr($module, 'taxonomy_term')) { + //Check if taxonomy term is included in the article vocabularies + $tid = str_replace('taxonomy/term/', '', $link['href']); + if (in_array($tid, $terms)) { + //Change current link to the article path + $links[$module]['href'] = 'article/'. $tid; + } + } + } +} + +/** @} End of the module_article group **/ + + +/** + @addtogroup theme_system + + Article module specific theme functions. + @{ +**/ + + +/** + * Controls the output of the rendered index list. + * + * @return string the output for the index list. + */ +function theme_article_index(&$name, &$index_list) { + if ($index_list) { + return "
\n$index_list\n
\n"; + } + return ''; +} + + +/** + * Displays a single one level list. Called for each group of items at the same depth. + * + * @return string the output for this list. + */ +function theme_article_list(&$output) { + if ($output) { + return "\n"; + } + return ''; +} + + +/** + * Displays a single index item. + * + * @return string the output for this item. + */ +function theme_article_index_item(&$term) { + $description = ($term->description != '') ? '

'. $term->description .'

' : ''; + if ($term->count > 0) { + return '
  • '. l($term->name ." ($term->count)", $term->link) .'
    '. $description.$term->children .'
  • '; + } + else { + return '
  • '. $term->name ." ($term->count)
    ". $description.$term->children .'
  • '; + } +} + + +/** + * Displays more information content, suck as "more" links, and feed images. + * + * @return formatted string containing the output. + */ +function theme_article_more_info($content) { + return ''; +} + +/** + * @} End of addtogroup theme_system + */ + + +/** + * @addtogroup helper_functions + * + * Article module specific helper functions. + * @{ + */ + +/** + * Gets the configuration form for the block. + * + * @return a drupal FAPI array. + */ +function _article_block_configure() { + $form['article_block_title'] = array( + '#type' => 'textfield', + '#title' => t('Block Title'), + '#default_value' => t(variable_get('article_block_title', 'Latest Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Articles block.') + ); + $form['article_recent_block'] = array( + '#type' => 'select', + '#title' => t('Recent Articles to Display'), + '#options' => drupal_map_assoc(array(5, 10, 15, 20)), + '#default_value' => variable_get('article_recent_block', 5), + '#description' => t('Sets the number of recent articles that will be displayed in the Recent Articles block.'), + '#multiple' => false + ); + return $form; +} + +/** + * @} End of addtogroup helper_functions + */ + +// pathauto integration. +if (module_exists("pathauto")) { + if (variable_get('article_pathauto', false)) { + require("pathauto.inc"); + } +} + +?> Index: contributions/modules/article/article.module --- contributions/modules/article/article.module Base (1.23.2.5.2.1.2.13.2.3) +++ contributions/modules/article/article.module Locally Modified (Based On 1.23.2.5.2.1.2.13.2.3) @@ -2,62 +2,68 @@ // $Id: article.module,v 1.23.2.5.2.1.2.13.2.3 2009/01/01 19:07:42 msameer Exp $ /** - Article Module - an easy to use integrated article management module. + * @file + * Article Module - an easy to use integrated article management module. + * + * The article module allows for articles to be organized and displayed in + * a cenrtalized location. In essence it is a specialized taxonomy display + * module with some specific features that make it sutible for articles. + * + * @author Nicholas Young-Soares + * @author Mohammed Sameer + * @package module_article + * + * @defgroup module_article an easy to use intergrated article management module. + * @{ + */ - The article module allows for articles to be organized and displayed in - a cenrtalized location. In essence it is a specialized taxonomy display - module with some specific features that make it sutible for articles. - - @author Nicholas Young-Soares - @author Mohammed Sameer - @package module_article - - @defgroup module_article an easy to use intergrated article management module. - @{ -**/ - /** - * implementation of hook_theme() + * Implementation of hook_theme(); */ - function article_theme() { return array( 'article_index' => array( 'arguments' => array( - 'name' => NULL, 'index_list' => NULL + 'name' => NULL, + 'index_list' => NULL, ) ), - 'article_list' => array( - 'arguments' => array('output' => NULL) + 'arguments' => array( + 'output' => NULL, + ) ), - 'article_index_item' => array( - 'arguments' => array('term' => NULL) + 'arguments' => array( + 'term' => NULL, + ) ), - 'article_more_info' => array( - 'arguments' => array('content' => NULL) + 'arguments' => array( + 'content' => NULL, + ) ), ); } /** - * implementation of hook_block() + * Implementation of hook_block(); */ function article_block($op = 'list', $delta = 0, $edit = array()) { switch ($op) { case 'list': return array(array('info' => t('Latest Articles'))); + break; case 'view': $content = module_invoke('node', 'title_list', article_get_latest(variable_get('article_recent_block', '5'))); $content .= theme('article_more_info', l(t('more'), 'article', array('title' => t('Read more articles.')))); - return array('subject' => t(variable_get('article_block_title', 'Latest Articles')), - 'content' => $content); + return array('subject' => t(variable_get('article_block_title', 'Latest Articles')), 'content' => $content); + break; case 'configure': return _article_block_configure(); + break; case 'save': variable_set('article_recent_block', $edit['article_recent_block']); @@ -67,7 +73,7 @@ } /** - * implementation of hook_help() + * Implementation of hook_help(); */ function article_help($section) { switch ($section) { @@ -77,25 +83,26 @@ } /** - * implementation of hook_menu() + * Implementation of hook_menu(); */ function article_menu() { $items = array(); $items['article'] = array( - 'title' => t(variable_get('article_title', 'Articles')), + 'title' => variable_get('article_title', 'Articles'), 'page callback' => 'article_page', 'access callback' => 'user_access', 'access arguments' => array('access content'), ); $items['admin/settings/article'] = array( - 'title' => t('Article'), - 'description' => t('Administer settings for Article'), + 'title' => 'Article', + 'description' => 'Administer settings for Article', 'page callback' => 'drupal_get_form', 'page arguments' => array('article_admin_settings'), 'access callback' => 'user_access', 'access arguments' => array('administer site configuration'), ); + return $items; } @@ -137,7 +144,6 @@ '#default_value' => variable_get('article_index_depth', 'all'), '#description' => t('Defines how many levels of terms should be displayed on any given article index page. For example, if you select 1 then only one level of the Article index tree will be displayed at a time.'), ); - $form['article_categories_title'] = array( '#type' => 'textfield', '#title' => t('Categories Title'), @@ -176,7 +182,7 @@ $form['article_pathauto'] = array( '#type' => 'checkbox', '#title' => t('Enable pathauto integration'), - '#default_value' => variable_get('article_pathauto', false), + '#default_value' => variable_get('article_pathauto', FALSE), '#description' => t('Use the pathauto module to create links to article categories.') ); @@ -203,9 +209,7 @@ if ($term) { $article_index_output = article_index($term->tid); - $output = $article_index_output ? theme('box', t('%term_name - Sub Categories', - array('%term_name' => $term->name)), - $article_index_output) : ''; + $output = $article_index_output ? theme('box', t('%term_name - Sub Categories', array('%term_name' => $term->name)), $article_index_output) : ''; $output .= taxonomy_render_nodes(taxonomy_select_nodes(array($term->tid), 'or', variable_get('article_index_depth', 'all'))); return $output; } @@ -214,18 +218,18 @@ return ''; } } - else if (arg(1)) { + elseif (arg(1)) { drupal_goto('article'); } else { if (variable_get('article_recent_box_enable', 1)) { $feed = drupal_add_feed(url('article/feed'), t('Articles')); $body = theme('box', t(variable_get('article_recent_box_title', 'Latest Articles')), - node_title_list(article_get_latest(variable_get('article_recent_display', '5'))). + node_title_list(article_get_latest(variable_get('article_recent_display', '5'))) . theme('article_more_info', $feed['article/feed'])); } $content = article_index(); - return $body.theme('box', t(variable_get('article_categories_title', 'Article Categories')), $content); + return $body . theme('box', t(variable_get('article_categories_title', 'Article Categories')), $content); } } @@ -272,7 +276,7 @@ do { $cur = current($tree); $nex = next($tree); - if ($nex === false) { + if ($nex === FALSE) { $next_depth = -1; } else { @@ -288,7 +292,7 @@ // sync $next_depth, because 'next item' may be shoved forward // Thanks for the patch Roderik. $nex = current($tree); - if ($nex === false) { + if ($nex === FALSE) { $next_depth = -1; } else { @@ -352,10 +356,10 @@ /** - Get the latest articles - - @return a database query result. -**/ + * Get the latest articles + * + * @return a database query result. + */ function article_get_latest($count = 0) { $tids = article_get_article_terms(); return article_select_nodes($tids, 'or', 'all', $count); @@ -426,7 +430,7 @@ $parents = array_reverse($parents); foreach ($parents as $term) { - $breadcrumb[] = l(drupal_ucfirst($term->name), 'article/'.$term->tid); + $breadcrumb[] = l(drupal_ucfirst($term->name), 'article/'. $term->tid); } drupal_set_breadcrumb($breadcrumb); return $term; @@ -440,7 +444,7 @@ Article module specific theme functions. @{ -**/ + */ /** @@ -450,7 +454,7 @@ */ function theme_article_index(&$name, &$index_list) { if ($index_list) { - return "
    \n$index_list\n
    \n"; + return "
    \n". $index_list ."\n
    \n"; } return ''; } @@ -477,10 +481,10 @@ function theme_article_index_item(&$term) { $description = ($term->description != '') ? '

    '. $term->description .'

    ' : ''; if ($term->count > 0) { - return '
  • '. l($term->name ." ($term->count)", $term->link) .'
    '. $description.$term->children .'
  • '; + return '
  • '. l($term->name ." (". $term->count .")", $term->link) .'
    '. $description . $term->children .'
  • '; } else { - return '
  • '. $term->name ." ($term->count)
    ". $description.$term->children .'
  • '; + return '
  • '. $term->name ." (". $term->count .")
    ". $description . $term->children .'
  • '; } } @@ -491,7 +495,7 @@ * @return formatted string containing the output. */ function theme_article_more_info($content) { - return ''; + return ''; } /** @@ -526,7 +530,7 @@ '#options' => drupal_map_assoc(array(5, 10, 15, 20)), '#default_value' => variable_get('article_recent_block', 5), '#description' => t('Sets the number of recent articles that will be displayed in the Recent Articles block.'), - '#multiple' => false + '#multiple' => FALSE ); return $form; } @@ -537,9 +541,8 @@ // pathauto integration. if (module_exists("pathauto")) { - if (variable_get('article_pathauto', false)) { + if (variable_get('article_pathauto', FALSE)) { require("pathauto.inc"); } } -?> Index: contributions/modules/article/Copia de article con cambios para listar nodos.module --- contributions/modules/article/Copia de article con cambios para listar nodos.module No Base Revision +++ contributions/modules/article/Copia de article con cambios para listar nodos.module Locally New @@ -0,0 +1,575 @@ + array( + 'arguments' => array( + 'name' => NULL, 'index_list' => NULL + ) + ), + + 'article_list' => array( + 'arguments' => array('output' => NULL) + ), + + 'article_item_list' => array( + 'arguments' => array('output' => NULL) + ), + + 'article_index_item' => array( + 'arguments' => array('term' => NULL) + ), + + 'article_more_info' => array( + 'arguments' => array('content' => NULL) + ), + ); +} + +/** + * implementation of hook_block() + */ +function article_block($op = 'list', $delta = 0, $edit = array()) { + switch ($op) { + case 'list': + return array(array('info' => t('Latest Articles'))); + + case 'view': + $content = module_invoke('node', 'title_list', article_get_latest(variable_get('article_recent_block', '5'))); + $content .= theme('article_more_info', l(t('more'), 'article', array('title' => t('Read more articles.')))); + return array('subject' => t(variable_get('article_block_title', 'Latest Articles')), + 'content' => $content); + + case 'configure': + return _article_block_configure(); + + case 'save': + variable_set('article_recent_block', $edit['article_recent_block']); + variable_set('article_block_title', $edit['article_block_title']); + break; + } +} + +/** + * implementation of hook_help() + */ +function article_help($section) { + switch ($section) { + case 'admin/help#article': + return t('Allow users to view nodes of multiple types in a central location.'); + } +} + +/** + * implementation of hook_menu() + */ +function article_menu() { + $items = array(); + + $items['article'] = array( + 'title' => t(variable_get('article_title', 'Articles')), + 'page callback' => 'article_page', + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + ); + $items['admin/settings/article'] = array( + 'title' => t('Article'), + 'description' => t('Administer settings for Article'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('article_admin_settings'), + 'access callback' => 'user_access', + 'access arguments' => array('administer site configuration'), + ); + return $items; +} + +/** + * admin settings for the article module. + */ +function article_admin_settings() { + $select = array(); + + $vocabularies = taxonomy_get_vocabularies(); + if (is_array($vocabularies) && count($vocabularies) > 0) { + foreach ($vocabularies as $vocabulary) { + $select[$vocabulary->vid] = $vocabulary->name; + } + } + + $form['article_vocab'] = array( + '#type' => 'select', + '#title' => t('Article Vocabularies'), + '#size' => min(9, count($select)), + '#options' => $select, + '#multiple' => TRUE, + '#required' => TRUE, + '#default_value' => variable_get('article_vocab', ''), + '#description' => t('Select the vocabularies which contain the Article categories. All the vocabularies you select here will show up on the Article index. You must select at least one value.'), + ); + $form['article_title'] = array( + '#type' => 'textfield', + '#title' => t('Overview Title'), + '#default_value' => t(variable_get('article_title', 'Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Articles page.') + ); + $form['article_index_depth'] = array( + '#type' => 'select', + '#title' => t('Index Depth'), + '#options' => array('all' => 'All Terms', 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6), + '#default_value' => variable_get('article_index_depth', 'all'), + '#description' => t('Defines how many levels of terms should be displayed on any given article index page. For example, if you select 1 then only one level of the Article index tree will be displayed at a time.'), + ); + + $form['article_categories_title'] = array( + '#type' => 'textfield', + '#title' => t('Categories Title'), + '#default_value' => t(variable_get('article_categories_title', 'Article Categories')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title displayed before the list of categories.') + ); + + $form['recent_group'] = array('#type' => 'fieldset', + '#title' => t('Article Page Settings'), + '#collapsible' => TRUE, + ); + $form['recent_group']['article_recent_box_enable'] = array( + '#type' => 'radios', + '#title' => t('Recent Articles Box'), + '#options' => array(t('Disabled'), t('Enabled')), + '#default_value' => variable_get('article_recent_box_enable', 1), + '#description' => t('Enables or Disables the recent articles box on the article index page.'), + ); + $form['recent_group']['article_recent_box_title'] = array( + '#type' => 'textfield', + '#title' => t('Box Title'), + '#default_value' => t(variable_get('article_recent_box_title', 'Latest Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Recent Articles Box on the Article index page.') + ); + $form['recent_group']['article_recent_display'] = array( + '#type' => 'select', + '#options' => drupal_map_assoc(array(5, 10, 15)), + '#default_value' => variable_get('article_recent_display', '5'), + '#title' => t('Articles to Display'), + '#description' => t('Sets the number of recent articles that will be displayed in the Recent Articles box. (0 = not displayed).'), + ); + $form['article_pathauto'] = array( + '#type' => 'checkbox', + '#title' => t('Enable pathauto integration'), + '#default_value' => variable_get('article_pathauto', false), + '#description' => t('Use the pathauto module to create links to article categories.') +); + + return system_settings_form($form); +} + +/** + * displays the main article page. + */ +function article_page() { + if (arg(1) == 'feed') { + // TODO: Should we set a channel title and URL here ? + $nids = array(); + $obj = taxonomy_select_nodes(article_get_article_terms(), 'or', variable_get('article_index_depth', 'all'), FALSE); + while ($node = db_fetch_object($obj)) { + $nids[] = $node->nid; + } + node_feed($nids); + return; + } + + if (arg(1) && is_numeric(arg(1))) { + $term = article_build_breadcrumbs(arg(1)); + + if ($term) { + $article_index_output = article_index($term->tid); + $output = $article_index_output ? theme('box', t('%term_name - Sub Categories', + array('%term_name' => $term->name)), + $article_index_output) : ''; + //Include node list + $output .= taxonomy_render_nodes(taxonomy_select_nodes(array($term->tid), 'or', variable_get('article_index_depth', 'all'))); + return $output; + } + else { + drupal_set_message(t('The category you requested can not be found.')); + return ''; + } + } + else if (arg(1)) { + drupal_goto('article'); + } + else { + if (variable_get('article_recent_box_enable', 1)) { + $feed = drupal_add_feed(url('article/feed'), t('Articles')); + $body = theme('box', t(variable_get('article_recent_box_title', 'Latest Articles')), + node_title_list(article_get_latest(variable_get('article_recent_display', '5'))). + theme('article_more_info', $feed['article/feed'])); + } + $content = article_index(); + return $body.theme('box', t(variable_get('article_categories_title', 'Article Categories')), $content); + } +} + +/** + * Constructs the article index page (Article categories), using theme functions. + * + * @return a string containing the output ready for display. + */ +function article_index($tid = 0) { + $output = ''; + $max_depth = variable_get('article_index_depth', 'all'); + $max_depth = is_numeric($max_depth) ? $max_depth : NULL; + $vocabularies = article_get_vocabularies(); + foreach ($vocabularies as $vocab) { + $vocab_tree = taxonomy_get_tree($vocab->vid, $tid, -1, $max_depth); + $content = ''; + + while (current($vocab_tree)) { + $content .= article_build_index($vocab_tree); + } + + if ($content) { + $output .= theme('article_index', $vocab->name, $content); + } + } + + return $output; +} + + +/** + * Recursivly traverses the term tree to construct the index. + * + * @param &$tree A reference to a taxonomy tree. + * @return string the output for this tree. + */ +function article_build_index(&$tree) { + $output = ''; + + if ($tree == array()) { + return ''; + } + + do { + $cur = current($tree); + $nex = next($tree); + if ($nex === false) { + $next_depth = -1; + } + else { + $next_depth = $nex->depth; + } + + $cur->link = 'article/' . $cur->tid; + + $cur->children = ''; + if ($next_depth > $cur->depth) { + $cur->children = article_build_index($tree); + + // sync $next_depth, because 'next item' may be shoved forward + // Thanks for the patch Roderik. + $nex = current($tree); + if ($nex === false) { + $next_depth = -1; + } + else { + $next_depth = $nex->depth; + } + } + + $cur->count = taxonomy_term_count_nodes($cur->tid); + + $output .= theme('article_index_item', $cur); + + //Include node list + $output .= theme('article_item_list', module_invoke('node', 'title_list', article_get_latest_tid($cur->tid, variable_get('article_recent_block', '5')))); + $output .= theme('article_more_info', l(t('more'), 'article', array('title' => t('Read more articles.')))); + + } while ($cur->depth == $next_depth); + + return theme('article_list', $output); +} + + +/** + * Gets all the vocabularies that are associated with the article module. + * + * @return array the vocabularies. + */ +function article_get_vocabularies() { + $allvocabularies = module_invoke('taxonomy', 'get_vocabularies'); + $article_vocabs = variable_get('article_vocab', array()); + $vocabularies = array(); + foreach ($article_vocabs as $vocab) { + $vocabularies[] = $allvocabularies[$vocab]; + } + return $vocabularies; +} + + +/** + * Get all the terms associated with Articles. + * + * @return an array of unique term ids. + */ +function article_get_article_terms() { + $vocabs = article_get_vocabularies(); + $tids = array(); + foreach ($vocabs as $vocab) { + $tids = array_merge($tids, article_tax_get_terms($vocab->vid)); + } + return array_unique($tids); +} + + +/** + * Get all the terms in a given vocabulary. + * + * @return an array of unique term ids. + */ +function article_tax_get_terms($vid) { + $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid); + $tids = array(); + while ($term = db_fetch_array($result)) { + $tids[] = $term['tid']; + } + return array_unique($tids); +} + + +/** + Get the latest articles + + @return a database query result. +**/ +function article_get_latest($count = 0) { + $tids = article_get_article_terms(); + return article_select_nodes($tids, 'or', 'all', $count); +} + +/** + Get the latest articles of a tid + + @return a database query result. +**/ +function article_get_latest_tid($tid, $count = 0) { + return article_select_nodes(array($tid), 'or', 'all', $count); +} + +/** + * Finds all nodes that match selected taxonomy conditions. + * This is just a copy of taxonomy_select_nodes() but it gets a $count argument. + * I also removed some not needed parameters. + * + * @param $tids + * An array of term IDs to match. + * @param $operator + * How to interpret multiple IDs in the array. Can be "or" or "and". + * @param $depth + * How many levels deep to traverse the taxonomy tree. Can be a nonnegative + * integer or "all". + * @return + * A resource identifier pointing to the query results. + */ +function article_select_nodes($tids = array(), $operator = 'or', $depth = 0, $count = 0, $order = 'n.sticky DESC, n.created DESC') { + if (count($tids) > 0) { + // For each term ID, generate an array of descendant term IDs to the right depth. + $descendant_tids = array(); + if ($depth === 'all') { + $depth = NULL; + } + foreach ($tids as $index => $tid) { + $term = taxonomy_get_term($tid); + $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth); + $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree)); + } + + if ($operator == 'or') { + $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids)); + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1'; + } + else { + $joins = ''; + $wheres = ''; + foreach ($descendant_tids as $index => $tids) { + $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid'; + $wheres .= ' AND tn'. $index .'.tid IN ('. implode(',', $tids) .')'; + } + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 ' . $wheres; + } + $sql = db_rewrite_sql($sql); + $sql_count = db_rewrite_sql($sql_count); + $result = db_query_range($sql, 0, $count); + } + + return $result; +} + +/** + * Builds a breadcrumb list. + * + * @param $tid the term ID we want to build the breadcrumb for. + * @return a term object for the term ID passed as an argument. + */ +function article_build_breadcrumbs($tid) { + $parents = taxonomy_get_parents_all($tid); + $breadcrumb[] = l(drupal_ucfirst(t('home')), '/'); + $breadcrumb[] = l(drupal_ucfirst(t(variable_get('article_title', 'Article'))), 'article/'); + + $parents = array_reverse($parents); + + foreach ($parents as $term) { + $breadcrumb[] = l(drupal_ucfirst($term->name), 'article/'.$term->tid); + } + drupal_set_breadcrumb($breadcrumb); + return $term; +} + +/** @} End of the module_article group **/ + + +/** + @addtogroup theme_system + + Article module specific theme functions. + @{ +**/ + + +/** + * Controls the output of the rendered index list. + * + * @return string the output for the index list. + */ +function theme_article_index(&$name, &$index_list) { + if ($index_list) { + return "
    \n$index_list\n
    \n"; + } + return ''; +} + + +/** + * Displays a single one level list. Called for each group of items at the same depth. + * + * @return string the output for this list. + */ +function theme_article_list(&$output) { + if ($output) { + return "\n"; + } + return ''; +} + +/** + * Displays a second level list. Called for each group of nodes in each category + * + * @return string the output for this list. + */ +function theme_article_item_list(&$output) { + if ($output) { + return "
    $output

    "; + } + return ''; +} + +/** + * Displays a single index item. + * + * @return string the output for this item. + */ +function theme_article_index_item(&$term) { + $description = ($term->description != '') ? '

    '. $term->description .'

    ' : ''; + if ($term->count > 0) { + return '
  • '. l($term->name ." ($term->count)", $term->link) .'
    '. $description.$term->children .'
  • '; + } + else { + return '
  • '. $term->name ." ($term->count)
    ". $description.$term->children .'
  • '; + } +} + + +/** + * Displays more information content, suck as "more" links, and feed images. + * + * @return formatted string containing the output. + */ +function theme_article_more_info($content) { + return '
    '.$content.'
    '; +} + +/** + * @} End of addtogroup theme_system + */ + + +/** + * @addtogroup helper_functions + * + * Article module specific helper functions. + * @{ + */ + +/** + * Gets the configuration form for the block. + * + * @return a drupal FAPI array. + */ +function _article_block_configure() { + $form['article_block_title'] = array( + '#type' => 'textfield', + '#title' => t('Block Title'), + '#default_value' => t(variable_get('article_block_title', 'Latest Articles')), + '#size' => 35, + '#maxlength' => 255, + '#description' => t('Title of the Articles block.') + ); + $form['article_recent_block'] = array( + '#type' => 'select', + '#title' => t('Recent Articles to Display'), + '#options' => drupal_map_assoc(array(5, 10, 15, 20)), + '#default_value' => variable_get('article_recent_block', 5), + '#description' => t('Sets the number of recent articles that will be displayed in the Recent Articles block.'), + '#multiple' => false + ); + return $form; +} + +/** + * @} End of addtogroup helper_functions + */ + +// pathauto integration. +if (module_exists("pathauto")) { + if (variable_get('article_pathauto', false)) { + require("pathauto.inc"); + } +} + +?> Index: contributions/modules/article/pathauto.inc --- contributions/modules/article/pathauto.inc Base (1.1.2.1) +++ contributions/modules/article/pathauto.inc Locally Modified (Based On 1.1.2.1) @@ -1,6 +1,13 @@ +