/[drupal]/contributions/modules/TaxTreeNodes/taxtreenodes.module
ViewVC logotype

Contents of /contributions/modules/TaxTreeNodes/taxtreenodes.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Sun Jul 13 12:24:06 2008 UTC (16 months, 1 week ago) by attiks
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +11 -4 lines
File MIME type: text/x-php
added taxtreenodes.css with placeholders so it's easier to override
1 <?php
2 // $Id: taxtreenodes.module,v 1.1 2007/12/07 09:24:53 attiks Exp $
3
4 /**
5 * @file
6 * Original author: Peter Droogmans (Attiks)
7 * Inspired by site_map module
8 */
9
10 /**
11 * Implementation of hook_help().
12 */
13 function taxtreenodes_help($section) {
14 switch ($section) {
15 case 'taxtreenodes':
16 $output = '<p>'. t('This module displays a hierarchical tree of a taxonomy including all nodes.') .'</p>';
17 $output = '<p>'. t('You can show/hide the number of items under each term.') .'</p>';
18 $output = '<p>'. t('You can make the whole tree jquery collapsible.') .'</p>';
19 }
20 }
21
22 /**
23 * Implementation of hook_perm().
24 */
25 function taxtreenodes_perm() {
26 return array('access taxtreenodes');
27 }
28
29 /**
30 * Implementation of hook_settings().
31 */
32 function taxtreenodes_admin_settings() {
33
34 $vocab_options = array();
35 if (module_exists('taxonomy')) {
36 foreach (taxonomy_get_vocabularies() as $vocabulary) {
37 $vocab_options[$vocabulary->vid] = $vocabulary->name;
38 }
39 $vocab_options[''] = t('(none)');
40 }
41
42 $nodetypes = node_get_types('names');
43 $nodetypes[''] = t('(none)');
44
45 $form['taxtreenodes_options']['taxtreenodes_show_count'] = array(
46 '#type' => 'checkbox',
47 '#title' => t('Show node counts by categories (exclude using list below)'),
48 '#return_value' => 1,
49 '#default_value' => variable_get('taxtreenodes_show_count', 0),
50 '#description' => t('When enabled, this option will show the number of nodes in each taxonomy term.'),
51 );
52
53 $form['taxtreenodes_options']['taxtreenodes_show_count_exclude'] = array(
54 '#type' => 'select',
55 '#title' => t('Categories to exclude from default behaviour'),
56 '#default_value' => variable_get('taxtreenodes_show_count_exclude', array()),
57 '#options' => $vocab_options,
58 '#multiple' => TRUE,
59 '#description' => t('Ctrl-click (Windows) or Command-click (Mac) to select more than one value.'),
60 );
61
62 $form['taxtreenodes_options']['taxtreenodes_collapsible'] = array(
63 '#type' => 'checkbox',
64 '#title' => t('Make the tree collapsible using jQuery (exclude using list below)'),
65 '#return_value' => 1,
66 '#default_value' => variable_get('taxtreenodes_collapsible', 0),
67 '#description' => t('When enabled, the tree will be displayed collapsed, all terms will toggle the display of their childs.'),
68 );
69
70 $form['taxtreenodes_options']['taxtreenodes_collapsible_exclude'] = array(
71 '#type' => 'select',
72 '#title' => t('Categories to exclude from default behaviour'),
73 '#default_value' => variable_get('taxtreenodes_collapsible_exclude', array()),
74 '#options' => $vocab_options,
75 '#multiple' => TRUE,
76 '#description' => t('Ctrl-click (Windows) or Command-click (Mac) to select more than one value.'),
77 );
78
79 $form['taxtreenodes_options']['taxtreenodes_nodetypes_to_exclude'] = array(
80 '#type' => 'select',
81 '#title' => t('Node types to exclude from the tree'),
82 '#default_value' => variable_get('taxtreenodes_nodetypes_to_exclude', array()),
83 '#options' => $nodetypes,
84 '#multiple' => TRUE,
85 '#description' => t('Ctrl-click (Windows) or Command-click (Mac) to select more than one value.'),
86 );
87
88 return system_settings_form($form);
89 }
90
91 /**
92 * Implementation of hook_menu().
93 */
94 function taxtreenodes_menu($may_cache) {
95 $items = array();
96
97 if ($may_cache) {
98 $items[] = array(
99 'path' => 'admin/settings/taxtreenodes',
100 'title' => t('Tax Tree Nodes'),
101 'description' => t('Settings.'),
102 'callback' => 'drupal_get_form',
103 'callback arguments' => 'taxtreenodes_admin_settings',
104 'access' => user_access('administer site configuration'),
105 'type' => MENU_NORMAL_ITEM
106 );
107 $items[] = array(
108 'path' => 'taxtreenodes',
109 'title' => t('Tax Tree Nodes'),
110 'description' => t('Display a tax tree node.'),
111 'callback' => 'taxtreenodes_page',
112 'access' => user_access('access taxtreenodes'),
113 'type' => MENU_SUGGESTED_ITEM
114 );
115 }
116
117 return $items;
118 }
119
120 /**
121 * Menu callback for the Tax Tree Node.
122 */
123 function taxtreenodes_page($vid = 0) {
124
125 if (!is_numeric($vid)) {
126 return drupal_not_found();
127 }
128
129 drupal_add_css(drupal_get_path('module', 'taxtreenodes') .'/taxtreenodes.css');
130
131 global $_taxtreenodes_collapsible_;
132 $_taxtreenodes_collapsible_ = (variable_get('taxtreenodes_collapsible', 0) && !array_key_exists($vid, variable_get('taxtreenodes_collapsible_exclude', array())))
133 || (!variable_get('taxtreenodes_collapsible', 0) && array_key_exists($vid, variable_get('taxtreenodes_collapsible_exclude', array())));
134
135 global $_taxtreenodes_show_count_;
136 $_taxtreenodes_show_count_ = (variable_get('taxtreenodes_show_count', 0) && !array_key_exists($vid, variable_get('taxtreenodes_show_count_exclude', array())))
137 || (!variable_get('taxtreenodes_show_count', 0) && array_key_exists($vid, variable_get('taxtreenodes_show_count_exclude', array())));
138
139 if ($_taxtreenodes_collapsible_) {
140 jquery_interface_add();
141 drupal_add_js(drupal_get_path('module', 'taxtreenodes') .'/taxtreenodes.js');
142 }
143
144 $output = '';
145 $output = 'vid='.$vid;
146
147 $result = db_query('SELECT vid, name, description FROM {vocabulary} WHERE vid IN (\'%s\') ORDER BY weight ASC, name', $vid);
148 while ($t = db_fetch_object($result)) {
149 $output .= _taxtreenodes_taxonomy_tree($t->vid, $t->name, $t->description);
150 }
151
152 $output = '<div id="taxtreenodes_'. $vid .'" class="taxtreenodes">'. $output .'</div>';
153
154 return $output;
155 }
156
157 /**
158 * Render taxonomy tree
159 *
160 * @param $tree The results of taxonomy_get_tree() with optional 'count' fields.
161 * @param $name An optional name for the tree. (Default: NULL)
162 * @param $description An optional description of the tree. (Default: NULL)
163 * @return A string representing a rendered tree.
164 */
165 function _taxtreenodes_taxonomy_tree($vid, $name = NULL, $description = NULL) {
166
167 $title = $name ? check_plain($name) : '';
168
169 $last_depth = -1;
170
171 $cat_depth = variable_get('taxtreenodes_categories_depth', 'all');
172 if (!is_numeric($cat_depth)) {
173 $cat_depth = 'all';
174 }
175
176 $output = $description ? '<div class="description">'. check_plain($description) .'</div>' : '';
177
178 $output .= '<div class="tree">'."\n";
179 // taxonomy_get_tree() honors access controls
180 $tree = taxonomy_get_tree($vid);
181
182 $nodestoexclude = variable_get('taxtreenodes_nodetypes_to_exclude', 0);
183 if ($nodestoexclude != 0) {
184 $nodestoexclude = "'" . implode ("','", $nodestoexclude) . "'";
185 }
186
187 // Load all the nodes so we can hide the empty ones
188 foreach ($tree as $term) {
189
190 $term->count = taxtreenodes_taxonomy_term_count_nodes($term->tid, $nodestoexclude);
191
192 if ($term->count) {
193
194 // Adjust the depth of the <ul> based on the change
195 // in $term->depth since the $last_depth.
196 if ($last_depth == -1) {
197 $output .= '<ul class="depth_'. $term->depth .'">'."\n";
198 }
199 else if ($term->depth > $last_depth) {
200 for ($i = 0; $i < ($term->depth - $last_depth); $i++) {
201 $output .= '<ul class="depth_'. $term->depth .'">'."\n";
202 }
203 }
204 else if ($term->depth < $last_depth) {
205 for ($i = 0; $i < ($last_depth - $term->depth); $i++) {
206 $output .= '</li>'."\n";
207 $output .= '</ul>'."\n";
208 $output .= '</li>'."\n";
209 }
210 }
211
212 $output .= '<li class="term">';
213 $output .= theme('taxtreenodes_term', $term, $cat_depth);
214 $term->nodes = taxtreenodes_taxonomy_select_nodes(array($term->tid), 'or', 0, FALSE, 'n.sticky DESC, n.title ASC', $nodestoexclude);
215 if (db_num_rows($term->nodes)) {
216 $output .= theme('taxtreenodes_nodes', $term->nodes, $cat_depth);
217 }
218
219 // Reset $last_depth in preparation for the next $term.
220 $last_depth = $term->depth;
221 }
222 }
223
224 // Close last term
225 $output .= '</li>'."\n";
226
227 // Bring the depth back to where it began, -1.
228 if ($last_depth > -1) {
229 for ($i = 0; $i < ($last_depth + 1); $i++) {
230 $output .= '</ul>'."\n";
231 if ($last_depth + 1 - $i > 1) {
232 $output .= '</li>'."\n";
233 }
234 }
235 }
236 $output .= "</div>\n";
237 $output = theme('box', $title, $output);
238
239 return $output;
240 }
241
242 /**
243 * Theme functions.
244 */
245
246 function theme_taxtreenodes_nodes($nodes, $cat_depth) {
247
248 $output = '';
249
250 $output .= '<ul class="nodelist">';
251 while ($node = db_fetch_object($nodes)) {
252 $output .= '<li class="node-type-'. $node->type .'">'. theme('taxtreenodes_node', $node, $cat_depth) .'</li>';
253 }
254 $output .= '</ul>'."\n";
255
256 return $output;
257
258 }
259
260 function theme_taxtreenodes_node($node) {
261 return l($node->title, drupal_get_path_alias('node/'. $node->nid), array('title' => $node->title, 'class' => 'linktonode'));
262 }
263
264 function theme_taxtreenodes_term($term, $cat_depth) {
265
266 $output = '';
267
268 global $_taxtreenodes_collapsible_;
269 global $_taxtreenodes_show_count_;
270
271 if ($_taxtreenodes_collapsible_) {
272
273 if ($term->count) {
274 $output .= '<a href="#" class="taxtreenodestoggle">'. check_plain($term->name);
275
276 if ($_taxtreenodes_show_count_) {
277 $output .= " ($term->count)";
278 }
279
280 $output .= '</a>';
281
282 }
283 else {
284 $output .= check_plain($term->name);
285 }
286
287 }
288 else {
289
290 if ($term->count) {
291
292 if ($cat_depth < 0) {
293 $output .= l($term->name, taxonomy_term_path($term), array('title' => $term->description));
294 }
295 else {
296 $output .= l($term->name, "taxonomy/term/$term->tid/$cat_depth", array('title' => $term->description));
297 }
298
299 if ($_taxtreenodes_show_count_) {
300 $output .= " ($term->count)";
301 }
302
303 }
304 else {
305 $output .= check_plain($term->name);
306 }
307
308 }
309
310 return $output;
311 }
312
313 /*
314 * Copy of taxonomy_term_count_nodes with support to exclude node types
315 * !!! Plain old concat of the NOT IN statement, otherwise the ' is escaped !!!!!
316 */
317
318 function taxtreenodes_taxonomy_term_count_nodes($tid, $type = 0) {
319 static $count;
320
321 if (!isset($count[$type])) {
322 // $type == 0 always evaluates TRUE if $type is a string
323 if (is_numeric($type)) {
324 $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 GROUP BY t.tid'));
325 }
326 else {
327 $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND n.type not in ($type) GROUP BY t.tid"));
328 }
329 while ($term = db_fetch_object($result)) {
330 $count[$type][$term->tid] = $term->c;
331 }
332 }
333
334 foreach (_taxonomy_term_children($tid) as $c) {
335 $children_count += taxtreenodes_taxonomy_term_count_nodes($c, $type);
336 }
337 return $count[$type][$tid] + $children_count;
338 }
339
340 /*
341 * Copy of taxonomy_select_nodes with support to exclude node types
342 * Removed parts we don't need
343 */
344
345 function taxtreenodes_taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC', $type = 0) {
346 if (count($tids) > 0) {
347 // For each term ID, generate an array of descendant term IDs to the right depth.
348 $descendant_tids = array();
349 if ($depth === 'all') {
350 $depth = NULL;
351 }
352 foreach ($tids as $index => $tid) {
353 $term = taxonomy_get_term($tid);
354 $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
355 $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
356 }
357
358 if ($operator == 'or') {
359 $args = call_user_func_array('array_merge', $descendant_tids);
360 $placeholders = implode(',', array_fill(0, count($args), '%d'));
361
362 if (is_numeric($type)) {
363 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created, n.type FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1 ORDER BY '. $order;
364 }
365 else {
366 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created, n.type FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .') AND n.type not in (' . $type . ') AND n.status = 1 ORDER BY '. $order;
367 }
368
369 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1';
370 }
371 $sql = db_rewrite_sql($sql);
372 $sql_count = db_rewrite_sql($sql_count);
373 if ($pager) {
374 $result = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count, $args);
375 }
376 else {
377 $result = db_query_range($sql, $args, 0, variable_get('feed_default_items', 10));
378 }
379 }
380
381 return $result;
382 }

  ViewVC Help
Powered by ViewVC 1.1.2