vendor/assets/javascripts/responsive-nav.js in responsive-nav-rails-1.0.25 vs vendor/assets/javascripts/responsive-nav.js in responsive-nav-rails-1.0.30
- old
+ new
@@ -1,20 +1,19 @@
-/*! responsive-nav.js 1.0.25
+/*! responsive-nav.js 1.0.30
* https://github.com/viljamis/responsive-nav.js
* http://responsive-nav.com
*
- * Copyright (c) 2013 @viljamis
+ * Copyright (c) 2014 @viljamis
* Available under the MIT license
*/
-(function () {
+(function (document, window, index) {
"use strict";
- /* exported responsiveNav */
var responsiveNav = function (el, options) {
-
+
var computed = !!window.getComputedStyle;
// getComputedStyle polyfill
if (!computed) {
window.getComputedStyle = function(el) {
@@ -119,146 +118,176 @@
removeClass = function (el, cls) {
var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
el.className = el.className.replace(reg, " ").replace(/(^\s*)|(\s*$)/g,"");
};
-
+
var nav,
opts,
navToggle,
styleElement = document.createElement("style"),
+ htmlEl = document.documentElement,
hasAnimFinished,
+ isMobile,
navOpen;
-
+
var ResponsiveNav = function (el, options) {
var i;
-
+
// Default options
this.options = {
- animate: true, // Boolean: Use CSS3 transitions, true or false
- transition: 250, // Integer: Speed of the transition, in milliseconds
- label: "Menu", // String: Label for the navigation toggle
- insert: "after", // String: Insert the toggle before or after the navigation
- customToggle: "", // Selector: Specify the ID of a custom toggle
- openPos: "relative", // String: Position of the opened nav, relative or static
- navClass: "nav-collapse", // String: Default CSS class. If changed, you need to edit the CSS too!
- jsClass: "js", // String: 'JS enabled' class which is added to <html> element
- init: function(){}, // Function: Init callback
- open: function(){}, // Function: Open callback
- close: function(){} // Function: Close callback
+ animate: true, // Boolean: Use CSS3 transitions, true or false
+ transition: 284, // Integer: Speed of the transition, in milliseconds
+ label: "Menu", // String: Label for the navigation toggle
+ insert: "before", // String: Insert the toggle before or after the navigation
+ customToggle: "", // Selector: Specify the ID of a custom toggle
+ closeOnNavClick: false, // Boolean: Close the navigation when one of the links are clicked
+ openPos: "relative", // String: Position of the opened nav, relative or static
+ navClass: "nav-collapse", // String: Default CSS class. If changed, you need to edit the CSS too!
+ navActiveClass: "js-nav-active", // String: Class that is added to <html> element when nav is active
+ jsClass: "js", // String: 'JS enabled' class which is added to <html> element
+ init: function(){}, // Function: Init callback
+ open: function(){}, // Function: Open callback
+ close: function(){} // Function: Close callback
};
-
+
// User defined options
for (i in options) {
this.options[i] = options[i];
}
-
+
// Adds "js" class for <html>
- addClass(document.documentElement, this.options.jsClass);
-
+ addClass(htmlEl, this.options.jsClass);
+
// Wrapper
this.wrapperEl = el.replace("#", "");
+
+ // Try selecting ID first
if (document.getElementById(this.wrapperEl)) {
this.wrapper = document.getElementById(this.wrapperEl);
+
+ // If element with an ID doesn't exist, use querySelector
} else if (document.querySelector(this.wrapperEl)) {
this.wrapper = document.querySelector(this.wrapperEl);
+
+ // If element doesn't exists, stop here.
} else {
- // If el doesn't exists, stop here.
throw new Error("The nav element you are trying to select doesn't exist");
}
-
+
// Inner wrapper
this.wrapper.inner = getChildren(this.wrapper);
-
+
// For minification
opts = this.options;
nav = this.wrapper;
-
+
// Init
this._init(this);
};
-
+
ResponsiveNav.prototype = {
-
+
// Public methods
destroy: function () {
this._removeStyles();
removeClass(nav, "closed");
removeClass(nav, "opened");
removeClass(nav, opts.navClass);
+ removeClass(nav, opts.navClass + "-" + this.index);
+ removeClass(htmlEl, opts.navActiveClass);
nav.removeAttribute("style");
nav.removeAttribute("aria-hidden");
-
+
removeEvent(window, "resize", this, false);
removeEvent(document.body, "touchmove", this, false);
removeEvent(navToggle, "touchstart", this, false);
removeEvent(navToggle, "touchend", this, false);
removeEvent(navToggle, "mouseup", this, false);
removeEvent(navToggle, "keyup", this, false);
removeEvent(navToggle, "click", this, false);
-
+
if (!opts.customToggle) {
navToggle.parentNode.removeChild(navToggle);
} else {
navToggle.removeAttribute("aria-hidden");
}
},
-
+
toggle: function () {
if (hasAnimFinished === true) {
if (!navOpen) {
- removeClass(nav, "closed");
- addClass(nav, "opened");
- nav.style.position = opts.openPos;
- setAttributes(nav, {"aria-hidden": "false"});
-
- navOpen = true;
- opts.open();
+ this.open();
} else {
- removeClass(nav, "opened");
- addClass(nav, "closed");
- setAttributes(nav, {"aria-hidden": "true"});
-
- if (opts.animate) {
- hasAnimFinished = false;
- setTimeout(function () {
- nav.style.position = "absolute";
- hasAnimFinished = true;
- }, opts.transition + 10);
- } else {
+ this.close();
+ }
+ }
+ },
+
+ open: function () {
+ if (!navOpen) {
+ removeClass(nav, "closed");
+ addClass(nav, "opened");
+ addClass(htmlEl, opts.navActiveClass);
+ addClass(navToggle, "active");
+ nav.style.position = opts.openPos;
+ setAttributes(nav, {"aria-hidden": "false"});
+ navOpen = true;
+ opts.open();
+ }
+ },
+
+ close: function () {
+ if (navOpen) {
+ addClass(nav, "closed");
+ removeClass(nav, "opened");
+ removeClass(htmlEl, opts.navActiveClass);
+ removeClass(navToggle, "active");
+ setAttributes(nav, {"aria-hidden": "true"});
+
+ if (opts.animate) {
+ hasAnimFinished = false;
+ setTimeout(function () {
nav.style.position = "absolute";
- }
-
- navOpen = false;
- opts.close();
+ hasAnimFinished = true;
+ }, opts.transition + 10);
+ } else {
+ nav.style.position = "absolute";
}
+
+ navOpen = false;
+ opts.close();
}
},
-
+
resize: function () {
if (window.getComputedStyle(navToggle, null).getPropertyValue("display") !== "none") {
+
+ isMobile = true;
setAttributes(navToggle, {"aria-hidden": "false"});
-
+
// If the navigation is hidden
if (nav.className.match(/(^|\s)closed(\s|$)/)) {
setAttributes(nav, {"aria-hidden": "true"});
nav.style.position = "absolute";
}
-
+
this._createStyles();
this._calcHeight();
} else {
+
+ isMobile = false;
setAttributes(navToggle, {"aria-hidden": "true"});
setAttributes(nav, {"aria-hidden": "false"});
nav.style.position = opts.openPos;
this._removeStyles();
}
},
-
+
handleEvent: function (e) {
var evt = e || window.event;
-
+
switch (evt.type) {
case "touchstart":
this._onTouchStart(evt);
break;
case "touchmove":
@@ -277,165 +306,187 @@
case "resize":
this.resize(evt);
break;
}
},
-
+
// Private methods
_init: function () {
+ this.index = index++;
+
addClass(nav, opts.navClass);
+ addClass(nav, opts.navClass + "-" + this.index);
addClass(nav, "closed");
hasAnimFinished = true;
navOpen = false;
-
+
+ this._closeOnNavClick();
this._createToggle();
this._transitions();
this.resize();
-
+
// IE8 hack
var self = this;
setTimeout(function () {
self.resize();
}, 20);
-
+
addEvent(window, "resize", this, false);
addEvent(document.body, "touchmove", this, false);
addEvent(navToggle, "touchstart", this, false);
addEvent(navToggle, "touchend", this, false);
addEvent(navToggle, "mouseup", this, false);
addEvent(navToggle, "keyup", this, false);
addEvent(navToggle, "click", this, false);
-
+
// Init callback
opts.init();
},
-
+
_createStyles: function () {
if (!styleElement.parentNode) {
styleElement.type = "text/css";
document.getElementsByTagName("head")[0].appendChild(styleElement);
}
},
-
+
_removeStyles: function () {
if (styleElement.parentNode) {
styleElement.parentNode.removeChild(styleElement);
}
},
-
+
_createToggle: function () {
if (!opts.customToggle) {
var toggle = document.createElement("a");
toggle.innerHTML = opts.label;
setAttributes(toggle, {
"href": "#",
"class": "nav-toggle"
});
-
+
if (opts.insert === "after") {
nav.parentNode.insertBefore(toggle, nav.nextSibling);
} else {
nav.parentNode.insertBefore(toggle, nav);
}
-
+
navToggle = toggle;
} else {
var toggleEl = opts.customToggle.replace("#", "");
-
+
if (document.getElementById(toggleEl)) {
navToggle = document.getElementById(toggleEl);
} else if (document.querySelector(toggleEl)) {
navToggle = document.querySelector(toggleEl);
} else {
throw new Error("The custom nav toggle you are trying to select doesn't exist");
}
}
},
-
+
+ _closeOnNavClick: function () {
+ if (opts.closeOnNavClick && "querySelectorAll" in document && Array.prototype.forEach) {
+ var links = nav.querySelectorAll("a"),
+ self = this;
+ [].forEach.call(links, function (el, i) {
+ addEvent(links[i], "click", function () {
+ if (isMobile) {
+ self.toggle();
+ }
+ }, false);
+ });
+ }
+ },
+
_preventDefault: function(e) {
if (e.preventDefault) {
e.preventDefault();
e.stopPropagation();
} else {
e.returnValue = false;
}
},
-
+
_onTouchStart: function (e) {
e.stopPropagation();
- addClass(nav, "disable-pointer-events");
+ if (opts.insert === "after") {
+ addClass(document.body, "disable-pointer-events");
+ }
this.startX = e.touches[0].clientX;
this.startY = e.touches[0].clientY;
this.touchHasMoved = false;
removeEvent(navToggle, "mouseup", this, false);
},
-
+
_onTouchMove: function (e) {
if (Math.abs(e.touches[0].clientX - this.startX) > 10 ||
Math.abs(e.touches[0].clientY - this.startY) > 10) {
this.touchHasMoved = true;
}
},
-
+
_onTouchEnd: function (e) {
this._preventDefault(e);
if (!this.touchHasMoved) {
if (e.type === "touchend") {
- this.toggle(e);
- setTimeout(function () {
- removeClass(nav, "disable-pointer-events");
- }, opts.transition + 300);
+ this.toggle();
+ if (opts.insert === "after") {
+ setTimeout(function () {
+ removeClass(document.body, "disable-pointer-events");
+ }, opts.transition + 300);
+ }
return;
} else {
var evt = e || window.event;
// If it isn't a right click
if (!(evt.which === 3 || evt.button === 2)) {
- this.toggle(e);
+ this.toggle();
}
}
}
},
-
+
_onKeyUp: function (e) {
var evt = e || window.event;
if (evt.keyCode === 13) {
- this.toggle(e);
+ this.toggle();
}
},
-
+
_transitions: function () {
if (opts.animate) {
var objStyle = nav.style,
transition = "max-height " + opts.transition + "ms";
-
+
objStyle.WebkitTransition = transition;
objStyle.MozTransition = transition;
objStyle.OTransition = transition;
objStyle.transition = transition;
}
},
-
+
_calcHeight: function () {
var savedHeight = 0;
for (var i = 0; i < nav.inner.length; i++) {
savedHeight += nav.inner[i].offsetHeight;
}
- var innerStyles = "." + opts.navClass + ".opened{max-height:" + savedHeight + "px !important}";
-
+ var innerStyles = "." + opts.navClass + "-" + this.index + ".opened{max-height:" + savedHeight + "px !important}";
+
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = innerStyles;
} else {
styleElement.innerHTML = innerStyles;
}
-
+
innerStyles = "";
}
-
+
};
-
+
return new ResponsiveNav(el, options);
-
+
};
window.responsiveNav = responsiveNav;
-}());
+}(document, window, 0));
\ No newline at end of file