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

Contents of /contributions/modules/menu_block/menu_block.module

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


Revision 1.53 - (show annotations) (download) (as text)
Fri Aug 14 16:26:33 2009 UTC (3 months, 1 week ago) by johnalbin
Branch: MAIN
CVS Tags: HEAD
Changes since 1.52: +13 -12 lines
File MIME type: text/x-php
Added context variable to hook_menu_block_tree_alter().
1 <?php
2 // $Id: menu_block.module,v 1.52 2009/08/13 22:15:51 johnalbin Exp $
3
4 /**
5 * @file
6 * Provides configurable blocks of menu items.
7 */
8
9 // @TODO: For PHP 4 compatibility we use foreach (array_keys($array) AS $key).
10 // When PHP 5 becomes required (Drupal 7.x), use the following faster
11 // implementation: foreach ($array AS $key => &$value) {}
12
13 /**
14 * Implements hook_menu().
15 */
16 function menu_block_menu() {
17 $items['admin/build/block/add-menu-block'] = array(
18 'title' => 'Add menu block',
19 'description' => 'Add a new menu block.',
20 'access arguments' => array('administer blocks'),
21 'page callback' => 'drupal_get_form',
22 'page arguments' => array('menu_block_add_block_form'),
23 'type' => MENU_LOCAL_TASK,
24 'file' => 'menu_block.admin.inc',
25 );
26 $items['admin/build/block/delete-menu-block'] = array(
27 'title' => 'Delete menu block',
28 'access arguments' => array('administer blocks'),
29 'page callback' => 'drupal_get_form',
30 'page arguments' => array('menu_block_delete'),
31 'type' => MENU_CALLBACK,
32 'file' => 'menu_block.admin.inc',
33 );
34 return $items;
35 }
36
37 /**
38 * Implements hook_help().
39 */
40 function menu_block_help($path, $arg) {
41 switch ($path) {
42 case 'admin/build/block/configure':
43 if ($arg[4] != 'menu_block') {
44 break;
45 }
46 case 'admin/help#menu_block':
47 case 'admin/build/block':
48 case 'admin/build/block/add-menu-block':
49 module_load_include('inc', 'menu_block', 'menu_block.pages');
50 return _menu_block_help($path, $arg);
51 }
52 }
53
54 /**
55 * Implements hook_theme().
56 */
57 function menu_block_theme() {
58 return array(
59 'menu_block_wrapper' => array(
60 'template' => 'menu-block-wrapper',
61 'arguments' => array('content' => NULL, 'settings' => NULL, 'delta' => NULL),
62 ),
63 );
64 }
65
66 /**
67 * Process variables for menu-block-wrapper.tpl.php.
68 *
69 * @see menu-block-wrapper.tpl.php
70 * @see theme_menu_block_wrapper()
71 */
72 function template_preprocess_menu_block_wrapper(&$variables) {
73 $variables['classes_array'][] = 'menu-block-' . $variables['delta'];
74 $variables['classes_array'][] = 'menu-name-' . $variables['settings']['menu_name'];
75 $variables['classes_array'][] = 'parent-mlid-' . $variables['settings']['parent_mlid'];
76 $variables['classes_array'][] = 'menu-level-' . $variables['settings']['level'];
77 $variables['classes'] = check_plain(implode(' ', $variables['classes_array']));
78 $variables['template_files'][] = 'menu-block-wrapper-' . $variables['settings']['menu_name'];
79 }
80
81 /**
82 * Alters the block admin form to add delete links next to menu blocks.
83 */
84 function menu_block_form_block_admin_display_form_alter(&$form, $form_state) {
85 module_load_include('inc', 'menu_block', 'menu_block.admin');
86 _menu_block_form_block_admin_display_form_alter($form, $form_state);
87 }
88
89 /**
90 * Returns a list of menu names implemented by all modules.
91 *
92 * @return
93 * array A list of menu names and titles.
94 */
95 function menu_block_get_all_menus() {
96 static $all_menus;
97
98 if (!$all_menus) {
99 // Include book support.
100 if (module_exists('book')) {
101 module_load_include('inc', 'menu_block', 'menu_block.book');
102 }
103 // We're generalizing menu's menu_get_menus() by making it into a hook.
104 // Retrieve all the menu names provided by hook_get_menus().
105 $all_menus = module_invoke_all('get_menus');
106 asort($all_menus);
107 }
108 return $all_menus;
109 }
110
111 /**
112 * Implements hook_block().
113 */
114 function menu_block_block($op = 'list', $delta = NULL, $edit = NULL) {
115 $function = '_menu_block_block_' . $op;
116 if (function_exists($function)) {
117 return $function($delta, $edit);
118 }
119 else {
120 // "op"s besides "view" are seldom used, so we store them in a separate file.
121 module_load_include('inc', 'menu_block', 'menu_block.admin');
122 if (function_exists($function)) {
123 return $function($delta, $edit);
124 }
125 }
126 }
127
128 /**
129 * Returns the 'view' $op info for hook_block().
130 *
131 * @param $delta
132 * string The name of the block to render.
133 */
134 function _menu_block_block_view($delta) {
135 $data = array();
136
137 // Get the block configuration options.
138 list($menu_name, $parent_mlid) = split(':', variable_get("menu_block_{$delta}_parent", 'primary-links:0'));
139 $level = variable_get("menu_block_{$delta}_level", 1);
140 $follow = variable_get("menu_block_{$delta}_follow", 0);
141 $depth = variable_get("menu_block_{$delta}_depth", 0);
142 $expanded = variable_get("menu_block_{$delta}_expanded", 0);
143 $sort = variable_get("menu_block_{$delta}_sort", 0);
144 $context = array(
145 'delta' => $delta,
146 'menu_name' => $menu_name,
147 'parent_mlid' => $parent_mlid,
148 'level' => $level,
149 'follow' => $follow,
150 'depth' => $depth,
151 'expanded' => $expanded,
152 'sort' => $sort,
153 );
154
155 // Get the default block name
156 $menu_names = menu_block_get_all_menus();
157 menu_block_set_title(t($menu_names[$menu_name]), $delta);
158
159 if ($expanded || $parent_mlid) {
160 // Get the full, un-pruned tree.
161 $tree = menu_tree_all_data($menu_name);
162 // And add the active trail data back to the full tree.
163 menu_tree_add_active_path($tree);
164 }
165 else {
166 // Get the tree pruned for just the active trail.
167 $tree = menu_tree_page_data($menu_name);
168 }
169
170 // Allow other modules to alter the tree before we begin operations on it.
171 drupal_alter('menu_block_tree', $tree, $context);
172
173 // Localize the tree.
174 if (module_exists('i18nmenu')) {
175 i18nmenu_localize_tree($tree);
176 }
177
178 // Prune the tree along the active trail to the specified level.
179 if ($level > 1 || $parent_mlid) {
180 if ($parent_mlid) {
181 $parent_item = menu_link_load($parent_mlid);
182 menu_block_set_title($parent_item);
183 menu_tree_prune_tree($tree, $level, $parent_item);
184 }
185 else {
186 menu_tree_prune_tree($tree, $level);
187 }
188 }
189
190 // Prune the tree to the active menu item.
191 if ($follow) {
192 menu_tree_prune_active_tree($tree, $follow);
193 }
194
195 // If the menu-item-based tree is not "expanded", trim the tree to the active path.
196 if ($parent_mlid && !$expanded) {
197 menu_tree_trim_active_path($tree);
198 }
199
200 // Trim the branches that extend beyond the specified depth.
201 if ($depth > 0) {
202 menu_tree_depth_trim($tree, $depth);
203 }
204
205 // Sort the active path to the top of the tree.
206 if ($sort) {
207 menu_tree_sort_active_path($tree);
208 }
209
210 // Render the tree.
211 $data['subject'] = menu_block_get_title();
212 $data['content'] = menu_block_tree_output($tree);
213 if ($data['content']) {
214 $data['content'] = theme('menu_block_wrapper', $data['content'], $context, $delta);
215 }
216
217 return $data;
218 }
219
220 /**
221 * Sets the menu item to use for the block title.
222 */
223 function menu_block_get_title() {
224 return menu_block_set_title();
225 }
226
227 /**
228 * Sets the menu item to use for the block title.
229 */
230 function menu_block_set_title($item = NULL, $delta = NULL) {
231 static $block_delta;
232 static $menu_item;
233
234 // Save block delta so we can render the title later.
235 if (!is_null($delta)) {
236 $block_delta = $delta;
237 $menu_item = $item;
238 return;
239 }
240
241 // Save the menu item and immediately return.
242 if (!is_null($item)) {
243 $menu_item = $item;
244 return;
245 }
246
247 // The block title is a menu title, a normal string.
248 if (is_string($menu_item)) {
249 $title = $menu_item;
250 }
251 // The block title is a menu item with a link.
252 elseif (variable_get("menu_block_{$block_delta}_title_link", 0)) {
253 if (!empty($menu_item['localized_options']['attributes']['class'])) {
254 $menu_item['localized_options']['attributes']['class'] .= ' active-trail';
255 }
256 else {
257 $menu_item['localized_options']['attributes']['class'] = 'active-trail';
258 }
259 $title = theme('menu_item_link', $menu_item);
260 }
261 // The block title is a menu item.
262 else {
263 $title = $menu_item['title'];
264 }
265 return $title;
266 }
267
268 /**
269 * Add the active trail indicators into the tree.
270 *
271 * The data returned by menu_tree_page_data() has link['in_active_trail'] set to
272 * TRUE for each menu item in the active trail. The data returned from
273 * menu_tree_all_data() does not contain the active trail indicators. This is a
274 * helper function that adds it back in.
275 *
276 * @param $tree
277 * array The menu tree to prune.
278 * @return
279 * void
280 */
281 function menu_tree_add_active_path(&$tree) {
282 // Grab any menu item to find the menu_name for this tree.
283 $menu_item = current($tree);
284 $tree_with_trail = menu_tree_page_data($menu_item['link']['menu_name']);
285
286 // To traverse the original tree down the active trail, we use a pointer.
287 $subtree_pointer =& $tree;
288
289 // Find each key in the active trail.
290 while ($tree_with_trail) {
291 foreach (array_keys($tree_with_trail) AS $key) {
292 if ($tree_with_trail[$key]['link']['in_active_trail']) {
293 // Set the active trail info in the original tree.
294 $subtree_pointer[$key]['link']['in_active_trail'] = TRUE;
295 // Continue in the subtree, if it exists.
296 $tree_with_trail =& $tree_with_trail[$key]['below'];
297 $subtree_pointer =& $subtree_pointer[$key]['below'];
298 break;
299 }
300 else {
301 unset($tree_with_trail[$key]);
302 }
303 }
304 }
305 }
306
307 /**
308 * Trim everything but the active trail in the tree.
309 *
310 * @param $tree
311 * array The menu tree to trim.
312 * @return
313 * void
314 */
315 function menu_tree_trim_active_path(&$tree) {
316 // To traverse the original tree down the active trail, we use a pointer.
317 $current_level =& $tree;
318
319 // Traverse the tree along the active trail.
320 do {
321 $next_level = FALSE;
322 foreach (array_keys($current_level) AS $key) {
323 if ($current_level[$key]['link']['in_active_trail'] && $current_level[$key]['below']) {
324 // Continue in the subtree, if it exists.
325 $next_level = $key;
326 }
327 else {
328 // Trim anything not along the active trail.
329 $current_level[$key]['below'] = FALSE;
330 }
331 }
332 if ($next_level) {
333 $current_level =& $current_level[$next_level]['below'];
334 }
335 } while ($next_level);
336 }
337
338 /**
339 * Sort the active trail to the top of the tree.
340 *
341 * @param $tree
342 * array The menu tree to sort.
343 * @return
344 * void
345 */
346 function menu_tree_sort_active_path(&$tree) {
347 module_load_include('inc', 'menu_block', 'menu_block.sort');
348 _menu_tree_sort_active_path($tree);
349 }
350
351 /**
352 * Prune a tree so that it begins at the specified level.
353 *
354 * This function will follow the active menu trail to the specified level.
355 *
356 * @param $tree
357 * array The menu tree to prune.
358 * @param $level
359 * int The level of the original tree that will start the pruned tree.
360 * @param $parent_item
361 * array The menu item that should be used as the root of the tree.
362 * @return
363 * void
364 */
365 function menu_tree_prune_tree(&$tree, $level, $parent_item = FALSE) {
366 if (!empty($parent_item)) {
367 // Prune the tree along the path to the menu item.
368 for ($i = 1; $i <= MENU_MAX_DEPTH && $parent_item["p$i"] != '0'; $i++) {
369 $plid = $parent_item["p$i"];
370 $found_active_trail = FALSE;
371 // Examine each element at this level for the ancestor.
372 foreach (array_keys($tree) AS $key) {
373 if ($tree[$key]['link']['mlid'] == $plid) {
374 // Prune the tree to the children of this ancestor.
375 $tree = $tree[$key]['below'] ? $tree[$key]['below'] : array();
376 $found_active_trail = TRUE;
377 break;
378 }
379 }
380 // If we don't find the ancestor, bail out.
381 if (!$found_active_trail) {
382 $tree = array();
383 break;
384 }
385 }
386 }
387
388 // Trim the upper levels down to the one desired.
389 for ($i = 1; $i < $level; $i++) {
390 $found_active_trail = FALSE;
391 // Examine each element at this level for the active trail.
392 foreach (array_keys($tree) AS $key) {
393 if ($tree[$key]['link']['in_active_trail']) {
394 // Get the title for the pruned tree.
395 menu_block_set_title($tree[$key]['link']);
396 // Prune the tree to the children of the item in the active trail.
397 $tree = $tree[$key]['below'] ? $tree[$key]['below'] : array();
398 $found_active_trail = TRUE;
399 break;
400 }
401 }
402 // If we don't find the active trail, the active item isn't in the tree we want.
403 if (!$found_active_trail) {
404 $tree = array();
405 break;
406 }
407 }
408 }
409
410 /**
411 * Prune a tree so that it begins at the active menu item.
412 *
413 * @param $tree
414 * array The menu tree to prune.
415 * @param $level
416 * string The level which the tree will be pruned to: 'active' or 'child'.
417 * @return
418 * void
419 */
420 function menu_tree_prune_active_tree(&$tree, $level) {
421 module_load_include('inc', 'menu_block', 'menu_block.follow');
422 _menu_tree_prune_active_tree($tree, $level);
423 }
424
425 /**
426 * Prune a tree so it does not extend beyond the specified depth limit.
427 *
428 * @param $tree
429 * array The menu tree to prune.
430 * @param $depth_limit
431 * int The maximum depth of the returned tree; must be a positive integer.
432 * @return
433 * void
434 */
435 function menu_tree_depth_trim(&$tree, $depth_limit) {
436 // Prevent invalid input from returning a trimmed tree.
437 if ($depth_limit < 1) { return; }
438
439 // Examine each element at this level to find any possible children.
440 foreach (array_keys($tree) AS $key) {
441 if ($tree[$key]['below']) {
442 if ($depth_limit > 1) {
443 menu_tree_depth_trim($tree[$key]['below'], $depth_limit-1);
444 }
445 else {
446 // Remove the children items.
447 $tree[$key]['below'] = FALSE;
448 }
449 }
450 if ($depth_limit == 1 && $tree[$key]['link']['has_children']) {
451 // Turn off the menu styling that shows there were children.
452 $tree[$key]['link']['has_children'] = FALSE;
453 $tree[$key]['link']['leaf_has_children'] = TRUE;
454 }
455 }
456 }
457
458 /**
459 * Returns a rendered menu tree.
460 *
461 * This is an optimized version of menu_tree_output() with additional classes
462 * added to the output.
463 *
464 * @param $tree
465 * array A data structure representing the tree as returned from menu_tree_data.
466 * @return
467 * string The rendered HTML of that data structure.
468 */
469 function menu_block_tree_output(&$tree) {
470 $output = '';
471 $items = array();
472
473 // Pull out just the menu items we are going to render so that we
474 // get an accurate count for the first/last classes.
475 foreach (array_keys($tree) as $key) {
476 if (!$tree[$key]['link']['hidden']) {
477 $items[$key] = array(
478 'link' => $tree[$key]['link'],
479 // To prevent copying the entire child array, we render it first.
480 'below' => !empty($tree[$key]['below']) ? menu_block_tree_output($tree[$key]['below']) : '',
481 );
482 }
483 }
484
485 $num_items = count($items);
486 $i = 1;
487 foreach (array_keys($items) as $key) {
488 // Render the link.
489 $link_class = array();
490 if (!empty($items[$key]['link']['localized_options']['attributes']['class'])) {
491 $link_class[] = $items[$key]['link']['localized_options']['attributes']['class'];
492 }
493 if ($items[$key]['link']['in_active_trail']) {
494 $link_class[] = 'active-trail';
495 }
496 if (!empty($link_class)) {
497 $items[$key]['link']['localized_options']['attributes']['class'] = implode(' ', $link_class);
498 }
499 $link = theme('menu_item_link', $items[$key]['link']);
500 // Render the menu item.
501 $extra_class = array();
502 if ($i == 1) {
503 $extra_class[] = 'first';
504 }
505 if ($i == $num_items) {
506 $extra_class[] = 'last';
507 }
508 $extra_class[] = 'menu-mlid-' . $items[$key]['link']['mlid'];
509 if (!empty($items[$key]['link']['leaf_has_children'])) {
510 $extra_class[] = 'has-children';
511 }
512 if ($items[$key]['link']['href'] == $_GET['q'] || ($items[$key]['link']['href'] == '<front>' && drupal_is_front_page())) {
513 $extra_class[] = 'active';
514 }
515 $extra_class = !empty($extra_class) ? implode(' ', $extra_class) : NULL;
516 $output .= theme('menu_item', $link, $items[$key]['link']['has_children'], $items[$key]['below'], $items[$key]['link']['in_active_trail'], $extra_class);
517 $i++;
518 }
519 return $output ? theme('menu_tree', $output) : '';
520 }

  ViewVC Help
Powered by ViewVC 1.1.2