/[drupal]/contributions/modules/submenutree/submenutree.module
ViewVC logotype

Contents of /contributions/modules/submenutree/submenutree.module

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


Revision 1.4 - (show annotations) (download) (as text)
Mon May 26 05:18:12 2008 UTC (18 months ago) by bengtan
Branch: MAIN
CVS Tags: DRUPAL-6--1-0, DRUPAL-6--1-1, HEAD
Branch point for: DRUPAL-6--1
Changes since 1.3: +407 -217 lines
File MIME type: text/x-php
Preparation for branching for Drupal 6.x.
1 <?php
2 // $Id: submenutree.module,v 1.2.2.3 2007/11/11 02:23:00 bengtan Exp $
3 // Modeline for drupal
4 // vim: set expandtab tabstop=2 shiftwidth=2 autoindent smartindent filetype=php:
5
6 define('SUBMENUTREE_DISPLAY_MENU', 0);
7 define('SUBMENUTREE_DISPLAY_TITLES', 1);
8 define('SUBMENUTREE_DISPLAY_TEASERS', 2);
9 define('SUBMENUTREE_DISPLAY_TEASERS_LINKS', 3);
10 define('SUBMENUTREE_DISPLAY_FULLTEXT', 4);
11 define('SUBMENUTREE_DISPLAY_FULLTEXT_LINKS', 5);
12
13 define('SUBMENUTREE_DISPLAY_BLOCK_MASK', 15);
14 define('SUBMENUTREE_DISPLAY_BLOCK_MENU', 16);
15 define('SUBMENUTREE_DISPLAY_BLOCK_TITLES', 17);
16 define('SUBMENUTREE_DISPLAY_BLOCK_TEASERS', 18);
17 define('SUBMENUTREE_DISPLAY_BLOCK_TEASERS_LINKS', 19);
18 define('SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT', 20);
19 define('SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT_LINKS', 21);
20
21 define('SUBMENUTREE_BLOCK_SUBMENU', 0);
22 define('SUBMENUTREE_BLOCK_SIBLINGMENU', 1);
23
24
25 /**
26 * Implementation of hook_help().
27 */
28 function submenutree_help($section) {
29 switch ($section) {
30 case 'admin/help#submenutree':
31 return t("For nodes which are displayed as menu items, this module adds a listing of any submenu items below it into the content or into a block. It can also add a listing of sibling menu items.");
32 }
33 }
34
35
36 /**
37 * Implementation of hook_form_alter().
38 */
39 function submenutree_form_alter(&$form, $form_state, $form_id) {
40 if (strpos($form_id, 'node_form') > 0) {
41 $node = $form['#node'];
42 // Inject some sane defaults
43 if (empty($node->submenutree_enable)) {
44 $node->submenutree_enable = 0;
45 $node->submenutree_display = SUBMENUTREE_DISPLAY_MENU;
46 $node->submenutree_weight = 1;
47 }
48 if (empty($node->siblingmenutree_enable)) {
49 $node->siblingmenutree_enable = 0;
50 $node->siblingmenutree_display = SUBMENUTREE_DISPLAY_MENU;
51 $node->siblingmenutree_weight = 1;
52 }
53
54 $form['menu']['submenutree'] = array(
55 '#type' => 'fieldset',
56 '#title' => t('Submenu Tree Settings'),
57 '#collapsible' => true,
58 '#collapsed' => !$node->submenutree_enable,
59
60 'submenutree_enable' => array(
61 '#type' => 'checkbox',
62 '#title' => t('Enable submenu trees for this node'),
63 '#default_value' => $node->submenutree_enable,
64 ),
65
66 'submenutree_title' => array(
67 '#type' => 'textfield',
68 '#title' => t('Title'),
69 '#default_value' => $node->submenutree_title,
70 '#description' => t('The title of the submenu tree content or block. If you leave this blank, the submenu tree content will have no title, or the submenu tree block will use the node title.'),
71 ),
72
73 'submenutree_display' => array(
74 '#type' => 'select',
75 '#title' => t('Display submenu trees as'),
76 '#options' => array(
77 'content' => array(
78 SUBMENUTREE_DISPLAY_MENU => t('Menu'),
79 SUBMENUTREE_DISPLAY_TITLES => t('Titles only'),
80 SUBMENUTREE_DISPLAY_TEASERS => t('Teasers'),
81 SUBMENUTREE_DISPLAY_TEASERS_LINKS => t('Teasers with links'),
82 SUBMENUTREE_DISPLAY_FULLTEXT => t('Full text'),
83 SUBMENUTREE_DISPLAY_FULLTEXT_LINKS => t('Full text with links'),
84 ),
85 'block' => array(
86 SUBMENUTREE_DISPLAY_BLOCK_MENU => t('Menu'),
87 SUBMENUTREE_DISPLAY_BLOCK_TITLES => t('Titles only'),
88 SUBMENUTREE_DISPLAY_BLOCK_TEASERS => t('Teasers'),
89 SUBMENUTREE_DISPLAY_BLOCK_TEASERS_LINKS => t('Teasers with links'),
90 SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT => t('Full text'),
91 SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT_LINKS => t('Full text with links'),
92 ),
93 ),
94 '#default_value' => $node->submenutree_display,
95 '#description' => t('Select where and how the submenu tree should be displayed. If selecting a block display, the block also needs to be made visible.'),
96 ),
97
98 'submenutree_weight' => array(
99 '#type' => 'weight',
100 '#title' => t('Weight'),
101 '#default_value' => $node->submenutree_weight,
102 '#description' => t('The weight of the submenu tree listing. This only applies when displaying as content and affects where the submenu tree appears in the content.'),
103 ),
104 );
105
106 $form['menu']['siblingmenutree'] = array(
107 '#type' => 'fieldset',
108 '#title' => t('Siblingmenu Tree Settings'),
109 '#collapsible' => true,
110 '#collapsed' => !$node->siblingmenutree_enable,
111
112 'siblingmenutree_enable' => array(
113 '#type' => 'checkbox',
114 '#title' => t('Enable siblingmenu trees for this node'),
115 '#default_value' => $node->siblingmenutree_enable,
116 ),
117
118 'siblingmenutree_title' => array(
119 '#type' => 'textfield',
120 '#title' => t('Title'),
121 '#default_value' => $node->siblingmenutree_title,
122 '#description' => t('The title of the siblingmenu tree content or block. If you leave this blank, the siblingmenu tree content will have no title, or the siblingmenu tree block will use the node title.'),
123 ),
124
125 'siblingmenutree_display' => array(
126 '#type' => 'select',
127 '#title' => t('Display siblingmenu trees as'),
128 '#options' => array(
129 'content' => array(
130 SUBMENUTREE_DISPLAY_MENU => t('Menu'),
131 SUBMENUTREE_DISPLAY_TITLES => t('Titles only'),
132 SUBMENUTREE_DISPLAY_TEASERS => t('Teasers'),
133 SUBMENUTREE_DISPLAY_TEASERS_LINKS => t('Teasers with links'),
134 SUBMENUTREE_DISPLAY_FULLTEXT => t('Full text'),
135 SUBMENUTREE_DISPLAY_FULLTEXT_LINKS => t('Full text with links'),
136 ),
137 'block' => array(
138 SUBMENUTREE_DISPLAY_BLOCK_MENU => t('Menu'),
139 SUBMENUTREE_DISPLAY_BLOCK_TITLES => t('Titles only'),
140 SUBMENUTREE_DISPLAY_BLOCK_TEASERS => t('Teasers'),
141 SUBMENUTREE_DISPLAY_BLOCK_TEASERS_LINKS => t('Teasers with links'),
142 SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT => t('Full text'),
143 SUBMENUTREE_DISPLAY_BLOCK_FULLTEXT_LINKS => t('Full text with links'),
144 ),
145 ),
146 '#default_value' => $node->siblingmenutree_display,
147 '#description' => t('Select where and how the siblingmenu tree should be displayed. If selecting a block display, the block also needs to be made visible.'),
148 ),
149
150 'siblingmenutree_weight' => array(
151 '#type' => 'weight',
152 '#title' => t('Weight'),
153 '#default_value' => $node->siblingmenutree_weight,
154 '#description' => t('The weight of the siblingmenu tree listing. This only applies when displaying as content and affects where the siblingmenu tree appears in the content.'),
155 ),
156 );
157 }
158 }
159
160
161 /**
162 * Implementation of hook_nodeapi().
163 */
164 function submenutree_nodeapi(&$node, $op, $teaser, $page) {
165 switch ($op) {
166 case 'delete':
167 db_query('DELETE FROM {node_submenutree} WHERE nid = %d', $node->nid);
168 break;
169
170 case 'load':
171 $additions = db_fetch_array(db_query('SELECT submenutree_enable, submenutree_title, submenutree_display, submenutree_weight, siblingmenutree_enable, siblingmenutree_title, siblingmenutree_display, siblingmenutree_weight FROM {node_submenutree} WHERE nid = %d', $node->nid));
172 if ($additions)
173 return $additions;
174 break;
175
176 case 'update':
177 if (!$node->submenutree_enable && !$node->siblingmenutree_enable) {
178 db_query('DELETE FROM {node_submenutree} WHERE nid = %d', $node->nid);
179 }
180 // deliberate fullthrough
181
182 case 'insert':
183 if ($node->submenutree_enable || $node->siblingmenutree_enable) {
184 // SQL INSERT or UPDATE depending on whether a row already exists
185 $num_rows = db_result(db_query('SELECT COUNT(*) FROM {node_submenutree} WHERE nid = %d', $node->nid));
186 if ($num_rows > 0)
187 db_query("UPDATE {node_submenutree} SET submenutree_enable = %d, submenutree_title = '%s', submenutree_display = %d, submenutree_weight = %d, siblingmenutree_enable = %d, siblingmenutree_title = '%s', siblingmenutree_display = %d, siblingmenutree_weight = %d WHERE nid = %d", $node->submenutree_enable, $node->submenutree_title, $node->submenutree_display, $node->submenutree_weight, $node->siblingmenutree_enable, $node->siblingmenutree_title, $node->siblingmenutree_display, $node->siblingmenutree_weight, $node->nid);
188 else
189 db_query("INSERT INTO {node_submenutree} (nid, submenutree_enable, submenutree_title, submenutree_display, submenutree_weight, siblingmenutree_enable, siblingmenutree_title, siblingmenutree_display, siblingmenutree_weight) VALUES (%d, %d, '%s', %d, %d, %d, '%s', %d, %d)", $node->nid, $node->submenutree_enable, $node->submenutree_title, $node->submenutree_display, $node->submenutree_weight, $node->siblingmenutree_enable, $node->siblingmenutree_title, $node->siblingmenutree_display, $node->siblingmenutree_weight);
190 }
191 break;
192
193 case 'presave':
194 // copy fields from $node->menu['submenutree']['submenutree_*'] to ['submenutree_*'] if necessary
195 // Shouldn't drupal flatten these form fields already? Apparently not
196 if (!empty($node->menu['submenutree'])) {
197 foreach ($node->menu['submenutree'] as $k => $v)
198 $node->$k = $v;
199 }
200 if (!empty($node->menu['siblingmenutree'])) {
201 foreach ($node->menu['siblingmenutree'] as $k => $v)
202 $node->$k = $v;
203 }
204 break;
205
206 case 'view':
207 // Calling a helper function because it's too big to live in the switch
208 submenutree_nodeapi_view($node, $op, $teaser, $page);
209 break;
210 }
211 }
212
213
214 function submenutree_nodeapi_view(&$node, $op, $teaser, $page) {
215 if ($teaser == false && $page == true && ($node->submenutree_enable || $node->siblingmenutree_enable)) {
216 $menu_name = variable_get('menu_default_node_menu', 'primary-links');
217
218 // Give priority to the default menu
219 $mlid = db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND menu_name = '%s' AND module = 'menu' ORDER BY mlid ASC", $node->nid, $menu_name, 0, 1));
220 // Check all menus if a link does not exist in the default menu.
221 if (!$mlid) {
222 $mlid = db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND module = 'menu' ORDER BY mlid ASC", $node->nid, 0, 1));
223 }
224
225 if ($mlid) {
226 $item = menu_link_load($mlid);
227 $tree = menu_tree_page_data($item['menu_name']);
228
229 // Traverse down the tree to find our node, following in_active_trial
230 // This code stanza is loosely inspired by menu_set_active_trail()
231 list($key, $curr) = each($tree);
232 while ($curr) {
233 if ($curr['link']['href'] == $item['href']) {
234 $my_tree = $curr['below'];
235 $parent_tree = $tree;
236 $curr = FALSE;
237 }
238 else {
239 // Move to the child link if it's in the active trail.
240 if ($curr['below'] && $curr['link']['in_active_trail']) {
241 $tree = $curr['below'];
242 }
243 list($key, $curr) = each($tree);
244 }
245 }
246
247 // Sanity check that we did find something
248 if ($my_tree) {
249 if ($node->submenutree_enable) {
250 _submenutree_menutree_view($node, 'submenutree', $my_tree);
251 }
252 if ($node->siblingmenutree_enable) {
253 _submenutree_menutree_view($node, 'siblingmenutree', $parent_tree);
254 }
255 }
256 }
257 }
258 }
259
260
261 /**
262 * Implementation of hook_block().
263 */
264 function submenutree_block($op = 'list', $delta = 0, $edit = array()) {
265 if ($op == 'list') {
266 $blocks[SUBMENUTREE_BLOCK_SUBMENU]['info'] = t('Submenu Tree Display');
267 $blocks[SUBMENUTREE_BLOCK_SUBMENU]['cache'] = BLOCK_CACHE_PER_PAGE;
268 $blocks[SUBMENUTREE_BLOCK_SIBLINGMENU]['info'] = t('Siblingmenu Tree Display');
269 $blocks[SUBMENUTREE_BLOCK_SIBLINGMENU]['cache'] = BLOCK_CACHE_PER_PAGE;
270 return $blocks;
271 }
272 else if ($op == 'view') {
273 return _submenutree_get_block_content($delta);
274 }
275 }
276
277
278 /**
279 * Implementation of hook_theme().
280 */
281 function submenutree_theme() {
282 return array(
283 'submenu_tree_menu' => array(
284 ),
285 'submenu_tree_titles' => array(
286 ),
287 'submenu_tree_teasers' => array(
288 ),
289 'submenu_tree_fulltext' => array(
290 ),
291 );
292 }
293
294
295 /**
296 * View the menu tree, either by poking into $node->content, or via the block functions
297 *
298 * @param $node
299 * The node being operated upon. This is also used for configuration information.
300 * @param $type
301 * The type of menu to produce, either "submenutree" or "siblingmenutree"
302 * @param $tree
303 * A fragment of a menu tree to be viewed
304 */
305
306 function _submenutree_menutree_view(&$node, $type, $tree) {
307 // grab config from $node, depending on $type
308 $config_item = $type . '_title';
309 $title = $node->$config_item;
310 $config_item = $type . '_display';
311 $display = intval($node->$config_item) & SUBMENUTREE_DISPLAY_BLOCK_MASK;
312 $display_in_block = intval($node->$config_item) & ~SUBMENUTREE_DISPLAY_BLOCK_MASK;
313 $config_item = $type . '_weight';
314 $weight = $node->$config_item;
315
316 // tweak $title
317 if ($display_in_block) {
318 $block_title = $title;
319 if ($block_title == '')
320 $block_title = $node->title;
321 // wipe out $title so it doesn't get passed into the theme functions
322 $title = null;
323 }
324 else {
325 if ($title == '')
326 $title = null;
327 }
328
329 $output = '';
330 if ($display == SUBMENUTREE_DISPLAY_MENU) {
331 $output = theme('submenu_tree_menu', $tree, $title);
332 }
333 else {
334 $items = array();
335 foreach ($tree as $k => $v) {
336 // use page_callback == node_page_view to detect nodes
337 if ($v['link']['hidden'] == false && $v['link']['page_callback'] == 'node_page_view') {
338 $nid = substr($v['link']['href'], 5);
339 $child = node_load(array('nid' => $nid));
340 $items[] = array('node' => $child, 'weight' => $v['link']['weight'], 'title' => check_plain($v['link']['title']));
341 }
342 }
343 _submenutree_sort_items($items);
344
345 // Now render our links or our nodes
346 $links = false;
347 switch ($display) {
348 case SUBMENUTREE_DISPLAY_TITLES:
349 $output = theme('submenu_tree_titles', $items, $title);
350 break;
351
352 case SUBMENUTREE_DISPLAY_TEASERS_LINKS:
353 $links = true;
354 case SUBMENUTREE_DISPLAY_TEASERS:
355 $output = theme('submenu_tree_teasers', $items, $title, $links);
356 break;
357
358 case SUBMENUTREE_DISPLAY_FULLTEXT_LINKS:
359 $links = true;
360 case SUBMENUTREE_DISPLAY_FULLTEXT:
361 $output = theme('submenu_tree_fulltext', $items, $title, $links);
362 break;
363 }
364 }
365
366 if ($output) {
367 if ($display_in_block == 0) {
368 $node->content[$type] = array(
369 '#value' => $output,
370 '#weight' => $weight,
371 );
372 }
373 else {
374 $blocks_map = array(
375 'submenutree' => SUBMENUTREE_BLOCK_SUBMENU,
376 'siblingmenutree' => SUBMENUTREE_BLOCK_SIBLINGMENU,
377 );
378 _submenutree_set_block_content($blocks_map[$type], array('subject' => $block_title, 'content' => $output));
379 }
380 }
381 }
382
383
384 /**
385 * $block should be an array like those used in hook_block
386 * ie array('subject' => 'title', 'content' => 'some content');
387 */
388 function _submenutree_set_block_content($delta, $block = null) {
389 static $stored_content = array(
390 SUBMENUTREE_BLOCK_SUBMENU => array(),
391 SUBMENUTREE_BLOCK_SIBLINGMENU => array(),
392 );
393
394 if (isset($block) && is_array($block)) {
395 $stored_content[$delta] = $block;
396 }
397 return $stored_content[$delta];
398 }
399
400
401 function _submenutree_get_block_content($delta) {
402 return _submenutree_set_block_content($delta);
403 }
404
405
406 /**
407 * Sort an array of items.
408 *
409 * @param $items
410 * The array of items to be sorted.
411 */
412 function _submenutree_sort_items(&$items) {
413 usort($items, '_submenutree_sort_items_compare');
414 }
415
416
417 /**
418 * Compare two items by weight then title.
419 *
420 * @param a
421 * The first item to compare.
422 * @param b
423 * The second item to compare.
424 * @return
425 * An integer less than, equal to, or greater than zero if $a is considered
426 * to be respectively less than, equal to, or greater than $b.
427 */
428 function _submenutree_sort_items_compare($a, $b) {
429 $ret = $a['weight'] - $b['weight'];
430 if ($ret == 0) {
431 $ret = strcasecmp($a['title'], $b['title']);
432 }
433 return $ret;
434 }
435
436
437 function theme_submenu_tree_menu($tree, $title = null) {
438 $output = '';
439 if (isset($title))
440 $output .= '<h3>'. $title .'</h3>';
441 $output .= menu_tree_output($tree);
442 return $output;
443 }
444
445
446 function theme_submenu_tree_titles($items, $title = null) {
447 $list = array();
448 foreach ($items as $item) {
449 $list[] = l($item['node']->title, 'node/' . $item['node']->nid);
450 }
451 return theme('item_list', $list, $title);
452 }
453
454
455 function theme_submenu_tree_teasers($items, $title = null, $links) {
456 $output = '';
457 if (isset($title))
458 $output .= '<h3>'. $title .'</h3>';
459 foreach ($items as $item) {
460 $output .= node_view($item['node'], true, false, $links);
461 }
462 return $output;
463 }
464
465
466 function theme_submenu_tree_fulltext($items, $title = null, $links) {
467 $output = '';
468 if (isset($title))
469 $output .= '<h3>'. $title .'</h3>';
470 foreach ($items as $item) {
471 $output .= node_view($item['node'], false, false, $links);
472 }
473 return $output;
474 }
475
476

  ViewVC Help
Powered by ViewVC 1.1.2