PageSourceSearch

http://www.jable.si/templates/j51_virtuoso/js/responsive-nav/responsive-nav.js

js jable.si collected 2026-10-02 22:57:23 UTC 12,869 bytes, 429 lines download raw bytes

1/*! responsive-nav.js v1.0.20
2 * https://github.com/viljamis/responsive-nav.js
3 * http://responsive-nav.com
4 *
5 * Copyright (c) 2013 @viljamis
6 * Available under the MIT license
7 */
8
9/* jshint strict:false, forin:false, noarg:true, noempty:true, eqeqeq:true,
10boss:true, bitwise:true, browser:true, devel:true, indent:2 */
11/* exported responsiveNav */
12
13var responsiveNav = (function (window, document) {
14
15  var computed = !!window.getComputedStyle;
16
17  // getComputedStyle polyfill
18  if (!window.getComputedStyle) {
19    window.getComputedStyle = function(el) {
20      this.el = el;
21      this.getPropertyValue = function(prop) {
22        var re = /(\-([a-z]){1})/g;
23        if (prop === "float") {
24          prop = "styleFloat";
25        }
26        if (re.test(prop)) {
27          prop = prop.replace(re, function () {
28            return arguments[2].toUpperCase();
29          });
30        }
31        return el.currentStyle[prop] ? el.currentStyle[prop] : null;
32      };
33      return this;
34    };
35  }
36
37  var nav,
38    opts,
39    navToggle,
40    styleElement = document.createElement("style"),
41    hasAnimFinished,
42    navOpen,
43
44    // fn arg can be an object or a function, thanks to handleEvent
45    // read more at: http://www.thecssninja.com/javascript/handleevent
46    addEvent = function (el, evt, fn, bubble) {
47      if ("addEventListener" in el) {
48        // BBOS6 doesn't support handleEvent, catch and polyfill
49        try {
50          el.addEventListener(evt, fn, bubble);
51        } catch (e) {
52          if (typeof fn === "object" && fn.handleEvent) {
53            el.addEventListener(evt, function (e) {
54              // Bind fn as this and set first arg as event object
55              fn.handleEvent.call(fn, e);
56            }, bubble);
57          } else {
58            throw e;
59          }
60        }
61      } else if ("attachEvent" in el) {
62        // check if the callback is an object and contains handleEvent
63        if (typeof fn === "object" && fn.handleEvent) {
64          el.attachEvent("on" + evt, function () {
65            // Bind fn as this
66            fn.handleEvent.call(fn);
67          });
68        } else {
69          el.attachEvent("on" + evt, fn);
70        }
71      }
72    },
73
74    removeEvent = function (el, evt, fn, bubble) {
75      if ("removeEventListener" in el) {
76        try {
77          el.removeEventListener(evt, fn, bubble);
78        } catch (e) {
79          if (typeof fn === "object" && fn.handleEvent) {
80            el.removeEventListener(evt, function (e) {
81              fn.handleEvent.call(fn, e);
82            }, bubble);
83          } else {
84            throw e;
85          }
86        }
87      } else if ("detachEvent" in el) {
88        if (typeof fn === "object" && fn.handleEvent) {
89          el.detachEvent("on" + evt, function () {
90            fn.handleEvent.call(fn);
91          });
92        } else {
93          el.detachEvent("on" + evt, fn);
94        }
95      }
96    },
97
98    getChildren = function (e) {
99      if (e.children.length < 1) {
100        throw new Error("The Nav container has no containing elements");
101      }
102      // Store all children in array
103      var children = [];
104      // Loop through children and store in array if child != TextNode
105      for (var i = 0; i < e.children.length; i++) {
106        if (e.children[i].nodeType === 1) {
107          children.push(e.children[i]);
108        }
109      }
110      return children;
111    },
112
113    setAttributes = function (el, attrs) {
114      for (var key in attrs) {
115        el.setAttribute(key, attrs[key]);
116      }
117    },
118
119    addClass = function (el, cls) {
120      el.className += " " + cls;
121      el.className = el.className.replace(/(^\s*)|(\s*$)/g,"");
122    },
123
124    removeClass = function (el, cls) {
125      var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
126      el.className = el.className.replace(reg, " ").replace(/(^\s*)|(\s*$)/g,"");
127    },
128
129    ResponsiveNav = function (el, options) {
130      var i;
131
132      // Default options
133      this.options = {
134        animate: true,        // Boolean: Use CSS3 transitions, true or false
135        transition: 350,      // Integer: Speed of the transition, in milliseconds
136        label: "Menu",        // String: Label for the navigation toggle
137        insert: "after",      // String: Insert the toggle before or after the navigation
138        customToggle: "",     // Selector: Specify the ID of a custom toggle
139        openPos: "relative",  // String: Position of the opened nav, relative or static
140        jsClass: "js",        // String: 'JS enabled' class which is added to <html> el
141        init: function(){},   // Function: Init callback
142        open: function(){},   // Function: Open callback
143        close: function(){}   // Function: Close callback
144      };
145
146      // User defined options
147      for (i in options) {
148        this.options[i] = options[i];
149      }
150
151      // Adds "js" class for <html>
152      addClass(document.documentElement, this.options.jsClass);
153
154      // Wrapper
155      this.wrapperEl = el.replace("#", "");
156      if (document.getElementById(this.wrapperEl)) {
157        this.wrapper = document.getElementById(this.wrapperEl);
158      } else {
159        // If el doesn't exists, stop here.
160        throw new Error("The nav element you are trying to select doesn't exist");
161      }
162
163      // Inner wrapper
164      this.wrapper.inner = getChildren(this.wrapper);
165
166      // For minification
167      opts = this.options;
168      nav = this.wrapper;
169
170      // Init
171      this._init(this);
172    };
173
174  ResponsiveNav.prototype = {
175    // Public methods
176    destroy: function () {
177      this._removeStyles();
178      removeClass(nav, "closed");
179      removeClass(nav, "opened");
180      nav.removeAttribute("style");
181      nav.removeAttribute("aria-hidden");
182      nav = null;
183      _instance = null;
184
185      removeEvent(window, "resize", this, false);
186      removeEvent(document.body, "touchmove", this, false);
187      removeEvent(navToggle, "touchstart", this, false);
188      removeEvent(navToggle, "touchend", this, false);
189      removeEvent(navToggle, "keyup", this, false);
190      removeEvent(navToggle, "click", this, false);
191      removeEvent(navToggle, "mouseup", this, false);
192
193      if (!opts.customToggle) {
194        navToggle.parentNode.removeChild(navToggle);
195      } else {
196        navToggle.removeAttribute("aria-hidden");
197      }
198    },
199
200    toggle: function () {
201      if (hasAnimFinished === true) {
202        if (!navOpen) {
203          removeClass(nav, "closed");
204          addClass(nav, "opened");
205          nav.style.position = opts.openPos;
206          setAttributes(nav, {"aria-hidden": "false"});
207
208          navOpen = true;
209          opts.open();
210        } else {
211          removeClass(nav, "opened");
212          addClass(nav, "closed");
213          setAttributes(nav, {"aria-hidden": "true"});
214
215          if (opts.animate) {
216            hasAnimFinished = false;
217            setTimeout(function () {
218              nav.style.position = "absolute";
219              hasAnimFinished = true;
220            }, opts.transition + 10);
221          } else {
222            nav.style.position = "absolute";
223          }
224
225          navOpen = false;
226          opts.close();
227        }
228      }
229    },
230
231    handleEvent: function (e) {
232      var evt = e || window.event;
233
234      switch (evt.type) {
235      case "touchstart":
236        this._onTouchStart(evt);
237        break;
238      case "touchmove":
239        this._onTouchMove(evt);
240        break;
241      case "touchend":
242      case "mouseup":
243        this._onTouchEnd(evt);
244        break;
245      case "click":
246        this._preventDefault(evt);
247        break;
248      case "keyup":
249        this._onKeyUp(evt);
250        break;
251      case "resize":
252        this._resize(evt);
253        break;
254      }
255    },
256
257    // Private methods
258    _init: function () {
259      addClass(nav, "closed");
260      hasAnimFinished = true;
261      navOpen = false;
262
263      this._createToggle();
264      this._transitions();
265      this._resize();
266
267      addEvent(window, "resize", this, false);
268      addEvent(document.body, "touchmove", this, false);
269      addEvent(navToggle, "touchstart", this, false);
270      addEvent(navToggle, "touchend", this, false);
271      addEvent(navToggle, "mouseup", this, false);
272      addEvent(navToggle, "keyup", this, false);
273      addEvent(navToggle, "click", this, false);
274
275      // Init callback
276      opts.init();
277    },
278
279    _createStyles: function () {
280      if (!styleElement.parentNode) {
281        document.getElementsByTagName("head")[0].appendChild(styleElement);
282      }
283    },
284
285    _removeStyles: function () {
286      if (styleElement.parentNode) {
287        styleElement.parentNode.removeChild(styleElement);
288      }
289    },
290
291    _createToggle: function () {
292      if (!opts.customToggle) {
293        var toggle = document.createElement("a");
294        toggle.innerHTML = opts.label;
295        setAttributes(toggle, {
296          "href": "#",
297          "id": "nav-toggle"
298        });
299
300        if (opts.insert === "after") {
301          nav.parentNode.insertBefore(toggle, nav.nextSibling);
302        } else {
303          nav.parentNode.insertBefore(toggle, nav);
304        }
305
306        navToggle = document.getElementById("nav-toggle");
307      } else {
308        var toggleEl = opts.customToggle.replace("#", "");
309
310        if (document.getElementById(toggleEl)) {
311          navToggle = document.getElementById(toggleEl);
312        } else {
313          throw new Error("The custom nav toggle you are trying to select doesn't exist");
314        }
315      }
316    },
317
318    _preventDefault: function(e) {
319      if (e.preventDefault) {
320        e.preventDefault();
321        e.stopPropagation();
322      } else {
323        e.returnValue = false;
324      }
325    },
326
327    _onTouchStart: function (e) {
328      e.stopPropagation();
329      this.startX = e.touches[0].clientX;
330      this.startY = e.touches[0].clientY;
331      this.touchHasMoved = false;
332      removeEvent(navToggle, "mouseup", this, false);
333    },
334
335    _onTouchMove: function (e) {
336      if (Math.abs(e.touches[0].clientX - this.startX) > 10 ||
337      Math.abs(e.touches[0].clientY - this.startY) > 10) {
338        this.touchHasMoved = true;
339      }
340    },
341
342    _onTouchEnd: function (e) {
343      this._preventDefault(e);
344      if (!this.touchHasMoved) {
345        if (e.type === "touchend") {
346          this.toggle(e);
347          // Prevent click on the underlying menu on Android 2.3
348          var that = this;
349          nav.addEventListener("click", that._preventDefault, true);
350          setTimeout(function () {
351            nav.removeEventListener("click", that._preventDefault, true);
352          }, opts.transition + 100);
353          return;
354        } else {
355          var evt = e || window.event;
356          // If it isn't a right click
357          if (!(evt.which === 3 || evt.button === 2)) {
358            this.toggle(e);
359          }
360        }
361      }
362    },
363
364    _onKeyUp: function (e) {
365      var evt = e || window.event;
366      if (evt.keyCode === 13) {
367        this.toggle(e);
368      }
369    },
370
371    _transitions: function () {
372      if (opts.animate) {
373        var objStyle = nav.style,
374          transition = "max-height " + opts.transition + "ms";
375
376        objStyle.WebkitTransition = transition;
377        objStyle.MozTransition = transition;
378        objStyle.OTransition = transition;
379        objStyle.transition = transition;
380      }
381    },
382
383    _calcHeight: function () {
384      var savedHeight = 0;
385      for (var i = 0; i < nav.inner.length; i++) {
386        savedHeight += nav.inner[i].offsetHeight;
387      }
388
389      var innerStyles = "#" + this.wrapperEl + ".opened{max-height:" + savedHeight + "px}";
390
391      // Hide from old IE
392      if (computed) {
393        styleElement.innerHTML = innerStyles;
394        innerStyles = "";
395      }
396    },
397
398    _resize: function () {
399      if (window.getComputedStyle(navToggle, null).getPropertyValue("display") !== "none") {
400        setAttributes(navToggle, {"aria-hidden": "false"});
401
402        // If the navigation is hidden
403        if (nav.className.match(/(^|\s)closed(\s|$)/)) {
404          setAttributes(nav, {"aria-hidden": "true"});
405          nav.style.position = "absolute";
406        }
407
408        this._createStyles();
409        this._calcHeight();
410      } else {
411        setAttributes(navToggle, {"aria-hidden": "true"});
412        setAttributes(nav, {"aria-hidden": "false"});
413        nav.style.position = opts.openPos;
414        this._removeStyles();
415      }
416    }
417
418  };
419
420  var _instance;
421  function rn (el, options) {
422    if (!_instance) {
423      _instance = new ResponsiveNav(el, options);
424    }
425    return _instance;
426  }
427
428  return rn;
429})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.