PluginProbe
Float menu – awesome floating side menu / 6.0
Float menu – awesome floating side menu v6.0
7.2.5 trunk 2.1 2.2 3.0.1 3.1 3.2.2 3.3.1 3.5 3.5.1 3.5.2 3.5.3. 3.5.4 4.0 4.1 4.1.1 4.2 4.3 4.3.1 4.3.2 5.0 5.0.1 5.0.2 5.0.3 5.1 All 57 releases
← All changes | public/assets/js/floatMenu.js +1034 -488 trunk6.0 View file →
@@ -1,662 +1,1208 @@
1 -/**
2 - * FloatMenu
3 - * A JavaScript class for creating customizable side menus.
4 - *
5 - * @version 7.1
6 - * @license MIT License
7 - * @author Dmytro Lobov
8 - * @url https://wow-estore.com/item/float-menu-pro/
9 - */
1 +/*! ========= INFORMATION ============================
2 + - author: Wow-Company
3 + - url: https://wow-estore.com/item/float-menu-pro/
4 +==================================================== */
10 5
11 6 'use strict';
12 7
13 -class FloatMenu {
8 +(function($) {
14 9
15 - static ATTR = `data-float-menu`;
10 + var defaults = {
11 + // Main
12 + position: ['left', 'center'],
13 + offset: [0, 0],
14 + buttonShape: 'round',
15 + buttonColor: 'custom',
16 + buttonOverColor: 'custom',
17 + iconColor: 'white',
18 + iconOverColor: 'white',
19 + labelColor: 'match',
20 + labelTextColor: 'match',
21 + labelEffect: 'slide-out-fade',
22 + labelAnimate: 'default',
23 + labelConnected: false,
24 + labelsOn: true,
25 + sideSpace: false,
26 + buttonSpace: false,
27 + labelSpace: false,
28 + mobileEnable: false,
29 + mobileScreen: 768,
30 + // Subbar
31 + subPosition: ['circular', 100, -90, 90],
32 + subEffect: ['slide', 30],
33 + subAnimate: [400, 'easeOutQuad'],
34 + subSpace: false,
35 + subOpen: 'mouseover',
36 + subTop: 42,
37 + // Window
38 + windowPosition: ['center', 'center'],
39 + windowOffset: [0, 0],
40 + windowCorners: 'match',
41 + windowColor: 'match',
42 + windowShadow: true,
43 + // Other
44 + showAfterPosition: false,
45 + hideAfterPosition: false,
46 + barAnimate: [250, 'easeOutQuad'],
47 + hideUnderWidth: false,
48 + shareTarget: 'default',
49 + };
50 + var labelAnimateDefaults = {
51 + 'default': [400, 'easeOutQuad'],
52 + 'fade': [200, 'easeOutQuad'],
53 + 'slide-in-in': {
54 + show: [400, 'easeOutQuad'],
55 + hide: [400, 'swing'],
56 + },
57 + };
16 58
17 - static initialize() {
18 - window.floatMenus = {};
19 - document.querySelectorAll(`[${FloatMenu.ATTR}]`).forEach((floatmenu) => {
20 - const instance = new FloatMenu(floatmenu);
21 - const match = floatmenu.className.match(/float-menu-(\d+)/);
22 - if (match && match[1]) {
23 - const key = match[1];
24 - window.floatMenus[key] = instance;
25 - }
26 - });
59 + var methods = {
60 + 'build': build,
61 + 'destroy': destroy,
62 + };
63 +
64 + $.fn.floatingMenu = function(arg) {
65 + if (typeof arg === 'object' || !arg) {
66 + build.apply(this, arguments);
67 + } else if (methods[arg]) {
68 + methods[arg].apply(this, Array.prototype.slice.call(arguments, 1));
69 + } else {
70 + $.error('The method ' + arg + ' does not exist in Float Menu.');
27 71 }
72 + };
28 73
29 - constructor(floatmenuElement, options = {}) {
30 - if (!(floatmenuElement instanceof HTMLElement)) {
31 - return;
32 - }
74 + function build(options) {
75 + var settings = createSettings(options);
33 76
34 - const defaultConfig = {
35 - 'position': ['left', 'center'],
36 - };
77 + return this.each(function() {
78 + var sidebar = $(this);
37 79
38 - this.element = floatmenuElement;
39 - this.config = Object.assign({}, defaultConfig, this.#parseConfig(), options);
40 - if (this.config === null) return;
80 + if (sidebar.data('fm-built')) destroy.apply(this);
81 + sidebar.data('fm-built', true);
41 82
42 - this.items = floatmenuElement.querySelectorAll(`.fm-item`);
43 - this.links = floatmenuElement.querySelectorAll(`.fm-link`);
44 - this.labels = floatmenuElement.querySelectorAll(`.fm-label`);
83 + // VARS
84 + var bar = sidebar.children('.fm-bar');
85 + var barList = bar.children();
86 + var sbwindow = sidebar.children('.fm-window');
45 87
46 - if (this.items.length === 0) {
47 - return;
48 - }
88 + var $window = $(window);
89 + var $document = $(document);
49 90
50 - const ITEM_PADDING = 15;
91 + var barVisible = true;
92 + var right = false;
93 + var csub = null;
94 + var cwindow = null;
95 + var nextMargins = [];
51 96
52 - this.itemWidth = this.items[0].offsetWidth + ITEM_PADDING;
97 + // INIT
98 + if (settings.position[0] === 'right') {
99 + right = true;
100 + bar.addClass('fm-right');
101 + }
53 102
54 - if (this.config?.remove) {
55 - this.element.removeAttribute(FloatMenu.ATTR);
56 - }
103 + if (settings.buttonShape !== 'square') bar.addClass('fm-' + settings.buttonShape);
57 104
58 - this.init();
105 + if (settings.labelConnected) bar.addClass('fm-connected');
59 106
60 - }
107 + if (settings.buttonColor !== 'custom') bar.addClass('fm-' + settings.buttonColor + '-button');
108 + if (settings.buttonOverColor !== 'custom') bar.addClass('fm-' + settings.buttonOverColor + '-button-over');
61 109
62 - init() {
110 + if (settings.iconColor !== 'custom') bar.addClass('fm-' + settings.iconColor + '-icon');
111 + if (settings.iconOverColor !== 'custom') bar.addClass('fm-' + settings.iconOverColor + '-icon-over');
63 112
64 - this.screen();
65 - window.addEventListener('resize', this.screen.bind(this));
66 - this.mobileStyle();
67 - window.addEventListener('resize', this.mobileStyle.bind(this));
68 - this.labelDisabele();
69 - this.mobileClick();
70 - this.position();
71 - this.appearance();
72 - this.setLinkProperties();
73 - this.setSubMenu();
74 - this.extraText();
75 - this.visibleMenu();
76 - this.closePopup();
77 - }
113 + if (settings.labelColor !== 'custom') bar.addClass('fm-' + settings.labelColor + '-label');
114 + if (settings.labelTextColor !== 'custom') bar.addClass('fm-' + settings.labelTextColor + '-label-text');
78 115
116 + if (settings.sideSpace) bar.addClass('fm-side-space');
117 + if (settings.buttonSpace) bar.addClass('fm-button-space');
118 + if (settings.labelSpace) bar.addClass('fm-label-space');
79 119
80 - appearance() {
81 - if (!this.config?.appearance) {
82 - return;
83 - }
120 + if (settings.windowCorners === 'round') sbwindow.addClass('fm-round');
121 + if (settings.windowColor !== 'custom') sbwindow.addClass('fm-' + settings.windowColor);
122 + if (settings.windowShadow) sbwindow.addClass('fm-winshadow');
84 123
85 - if (this.config?.appearance?.shape) {
86 - this.element.classList.add(this.config?.appearance?.shape);
87 - }
124 + buildList(bar);
88 125
89 - if (this.config?.appearance?.sideSpace) {
90 - this.element.classList.add('-side-space');
91 - }
126 + // Subbar animate fix.
127 + barList.each(function(ind) {
128 + nextMargins[ind] = getInt(barList.eq(ind).css('margin-top'));
129 + });
92 130
93 - if (this.config?.appearance?.buttonSpace) {
94 - this.element.classList.add('-button-space');
131 + sbwindow.children('.fm-shadow').on('click', closeWindow);
132 +
133 + sbwindow.children('.fm-panel').each(buildPanel);
134 +
135 + resize();
136 +
137 + $window.on('resize.superSidebar', resize);
138 +
139 + if (settings.showAfterPosition) {
140 + if ($window.scrollTop() < settings.showAfterPosition) {
141 + bar.css('opacity', 0).addClass('fm-hide');
142 + barVisible = false;
95 143 }
96 144
97 - if (this.config?.appearance?.labelConnected) {
98 - this.element.classList.add('-label-connect');
99 - }
145 + $window.on('scroll.superSidebar', function() {
146 + if ($window.scrollTop() < settings.showAfterPosition) {
147 + if (barVisible) hideBar();
148 + } else {
149 + if (!barVisible) showBar();
150 + }
151 + });
152 + }
100 153
101 - if (this.config?.appearance?.subSpace) {
102 - this.element.classList.add('-sub-space');
154 + if (settings.hideAfterPosition) {
155 + if ($window.scrollTop() > settings.hideAfterPosition) {
156 + bar.css('opacity', 0).addClass('fm-hide');
157 + barVisible = false;
103 158 }
104 159
105 - }
160 + $window.on('scroll.superSidebar', function() {
161 + if ($window.scrollTop() > settings.hideAfterPosition) {
162 + if (barVisible) hideBar();
163 + } else {
164 + if (!barVisible) showBar();
165 + }
166 + });
167 + }
106 168
107 - labelDisabele() {
169 + bar.addClass('fm-css-anim');
108 170
171 + sidebar.addClass('fm-ready');
109 172
110 - if (!this.config?.label?.off) {
111 - return false;
112 - }
113 - this.links.forEach((label) => {
114 - label.classList.add('-label-hidden');
173 + // FUNCTIONS
174 + function buildList(list) {
175 + list.children().each(function(i) {
176 + if ($(this).hasClass('fm-sub')) buildSub(this, i);
177 + else buildButton(this);
115 178 });
116 - }
179 + }
117 180
118 - screen() {
119 - if (!this.config?.screen) {
120 - return;
121 - }
181 + function buildButton(btn) {
182 + var button = $(btn);
183 + var link = button.children('a, .fm-link');
184 + var icon = link.children('.fm-icon');
185 + var label = link.children('.fm-label');
186 + var mask, hit = null;
122 187
123 - const {small, large} = this.config.screen;
124 - const viewportWidth = window.innerWidth;
188 + var linkClick = 0;
189 + var screen = $(window).width();
125 190
126 - const hideMenu = () => {
127 - this.element.classList.add('fm-hidden');
128 - };
191 + var maskHtml = '<div class="fm-mask"></div>';
192 + var hitHtml = '<div class="fm-hit"></div>';
129 193
130 - const showMenu = () => {
131 - this.element.classList.remove('fm-hidden');
132 - };
194 + var iw, lw;
195 + var side = right ? 'right' : 'left';
196 + var dist = 40;
197 + var maskOff = false;
198 + var start = {}, show = {}, end = {};
199 + var showLabel, hideLabel;
133 200
134 - if (typeof small !== 'undefined' && viewportWidth <= small) {
135 - hideMenu();
136 - return;
137 - }
201 + var showTime = settings.labelAnimate.show[0];
202 + var showEase = settings.labelAnimate.show[1];
203 + var hideTime = settings.labelAnimate.hide[0];
204 + var hideEase = settings.labelAnimate.hide[1];
138 205
139 - if (typeof large !== 'undefined' && viewportWidth >= large) {
140 - hideMenu();
141 - return;
206 + if (settings.labelsOn && label.length) {
207 + iw = getInt(icon.css('width'));
208 + lw = label.outerWidth(true);
209 + if(settings.position[0] === 'left') {
210 + label.css({'left': iw + 'px'});
211 + } else {
212 + label.css({'right': iw + 'px'});
213 + }
214 +
215 +
216 + if (settings.buttonShape === 'round' || settings.buttonShape === 'rounded') maskOff = true;
217 +
218 + if(settings.labelConnected && settings.position[0] === 'left') {
219 + label.css({'left': 0 , 'padding-left': iw + 12 +'px'});
220 + } else if( settings.labelConnected && settings.position[0] === 'right') {
221 + label.css({'right': 0 , 'padding-right': iw + 12 +'px'});
222 + }
223 +
224 + if (!settings.labelConnected &&
225 + (settings.labelSpace || settings.buttonShape === 'round' || settings.buttonShape === 'rounded' ||
226 + settings.buttonShape === 'rounded-out')) {
227 + hit = $(hitHtml).appendTo(link);
228 + }
229 +
230 +
231 + switch (settings.labelEffect) {
232 + case 'fade':
233 + start = {'opacity': 0};
234 + show = {'opacity': 1};
235 +
236 + label.css(start);
237 +
238 + showLabel = function() {
239 + if (hit) hit.addClass('fm-show');
240 + label.velocity('stop').addClass('fm-show').velocity(show, showTime, showEase);
241 + };
242 + hideLabel = function() {
243 + label.velocity('stop').velocity(start, hideTime, hideEase, function() {
244 + label.removeClass('fm-show');
245 + if (hit) hit.removeClass('fm-show');
246 + });
247 + };
248 + break;
249 + case 'slide-out':
250 + case 'slide-out-fade':
251 + mask = link.wrap(maskHtml).parent();
252 + mask.css('width', iw);
253 + if (maskOff) mask.addClass('fm-off');
254 +
255 + start[side] = -lw + iw;
256 + if (settings.labelConnected) show[side] = 0;
257 + else show[side] = iw;
258 +
259 + if (settings.labelEffect === 'slide-out-fade') {
260 + start['opacity'] = 0;
261 + show['opacity'] = 1;
262 + }
263 +
264 + label.css(start);
265 +
266 + showLabel = function() {
267 + mask.css('width', iw + lw);
268 + if (maskOff) mask.removeClass('fm-off');
269 + if (hit) hit.addClass('fm-show');
270 + label.velocity('stop').addClass('fm-show').velocity(show, showTime, showEase, function(){
271 + mask.addClass('fm-off');
272 + });
273 + };
274 + hideLabel = function() {
275 + mask.removeClass('fm-off');
276 + label.velocity('stop').velocity(start, hideTime, hideEase, function() {
277 + label.removeClass('fm-show');
278 + mask.css('width', iw);
279 + if (maskOff) mask.addClass('fm-off');
280 + if (hit) hit.removeClass('fm-show');
281 + });
282 + };
283 + break;
284 + case 'slide-in':
285 + start = {'opacity': 0};
286 + start[side] = iw + dist;
287 + show = {'opacity': 1};
288 + show[side] = iw;
289 +
290 + label.css(start);
291 +
292 + showLabel = function() {
293 + if (hit) hit.addClass('fm-show');
294 + label.velocity('stop').addClass('fm-show').velocity(show, showTime, showEase);
295 + };
296 + hideLabel = function() {
297 + label.velocity('stop').velocity(start, hideTime, hideEase, function() {
298 + label.removeClass('fm-show');
299 + if (hit) hit.removeClass('fm-show');
300 + });
301 + };
302 + break;
303 + case 'slide-out-out':
304 + case 'slide-in-in':
305 + mask = link.wrap(maskHtml).parent();
306 + mask.css('width', iw);
307 + if (maskOff) mask.addClass('fm-off');
308 +
309 + if (settings.labelEffect === 'slide-out-out') {
310 + start[side] = -lw + iw;
311 + show[side] = iw;
312 + end[side] = iw + dist;
313 + } else {
314 + start[side] = iw + dist;
315 + show[side] = iw;
316 + end[side] = -lw + iw;
317 + }
318 + start['opacity'] = 0;
319 + show['opacity'] = 1;
320 + end['opacity'] = 0;
321 +
322 + showLabel = function() {
323 + mask.css('width', iw + lw + dist);
324 + if (maskOff) mask.removeClass('fm-off');
325 + if (hit) hit.addClass('fm-show');
326 + label.velocity('stop').css(start).addClass('fm-show').velocity(show, showTime, showEase, function() {
327 + mask.css('width', iw + lw);
328 + mask.addClass('fm-off');
329 + });
330 + };
331 + hideLabel = function() {
332 + mask.removeClass('fm-off');
333 + mask.css('width', iw + lw + dist);
334 + label.velocity('stop').velocity(end, hideTime, hideEase, function() {
335 + label.removeClass('fm-show');
336 + mask.css('width', iw);
337 + if (maskOff) mask.addClass('fm-off');
338 + if (hit) hit.removeClass('fm-show');
339 + });
340 + };
341 + break;
342 + default:
343 + showLabel = function() {
344 + if (hit) hit.addClass('fm-show');
345 + label.addClass('fm-show');
346 + };
347 + hideLabel = function() {
348 + label.removeClass('fm-show');
349 + if (hit) hit.removeClass('fm-show');
350 + };
351 + break;
352 + }
353 +
354 + if (settings.mobileEnable == true && settings.mobileScreen >= screen) {
355 +
356 + link.on('touchend', function(e) {
357 +
358 + if (linkClick == 0) {
359 + e.preventDefault();
360 + showLabel();
361 + linkClick = 1;
362 + setTimeout(function() {
363 + hideLabel();
364 + linkClick = 0;
365 + }, 3000);
366 + return;
367 + } else if (linkClick == 1) {
368 + hideLabel();
369 + linkClick = 0;
370 + }
371 + });
372 + } else {
373 + link.on('mouseenter', showLabel);
374 + link.on('mouseleave', hideLabel);
375 + }
142 376 }
143 377
144 - if (typeof small === 'undefined' || typeof large === 'undefined' ||
145 - (viewportWidth > small && viewportWidth < large)) {
146 - showMenu();
147 - }
378 + var shareVal = link.data('share');
379 + var shareData;
380 + var shareUrl;
381 + var shareTarget;
382 + var href;
383 + var labelShow;
148 384
149 - }
385 + if (shareVal) {
386 + if (shareVal === 'pinterest') {
387 + link.on('click', pinterestShare);
388 + } else {
389 + shareData = settings.shareServices[shareVal];
150 390
151 - closePopup() {
152 - const popups = this.element.querySelectorAll(`.fm-window`);
153 - if (popups.length === 0) {
154 - return;
155 - }
391 + if (shareData) {
392 + shareUrl = shareData.url.replace('{URL}', PAGE_URL).replace('{TITLE}', PAGE_TITLE);
156 393
157 - popups.forEach((popup) => {
158 - const close = popup.querySelector(`.fm-close`);
159 - if (close) {
160 - close.addEventListener('click', () => {
161 - popup.close();
162 - });
163 - }
394 + link.attr('href', shareUrl);
164 395
165 - popup.addEventListener('click', closeOnBackDropClick);
396 + if (shareData.target === 'app') {
397 + link.attr('target', '_self');
398 + } else {
399 + if (settings.shareTarget === 'default') shareTarget = shareData.target;
400 + else shareTarget = settings.shareTarget;
166 401
167 - function closeOnBackDropClick({currentTarget, target}) {
168 - const dialogElement = currentTarget;
169 - const isClickedOnBackDrop = target === dialogElement;
170 - if (isClickedOnBackDrop) {
171 - dialogElement.close();
402 + if (shareTarget === 'popup') {
403 + link.on('click', {'url': shareUrl, 'params': shareData.popup}, sharePopup);
404 + } else {
405 + link.attr('target', '_blank');
172 406 }
407 + }
408 + } else {
409 + warn('There is no share data for "' + shareVal + '".');
173 410 }
174 - });
175 - }
411 + }
412 + } else {
413 + href = link.attr('href');
176 414
177 - extraText() {
178 - const textBox = this.element.querySelectorAll(`.fm-extra-text`);
179 - if (textBox.length === 0) {
180 - return;
415 + if (href && href.indexOf('fm-popup') > -1 && href !== '#') {
416 + link.on('click', function() {
417 + openWindow(href);
418 + return false;
419 + });
420 + }
181 421 }
182 422
183 - textBox.forEach(text => {
184 - const space = parseFloat(this.config?.label?.space) || 0;
185 - text.style.setProperty('--text_margin', space);
186 - const item = text.closest('.fm-item');
187 - const link = item.querySelector('.fm-link');
423 + labelShow = link.attr('data-label');
188 424
189 - item.addEventListener('mouseenter', () => {
190 - link.classList.toggle('-active');
191 - });
192 - item.addEventListener('mouseleave', () => {
193 - link.classList.remove('-active');
194 - });
425 + if (labelShow === 'show') {
426 + showLabel();
427 + }
195 428
196 - });
429 + }
197 430
198 - }
431 + function buildSub(sub, ind) {
432 + var sub = $(sub);
433 + var icon = sub.children('.fm-icon');
434 + var list = sub.children('ul');
435 + var buttonList = list.children();
436 + var hit = null;
437 + var nextButton = null;
199 438
200 - visibleMenu() {
439 + var hitHtml = '<div class="fm-subhit"></div>';
201 440
202 - if (
203 - (!this.config.visible || this.config.visible.every(v => v === 'show' || v === '0')) &&
204 - (!this.config.time || this.config.time.every(t => t === 'show' || t === '0'))
205 - ) {
206 - this.element.classList.add('fm-ready');
207 - return;
208 - }
441 + var position = settings.subPosition[0];
442 + var effect = settings.subEffect[0];
443 + var side = right ? 'right' : 'left';
444 + var total = buttonList.length;
445 + var iw = getInt(icon.css('width'));
446 + var ih = getInt(icon.css('height'));
447 + var positions = [];
448 + var status = null;
449 + var start = {}, show = {};
450 + var interval;
451 + var showList, hideList;
452 + var i;
453 + var nextOffset = 0;
454 + var prevOffset = 0;
455 + var nextMargin;
456 + var buttonMargin;
457 + var barMargin;
458 + var subOpen = false;
209 459
210 - let isReady = false;
460 + var showTime = settings.subAnimate.show[0];
461 + var showEase = settings.subAnimate.show[1];
462 + var hideTime = settings.subAnimate.hide[0];
463 + var hideEase = settings.subAnimate.hide[1];
211 464
212 - const showMenu = () => {
213 - if (!isReady) {
214 - this.element.classList.add('fm-ready');
215 - isReady = true;
216 - }
217 - };
465 + buildList(list);
218 466
219 - const hideMenu = () => {
220 - if (isReady) {
221 - this.element.classList.remove('fm-ready');
222 - isReady = false;
223 - }
224 - };
467 + if (position === 'side') sub.addClass('fm-side');
468 + if (settings.subSpace) sub.addClass('fm-sub-space');
225 469
226 - if (this.config.time) {
227 - const time = this.config.time || ['show', '0'];
228 - const [timeAction, timeValue] = time;
229 - const timeThreshold = Number(timeValue);
470 + if (effect === 'linear-slide' || position === 'circular')
471 + sub.addClass('fm-posabs');
230 472
231 - if (timeAction === 'show' && timeThreshold > 0) {
232 - setTimeout(showMenu, timeThreshold * 1000);
233 - }
473 + if ((position === 'under' && effect === 'linear-slide') ||
474 + (position === 'circular' && effect === 'slide') ||
475 + (position === 'circular' && effect === 'linear-slide')) {
476 + buttonList.each(function(i) {
477 + $(this).css('z-index', 100 - i);
478 + });
479 + }
234 480
235 - if (timeAction === 'hide' && timeThreshold > 0) {
236 - showMenu();
237 - setTimeout(hideMenu, timeThreshold * 1000);
238 - }
481 + if (barList[ind + 1]) {
482 + nextButton = barList.eq(ind + 1);
483 + //nextMargin = getInt(nextButton.css("margin-top"));
239 484 }
240 485
241 - if (this.config.visible) {
486 + if (position === 'circular') {
487 + sub.addClass('fm-circular');
242 488
243 - const visible = this.config.visible || ['show', '0'];
244 - const [visibleAction, visibleValue] = visible;
245 - const visibleThreshold = Number(visibleValue);
489 + var r = settings.subPosition[1];
490 + var sa = settings.subPosition[2];
491 + var ea = settings.subPosition[3];
246 492
247 - if (visibleAction === 'hide') {
248 - showMenu();
249 - }
493 + var startRad = sa * Math.PI / 180;
494 + var endRad = ea * Math.PI / 180;
495 + var stepRad = (endRad - startRad) / (total - 1);
496 + var a, s, t, p;
250 497
251 - window.addEventListener('scroll', () => {
252 - const scrollTop = window.scrollY || document.documentElement.scrollTop;
498 + buttonList.each(function(i) {
499 + a = i * stepRad + startRad;
500 + s = Math.round(r * Math.cos(a));
501 + t = Math.round(r * Math.sin(a));
253 502
254 - if (visibleAction === 'show') {
255 - if (scrollTop >= visibleThreshold) {
256 - showMenu();
503 + p = {'top': t};
504 + p[side] = s;
505 + $(this).css(p);
506 + positions[i] = [s, t];
507 + });
257 508
258 - } else {
259 - hideMenu();
260 - }
261 - }
509 + hit = $(hitHtml).appendTo(sub);
510 + hit.css({
511 + 'width': r + iw,
512 + 'height': 2 * r + iw,
513 + 'border-radius': right ? r + 'px 0 0 ' + r + 'px' : '0 ' + r + 'px ' + r + 'px 0',
514 + 'top': -r,
515 + });
262 516
263 - if (visibleAction === 'hide') {
264 - if (scrollTop > visibleThreshold) {
265 - hideMenu();
266 - } else {
267 - showMenu();
268 - }
269 - }
517 + buttonMargin = getInt(barList.eq(0).css('margin-bottom'));
270 518
519 + if (ind !== 0) {
520 + prevOffset = r + buttonMargin;
521 + barMargin = getInt(bar.css('margin-top'));
522 + sub.css('margin-top', buttonMargin);
523 + }
524 +
525 + if (nextButton) {
526 + nextOffset = r + buttonMargin;
527 + }
528 + } else {
529 + if (effect === 'linear-slide') {
530 + var c = 0;
531 + buttonList.each(function(i) {
532 + var btn = $(this);
533 + btn.css('top', c);
534 + positions[i] = c;
535 + c += getInt(btn.css('height')) + getInt(btn.css('margin-bottom'));
271 536 });
537 +
538 + list.css({'width': iw, 'height': c});
539 + }
540 +
541 + hit = $(hitHtml).appendTo(sub);
542 + if (position === 'side')
543 + hit.css({'width': iw + getInt(list.css('margin-' + side)), 'height': ih});
544 + else
545 + hit.css({'width': iw, 'height': ih + getInt(list.css('margin-top'))});
546 +
547 + if (position === 'under' && nextButton) {
548 + nextOffset = list.outerHeight(true) + getInt(nextButton.css('margin-top')) + getInt(list.css('margin-top'));
549 + }
272 550 }
273 551
274 - }
552 + list.addClass('fm-hide');
275 553
276 - mobileStyle() {
554 + switch (effect) {
555 + case 'fade':
556 + start = {'opacity': 0};
557 + show = {'opacity': 1};
277 558
278 - if (!this.config?.mobile) {
279 - return;
280 - }
559 + list.css(start);
281 560
282 - const screenWidth = window.innerWidth;
283 - const screen = parseInt(this.config?.mobile[0]) || 0;
284 - const iconSize = parseInt(this.config?.mobile[1]) || 24;
285 - const labelSize = parseInt(this.config?.mobile[2]) || 15;
286 - const boxSize = parseInt(this.config?.mobile[3]) || 0;
287 - const textSize = parseInt(this.config?.mobile[4]) || 12;
561 + showList = function() {
562 + list.velocity('stop').removeClass('fm-hide').velocity(show, showTime, showEase);
563 + };
564 + hideList = function() {
565 + list.velocity('stop').velocity(start, hideTime, hideEase, function() {
566 + list.addClass('fm-hide');
567 + });
568 + };
569 + break;
570 + case 'slide':
571 + if (position === 'circular') {
572 + start = {'top': 0, 'opacity': 0};
573 + start[side] = 0;
574 + buttonList.css(start);
288 575
289 - if (screenWidth < screen) {
290 - this.element.style.setProperty('--fm-icon-size', iconSize);
291 - this.element.style.setProperty('--fm-label-size', labelSize);
292 - this.element.style.setProperty('--fm-icon-text', textSize);
293 - if(boxSize !== 0 ) {
294 - this.element.style.setProperty('--fm-icon-box', boxSize);
576 + showList = function() {
577 + list.removeClass('fm-hide');
578 + buttonList.each(function(i) {
579 + show = {'top': positions[i][1], 'opacity': 1};
580 + show[side] = positions[i][0];
581 + $(this).velocity('stop').velocity(show, showTime, showEase);
582 + });
583 + };
584 + hideList = function() {
585 + buttonList.each(function(i) {
586 + $(this).velocity('stop').velocity(start, hideTime, hideEase, function() {
587 + if (i === total - 1) list.addClass('fm-hide');
588 + });
589 + });
590 + };
591 + } else {
592 + if (position === 'side') {
593 + start[side] = 0;
594 + show[side] = iw;
595 + } else {
596 + start = {'top': 0};
597 + show = {'top': icon[0].clientHeight};
598 + }
599 + start['opacity'] = 0;
600 + show['opacity'] = 1;
601 +
602 + list.css(start);
603 +
604 + showList = function() {
605 + list.velocity('stop').removeClass('fm-hide').velocity(show, showTime, showEase);
606 + };
607 + hideList = function() {
608 + list.velocity('stop').velocity(start, hideTime, hideEase, function() {
609 + list.addClass('fm-hide');
610 + });
611 + };
295 612 }
613 + break;
614 + case 'linear-fade':
615 + start = {'opacity': 0};
616 + show = {'opacity': 1};
617 +
618 + buttonList.css(start);
619 +
620 + showList = function() {
621 + status = 'show';
622 + list.removeClass('fm-hide');
623 + stopInterval();
624 + i = 0;
625 + interval = setInterval(function() {
626 + buttonList.eq(i).velocity('stop').velocity(show, showTime, showEase);
627 + if (i === total - 1) stopInterval();
628 + else i++;
629 + }, settings.subEffect[1]);
630 + };
631 + hideList = function() {
632 + status = 'hide';
633 + stopInterval();
634 + i = total - 1;
635 + interval = setInterval(function() {
636 + var bi = i;
637 + buttonList.eq(i).velocity('stop').velocity(start, showTime, showEase, function() {
638 + if (status === 'hide' && bi === 0) list.addClass('fm-hide');
639 + });
640 + if (i === 0) stopInterval();
641 + else i--;
642 + }, settings.subEffect[1]);
643 + };
644 + break;
645 + case 'linear-slide':
646 + var first, last, step;
647 +
648 + if (position === 'side') start[side] = -iw;
649 + else if (position === 'circular') {
650 + start = {'top': 0};
651 + start[side] = 0;
652 + } else start = {'top': -ih};
653 + start['opacity'] = 0;
654 +
655 + buttonList.css(start);
656 +
657 + showList = function() {
658 + status = 'show';
659 + list.removeClass('fm-hide');
660 + stopInterval();
661 + i = 0;
662 + interval = setInterval(function() {
663 + if (position === 'side') show[side] = 0;
664 + else if (position === 'circular') {
665 + show = {'top': positions[i][1]};
666 + show[side] = positions[i][0];
667 + } else show = {'top': positions[i]};
668 + show['opacity'] = 1;
669 +
670 + buttonList.eq(i).velocity('stop').velocity(show, showTime, showEase);
671 + if (i === total - 1) stopInterval();
672 + else i++;
673 + }, settings.subEffect[1]);
674 + };
675 + hideList = function() {
676 + status = 'hide';
677 +
678 + if (position === 'side' || position === 'circular') {
679 + first = 0;
680 + last = total - 1;
681 + step = 1;
682 + } else {
683 + first = total - 1;
684 + last = 0;
685 + step = -1;
686 + }
687 +
688 + stopInterval();
689 + i = first;
690 + interval = setInterval(function() {
691 + var bi = i;
692 + buttonList.eq(i).velocity('stop').velocity(start, showTime, showEase, function() {
693 + if (status === 'hide' && bi === last) list.addClass('fm-hide');
694 + });
695 + if (i === last) stopInterval();
696 + else i += step;
697 + }, settings.subEffect[1]);
698 + };
699 + break;
700 + default:
701 + showList = function() {
702 + list.removeClass('fm-hide');
703 + };
704 + hideList = function() {
705 + list.addClass('fm-hide');
706 + };
707 + break;
296 708 }
297 709
298 - }
710 + function stopInterval() {
711 + clearInterval(interval);
712 + }
299 713
300 - mobileClick() {
301 - if (!this._isMobile()) {
302 - return;
714 + function showSub() {
715 + showList();
716 + if (hit) hit.addClass('fm-show');
717 +
718 + if (prevOffset) {
719 + bar.velocity('stop').velocity({'margin-top': barMargin - prevOffset + buttonMargin}, showTime, showEase);
720 + sub.velocity('stop').velocity({'margin-top': prevOffset}, showTime, showEase);
721 + }
722 +
723 + if (nextOffset) {
724 + nextButton.velocity('stop').velocity({'margin-top': nextOffset}, showTime, showEase);
725 + }
726 +
727 + subOpen = true;
728 + csub = sub;
303 729 }
304 730
305 - if (!this.config?.mobileRules) {
306 - return;
731 + function hideSub() {
732 + hideList();
733 + if (hit) hit.removeClass('fm-show');
734 +
735 + if (prevOffset) {
736 + bar.velocity('stop').velocity({'margin-top': barMargin}, showTime, showEase);
737 + sub.velocity('stop').velocity({'margin-top': buttonMargin}, showTime, showEase);
738 + }
739 +
740 + if (nextOffset) {
741 + nextButton.velocity('stop').velocity({'margin-top': nextMargins[ind + 1]}, showTime, showEase);
742 + }
743 +
744 + subOpen = false;
745 + csub = null;
307 746 }
308 747
309 - this.links.forEach((link) => {
310 - let timer;
311 - link.addEventListener('click', (event) => {
748 + sub.show = showSub;
749 + sub.hide = hideSub;
312 750
313 - if (!link.classList.contains('-active')) {
314 - event.preventDefault();
315 - event.stopImmediatePropagation();
316 - this.links.forEach((otherLink) => {
317 - otherLink.classList.remove('-active');
318 - });
751 + if (settings.subOpen === 'click') {
752 + icon.on('click', function(event) {
753 + if (subOpen) {
754 + hideSub();
755 + } else {
756 + if (csub) {
757 + csub.hide();
758 + }
759 + showSub();
760 + }
761 + event.stopPropagation();
762 + });
319 763
320 - link.classList.add('-active');
321 - clearTimeout(timer);
764 + $document.on('click', function(event) {
765 + if (subOpen && !cwindow && !$(event.target).closest(sub).length) {
766 + hideSub();
767 + }
768 + });
769 + } else {
770 + sub.on('mouseenter touchstart', showSub);
771 + sub.on('mouseleave', hideSub);
772 + }
322 773
323 - setTimeout(() => {
324 - link.classList.remove('-active');
325 - link.blur();
326 - }, 3000);
327 - }
328 - });
774 + function triggerClick() {
775 + $document.on('click', function(event) {
776 + if (subOpen && !cwindow && !$(event.target).closest(sub).length) {
777 + hideSub();
778 + }
779 + });
780 + }
781 +
782 + window.addEventListener('scroll', function() {
783 + if (subOpen) {
784 + hideSub();
785 + }
329 786 });
787 + }
330 788
331 - document.addEventListener('click', (event) => {
332 - if (!this.element.contains(event.target)) {
333 - this.links.forEach((link) => {
334 - const item = link.closest('.fm-item');
335 - link.classList.remove('-active');
336 - item.classList.remove('-active');
337 - });
338 - }
789 + function buildPanel() {
790 + var panel = $(this);
791 + panel.find('.fm-close').on('click', function(event) {
792 + closeWindow();
793 + event.stopPropagation();
339 794 });
340 795
341 - }
796 + }
342 797
343 - position() {
344 - let side = this.config?.position[0] || 'left';
345 - let align = this.config?.position[1] || 'center';
798 + function openWindow(name) {
799 + sbwindow.addClass('fm-show');
800 + cwindow = $(name).addClass('fm-show');
801 + posWindow(cwindow);
802 + }
346 803
347 - this.element.classList.add(`-${side}`);
348 - this.element.classList.add(`-${align}`);
804 + function closeWindow() {
805 + sbwindow.removeClass('fm-show');
806 + cwindow.removeClass('fm-show');
807 + cwindow = null;
808 + }
349 809
350 - const style = this.element.getBoundingClientRect();
351 - let offsetSide = 0;
352 - let offsetTop = 0;
810 + function position() {
811 + posBar();
812 + if (cwindow) posWindow(cwindow);
813 + }
353 814
354 - if (this.config?.offset) {
355 - offsetSide = parseInt(this.config?.offset[0]);
356 - offsetTop = parseInt(this.config?.offset[1]);
357 - }
815 + function resize() {
816 + position();
358 817
359 - if (offsetSide !== 0) {
360 - this.element.style.setProperty('--fm-offset', `${offsetSide}px`);
818 + if (settings.hideUnderWidth) {
819 + if ($window.width() < settings.hideUnderWidth) {
820 + sidebar.addClass('fm-vhide');
821 + } else {
822 + sidebar.removeClass('fm-vhide');
823 + }
361 824 }
825 + }
362 826
827 + function posBar() {
828 + posObject(bar, settings.position, settings.offset);
829 + }
363 830
831 + function posWindow(win) {
832 + var pos, off;
364 833
365 - if (align === 'top') {
366 - let top = style.top + offsetTop;
367 - this.element.style.top = `${top}px`;
834 + if (win.data('position')) {
835 + pos = win.data('position').split('-');
836 + if (!pos[1]) pos[1] = defaults.windowPosition[1];
837 + } else {
838 + pos = settings.windowPosition;
368 839 }
369 - else if (align === 'center') {
370 - let top = style.top + offsetTop;
371 - const menuHeight = this.element.offsetHeight;
372 - top = top - menuHeight / 2;
373 - this.element.style.top = `${top}px`;
840 +
841 + if (win.data('offset')) {
842 + off = splitOffset(win.data('offset'));
843 + } else {
844 + off = settings.windowOffset;
374 845 }
375 - else if(align === 'bottom') {
376 - let bottom = offsetTop * (-1);
377 - this.element.style.bottom = `${bottom}px`;
378 - }
379 846
380 - }
847 + posObject(win, pos, off);
848 + }
381 849
382 - setLinkProperties() {
383 - const space = parseFloat(this.config?.label?.space) || 0;
384 - const labelEffect = this.config?.label?.effect || 'none';
850 + function posObject(tar, pos, off) {
851 + if (pos) {
852 + var ww = $window.width();
853 + var wh = $window.height();
854 + var tw = tar.outerWidth(true);
855 + var th = tar.outerHeight(true);
856 + var x, y;
857 + var p;
385 858
386 - this.links.forEach((link) => {
387 - const label = link.querySelector('.fm-label');
388 - let labelWidth = label.offsetWidth + space;
389 - const iconWidth = link.offsetWidth;
390 - const width = iconWidth + labelWidth;
391 - if (link.classList.contains('fm-hold-open')) {
392 - labelWidth = labelWidth - iconWidth + 12;
859 + if (typeof pos[0] === 'number') x = {'left': pos[0] + off[0]};
860 + else if (typeof pos[0] === 'string') {
861 + if (pos[0].indexOf('%') !== -1) {
862 + p = getInt(pos[0].split('%')[0]);
863 + x = {'left': p / 100 * ww + off[0]};
864 + } else {
865 + if (pos[0] === 'left') x = {'left': 0 + off[0]};
866 + else if (pos[0] === 'center') x = {'left': (ww - tw) / 2 + off[0]};
867 + else if (pos[0] === 'right') x = {'right': 0 + off[0]};
868 +
869 + else x = {'left': getInt(pos[0]) + off[0]};
393 870 }
394 - link.style.setProperty('--_width', labelWidth);
395 - link.classList.add(`-${labelEffect}`);
396 - });
397 - }
871 + }
398 872
399 - setSubMenu() {
400 - if (!this.config?.sub) {
401 - return;
873 + if (typeof pos[1] === 'number') y = {'top': pos[1] + off[1]};
874 + else if (typeof pos[1] === 'string') {
875 + if (pos[1].indexOf('%') !== -1) {
876 + p = getInt(pos[1].split('%')[0]);
877 + y = {'top': p / 100 * wh + off[1]};
878 + } else {
879 + if (pos[1] === 'top') y = {'top': 0 + off[1]};
880 + else if (pos[1] === 'center') y = {'top': (wh - th) / 2 + off[1]};
881 + else if (pos[1] === 'bottom') y = {'bottom': 0 + off[1]};
882 +
883 + else y = {'top': getInt(pos[1]) + off[1]};
884 + }
885 + }
886 +
887 + if (x.left) x.left = Math.round(x.left);
888 + if (x.right) x.right = Math.round(x.right);
889 +
890 + if (y.top) y.top = Math.round(y.top);
891 + if (y.bottom) y.bottom = Math.round(y.bottom);
892 +
893 + tar.css($.extend({}, x, y));
402 894 }
895 + }
403 896
404 - const hasSub = this.element.querySelectorAll('.fm-has-sub');
405 - if (hasSub.length === 0) {
406 - return;
897 + function pinterestShare(event) {
898 + $('body').
899 + append('<script src="https://assets.pinterest.com/js/pinmarklet.js" type="text/javascript"></script>');
900 + event.preventDefault();
901 + }
902 +
903 + function sharePopup(event) {
904 + var url = event.data.url;
905 + var params = event.data.params;
906 + var winLeft;
907 + var winParams;
908 +
909 + if (params.left === 'center') {
910 + winLeft = ($window.width() - params.width) / 2;
911 + } else {
912 + winLeft = params.left;
407 913 }
408 914
409 - const position = this.config?.sub?.position || 'under';
410 - const effect = this.config?.sub?.effect || 'none';
411 - const open = this.config?.sub?.open || 'click';
915 + winParams = 'menubar=no,toolbar=no,location=no,scrollbars=no,status=no,resizable=yes,width=' + params.width +
916 + ',height=' + params.height + ',top=' + params.top + ',left=' + winLeft;
412 917
413 - let activeSub = null;
918 + window.open(url, 'sbShareWindow', winParams);
414 919
415 - hasSub.forEach((sub) => {
416 - sub.classList.add(`fm-sub-${position}`);
417 - sub.classList.add(`-sub-${effect}`);
920 + event.preventDefault();
921 + }
418 922
419 - const previousElements = [];
420 - let sibling = sub.previousElementSibling;
923 + function showBar() {
924 + bar.removeClass('fm-hide');
925 + bar.velocity('stop').velocity({'opacity': 1}, settings.barAnimate.show[0], settings.barAnimate.show[1]);
926 + barVisible = true;
927 + }
421 928
422 - while (sibling) {
423 - if (sibling.classList.contains('fm-item')) {
424 - previousElements.push(sibling);
425 - }
426 - sibling = sibling.previousElementSibling;
427 - }
929 + function hideBar() {
930 + bar.velocity('stop').
931 + velocity({'opacity': 0}, settings.barAnimate.show[0], settings.barAnimate.show[1], function() {
932 + bar.addClass('fm-hide');
933 + });
934 + barVisible = false;
935 + }
936 + });
937 + }
428 938
429 - this.setSubProperties(sub, effect, position);
939 + function destroy() {
940 + return $(this).each(function() {
941 + var sidebar = $(this);
942 + var bar, sbwindow;
430 943
431 - const link = sub.querySelector('.fm-link');
944 + if (sidebar.data('fm-built')) {
945 + sidebar.data('fm-built', false);
432 946
433 - if (open === 'click' || this._isMobile()) {
947 + bar = sidebar.children('.fm-bar');
948 + sbwindow = sidebar.children('.fm-window');
434 949
435 - link.addEventListener('click', (event) => {
436 - event.preventDefault();
437 - })
950 + bar.attr('class', 'fm-bar').removeAttr('style');
951 + sbwindow.attr('class', 'fm-window');
438 952
439 - sub.addEventListener('click', (event) => {
440 - event.stopPropagation();
953 + destroyList(bar);
441 954
442 - if (activeSub && activeSub !== sub) {
443 - this.closeSubMenu(activeSub, position);
444 - }
955 + sbwindow.removeClass('fm-show');
956 + sbwindow.children('.fm-shadow').off('click');
957 + sbwindow.children('.fm-panel').removeClass('fm-show').removeAttr('style').each(destroyPanel);
445 958
446 - if (activeSub) {
447 - if (
448 - activeSub.contains(event.target) &&
449 - (event.target.matches('.fm-sub') || event.target.closest('.fm-link')) &&
450 - (link && !link.contains(event.target))
451 - ) {
452 - return;
453 - }
454 - }
959 + $(window).off('resize.superSidebar scroll.superSidebar');
455 960
456 - sub.classList.toggle(`-active`);
457 - // link.classList.toggle(`-active`);
458 - activeSub = sub.classList.contains(`-active`) ? sub : null;
961 + sidebar.removeClass('fm-ready');
962 + }
459 963
460 - if (position === 'circular') {
461 - link.classList.toggle(`-label-hidden`);
462 - if (previousElements.length > 0) {
463 - previousElements.forEach((item) => {
464 - item.classList.toggle(`-hidden`);
465 - });
466 - }
467 - }
468 - });
469 - } else {
470 - sub.addEventListener('mouseenter', () => {
471 - const link = sub.querySelector('.fm-link');
472 - sub.classList.add(`-active`);
473 - if (!link.classList.contains('-active')) {
474 - link.classList.add(`-active`);
475 - }
964 + function destroyList(list) {
965 + list.children().each(function() {
966 + if ($(this).hasClass('fm-sub')) destroySub(this);
967 + else destroyButton(this);
968 + });
969 + }
476 970
477 - if (position === 'circular') {
478 - link.classList.toggle(`-label-hidden`);
479 - if (previousElements.length > 0) {
480 - previousElements.forEach((item) => {
481 - item.classList.toggle(`-hidden`);
482 - });
483 - }
484 - }
485 - });
971 + function destroyButton(btn) {
972 + var button = $(btn);
973 + var link = button.find('a');
974 + var label = link.children('.fm-label');
486 975
487 - sub.addEventListener('mouseleave', () => {
488 - this.closeSubMenu(sub, position);
489 - });
976 + if (link.data('share')) link.removeAttr('href target');
490 977
491 - }
492 - });
978 + link.children('.fm-hit').remove();
493 979
494 - document.addEventListener('click', (event) => {
495 - if (activeSub && !activeSub.contains(event.target)) {
496 - this.closeSubMenu(activeSub, position);
497 - activeSub = null;
498 - }
499 - });
500 - };
980 + if (button.children('.fm-mask').length) link.unwrap();
501 981
502 - closeSubMenu(sub, position) {
503 - const link = sub.querySelector('.fm-link');
504 - sub.classList.remove(`-active`);
982 + label.removeAttr('style');
505 983
506 - if (!link.classList.contains('fm-hold-open')) {
507 - link.classList.remove(`-active`);
508 - } else {
509 - link.classList.add(`-active`);
510 - }
984 + link.off('mouseenter mouseleave click');
985 + }
511 986
512 - if (position === 'circular') {
513 - link.classList.toggle(`-label-hidden`);
514 - const previousElements = this.element.querySelectorAll('.fm-item.-hidden');
987 + function destroySub(sub) {
988 + var sub = $(sub);
989 + var list = sub.children('ul');
515 990
516 - if (previousElements.length > 0) {
517 - previousElements.forEach((item) => {
518 - item.classList.remove(`-hidden`);
519 - });
520 - }
521 - }
522 - }
991 + sub.removeClass('fm-side fm-circular fm-sub-space fm-posabs');
523 992
524 - setSubProperties(sub, effect, position) {
525 - const subMenu = sub.querySelector(`.fm-sub`);
526 - const height = subMenu.offsetHeight;
993 + list.removeClass('fm-hide');
994 + list.removeAttr('style');
995 + list.children().removeAttr('style');
527 996
528 - if (position !== 'circular') {
529 - sub.style.setProperty('--_offset', height);
530 - }
997 + sub.children('.fm-subhit').remove();
531 998
532 - const items = subMenu.querySelectorAll(`.fm-item`);
533 - const speed = parseInt(this.config?.sub?.speed) || 0;
534 - const count = items.length;
535 - const step = speed / count;
536 - let itemWidth = items[0].offsetWidth;
999 + sub.off('mouseenter mouseleave');
1000 + }
537 1001
538 - if ((effect === 'linear-fade') && items.length > 0) {
539 - items.forEach((item, index) => {
540 - const delay = index * step;
541 - const closeDelay = (count - 1 - index) * step;
542 - const duration = step;
543 - item.style.setProperty('--_delay', `${delay}`);
544 - item.style.setProperty('--_close_delay', `${closeDelay}`);
545 - });
546 - }
1002 + function destroyPanel() {
1003 + var panel = $(this);
547 1004
548 - if ((effect === 'linear-slide') && items.length > 0) {
549 - items.forEach((item, index) => {
550 - const top = ((index + 1) * itemWidth * -1);
551 - item.style.setProperty('--_top', `${top}px`);
552 - });
553 - }
1005 + panel.find('.fm-close').off('click');
554 1006
555 - if (position === 'circular') {
556 - this.subMenuCircular(subMenu, items, sub);
557 - }
1007 + var form = panel.find('form');
1008 + if (form.length) destroyForm(form);
1009 + }
558 1010
1011 + function destroyForm(form) {
1012 + var fieldList = form.find('input, textarea');
1013 +
1014 + form.find('.fm-submit').off('click');
1015 + form.off('submit');
1016 +
1017 + fieldList.removeClass('fm-formerror').off('focus');
1018 + fieldList.each(function() {
1019 + $(this).val('');
1020 + });
1021 +
1022 + form.find('.fm-status').attr('class', 'fm-status');
1023 + }
1024 + });
1025 + }
1026 +
1027 + function createSettings(options) {
1028 + var settings = $.extend({}, defaults, options);
1029 +
1030 + if (typeof settings.position === 'string') {
1031 + settings.position = settings.position.split('-');
559 1032 }
1033 + if (settings.position[0] === 'center') {
1034 + settings.position[0] = defaults.position[0];
1035 + warn('Bar horizontal position cannot be "center". Horizontal position reset to "left".');
1036 + }
1037 + if (!settings.position[1]) {
1038 + settings.position[1] = defaults.position[1];
1039 + }
560 1040
561 - subMenuCircular(subMenu, items, sub) {
562 - const itemWidth = this.itemWidth;
563 - const angleIncrement = this.calculateAngleIncrement(items.length);
564 - let radius = this.calculateOptimalRadius(itemWidth, angleIncrement);
565 - const minRadius = itemWidth * 1.5;
1041 + if (settings.offset === 0 || settings.offset === false) {
1042 + settings.offset = [0, 0];
1043 + } else if (typeof settings.offset === 'string') {
1044 + settings.offset = splitOffset(settings.offset);
1045 + }
566 1046
567 - if (radius < minRadius) {
568 - radius = minRadius;
569 - }
1047 + if (!options.buttonShape && options.shape) {
1048 + settings.buttonShape = settings.shape;
1049 + }
1050 + if (settings.buttonShape !== 'square') {
1051 + if (settings.buttonShape !== 'round' && settings.buttonShape !== 'rounded' && settings.buttonShape !==
1052 + 'rounded-out') {
1053 + settings.buttonShape = 'square';
1054 + }
1055 + }
570 1056
571 - sub.style.setProperty('--_offset', radius);
572 - sub.style.setProperty('--_box', radius);
1057 + if (!options.buttonColor && options.color) {
1058 + settings.buttonColor = settings.color;
1059 + }
1060 + if (settings.buttonColor === 'default') {
1061 + settings.buttonColor = 'custom';
1062 + }
573 1063
574 - this.setMenuProperties(items, angleIncrement, radius, subMenu, itemWidth);
1064 + if (!options.buttonOverColor && options.overColor) {
1065 + settings.buttonOverColor = settings.overColor;
575 1066 }
1067 + if (settings.buttonOverColor === 'default') {
1068 + settings.buttonOverColor = 'custom';
1069 + }
576 1070
577 - setMenuProperties(items, angleIncrement, radius, subMenu, itemWidth) {
578 - const offset = radius + 2;
579 - if (subMenu.classList.contains(`-active`)) {
580 - subMenu.style.setProperty('margin-bottom', `${offset}px`);
581 - } else {
582 - subMenu.style.setProperty('margin-bottom', `unset`);
583 - }
1071 + if (settings.labelColor === 'match') {
1072 + settings.labelColor = settings.buttonOverColor;
1073 + }
1074 + if (settings.labelTextColor === 'match') {
1075 + settings.labelTextColor = settings.iconOverColor;
1076 + }
584 1077
585 - const speed = parseInt(this.config?.sub?.speed) || 0;
586 - const count = items.length;
587 - const step = speed / count;
1078 + if (settings.labelEffect === 'slide') settings.labelEffect = 'slide-out';
1079 + if (settings.labelEffect === 'slide-in-fade') settings.labelEffect = 'slide-in';
588 1080
589 - items.forEach((item, index) => {
590 - const reverseIndex = items.length - 1 - index;
591 - const angle = this.determineAngleForMenu(subMenu, angleIncrement, index, reverseIndex);
592 - this.styleMenuItem(item, subMenu, radius, angle, index, step);
593 - });
1081 + if (!options.labelAnimate && options.labelAnim) {
1082 + settings.labelAnimate = settings.labelAnim;
594 1083 }
1084 + if (settings.labelAnimate === 'default') {
1085 + if (labelAnimateDefaults[settings.labelEffect]) {
1086 + settings.labelAnimate = labelAnimateDefaults[settings.labelEffect];
1087 + } else {
1088 + settings.labelAnimate = labelAnimateDefaults[0];
1089 + }
1090 + }
1091 + settings.labelAnimate = extendAnimateSetting(settings.labelAnimate);
595 1092
596 - determineAngleForMenu(menu, angleIncrement, index, reverseIndex) {
1093 + if (settings.labelConnected) {
1094 + if (settings.labelEffect === 'slide-in' || settings.labelEffect === 'slide-out-out' || settings.labelEffect ===
1095 + 'slide-in-in') {
1096 + settings.labelConnected = false;
1097 + warn('"labelConnected: true" incompatible with "labelEffect: ' + settings.labelEffect +
1098 + '". "labelConnected" reset to false.');
1099 + } else if (settings.labelSpace) {
1100 + settings.labelSpace = false;
1101 + warn('"labelSpace: true" incompatible with "labelConnected: true". "labelSpace" reset to false.');
1102 + }
1103 + }
597 1104
598 - const position = this.config?.position[0] || 'left';
1105 + if (typeof settings.subPosition === 'string') {
1106 + settings.subPosition = [settings.subPosition];
1107 + }
1108 + if (settings.subPosition[0] === 'circular') {
1109 + if (!settings.subPosition[1]) settings.subPosition[1] = defaults.subPosition[1];
1110 + if (typeof settings.subPosition[2] === 'undefined') settings.subPosition[2] = defaults.subPosition[2];
1111 + if (typeof settings.subPosition[3] === 'undefined') settings.subPosition[3] = defaults.subPosition[3];
599 1112
600 - if (position === 'left') {
601 - return angleIncrement * index - Math.PI / 2;
602 - } else if (position === 'right') {
603 - return angleIncrement * reverseIndex + Math.PI / 2;
604 - }
1113 + if (settings.subSpace) settings.subSpace = false;
1114 + }
605 1115
1116 + if (!options.subAnimate && options.subAnim) {
1117 + settings.subAnimate = settings.subAnim;
606 1118 }
1119 + if (settings.subAnimate === 'default') settings.subAnimate = defaults.subAnimate;
607 1120
608 - styleMenuItem(item, menu, radius, angle, index, step) {
609 - const delay = index * step;
1121 + if (typeof settings.subEffect === 'string') {
1122 + settings.subEffect = [settings.subEffect];
1123 + }
1124 + if ((settings.subEffect[0] === 'linear-fade' || settings.subEffect[0] === 'linear-slide') &&
1125 + !settings.subEffect[1]) {
1126 + settings.subEffect[1] = defaults.subEffect[1];
1127 + }
610 1128
611 - const x = radius * Math.cos(angle);
612 - const y = radius * Math.sin(angle);
613 - item.style.setProperty('--x', `${x}px`);
614 - item.style.setProperty('--y', `${y}px`);
615 - item.style.setProperty('--_delay', `${delay}`);
1129 + settings.subAnimate = extendAnimateSetting(settings.subAnimate);
616 1130
1131 + if (typeof settings.windowPosition === 'string') {
1132 + settings.windowPosition = settings.windowPosition.split('-');
617 1133 }
1134 + if (!settings.windowPosition[1]) {
1135 + settings.windowPosition[1] = defaults.windowPosition[1];
1136 + }
618 1137
619 - calculateAngleIncrement(itemCount) {
620 - const baseAngle = Math.PI;
621 - return baseAngle / (itemCount - 1);
1138 + if (settings.windowOffset === 0 || settings.windowOffset === false) {
1139 + settings.windowOffset = [0, 0];
1140 + } else if (typeof settings.windowOffset === 'string') {
1141 + settings.windowOffset = splitOffset(settings.windowOffset);
622 1142 }
623 1143
624 - calculateOptimalRadius(itemWidth, angleIncrement) {
625 - return (itemWidth / 2) / Math.sin(angleIncrement / 2);
1144 + if (settings.windowCorners === 'match') {
1145 + if (settings.buttonShape === 'round' || settings.buttonShape === 'rounded' || settings.buttonShape ===
1146 + 'rounded-out') {
1147 + settings.windowCorners = 'round';
1148 + }
626 1149 }
627 1150
628 - #parseConfig() {
629 - const options = this.element.getAttribute(`${FloatMenu.ATTR}`);
630 - if (!options || options.trim() === '') {
631 - return {};
632 - }
1151 + if (settings.windowColor === 'match') {
1152 + settings.windowColor = settings.buttonColor;
1153 + } else if (settings.windowColor === 'default') {
1154 + settings.windowColor = 'custom';
1155 + }
633 1156
634 - try {
635 - const parsedOptions = JSON.parse(options);
636 - return parsedOptions;
637 - } catch (error) {
638 - return {};
639 - }
1157 + if (settings.barAnimate === 'default') {
1158 + settings.barAnimate = defaults.barAnimate;
1159 + }
640 1160
1161 + settings.barAnimate = extendAnimateSetting(settings.barAnimate);
1162 +
1163 + if (settings.hideUnder) {
1164 + settings.hideUnderWidth = settings.hideUnder;
641 1165 }
642 1166
643 - _isMobile() {
644 - return /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
645 - window.innerWidth <= 768 ||
646 - 'ontouchstart' in window ||
647 - navigator.maxTouchPoints > 0;
1167 + return settings;
1168 + }
1169 +
1170 + function splitOffset(off) {
1171 + off = off.split('-');
1172 + off[0] = getInt(off[0]);
1173 + if (off[1]) off[1] = getInt(off[1]);
1174 + return off;
1175 + }
1176 +
1177 + function extendAnimateSetting(animate) {
1178 + if (Object.prototype.toString.call(animate) === '[object Array]') {
1179 + return {
1180 + show: animate,
1181 + hide: animate,
1182 + };
1183 + } else {
1184 + return animate;
648 1185 }
1186 + }
649 1187
650 - _isObjEmpty(obj) {
651 - return obj && typeof obj === 'object' && Object.keys(obj).length === 0;
1188 + function warn(msg) {
1189 + if (window.console) {
652 1190 }
1191 + }
653 1192
654 - _showConfig() {
655 - console.log(this.config);
656 - }
1193 + function getInt(val) {
1194 + return parseInt(val, 10);
1195 + }
657 1196
658 -}
659 1197
660 -document.addEventListener('DOMContentLoaded', function () {
661 - FloatMenu.initialize();
662 -});
1198 +}(jQuery));
1199 +
1200 +
1201 +document.addEventListener('DOMContentLoaded', function() {
1202 + for (let key in window) {
1203 + if (key.indexOf('FloatMenu_') >= 0) {
1204 + const val = window[key];
1205 + jQuery(val.selector).floatingMenu(val);
1206 + }
1207 + }
1208 +});