Revision: 31907
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at September 15, 2010 19:50 by dom111
Initial Code
Element.implement({
/**
* toParent
*
* Returns the number of nodes (or steps) to the specified elements
*
* @param string dest The CSS selector of the target element
* @param string step The CSS selector of each 'step' (optional)
* @return integer The number of steps from the current element to dest, or null on error
*/
toParent: function(dest, step) {
var cur = $(this), i = 0, max = 200;
while (i < max) {
if (!cur) {
return null;
}
if ($(cur).match(dest)) {
return i;
}
if (step) {
while (true) {
cur = $(cur).getParent();
if (!cur || $(cur).match(step) || $(cur).match(dest)) {
break;
}
}
} else {
cur = $(cur).getParent();
}
i++;
}
return null;
},
/**
* dropdownify
*
* Creates a multi-level drop-down menu using the current element as the base
*
* @param object options (optional)
* @return object The object for chaining
*/
dropdownify: function(options) {
options = $extend({
'delay': 100,
'items': 'li',
'menus': 'ul',
'onhide': null,
'onshow': null,
'position': {
// level (number: 1 being top level, all others being the respective level deep): position (string: top, bottom, left, right)
1: 'bottom',
'default': 'right'
},
'timeout': 750,
'zIndex': 200
}, options || {});
// add an identifier to the root element
$(this).addClass('dropdownify-root');
$(this).getElements(options.items).each(function(el, i) {
if ($(el).getElements(options.menus).length) {
$(el).addClass('submenu dropdownify-submenu');
}
});
// returns an object to be passed to $.css() for positioning
var getPos = function(el) {
// get the deptch of the current element
var level = $(el).toParent('.dropdownify-root', options.menus);
// check the positioning options
if (typeof options.position == 'object') {
// if it's an object, check for the current depth
if (level in options.position) {
var or = options.position[level];
// or use the default
} else {
var or = options.position['default'];
}
// just use it if it's not an object
} else {
var or = options.position;
}
// if the orientation item is also an object
if (typeof or == 'object') {
// use the .v .h and .p values
var offsetV = ('v' in or) ? or.v : 0;
var offsetH = ('h' in or) ? or.h : 0;
or = ('p' in or) ? or.p : 'bottom';
// use the defaults
} else {
var offsetV = 0;
var offsetH = 0;
}
// return the object
return (function(or) {
switch (or) {
case 'bottom':
return {
'top': ($(el).getStyle('height').toInt() + offsetV) + 'px',
'left': (0 + offsetH) + 'px'
};
break;
case 'top':
return {
'bottom': ($(el).getStyle('height').toInt() + offsetV) + 'px',
'left': (0 + offsetH) + 'px'
};
break;
case 'left':
return {
'top': (0 + offsetV) + 'px',
'right': ($(el).getStyle('width').toInt() + offsetH) + 'px'
};
break;
case 'right':
return {
'top': (0 + offsetV) + 'px',
'left': ($(el).getStyle('width').toInt() + offsetH) + 'px'
};
break;
}
})(or);
}
// find all 'items' in the current node
$(this).getElements(options.items).each(function(el, i) {
// hide all the submenus
$(el).setStyles({
'position': 'relative',
'overflow': 'visible'
}).getChildren(options.menus).setStyles({
'display': 'none',
'position': 'absolute'
});
// store the options locally
$(el).store('dropdownify', options);
// hover in function
$(el).addEvent('mouseenter', function() {
// hide any existing ones if we're top-level
if ($(this).toParent('.dropdownify-root', options.menus) == 1) {
$$('.dropdownify-root')[0].getElements(options.menus).setStyles({
'display': 'none',
'visibility': 'hidden'
});
}
// clear the close timeout
window.clearTimeout($(this).retrieve('dropdownify').timeoutClose);
// store the timeout function for possible clearing
$(this).retrieve('dropdownify').timeoutOpen = window.setTimeout(function() {
var object = this;
return function() {
return function() {
$(this).getChildren($(this).retrieve('dropdownify').menus).addClass('dropdownify-current').setStyles({
'z-index': (options.zIndex + $(this).toParent('.dropdownify-root', options.menus)),
'display': 'block',
'visibility': 'visible',
'width': $(this).getStyle('width')
}).setStyles(getPos(this));
if (options.onshow) {
try {
options.onshow.apply(this);
} catch (err) {}
}
}.apply(object);
}
}.apply(this), options.delay);
});
// hover out function
$(el).addEvent('mouseleave', function() {
// clear the open timeout
window.clearTimeout($(this).retrieve('dropdownify').timeoutOpen);
// store the timeout function for possible clearing
$(this).retrieve('dropdownify').timeoutClose = window.setTimeout(function() {
var object = this;
return function() {
return function() {
$(this).getChildren($(this).retrieve('dropdownify').menus).setStyles({
'visibility': 'hidden',
'display': 'none'
});
if (options.onhide) {
try {
options.onhide.apply(this);
} catch (err) {}
}
}.apply(object);
}
}.apply(this), $(this).retrieve('dropdownify').timeout);
});
});
// return the object for chaining
return this;
}
});
Initial URL
http://www.dom111.co.uk/blog/coding/dropdownify-minimal-effort-dropdown/218
Initial Description
So recently I was asked to change a navigation style of an existing site to drop-down menus. Simple, I thought, just use one of the many existing drop-down plugins. I tried many, but most seemed to use hardcoded styles and I had a few problems (some of which I encountered again, writing this). So I’ve made this, I think it’s fairly robust, but I’m sure there’ll be problems with embedded objects (flash) and select boxes (in <= IE6), but for my needs, it sufficed, so I thought I'd share, in case anyone else needs a simple script to manage drop-downs.
Initial Title
mootools dropdownify
Initial Tags
javascript, dropdown
Initial Language
JavaScript