PageSourceSearch

https://24sd.ru/catalog/view/javascript/oc_megamenu/slider/oc_slidermenu.js

js 24sd.ru collected 2026-10-09 23:09:45 UTC 11,936 bytes, 419 lines download raw bytes

1
2class Slinky {
3  // default options
4  get options() {
5    return {
6      resize: true,
7      speed: 300,
8      theme: 'slinky-theme-default',
9      title: false
10    }
11  }
12
13  constructor(element, options = {}) {
14    this.settings = {
15      ...this.options,
16      ...options
17    };
18
19    this.default = {
20      toggle: true,         //
21      preventDefault: true, // Выполнять действие по умолчанию или нет
22      triggerElement: 'a',  //
23      parentTrigger: 'li',  //
24      subMenu: 'ul'         //
25    };
26
27    this._init(element)
28  }
29
30  // setup the DOM just for us
31  _init(element) {
32    this.menu = jQuery(element);
33    this.base = this.menu.children().first();
34
35    const { menu, settings } = this;
36
37    // задать тему
38    menu.addClass('slinky-menu').addClass(settings.theme);
39
40    // установить скорость перехода
41    this._transition(settings.speed);
42
43    // добавить стрелки к ссылкам с дочками
44    jQuery('a + ul', menu)
45        .prev()
46        .addClass('next');
47
48    // обернуть текст ссылки с помощью <span>
49    // в основном для стилизации
50    jQuery('li > a', menu).wrapInner('<span>');
51
52    // создать элемент заголовка
53    const header = jQuery('<li>').addClass('header');
54
55    // добавить его в список
56    jQuery('li > ul', menu).prepend(header);
57
58    // создать кнопки возврата
59    const back = jQuery('<a>')
60        .prop('href', '#')
61        .addClass('back');
62
63    // добавить их в заголовки
64    jQuery('.header', menu).prepend(back);
65
66    // нам нужно добавить названия?
67    if (settings.title) {
68      // цикл по каждому дочернему списку
69      jQuery('li > ul', menu).each((index, element) => {
70        // получить метку по родительской ссылке
71        const label = jQuery(element)
72            .parent()
73            .find('a')
74            .first()
75            .text();
76
77        // если он не пустой, создайте заголовок
78        if (label) {
79          const title = jQuery('<header>')
80              .addClass('title')
81              .text(label);
82
83          // добавить его в непосредственный заголовок
84          jQuery('> .header > a', element).append(title)
85        }
86      })
87    }
88
89    // добавить слушиватели кликов
90    this._addListeners();
91
92    // перейти к начальному активному
93    this._jumpToInitial();
94  }
95
96  _psuedoClick(parentElem) {
97
98    let beforeClicked,
99        afterClicked;
100
101    let parentLeft = parseInt(parentElem.getBoundingClientRect().left, 10),
102        parentTop = parseInt(parentElem.getBoundingClientRect().top, 10);
103
104    let parentWidth = parseInt(window.getComputedStyle(parentElem).width, 10),
105        parentHeight = parseInt(window.getComputedStyle(parentElem).height, 10);
106
107    let before = window.getComputedStyle(parentElem, ':before');
108
109    let beforeStart = parentLeft + (parseInt(before.getPropertyValue("left"), 10)),
110        beforeEnd = beforeStart + parseInt(before.width, 10);
111
112    let beforeYStart = parentTop + (parseInt(before.getPropertyValue("top"), 10)),
113        beforeYEnd = beforeYStart + parseInt(before.height, 10);
114
115    let after = window.getComputedStyle(parentElem, ':after');
116
117    let afterStart = parentLeft + (parseInt(after.getPropertyValue("left"), 10)),
118        afterEnd = afterStart + parseInt(after.width, 10);
119
120    let afterYStart = parentTop + (parseInt(after.getPropertyValue("top"), 10)) - parseInt( after.getPropertyValue("top"), 10),
121        afterYEnd = afterYStart + parseInt(after.height, 10);
122
123    let mouseX = event.clientX,
124        mouseY = event.clientY;
125
126    beforeClicked = (mouseX >= beforeStart && mouseX <= beforeEnd && mouseY >= beforeYStart && mouseY <= beforeYEnd ? true : false);
127
128    afterClicked = (mouseX >= afterStart && mouseX <= afterEnd && mouseY >= afterYStart && mouseY <= afterYEnd ? true : false);
129
130    return {
131      "before" : beforeClicked,
132      "after"  : afterClicked
133
134    };
135  }
136
137  // click listeners
138  _addListeners() {
139    const { menu, settings } = this;
140
141    jQuery('a', menu).on('click', e => {
142      // предотвратить сломанные / половинчатые переходы
143      if (this._clicked + settings.speed > Date.now()) {
144        return false
145      }
146
147      // кешировать время клика для проверки следующего клика
148      this._clicked = Date.now();
149
150      // get the link
151      const link = jQuery(e.currentTarget);
152
153      // предотвратить дефолт, если это хэш или обтягивающая кнопка
154      if( !this._psuedoClick(link[0]).after && link.attr('href') && link.attr('href').indexOf('#') !== 0 ) {
155        document.location = link.attr('href');
156      }
157
158      if (
159          link.attr('href').indexOf('#') === 0 ||
160          link.hasClass('next') ||
161          link.hasClass('back')
162      ) {
163        e.preventDefault()
164      }
165
166      // двигаемся в перёд
167      if (link.hasClass('next')) {
168        // один шаг вперед
169
170        // удалить текущий active
171        menu.find('.active').removeClass('active');
172
173        // установить новый active
174        link
175            .next()
176            .show()
177            .addClass('active');
178
179        // сделать ход
180        this._move(1);
181
182        // изменить размер меню, если это необходимо
183        if (settings.resize) {
184          this._resize(link.next())
185        }
186      } else if (link.hasClass('back')) {
187        // и два шага назад
188        // всего один шаг назад, на самом деле
189
190        // сделать ход
191        this._move(-1, () => {
192          // удалить текущий active
193          menu.find('.active').removeClass('active');
194
195          // установить новый active
196          link
197              .parent()
198              .parent()
199              .hide()
200              .parentsUntil(menu, 'ul')
201              .first()
202              .addClass('active')
203        });
204
205        // изменить размер меню, если это необходимо
206        if (settings.resize) {
207          this._resize(
208              link
209                  .parent()
210                  .parent()
211                  .parentsUntil(menu, 'ul')
212          )
213        }
214      }
215    })
216  }
217
218  // перейти к начальному active при инициализации
219  _jumpToInitial() {
220    const { menu, settings } = this;
221
222    // получить начальный active
223    const active = menu.find('.active');
224
225    if (active.length > 0) {
226      // удалить начальный active
227      active.removeClass('active');
228
229      // прыжок без анимации
230      this.jump(active, false)
231    }
232
233    // установить начальную высоту в меню
234    // исправить ошибку изменения размера первого перехода
235    setTimeout(() => menu.height(menu.outerHeight()), settings.speed)
236  }
237
238  // сдвиньте меню
239  _move(depth = 0, callback = () => {}) {
240    // не утруждайте себя, если мы никуда не двигаемся
241    if (depth === 0) {
242      return
243    }
244
245    const { settings, base } = this;
246
247    // получить текущую позицию слева
248    const left = Math.round(parseInt(base.get(0).style.left)) || 0;
249
250    // установить новую позицию слева
251    base.css('left', `${left - depth * 100}%`);
252
253    // обратный вызов после анимации
254    if (typeof callback === 'function') {
255      setTimeout(callback, settings.speed);
256    }
257  }
258
259  // изменить размер меню чтобы соответствовать высоте контента
260  _resize(content) {
261    const { menu } = this;
262
263    menu.height(content.outerHeight())
264  }
265
266  // установить скорость перехода
267  _transition(speed = 300) {
268    const { menu, base } = this;
269
270    menu.css('transition-duration', `${speed}ms`);
271    base.css('transition-duration', `${speed}ms`);
272  }
273
274  // перейти к элементу
275  jump(target, animate = true) {
276    if (!target) {
277      return
278    }
279
280    const { menu, settings } = this;
281
282    const to = jQuery(target);
283
284    // получить все текущие active
285    const active = menu.find('.active');
286
287    // сколько ходов мы должны прыгнуть?
288    let count = 0;
289
290    // пока не достигнем родительского списка
291    if (active.length > 0) {
292      count = active.parentsUntil(menu, 'ul').length;
293    }
294
295    // удалить текущий  active
296    // скрыть все списки
297    menu
298        .find('ul')
299        .removeClass('active')
300        .hide();
301
302    // получить родительский список
303    const menus = to.parentsUntil(menu, 'ul');
304
305    // показать родительский список
306    menus.show();
307
308    // показать цель
309    to.show().addClass('active');
310
311    // установить скорость перехода на 0, если нет анимации
312    if (!animate) {
313      this._transition(0);
314    }
315
316    // заставить двигаться
317    this._move(menus.length - count);
318
319    // изменить размер меню, если это необходимо
320    if (settings.resize) {
321      this._resize(to);
322    }
323
324    // установить скорость перехода по умолчанию после перехода
325    if (!animate) {
326      this._transition(settings.speed);
327    }
328  }
329
330  // со щитом или на щите
331  // просто иди домой
332  home(animate = true) {
333    const { base, menu, settings } = this;
334
335    // установите скорость перехода на 0, если нет анимации
336    if (!animate) {
337      this._transition(0);
338    }
339
340    // get current active
341    const active = menu.find('.active');
342
343    // get all parent lists
344    const parents = active.parentsUntil(menu, 'ul');
345
346    // make the move
347    this._move(-parents.length, () => {
348      // remove the current active
349      active.removeClass('active').hide();
350
351      // hide all parents except base
352      parents.not(base).hide();
353    });
354
355    // resize if need be
356    if (settings.resize) {
357      this._resize(base);
358    }
359
360    // set transition speed back to default
361    if (animate === false) {
362      this._transition(settings.speed);
363    }
364  }
365
366  // crush, kill, destroy
367  destroy() {
368    const { base, menu } = this;
369
370    // remove all headers
371    jQuery('.header', menu).remove();
372
373    // remove Slinky links
374    // and click listeners
375    jQuery('a', menu)
376        .removeClass('next')
377        .off('click');
378
379    // remove inline styles
380    menu.css({
381      height: '',
382      'transition-duration': ''
383    });
384
385    base.css({
386      left: '',
387      'transition-duration': ''
388    });
389
390    // remove Slinky HTML
391    jQuery('li > a > span', menu)
392        .contents()
393        .unwrap();
394
395    // remove any current active
396    menu.find('.active').removeClass('active');
397
398    // remove any Slinky style classes
399    const styles = menu.attr('class').split(' ');
400
401    styles.forEach(style => {
402      if (style.indexOf('slinky') === 0) {
403        menu.removeClass(style);
404      }
405    });
406
407    // reset fields
408    const fields = ['settings', 'menu', 'base'];
409
410    fields.forEach(field => delete this[field]);
411  }
412}
413
414// jQuery plugin
415;($ => {
416  $.fn.slinky = function(options) {
417    return new Slinky(this, options);
418  }
419})(jQuery);

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.