PageSourceSearch

https://medinaportal.com/wp-content/themes/medina/js/jquery.okayNav.js?ver=6.3.7

js medinaportal.com collected 2026-10-03 00:29:23 UTC 14,413 bytes, 414 lines download raw bytes

1/*!
2 * jquery.okayNav.js 2.0.1 (https://github.com/VPenkov/okayNav)
3 * Author: Vergil Penkov (http://vergilpenkov.com/)
4 * MIT license: https://opensource.org/licenses/MIT
5 */
6
7;
8(function($, window, document, undefined) {
9
10    // Defaults
11    var okayNav = 'okayNav',
12        defaults = {
13            parent: '', // will call nav's parent() by default
14            toggle_icon_class: 'okayNav__menu-toggle',
15            toggle_icon_content: '<span /><span /><span />',
16            align_right: true, // If false, the menu and the kebab icon will be on the left
17            swipe_enabled: true, // If true, you'll be able to swipe left/right to open the navigation
18            threshold: 50, // Nav will auto open/close if swiped >= this many percent
19            beforeOpen: function() {}, // Will trigger before the nav gets opened
20            afterOpen: function() {}, // Will trigger after the nav gets opened
21            beforeClose: function() {}, // Will trigger before the nav gets closed
22            afterClose: function() {}, // Will trigger after the nav gets closed
23            itemHidden: function() {},
24            itemDisplayed: function() {}
25        };
26
27    // Begin
28    function Plugin(element, options) {
29        self = this;
30        this.options = $.extend({}, defaults, options);
31        _options = this.options;
32
33        $navigation = $(element);
34        $document = $(document);
35        $window = $(window);
36
37        this.options.parent == '' ? this.options.parent = $navigation.parent() : '';
38
39        _nav_visible = false; // Store the state of the hidden nav
40        _nav_full_width = 0;
41        _parent_full_width = 0;
42
43        // Swipe stuff
44        radCoef = 180 / Math.PI;
45        _sTouch = {
46            x: 0,
47            y: 0
48        };
49        _cTouch = {
50            x: 0,
51            y: 0
52        };
53        _sTime = 0;
54        _nav_position = 0;
55        _percent_open = 0;
56        _nav_moving = false;
57
58
59        self.init();
60    }
61
62    Plugin.prototype = {
63
64        init: function() {
65
66            $('body').addClass('okayNav-loaded');
67
68            // Add classes
69            $navigation
70                .addClass('okayNav loaded')
71                .children('ul').addClass('okayNav__nav--visible');
72
73            // Append elements
74            if (self.options.align_right) {
75                $navigation
76                    .append('<ul class="okayNav__nav--invisible transition-enabled nav-right" />')
77                    .append('<a href="#" class="' + _options.toggle_icon_class + ' okay-invisible">' + _options.toggle_icon_content + '</a>')
78            } else {
79                $navigation
80                    .prepend('<ul class="okayNav__nav--invisible transition-enabled nav-left" />')
81                    .prepend('<a href="#" class="' + _options.toggle_icon_class + ' okay-invisible">' + _options.toggle_icon_content + '</a>')
82            }
83
84            // Cache new elements for further use
85            $nav_visible = $navigation.children('.okayNav__nav--visible');
86            $nav_invisible = $navigation.children('.okayNav__nav--invisible');
87            $nav_toggle_icon = $navigation.children('.' + _options.toggle_icon_class);
88
89            _toggle_icon_width = $nav_toggle_icon.outerWidth(true);
90            _nav_default_width = self.getChildrenWidth($navigation);
91            _parent_full_width = $(_options.parent).outerWidth(true);
92            _last_visible_child_width = 0; // We'll define this later
93
94            // Events are up once everything is set
95            self.initEvents();
96            if (_options.swipe_enabled == true) self.initSwipeEvents();
97        },
98
99        initEvents: function() {
100            // Toggle hidden nav when hamburger icon is clicked and
101            // Collapse hidden nav on click outside the header
102            $document.on('click.okayNav', function(e) {
103                var _target = $(e.target);
104
105                if (_nav_visible === true && _target.closest('.okayNav').length == 0)
106                    self.closeInvisibleNav();
107
108                if (_target.hasClass(_options.toggle_icon_class)) {
109                    e.preventDefault();
110                    self.toggleInvisibleNav();
111                }
112            });
113
114            $window.on('load.okayNav resize.okayNav', function(e) {
115                self.recalcNav();
116            });
117        },
118
119        initSwipeEvents: function() {
120            $document
121                .on('touchstart.okayNav', function(e) {
122                    $nav_invisible.removeClass('transition-enabled');
123
124                    //Trigger only on touch with one finger
125                    if (e.originalEvent.touches.length == 1) {
126                        var touch = e.originalEvent.touches[0];
127                        if (
128                            ((touch.pageX < 25 && self.options.align_right == false) ||
129                                (touch.pageX > ($(_options.parent).outerWidth(true) - 25) && self.options.align_right == true)) ||
130                            _nav_visible === true) {
131
132                            _sTouch.x = _cTouch.x = touch.pageX;
133                            _sTouch.y = _cTouch.y = touch.pageY;
134                            _sTime = Date.now();
135                        }
136
137                    }
138                })
139                .on('touchmove.okayNav', function(e) {
140                    var touch = e.originalEvent.touches[0];
141                    self._triggerMove(touch.pageX, touch.pageY);
142                    _nav_moving = true;
143                })
144                .on('touchend.okayNav', function(e) {
145                    _sTouch = {
146                        x: 0,
147                        y: 0
148                    };
149                    _cTouch = {
150                        x: 0,
151                        y: 0
152                    };
153                    _sTime = 0;
154
155                    //Close menu if not swiped enough
156                    if (_percent_open > (100 - self.options.threshold)) {
157                        _nav_position = 0;
158                        self.closeInvisibleNav();
159
160                    } else if (_nav_moving == true) {
161                        _nav_position = $nav_invisible.width();
162                        self.openInvisibleNav();
163                    }
164
165                    _nav_moving = false;
166
167                    $nav_invisible.addClass('transition-enabled');
168                });
169        },
170
171        _getDirection: function(dx) {
172            if (self.options.align_right) {
173                return (dx > 0) ? -1 : 1;
174            } else {
175                return (dx < 0) ? -1 : 1;
176            }
177        },
178
179        _triggerMove: function(x, y) {
180            _cTouch.x = x;
181            _cTouch.y = y;
182
183            var currentTime = Date.now();
184            var dx = (_cTouch.x - _sTouch.x);
185            var dy = (_cTouch.y - _sTouch.y);
186
187            var opposing = dy * dy;
188            var distance = Math.sqrt(dx * dx + opposing);
189            //Length of the opposing side of the 90deg triagle
190            var dOpposing = Math.sqrt(opposing);
191
192            var angle = Math.asin(Math.sin(dOpposing / distance)) * radCoef;
193            var speed = distance / (currentTime - _sTime);
194
195            //Set new start position
196            _sTouch.x = x;
197            _sTouch.y = y;
198
199            //Remove false swipes
200            if (angle < 20) {
201                var dir = self._getDirection(dx);
202
203                var newPos = _nav_position + dir * distance;
204                var menuWidth = $nav_invisible.width();
205                var overflow = 0;
206
207
208                if (newPos < 0) {
209                    overflow = -newPos;
210                } else if (newPos > menuWidth) {
211                    overflow = menuWidth - newPos;
212                }
213
214                var size = menuWidth - (_nav_position + dir * distance + overflow);
215                var threshold = (size / menuWidth) * 100;
216
217                //Set new position and threshold
218                _nav_position += dir * distance + overflow;
219                _percent_open = threshold;
220
221                $nav_invisible.css('transform', 'translateX(' + (self.options.align_right ? 1 : -1) * threshold + '%)');
222            }
223
224        },
225
226        /*
227         * A few methods to allow working with elements
228         */
229        getParent: function() {
230            return _options.parent;
231        },
232
233        getVisibleNav: function() { // Visible navigation
234            return $nav_visible;
235        },
236
237        getInvisibleNav: function() { // Hidden behind the kebab icon
238            return $nav_invisible;
239        },
240
241        getNavToggleIcon: function() { // Kebab icon
242            return $nav_toggle_icon;
243        },
244
245        /*
246         * Operations
247         */
248        openInvisibleNav: function() {
249            !_options.enable_swipe ? _options.beforeOpen.call() : '';
250
251            $nav_toggle_icon.addClass('icon--active');
252            $nav_invisible.addClass('nav-open');
253            _nav_visible = true;
254            $nav_invisible.css({
255                '-webkit-transform': 'translateX(0%)',
256                'transform': 'translateX(0%)'
257            });
258
259            _options.afterOpen.call();
260        },
261
262        closeInvisibleNav: function() {
263            !_options.enable_swipe ? _options.beforeClose.call() : '';
264
265            $nav_toggle_icon.removeClass('icon--active');
266            $nav_invisible.removeClass('nav-open');
267
268            if (self.options.align_right) {
269                $nav_invisible.css({
270                    '-webkit-transform': 'translateX(100%)',
271                    'transform': 'translateX(100%)'
272                });
273            } else {
274                $nav_invisible.css({
275                    '-webkit-transform': 'translateX(-100%)',
276                    'transform': 'translateX(-100%)'
277                });
278            }
279            _nav_visible = false;
280
281            _options.afterClose.call();
282        },
283
284        toggleInvisibleNav: function() {
285            if (!_nav_visible) {
286                self.openInvisibleNav();
287            } else {
288                self.closeInvisibleNav();
289            }
290        },
291
292
293        /*
294         * Math stuff
295         */
296        getChildrenWidth: function(el) {
297            var children_width = 0;
298            var children = $(el).children();
299            for (var i = 0; i < children.length; i++) {
300                children_width += $(children[i]).outerWidth(true);
301            };
302
303            return children_width;
304        },
305
306        getVisibleItemCount: function() {
307            return $('li', $nav_visible).length;
308        },
309        getHiddenItemCount: function() {
310            return $('li', $nav_invisible).length;
311        },
312
313        recalcNav: function() {
314            var wrapper_width = $(_options.parent).outerWidth(true),
315                space_taken = self.getChildrenWidth(_options.parent),
316                nav_full_width = $navigation.outerWidth(true),
317                visible_nav_items = self.getVisibleItemCount(),
318                collapse_width = $nav_visible.outerWidth(true) + _toggle_icon_width,
319                expand_width = space_taken + _last_visible_child_width + _toggle_icon_width,
320                expandAll_width = space_taken - nav_full_width + _nav_default_width;
321
322            if (wrapper_width > expandAll_width) {
323                self._expandAllItems();
324                $nav_toggle_icon.addClass('okay-invisible');
325                return;
326            }
327
328            if (visible_nav_items > 0 &&
329                nav_full_width <= collapse_width &&
330                wrapper_width <= expand_width) {
331                self._collapseNavItem();
332            }
333
334            if (wrapper_width > expand_width + _toggle_icon_width * 2) {
335                self._expandNavItem();
336            }
337
338            // Hide the kebab icon if no items are hidden
339            self.getHiddenItemCount() == 0 ?
340                $nav_toggle_icon.addClass('okay-invisible') :
341                $nav_toggle_icon.removeClass('okay-invisible');
342        },
343
344        _collapseNavItem: function() {
345            var $last_child = $('li:last-child', $nav_visible);
346            _last_visible_child_width = $last_child.outerWidth(true);
347            $document.trigger('okayNav:collapseItem', $last_child);
348            $last_child.detach().prependTo($nav_invisible);
349            _options.itemHidden.call();
350            // All nav items are visible by default
351            // so we only need recursion when collapsing
352
353            self.recalcNav();
354        },
355
356        _expandNavItem: function() {
357            var $first = $('li:first-child', $nav_invisible);
358            $document.trigger('okayNav:expandItem', $first);
359            $first.detach().appendTo($nav_visible);
360            _options.itemDisplayed.call();
361        },
362
363        _expandAllItems: function() {
364            $('li', $nav_invisible).detach().appendTo($nav_visible);
365            _options.itemDisplayed.call();
366        },
367
368        _collapseAllItems: function() {
369            $('li', $nav_visible).detach().appendTo($nav_invisible);
370            _options.itemHidden.call();
371        },
372
373        destroy: function() {
vendor: 1,361 bytes, lines 374-414
374            $('li', $nav_invisible).appendTo($nav_visible);
375            $nav_invisible.remove();
376            $nav_visible.removeClass('okayNav__nav--visible');
377            $nav_toggle_icon.remove();
378
379            $document.unbind('.okayNav');
380            $window.unbind('.okayNav');
381        }
382
383    }
384
385    // Plugin wrapper
386    $.fn[okayNav] = function(options) {
387        var args = arguments;
388
389        if (options === undefined || typeof options === 'object') {
390            return this.each(function() {
391                if (!$.data(this, 'plugin_' + okayNav)) {
392                    $.data(this, 'plugin_' + okayNav, new Plugin(this, options));
393                }
394            });
395
396        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
397
398            var returns;
399            this.each(function() {
400                var instance = $.data(this, 'plugin_' + okayNav);
401                if (instance instanceof Plugin && typeof instance[options] === 'function') {
402                    returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
403                }
404
405                if (options === 'destroy') {
406                    $.data(this, 'plugin_' + okayNav, null);
407                }
408            });
409
410            return returns !== undefined ? returns : this;
411        }
412    };
413
414}(jQuery, 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.