Skip to content

Instantly share code, notes, and snippets.

@blakehaswell
Created April 19, 2012 23:14
Show Gist options
  • Save blakehaswell/2424807 to your computer and use it in GitHub Desktop.
Save blakehaswell/2424807 to your computer and use it in GitHub Desktop.
Vanilla JS Dropdown
/**
* Given a list of items, adds and removes an active class as you hover over
* them. Used to create a dropdown menu.
*
* Copyright (c) 2012 Blake Haswell
* Licensed under the MIT license: http://opensource.org/licenses/MIT
*
* Example:
* var items = document.getElementById("dropdown").children;
* new Dropdown(items);
*/
(function () {
"use strict";
window.Dropdown = function (items) {
this._items = items;
this._initEventHandlers();
};
window.Dropdown.prototype = {
show: function (item) {
this._addClass(item, this._activeClass);
},
hide: function (item) {
this._removeClass(item, this._activeClass);
},
_activeClass: "active",
_initEventHandlers: function () {
var self = this;
for (var i = 0, l = this._items.length; i < l; ++i) {
var item = this._items[i];
item.onmouseover = function () {
self.show(this);
};
item.onmouseout = function (e) {
if (self._mouseHasLeftElem(e, this)) {
self.hide(this);
}
};
}
},
// mouseHasLeftElem function stolen from PPK, with some changes to
// improve readability.
//
// http://www.quirksmode.org/js/events_mouse.html
_mouseHasLeftElem: function (e, elem) {
var e = e || window.event;
var relatedTarget = e.relatedTarget || e.toElement;
// Keep moving up the DOM until we hit either the element or the body.
while (relatedTarget !== elem && relatedTarget.nodeName !== "BODY") {
relatedTarget = relatedTarget.parentNode;
}
// If we hit the element first, then the related target was a child so
// we haven't left the element.
if (relatedTarget === elem) {
return false;
}
return true;
},
// Class manipulation functions stolen from Arjan Haverkamp (av01d).
//
// http://www.avoid.org/?p=78
_hasClass: function (el, name) {
return new RegExp('(\\s|^)' + name + '(\\s|$)').test(el.className);
},
_addClass: function (el, name) {
if (!this._hasClass(el, name)) {
el.className += (el.className ? ' ' : '') + name;
}
},
_removeClass: function (el, name) {
if (this._hasClass(el, name)) {
el.className = el.className.replace(new RegExp('(\\s|^)' + name + '(\\s|$)'), ' ').replace(/^\s+|\s+$/g, '');
}
}
};
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment