/* hover in mobile devices */ // page init function initNavFix() { new touchNav({ navBlock: 'main-nav' // String id or DOM-object }); } if (window.addEventListener) window.addEventListener("load", initNavFix, false); else if (window.attachEvent) window.attachEvent("onload", initNavFix); // navigation accesibility module function touchNav(opt) { this.options = { hoverClass: 'hover', menuItems: 'li', menuOpener: 'a', menuDrop: 'div', navBlock: null } for(var p in opt) { if(opt.hasOwnProperty(p)) { this.options[p] = opt[p]; } } this.init(); } touchNav.prototype = { init: function() { if(typeof this.options.navBlock === 'string') { this.menu = document.getElementById(this.options.navBlock); } else if(typeof this.options.navBlock === 'object') { this.menu = this.options.navBlock; } if(this.menu) { this.getElements(); this.addEvents(); } }, getElements: function() { this.menuItems = this.menu.getElementsByTagName(this.options.menuItems); }, getOpener: function(obj) { for(var i = 0; i < obj.childNodes.length; i++) { if(obj.childNodes[i].tagName && obj.childNodes[i].tagName.toLowerCase() == this.options.menuOpener.toLowerCase()) { return obj.childNodes[i]; } } return false; }, getDrop: function(obj) { for(var i = 0; i < obj.childNodes.length; i++) { if(obj.childNodes[i].tagName && obj.childNodes[i].tagName.toLowerCase() == this.options.menuDrop.toLowerCase()) { return obj.childNodes[i]; } } return false; }, addEvents: function() { // attach event handlers this.preventCurrentClick = true; for(var i = 0; i < this.menuItems.length; i++) { this.bind(function(i){ var item = this.menuItems[i]; // only for touch input devices if(this.isTouchDevice && this.getDrop(item)) { this.addHandler(this.getOpener(item), 'click', this.bind(this.clickHandler)); this.addHandler(this.getOpener(item), 'touchstart', this.bind(function(){ this.currentItem = item; this.currentLink = this.getOpener(item); this.pressHandler.apply(this, arguments); })); } // for desktop computers and touch devices this.addHandler(item, 'mouseover', this.bind(function(){ this.currentItem = item; this.mouseoverHandler(); })); this.addHandler(item, 'mouseout', this.bind(function(){ this.currentItem = item; this.mouseoutHandler(); })); })(i); } // hide dropdowns when clicking outside navigation if(this.isTouchDevice) { this.addHandler(document, 'touchstart', this.bind(this.clickOutsideHandler)); } }, mouseoverHandler: function() { this.addClass(this.currentItem, this.options.hoverClass); }, mouseoutHandler: function() { this.removeClass(this.currentItem, this.options.hoverClass); }, hideActiveDropdown: function() { for(var i = 0; i < this.menuItems.length; i++) { this.removeClass(this.menuItems[i], this.options.hoverClass); } this.activeParent = null; }, pressHandler: function(e) { // hide previous drop (if active) if(this.currentItem != this.activeParent && !this.isParent(this.activeParent, this.currentLink)) { this.hideActiveDropdown(); } // handle current drop this.activeParent = this.currentItem; if(this.hasClass(this.currentItem, this.options.hoverClass)) { this.preventCurrentClick = false; } else { this.preventEvent(e); this.preventCurrentClick = true; this.addClass(this.currentItem, this.options.hoverClass); } }, clickHandler: function(e) { // prevent first click on link if(this.preventCurrentClick) { this.preventEvent(e); } }, clickOutsideHandler: function(event) { var e = event.changedTouches ? event.changedTouches[0] : event; if(this.activeParent && !this.isParent(this.menu, e.target)) { this.hideActiveDropdown(); } }, preventEvent: function(e) { if(!e) e = window.event; if(e.preventDefault) e.preventDefault(); e.returnValue = false; }, isParent: function(parent, child) { while(child.parentNode) { if(child.parentNode == parent) { return true; } child = child.parentNode; } return false; }, isTouchDevice: (function() { try { return ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch; } catch (e) { return false; } }()), addHandler: function(object, event, handler) { if (object.addEventListener) object.addEventListener(event, handler, false); else if (object.attachEvent) object.attachEvent('on' + event, handler); }, removeHandler: function(object, event, handler) { if (object.removeEventListener) object.removeEventListener(event, handler, false); else if (object.detachEvent) object.detachEvent('on' + event, handler); }, hasClass: function(obj,cname) { return (obj.className ? obj.className.match(new RegExp('(\\s|^)'+cname+'(\\s|$)')) : false); }, addClass: function(obj,cname) { if (!this.hasClass(obj,cname)) obj.className += " "+cname; }, removeClass: function(obj,cname) { if (this.hasClass(obj,cname)) obj.className=obj.className.replace(new RegExp('(\\s|^)'+cname+'(\\s|$)'),' '); }, bind: function(func, scope){ var newScope = scope || this; return function() { return func.apply(newScope, arguments); } } }