Creating a Drupal fisheye menu block
This module is meant to give the ability create a mac style fisheye menu using interface see the sample demo
It uses the interface jQuery library you can see a demo of that here. While this could also be done through the template I wanted a module to allow for admin settings with future better image choices for links and the ability to drop into a site with little work.
The module simply allows a drupal menu to be selected for a fisheye menu which may then be assigned to a block.
It currently allows either a top or bottom menu Both the bottom and top version are loaded on this page.
Version 0.1 - test carefully
Download here
fisheyemenu.info
; $Id$
name = Fish Eye Menu
description = A fish eye style menu
core = 6.x
fisheyemenu.module
<?php
/**
* Display help and module information
* @param path which path of the site we're displaying help
* @param arg array that holds the current path as would be returned from arg() function
* @return help text for the path
*/
function fisheyemenu_help($path, $arg) {
$output = ''; //declare your output variable
switch ($path) {
case "admin/help#fisheyemenu":
$output = '<p>'. t("Outputs a menu in fish eye style") .'</p>';
break;
}
return $output;
} // function fisheye_help
/**
* Valid permissions for this module
* @return array An array of valid permissions for the onthisdate module
* access fisheyemenu not currently used
*/
function fisheyemenu_perm() {
return array('access fisheyemenu','administer fisheyemenu');
} // function onthisdate_perm()
/**
* Generate HTML for the fisheye block
* @param op list for block admin page
* @param delta
* @returns block HTML
*/
function fisheyemenu_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == "list") {
// Generate listing of blocks from this module, for the admin/block page
$block = array();
//todo: add non floating postitioned menu to stay in block assigned
$block[0]["info"] = t('Bottom Fisheye Menu');//menu on bottom of page
$block[1]["info"] = t('Top Fisheye Menu');//menu on top of page
return $block;
}
else if ($op == 'view') {
$menu_name = variable_get('fish_eye_menu','none');//get menu to use for fisheye
$output = '';
//make sure a menu has been selected
if ($menu_name != 'none'){
//set up image path todo: allow admin to choose base path
$image_base = base_path() . drupal_get_path('module', 'fisheyemenu') . '/images/';
$menu = menu_navigation_links($menu_name);// load the menu
//maybe add ability to not load css based on admin setting
drupal_add_css(drupal_get_path('module', 'fisheyemenu') .'/css/fisheyemenu.css', 'module', 'all', FALSE);
// load interface todo: add if Drupal.jsEnabled else
drupal_add_js(drupal_get_path('module', 'fisheyemenu') .'/interface/interface.js');
// todo: only add function for which menutype is being used currently covers both to bottom seems to work
drupal_add_js("$(document).ready(
function()
{
$('#fisheyeTop').Fisheye(
{
maxWidth: 50,
items: 'a',
itemsText: 'span',
container: '.fisheyeContainterTop',
itemWidth: 40,
proximity: 90,
halign : 'center'
}
)
$('#fisheyeBottom').Fisheye(
{
maxWidth: 60,
items: 'a',
itemsText: 'span',
container: '.fisheyeContainterBottom',
itemWidth: 40,
proximity: 80,
alignment : 'left',
valign: 'bottom',
halign : 'center'
}
)
}
);
", 'inline', 'header');
$divId = ($delta == 0) ? 'fisheyeBottom' : 'fisheyeTop'; //set main div id based on bottom:0 or top:1
$container = ($delta ==0) ? 'fisheyeContainterBottom' : 'fisheyeContainterTop';//set conainer class based on bottom:0 or top:1
$output = '<div id="' . $divId . '" class="fisheye">';
$output .= ' <div class="' . $container . '">';
$linkclass= ($delta == 0) ? 'fisheyeItemBottom' : 'fisheyeItem';//set main link class based on bottom:0 or top:1
foreach ($menu as $key=>$link){
$linkhref = $link['href'];
if ($linkhref == '<front>'){$linkhref = base_path();}
$image_path = $image_base. str_replace(" ","-",strtolower($link['title'])).'.png';//current image is expected to be the link title lowercase with - dashes for spaces
switch($delta){
case 0:
//bottom style fisheye menu
$output .= ' <a title="' . $link['attributes']['title'] .'" class="' . $linkclass . '" href="' . $linkhref .'"><span>' . $link['title'] . '</span><img src="' . $image_path . '" width="30" /></a>';
break;
case 1:
//top style fisheye menu
$output .= ' <a title="' . $link['attributes']['title'] .'" class="' . $linkclass . '" href="' . $linkhref .'"><img src="' . $image_path .'" width="30" /><span>' . $link['title'] . '</span></a>';
break;
}
}
$output .= '</div></div>';
}
$block['subject'] = '';
$block['content'] = $output;
return $block;
}
} // function fisheyemenu_block
/**
* fisheyemenu menu
*/
function fisheyemenu_menu(){
$items = array();
$items['admin/settings/fisheyemenu'] = array(
'title' => 'Fisheye Menu Configuraiton',
'description' => 'Configure Fisheye Menu',
'page callback' => 'fisheye_admin_entry',
'access arguments' => array('administer fisheyemenu'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
} // function fisheyemenu_menu
function fisheye_admin_entry(){
//The main admin entry page set menu see menu items for testing / image names
$path = base_path() . drupal_get_path('module', 'fisheyemenu');
$output = '';
$output = drupal_get_form('settingsmenuname_form');//show the settings form todo: add other options change name to fisheyemenu_settings_form
$menu_name = $menu_name = variable_get('fish_eye_menu','none');
if ($menu_name != 'none'){
//if a menu has been chosen display the menu info
$image_base = $path . '/images/';
$block = module_invoke('fisheyemenu', 'block', 'view',0);//displaying list of links and displaying bottom version of fisheye for verification
$menu = menu_navigation_links($menu_name);//load the menu
$output .= '<h3>' . $menu_name . '</h3>';
$output .= '<ul style="margin-bottom:80px">';
$output .= '<li style="color:#0f0">href - Title - image path - image</li>';
foreach ($menu as $key=>$link){
//loop through menu items display link items info
$image_path = $image_base . str_replace(" ","-",strtolower($link['title'])).'.png';//todo add check to see if image exists if not display a message of what image name should be uploaded
$output .= '<li>' . check_plain($link['href'] . ' - ' . $link['title']) . ' - Image: ' . $image_path . ' - <img src="' . $image_path .'" width="30" /></li>';
}
$output .= '</ul>' . $block['content'];
}
else{
$output .= '<strong>No Menu Selected</strong>';
}
return $output;
}
function settingsmenuname_form(){
$form = array();
$menus = menu_get_names();
$form_menus = array();
foreach($menus as $menu){
$form_menus[$menu] = $menu;
}
$form['menu_name'] = array(
'#type' => 'select',
'#title' => t('Menu for Fisheye'),
'#default_value' => variable_get('fish_eye_menu',''),
'#options' => $form_menus,
'#description' => t('The menu you wish to use for the Fisheye Menu'),
);
$form['submit'] = array('#weight'=>100,'#type' => 'submit', '#value' => t('Set'));
return $form;
}
function settingsmenuname_form_validate($form, &$form_state) {
//not really needed as its a select list but just in case
if (!isset($form_state['values']['menu_name'])){
form_set_error('menu_name', t('A Menu is required'));
}
}
function settingsmenuname_form_submit($form, &$form_states){
$menu_name = $form_states['values']['menu_name'];
variable_set('fish_eye_menu', $menu_name);
drupal_set_message(t('Fisheye Menu Set to ' . $menu_name));
}
?>

Comments
Thanks
I would like to do more in Drupal and finish up some of the modules I've done into a format I think would be worthy of submitting but most of the work I do is for clients that want something so specific that they'd need put out in more of a generalized format so that people could use them in more ways.
Awesome! :)
hey matt!
your module is rocks! with a few improvements (i.e. path to the folder for pictures via admin settings page and theme function for output overriding) this module would be even perfect. :)
Why don't you contribute it on drupal.org? There is also the dock module but it has still some bugs, isn't flexible as your module and the developer won't do any active development on it so it seem to be deprecated. I'm sure a lot of people would use it and appreciate your contribution.
thanks again and cheers! :)
stefan
Post new comment