PageSourceSearch

https://www.strafverteidiger-friis.at/js/_essentials/ruffnav.js

js strafverteidiger-friis.at collected 2026-10-07 04:16:27 UTC 11,614 bytes, 274 lines download raw bytes

1/**
2 * off-canvas nav
3 * @name ruffnav
4 * @author Dominik Kressler
5 * @version 2.2.6
6 * @thanks Jasmin Reiff
7 * @edit by Malte Zoudlik
8 * @edit by Dario Rieke
9 * @copyright (c) 2018
10 */
11 function Ruffnav(options) {
12    this.options = J.merge({
13        toggler: '#navi-toggled',
14        container: '#navigation',
15        navList: '.navi-main',
16        subParent: '.has-sub',
17        subClass: '.sub',
18        backText: false,
19        mobileBreak: 'large',
20        closeOnScroll: true,
21        desktopHover: false,
22        navSplit: false,
23        navAppend: false
24    }, options);
25    this.depth = 0;
26    this.toggler = document.querySelector(this.options.toggler);
27    this.container = document.querySelector(this.options.container);
28    this.navList = this.container.querySelector(this.options.navList)
29    this.sub = this.container.querySelectorAll(this.options.subClass);
30    this.subParent = this.container.querySelectorAll(this.options.subParent);
31    this.html = document.documentElement;
32    this.device = breakpoint(this.options.mobileBreak) ? 'desktop' : 'mobile';
33    this.isOpen = false;
34    this.subToggler = null;
35    this.windowSize = window.innerWidth;
36    this.navSize = 0;
37    this.activePath = '';
38    this.path = window.location.pathname.split('/').filter(function(el) {return el != ''});
39
40    // set back button text by language, or by overwrite
41    if(this.options.backText === false)
42    {
43        var html = document.querySelector('html');
44        this.options.backText = (html.lang == 'de') ? 'Zurück' : 'back';
45    }
46
47    this.backButton = create('li', {
48        'class': 'nav-back',
49        'tabindex': '0'
50    }, '<span>'+this.options.backText+'</span>');
51
52    var self = this;
53    this.init = function() {
54        if(!self.navList) return console.warn(`No element found with class "${self.options.navList}". Ruffnav could't be initialized. Please add the class to your main navigation UL-Element`);
55        // add class for desktop hover
56        self.container.classList.add('first-level'); 
57        if(self.options.desktopHover) self.container.classList.add('hover-navigation');
58
59        // append custom Content to Navigation
60        if(self.options.navAppend) {
61            var itemToAppend = create('li', {'class': 'nav-item appended-item'}, self.options.navAppend);
62            self.navList.appendChild(itemToAppend);
63        }
64
65        self.navSize = self.navList.childNodes.length;
66        // split navigation in half
67
68        // transform Navigation markup
69        [].forEach.call(self.subParent, function(parentItem) {
70            var childNode = parentItem.firstElementChild,
71                categoryLabel = (childNode.dataset && childNode.dataset.categoryLabel) ? childNode.dataset.categoryLabel : childNode.innerHTML; 
72
73            // parent-name attribute for UL's
74            childNode.nextElementSibling.setAttribute('data-parent-name', childNode.innerText);
75                
76            // only clone when Element is a link
77            if(childNode.nodeName !== 'SPAN') {
78                // var cActive = (window.location.origin+window.location.pathname === childNode.href) ? 'active' : '';
79
80                // copy link inside UL's
81                childNode.nextElementSibling.insertBefore(create('li', {
82                    'class': 'nav-item '+childNode.className.trim()
83                }, '<a href="'+childNode.href+'" title="'+childNode.title+'">'+categoryLabel+'</a>'), parentItem.children[1].children[0]);
84                if(self.path.length) {
85                    self.activeClassFallback(childNode);
86                }
87            }
88            // replace link's with span's
89            parentItem.replaceChild(create('span', {
90                'class': 'sub-toggler '+childNode.className.trim(),
91                'tabindex': 0,
92                'data-href': childNode.href
93            }, childNode.innerHTML), childNode)
94        });
95        [].forEach.call(self.sub, function(subItem){
96            // add backbuttons to UL's
97            subItem.insertBefore(self.backButton.cloneNode(true), subItem.childNodes[0]);
98        });
99
100        if(self.options.navSplit) {
101            var elm;
102            var splitList = create('ul', {class: "navi split-list"});
103            for (var i = parseInt(self.navSize / 2); i != splitList.childNodes.length; i) {
104                elm = self.navList.childNodes[i].cloneNode(true);
105                splitList.appendChild(elm)
106                self.navList.childNodes[i].remove();
107            }   
108            self.navList.parentElement.appendChild(splitList);
109        }
110
111        // close on mobile toggle
112        self.toggler.addEventListener('click', self._closeAll);
113
114        // add Listeners for different events
115        self.addListener();
116
117        // add global resize listener
118        self.listenResize();
119
120        return self;
121    }
122    this._open = function(e) {
123        // open event
124        var target, sameLevelCurrents;
125
126        if(e.type === 'mouseenter' && self.device === "mobile") return;
127        if(e.type === 'mouseenter') {
128            target = e.target;
129            target.childNodes[1].classList.add('current');
130            if(self.container.querySelector('.open') != null) self.container.querySelector('.open').classList.remove('open');
131            target.childNodes[1].classList.add('open');
132        } else {
133            target = e.currentTarget;
134            
135            //close other on same level when already opened
136            sameLevelCurrents = target.parentElement.parentElement.querySelector('.current');
137            if(sameLevelCurrents !== null) self.closeRecusive(sameLevelCurrents, false)
138
139            target.nextElementSibling.classList.add('current');
140            if(self.container.querySelector('.open') != null) self.container.querySelector('.open').classList.remove('open');
141            target.nextElementSibling.classList.add('open');
142        }
143        if(!self.isOpen && self.device !== 'mobile') {
144            if(self.options.closeOnScroll) window.addEventListener('scroll', self._closeAll);
145            document.addEventListener('click', self._closeAll);
146            document.addEventListener('keydown', self._closeAll);
147            self.isOpen = true;
148        }
149        self.container.classList.remove('first-level');
150        self.scrollTop();
151    }
152    this._close = function(e) {
153        // close event
154        var currentListTree;
155        
156        if(e.type === 'mouseleave' && self.device === "mobile") return;
157        if(e.type === 'mouseleave') currentListTree = e.currentTarget;
158        else currentListTree = e.currentTarget.parentElement;
159        
160        self.closeRecusive(currentListTree, false);
161        if(self.container.querySelectorAll('ul.current').length === 0) self.isOpen = false;
162        if(self.container.querySelectorAll('ul.current').length === 0) self.container.classList.add('first-level');
163
164        self.scrollTop();
165    }
166    this._closeAll = function(e) {
167        (self.toggler.checked) ? self.html.classList.add('hidden-scroll') : self.html.classList.remove('hidden-scroll');
168        // close all
169        if(e.type === 'scroll') {
170            self.closeRecusive(null, true);
171        } else if(e.type === 'click') {
172            // check if click was not inside navigation
173            if(e.target === self.container || self.container.contains(e.target)) return;
174            else self.closeRecusive(null, true)
175        } else if(e.type === 'keydown') {
176            // check if "enter" was pressed
177            if(e.keyCode === 27) self.closeRecusive(null, true);
178        } else {
179            self.closeRecusive(null, true);
180        }
181        self.removeListeners();        
182        self.isOpen = false
183    }
184    this.closeRecusive = function(firstList, closeAll) {
185        // close all open items
186        if(closeAll) {
187            [].forEach.call(self.container.querySelectorAll('.current'), function(openSubs) {openSubs.classList.remove('current')});
188            if(self.container.querySelector('.open') != null) self.container.querySelector('.open').classList.remove('open');
189            self.container.classList.add('first-level');
190        } else {
191            if(self.container.querySelector('.open') != null) self.container.querySelector('.open').classList.remove('open');
192            [].forEach.call(firstList.querySelectorAll('.current'), function(openSubs){
193                openSubs.classList.remove('current');
194            });
195            firstList.parentNode.parentNode.classList.add('open');
196            firstList.classList.remove('current');
197        }
198    }
199    this.removeListeners = function() {     
200        // remove eventListener for global close
201        window.removeEventListener('scroll', self._closeAll);
202        document.removeEventListener('keydown', self._closeAll);
203        document.removeEventListener('click', self._closeAll);
204    }
205    this.addListener = function() {
206        // add eventListener to subToggle and back
207        self.subToggler = self.container.querySelectorAll('.sub-toggler');
208        self.backButtons = self.container.querySelectorAll('.nav-back');
209        [].forEach.call(self.subToggler, function(subTogglerItem){
210            if(self.options.desktopHover) {
211                subTogglerItem.parentNode.addEventListener('mouseenter', self._open);
212                subTogglerItem.parentNode.addEventListener('mouseleave', self._close);
213            }
214            subTogglerItem.addEventListener('click', self._open);
215        });
216        [].forEach.call(self.backButtons, function(backButtonsItem){
217            backButtonsItem.addEventListener('click', self._close, false);
218        });
219    }
220    this.listenResize = function() {
221        // global resize Event
222        window.onresize =  function(){
223            self.device = breakpoint(self.options.mobileBreak) ? 'desktop' : 'mobile';
224            if(self.device === 'mobile') self.removeListeners();
225            if(self.windowSize != window.innerWidth && self.device === 'desktop') {
226                self.closeRecusive(null, true);
227                self.isOpen = false;
228            }
229            self.windowSize = window.innerWidth;
230        }
231    }
232
233    this.scrollTop = function() {
234        [].forEach.call(self.sub, function(item) {item.scrollTop = 0} )
235        self.container.childNodes[0].scrollTop = 0;
236    }
237
238    function create(type, attr, content) {
239        // create Node element
240        var elm = document.createElement(type);
241        [].forEach.call(Object.entries(attr), function(name){
242            elm.setAttribute(name[0], name[1]);
243        });
244        if(content) elm.innerHTML = content;
245        return elm
246    }
247
248    this.activeClassFallback = function(elem) {
249        if(elem.href === window.location.origin + '/' + this.activePath + this.path[0]+'/') {
250            elem.classList.add('active');
251            if(elem.parentNode.classList.contains(self.options.subParent.substring(1))) elem.parentNode.classList.add('active')
252            if(this.path.length === 1) elem.parentNode.querySelector('[href="'+window.location.origin+'/' + this.activePath + this.path[0]+'/"]').classList.add('active');
253            this.activePath += this.path[0] + '/';
254            this.path.splice(0,1);
255        }
256    }
257
258    this.init();
259}
260if (!Object.entries)
261Object.entries = function( obj ){
262    var ownProps = Object.keys( obj ),
263        i = ownProps.length,
264        resArray = new Array(i); // preallocate the Array
265    while (i--)
266    resArray[i] = [ownProps[i], obj[ownProps[i]]];
267
268    return resArray;
269};
270if (!('remove' in Element.prototype)) { 
271    Element.prototype.remove = function() { 
272        if (this.parentNode) this.parentNode.removeChild(this); 
273    }; 
274} 

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.