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

Contents of /contributions/modules/nice_menus/nice_menus.module

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


Revision 1.62 - (show annotations) (download) (as text)
Wed May 6 15:33:49 2009 UTC (6 months, 3 weeks ago) by add1sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.61: +2 -2 lines
File MIME type: text/x-php
#360064: Bug found by Linxor, remove www from the path class to avoid accidental browser links.
1 <?php
2 // $Id: nice_menus.module,v 1.61 2009/03/25 12:57:50 add1sun Exp $
3
4 /**
5 * @file
6 * Module to enable CSS dropdown and flyout menus.
7 *
8 * Maintainer: Addison Berry (add1sun)
9 * Originally written by Jake Gordon (jakeg)
10 */
11
12 /**
13 * Implementation of hook_help().
14 */
15 function nice_menus_help($path, $arg) {
16 $output = '';
17 switch ($path) {
18 case 'admin/settings/modules#description':
19 $output .= t('Make drop down/flyout CSS menus for site and admin menus.');
20 break;
21 case 'admin/settings/nice_menus':
22 $output .= t('<p>This is a simple module that enables the site to have drop down/flyout CSS menus for site and admin navigation.</p><p>Remember to activate and configure the menu blocks in !link</p>', array('!link' => l('admin/build/block', 'admin/build/block')));
23 break;
24 }
25 return $output;
26 }
27
28 /**
29 * Implementation of hook_form_alter().
30 */
31 function nice_menus_form_alter(&$form, $form_state, $form_id) {
32 switch ($form_id) {
33 case 'system_theme_settings':
34
35 // This is a global setting, so only insert the field
36 // on the global settings page.
37 if (arg(4)) {
38 return;
39 }
40
41 // Have to add a custom submit handler since this form doesn't use
42 // the standard system submit handler.
43 $form['#submit'][] = 'nice_menus_system_theme_settings_submit';
44
45 // Add global theme setting for a custom CSS file.
46 $form['nice_menus_custom_css'] = array(
47 '#type' => 'textfield',
48 '#title' => t('Path to custom Nice menus CSS file'),
49 '#description' => t('To override the default Nice menus CSS layout, enter the path to your custom CSS file. It should be a relative path from the root of your Drupal install (e.g. sites/all/themes/example/mymenu.css).'),
50 '#default_value' => variable_get('nice_menus_custom_css', ''),
51 // Field appears below submit buttons without this -- yucky.
52 '#weight' => 0,
53 );
54 break;
55 }
56 }
57
58 /**
59 * Records the Nice menu custom CSS file per theme.
60 */
61 function nice_menus_system_theme_settings_submit($form, &$form_state) {
62 variable_set('nice_menus_custom_css', $form_state['values']['nice_menus_custom_css']);
63 }
64
65 /**
66 * Implementation of hook_menu().
67 */
68 function nice_menus_menu() {
69 $items['admin/settings/nice_menus'] = array(
70 'title' => 'Nice menus',
71 'description' => 'Configure Nice menus.',
72 'page callback' => 'drupal_get_form',
73 'page arguments' => array('nice_menus_admin_settings'),
74 'access arguments' => array('administer site configuration'),
75 'type' => MENU_NORMAL_ITEM,
76 );
77
78 return $items;
79 }
80
81
82 /**
83 * Settings form as implemented by hook_menu
84 */
85 function nice_menus_admin_settings() {
86 $form['nice_menus_number'] = array(
87 '#type' => 'textfield',
88 '#description' => t('The total number of independent Nice menus blocks you want. Enter a number between 0 and 99. If you set this to 0, you will have no blocks created but you can still use the Nice menus theme functions directly in your theme.'),
89 '#default_value' => variable_get('nice_menus_number', '2'),
90 '#size' => 2,
91 );
92 $form['nice_menus_js'] = array(
93 '#type' => 'checkbox',
94 '#title' => t('Use JavaScript'),
95 '#description' => t('This will add Superfish Jquery to Nice menus. This is required for Nice menus to work properly in Internet Explorer.'),
96 '#default_value' => variable_get('nice_menus_js', 1),
97 );
98 $form['nice_menus_sf_options'] = array(
99 '#type' => 'fieldset',
100 '#title' => t('Advanced: Superfish options'),
101 '#description' => t('You can change the default Superfish options by filling out the desired values here. These only take effect if the Use JavaScript box above is checked.'),
102 '#collapsible' => TRUE,
103 '#collapsed' => TRUE,
104 );
105 $form['nice_menus_sf_options']['nice_menus_sf_delay'] = array(
106 '#type' => 'textfield',
107 '#title' => t('Mouse delay'),
108 '#description' => t('The delay in milliseconds that the mouse can remain outside a submenu without it closing.'),
109 '#default_value' => variable_get('nice_menus_sf_delay', 800),
110 '#size' => 5,
111 );
112 $form['nice_menus_sf_options']['nice_menus_sf_speed'] = array(
113 '#type' => 'select',
114 '#title' => t('Animation speed'),
115 '#multiple' => FALSE,
116 '#description' => t('Speed of the menu open/close animation.'),
117 '#options' => array(t('slow'), t('normal'), t('fast')),
118 '#default_value' => variable_get('nice_menus_sf_speed', 1),
119 );
120
121 // Custom validation to make sure the user is entering numbers.
122 $form['#validate'][] = 'nice_menus_settings_validate';
123
124 return system_settings_form($form);
125 }
126
127 /**
128 * Custom validation for the settings form.
129 */
130 function nice_menus_settings_validate($form, &$form_state) {
131 $number = $form_state['values']['nice_menus_number'];
132 // Check to make sure it is a number and that is a maximum of 2 digits.
133 if (!is_numeric($number) || strlen($number) > 2) {
134 form_set_error('nice_menus_number', t('You must enter a number from 0 to 99.'));
135 }
136 }
137
138 /**
139 * Implementation of hook_block().
140 */
141 function nice_menus_block($op = 'list', $delta = 0, $edit = array()) {
142 global $user;
143
144 switch ($op) {
145 case 'list':
146 for ($i = 1; $i <= variable_get('nice_menus_number', '2'); $i++) {
147 $blocks[$i]['info'] = variable_get('nice_menus_name_'. $i, 'Nice menu '. $i) .' (Nice menu)';
148 // We have too many things changing per user, per page to cache.
149 $blocks[$i]['cache'] = BLOCK_NO_CACHE;
150 }
151 return $blocks;
152 break;
153
154 case 'configure':
155 $form['nice_menus_name_'. $delta] = array(
156 '#type' => 'textfield',
157 '#title' => t('Menu Name'),
158 '#default_value' => variable_get('nice_menus_name_'. $delta, 'Nice menu '. $delta),
159 );
160 $form['nice_menus_menu_'. $delta] = array(
161 '#type' => 'select',
162 '#title' => t('Menu Parent'),
163 '#description' => t('The menu parent from which to show a Nice menu.'),
164 '#default_value' => variable_get('nice_menus_menu_'. $delta, 'navigation:0'),
165 '#options' => menu_parent_options(menu_get_menus(), 0),
166 );
167 $form['nice_menus_depth_'. $delta] = array(
168 '#type' => 'select',
169 '#title' => t('Menu Depth'),
170 '#description' => t('The depth of the menu, i.e. the number of child levels starting with the parent selected above. Leave set to -1 to display all children and use 0 to display no children.'),
171 '#default_value' => variable_get('nice_menus_depth_'. $delta, -1),
172 '#options' => drupal_map_assoc(range(-1, 5))
173 );
174 $form['nice_menus_type_'. $delta] = array(
175 '#type' => 'select',
176 '#title' => t('Menu Style'),
177 '#description' => t('right: menu items are listed on top of each other and expand to the right') .'<br />'. t('left: menu items are listed on top of each other and expand to the left') .'<br />'. t('down: menu items are listed side by side and expand down'),
178 '#default_value' => variable_get('nice_menus_type_'. $delta, 'right'),
179 '#options' => drupal_map_assoc(array('right', 'left', 'down')),
180 );
181 return $form;
182 break;
183
184 case 'save':
185 variable_set('nice_menus_name_'. $delta, $edit['nice_menus_name_'. $delta]);
186 variable_set('nice_menus_menu_'. $delta, $edit['nice_menus_menu_'. $delta]);
187 variable_set('nice_menus_depth_'. $delta, $edit['nice_menus_depth_'. $delta]);
188 variable_set('nice_menus_type_'. $delta, $edit['nice_menus_type_'. $delta]);
189 break;
190
191 case 'view':
192 // Build the Nice menu for the block.
193 list($menu_name, $mlid) = explode(':', variable_get('nice_menus_menu_'. $delta, 'navigation:0'));
194 $direction = variable_get('nice_menus_type_'. $delta, 'right');
195 $depth = variable_get('nice_menus_depth_'. $delta, '-1');
196 if ($output = theme('nice_menus', $delta, $menu_name, $mlid, $direction, $depth)) {
197 $block['content'] = $output['content'];
198 if (variable_get('nice_menus_type_'. $delta, 'right') == 'down') {
199 $class = 'nice-menu-hide-title';
200 }
201 else {
202 $class = 'nice-menu-show-title';
203 }
204 // If we're building the navigation block
205 // use the same block title logic as menu module.
206 if ($output['subject'] == t('Navigation') && $user->uid) {
207 $subject = $user->name;
208 }
209 else {
210 $subject = $output['subject'];
211 }
212 $block['subject'] = '<span class="'. $class .'">'. check_plain($subject) .'</span>';
213 }
214 else {
215 $block['content'] = FALSE;
216 }
217 return $block;
218 break;
219 }
220 }
221
222 /**
223 * Implementation of hook_theme().
224 */
225 function nice_menus_theme() {
226 return array(
227 'nice_menus_tree' => array(
228 'arguments' => array('menu_name' => NULL, 'mlid' => NULL, 'depth' => -1, 'menu' => NULL),
229 ),
230 'nice_menus_build' => array(
231 'arguments' => array('menu' => NULL, 'depth' => -1, 'trail' => NULL),
232 ),
233 'nice_menus' => array(
234 'arguments' => array('id' => NULL, 'menu_name' => NULL, 'mlid' => NULL, 'direction' => 'right', 'depth' => -1, 'menu' => NULL),
235 ),
236 'nice_menus_primary_links' => array(
237 'arguments' => array('direction' => 'down', 'depth' => -1, 'menu' => NULL),
238 ),
239 'nice_menus_secondary_links' => array(
240 'arguments' => array('direction' => 'down', 'depth' => -1, 'menu' => NULL),
241 ),
242 // Deprecated theme functions that will be removed in 7.x.
243 'nice_menu_tree' => array(
244 'arguments' => array('menu_name' => NULL, 'mlid' => NULL, 'depth' => -1, 'menu' => NULL),
245 ),
246 'nice_menu_build' => array(
247 'arguments' => array('menu' => NULL, 'depth' => -1, 'trail' => NULL),
248 ),
249 'nice_menu' => array(
250 'arguments' => array('id' => NULL, 'menu_name' => NULL, 'mlid' => NULL, 'direction' => 'right', 'depth' => -1, 'menu' => NULL),
251 ),
252 'nice_menu_primary_links' => array(
253 'arguments' => array('direction' => 'down', 'depth' => -1, 'menu' => NULL),
254 ),
255 );
256 }
257
258 /**
259 * Implementation of hook_init().
260 *
261 * We are adding the JavaScript and CSS here rather than theme_nice_menu
262 * because when block caching is enabled none of it would get fired
263 * and the menus are unstyled.
264 */
265 function nice_menus_init() {
266 // Add Superfish JavaScript, if enabled.
267 if (variable_get('nice_menus_js', 1) == 1) {
268 // The script, from http://users.tpg.com.au/j_birch/plugins/superfish.
269 drupal_add_js(drupal_get_path('module', 'nice_menus') .'/superfish/js/superfish.js');
270 // Add the Superfish options variables.
271 drupal_add_js(array(
272 'nice_menus_options' => array(
273 'delay' => variable_get('nice_menus_sf_delay', 800),
274 'speed' => variable_get('nice_menus_sf_speed', 1),
275 )),'setting');
276 // Add the bgIframe plugin.
277 drupal_add_js(drupal_get_path('module', 'nice_menus') .'/superfish/js/jquery.bgiframe.min.js');
278 // The Nice menus implementation.
279 drupal_add_js(drupal_get_path('module', 'nice_menus') .'/nice_menus.js');
280 }
281
282 // Add main CSS functionality.
283 drupal_add_css(drupal_get_path('module', 'nice_menus') .'/nice_menus.css');
284 // Add custom CSS layout if specified.
285 if ($custom = variable_get('nice_menus_custom_css', '')) {
286 drupal_add_css($custom);
287 }
288 // Fall back to default layout.
289 else {
290 drupal_add_css(drupal_get_path('module', 'nice_menus') .'/nice_menus_default.css');
291 }
292 }
293
294 /**
295 * Builds the active trail from the page's menu data.
296 *
297 * @param $page_menu
298 * The menu data for a page.
299 * @return
300 * An array of parent menu item ids.
301 */
302 function nice_menus_build_page_trail($page_menu) {
303 $trail = array();
304 foreach ($page_menu as $item) {
305 if ($item['link']['in_active_trail']) {
306 $trail[] = $item['link']['mlid'];
307 }
308 if ($item['below']) {
309 $trail = array_merge($trail, nice_menus_build_page_trail($item['below']));
310 }
311 }
312 return $trail;
313 }
314
315 /**
316 * Builds the final Nice menu.
317 *
318 * @param $menu_name
319 * The top-level menu name that contains the menu to use (e.g. navigation
320 * or primary-links) for Drupal menus. For custom $menus this is just the
321 * name for menu display.
322 * @param $mlid
323 * The menu ID from which to start building the items, i.e. the parent
324 * of the displayed menu.
325 * @param $depth
326 * The number of children levels to display. Use -1 to display all children
327 * and use 0 to display no children.
328 * @param $menu
329 * Optional. A custom menu array to use for theming -- it should have
330 * the same structure as that returned by menu_tree_all_data().
331 * @return
332 * An HTML string of properly nested Nice menu lists.
333 */
334 function theme_nice_menus_tree($menu_name, $mlid = NULL, $depth = -1, $menu = NULL) {
335 // Load the full menu array.
336 $menu = isset($menu) ? $menu : menu_tree_all_data($menu_name);
337
338 if (isset($menu)) {
339 $page_menu = menu_tree_page_data($menu_name);
340 $trail = nice_menus_build_page_trail($page_menu);
341 unset($page_menu);
342 }
343
344 // Allow i18n module to translate strings where available.
345 if(module_exists('i18nmenu')) {
346 i18nmenu_localize_tree($menu);
347 }
348
349 // For custom $menus and menus built all the way from the top-level we
350 // don't need to "create" the specific sub-menu and we need to get the title
351 // from the $menu_name since there is no "parent item" array.
352
353 // Create the specific menu if we have a mlid.
354 if (!empty($mlid)) {
355 // Load the parent menu item.
356 $item = menu_link_load($mlid);
357 $title = check_plain($item['title']);
358 // The depth for our parent item.
359 $parent_depth = $item['depth'];
360
361 // Narrow down the full menu to the specific sub-tree we need.
362 for ($p = 1; $p < 10; $p++) {
363 if ($sub_mlid = $item["p$p"]) {
364 $subitem = menu_link_load($sub_mlid);
365 // Menu sets these ghetto-ass keys in _menu_tree_check_access().
366 $menu = $menu[(50000 + $subitem['weight']) .' '. $subitem['title'] .' '. $subitem['mlid']]['below'];
367 }
368 }
369 }
370 // Otherwise just set a title and move on.
371 else {
372 // Get the title from the DB since we don't have it in the $menu.
373 $result = db_result(db_query("SELECT title FROM {menu_custom} WHERE menu_name = '%s'", $menu_name));
374 $title = check_plain($result);
375 }
376
377 $output['content'] = '';
378 $output['subject'] = $title;
379
380 if ($menu) {
381 // Set the total menu depth counting from this parent if we need it.
382 $depth = ($depth > 0) ? ($parent_depth + $depth) : $depth;
383 $output['content'] .= theme('nice_menus_build', $menu, $depth, $trail);
384 }
385
386 return $output;
387 }
388
389 /**
390 * Helper function that builds the nested lists of a Nice menu.
391 *
392 * @param $menu
393 * Menu array from which to build the nested lists.
394 * @param $depth
395 * The number of children levels to display. Use -1 to display all children
396 * and use 0 to display no children.
397 * @param $trail
398 * An array of parent menu items.
399 */
400 function theme_nice_menus_build($menu, $depth = -1, $trail = NULL) {
401 $output = '';
402 foreach ($menu as $menu_item) {
403 $mlid = $menu_item['link']['mlid'];
404 // Check to see if it is a visible menu item.
405 if ($menu_item['link']['hidden'] == 0) {
406 // Build class name based on menu path
407 // e.g. to give each menu item individual style.
408 // Strip funny symbols.
409 $clean_path = str_replace(array('http://', 'www', '<', '>', '&', '=', '?', ':'), '', $menu_item['link']['href']);
410 // Convert slashes to dashes.
411 $clean_path = str_replace('/', '-', $clean_path);
412 $class = 'menu-path-'. $clean_path;
413 if ($trail && in_array($mlid, $trail)) {
414 $class .= ' active-trail';
415 }
416 // If it has children build a nice little tree under it.
417 if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below'])) && $depth != 0) {
418 // Keep passing children into the function 'til we get them all.
419 $children = theme('nice_menus_build', $menu_item['below'], $depth, $trail);
420 // Set the class to parent only of children are displayed.
421 $parent_class = $children ? 'menuparent ' : '';
422 $output .= '<li id="menu-'. $mlid .'" class="'. $parent_class . $class .'">'. theme('menu_item_link', $menu_item['link']);
423 // Check our depth parameters.
424 if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
425 // Build the child UL only if children are displayed for the user.
426 if ($children) {
427 $output .= '<ul>';
428 $output .= $children;
429 $output .= "</ul>\n";
430 }
431 }
432 $output .= "</li>\n";
433 }
434 else {
435 $output .= '<li id="menu-'. $mlid .'" class="'. $class .'">'. theme('menu_item_link', $menu_item['link']) .'</li>'."\n";
436 }
437 }
438 }
439 return $output;
440 }
441
442 /**
443 * Theme function to allow any menu tree to be themed as a Nice menu.
444 *
445 * @param $id
446 * The Nice menu ID.
447 * @param $menu_name
448 * The top parent menu name from which to build the full menu.
449 * @param $mlid
450 * The menu ID from which to build the displayed menu.
451 * @param $direction
452 * Optional. The direction the menu expands. Default is 'right'.
453 * @param $depth
454 * The number of children levels to display. Use -1 to display all children
455 * and use 0 to display no children.
456 * @param $menu
457 * Optional. A custom menu array to use for theming --
458 * it should have the same structure as that returned
459 * by menu_tree_all_data(). Default is the standard menu tree.
460 * @return
461 * An HTML string of Nice menu links.
462 */
463 function theme_nice_menus($id, $menu_name, $mlid, $direction = 'right', $depth = -1, $menu = NULL) {
464 $output = array();
465
466 if ($menu_tree = theme('nice_menus_tree', $menu_name, $mlid, $depth, $menu)) {
467 if ($menu_tree['content']) {
468 $output['content'] = '<ul class="nice-menu nice-menu-'. $direction .'" id="nice-menu-'. $id .'">'. $menu_tree['content'] .'</ul>'."\n";
469 $output['subject'] = $menu_tree['subject'];
470 }
471 }
472 return $output;
473 }
474
475 /**
476 * Theme primary links as Nice menus.
477 *
478 * @param $direction
479 * Optional. The direction the menu expands. Default is 'down'.
480 * @param $depth
481 * The number of children levels to display. Use -1 to display all children
482 * and use 0 to display no children.
483 * @param $menu
484 * Optional. A custom menu array to use for theming --
485 * it should have the same structure as that returned
486 * by menu_tree_all_data(). Default is the standard menu tree.
487 * @return
488 * An HTML string of Nice menu primary links.
489 */
490 function theme_nice_menus_primary_links($direction = 'down', $depth = -1, $menu = NULL) {
491 $menu_name = variable_get('menu_primary_links_source', 'primary-links');
492 $output = theme('nice_menus', 0, $menu_name, 0, $direction, $depth, $menu);
493 return $output['content'];
494 }
495
496 /**
497 * Theme secondary links as nice menus.
498 *
499 * @param $direction
500 * Optional. The direction the menu expands. Default is 'down'.
501 * @param $depth
502 * The number of children levels to display. Use -1 to display all children
503 * and use 0 to display no children.
504 * @param $menu
505 * Optional. A custom menu array to use for theming --
506 * it should have the same structure as that returned
507 * by menu_tree_all_data(). Default is the standard menu tree.
508 * @return
509 * An HTML string of nice menu secondary links.
510 */
511 function theme_nice_menus_secondary_links($direction = 'down', $depth = -1, $menu = NULL) {
512 $menu_name = variable_get('menu_secondary_links_source', 'secondary-links');
513 $output = theme('nice_menus', 0, $menu_name, 0, $direction, $depth, $menu);
514 return $output['content'];
515 }
516
517 /*********** Legacy Theme Functions that will be removed in 7.x ************/
518
519 /**
520 * DEPRECATED theme function. Please switch to theme_nice_menus_tree().
521 */
522 function theme_nice_menu_tree($menu_name, $mlid = NULL, $depth = -1, $menu = NULL) {
523 return theme('nice_menus_tree', $menu_name, $mlid = NULL, $depth = -1, $menu = NULL);
524 }
525
526 /**
527 * DEPRECATED theme function. Please switch to theme_nice_menus_build().
528 */
529 function theme_nice_menu_build($menu, $depth = -1, $trail = NULL) {
530 return theme('nice_menus_build', $menu, $depth = -1, $trail = NULL);
531 }
532
533 /**
534 * DEPRECATED theme function. Please switch to theme_nice_menus().
535 */
536 function theme_nice_menu($id, $menu_name, $mlid, $direction = 'right', $depth = -1, $menu = NULL) {
537 return theme('nice_menus', $id, $menu_name, $mlid, $direction = 'right', $depth = -1, $menu = NULL);
538 }
539
540 /**
541 * DEPRECATED theme function. Please switch to
542 * theme_nice_menus_primary_links().
543 */
544 function theme_nice_menu_primary_links($direction = 'down', $depth = -1, $menu = NULL) {
545 return theme('nice_menus_primary_links', $direction = 'down', $depth = -1, $menu = NULL);
546 }

  ViewVC Help
Powered by ViewVC 1.1.2