-
Notifications
You must be signed in to change notification settings - Fork 0
/
jquery.smartmenus.bootstrap.js
executable file
·174 lines (160 loc) · 6.01 KB
/
jquery.smartmenus.bootstrap.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*!
* SmartMenus jQuery Plugin Bootstrap Addon - v0.3.1 - November 1, 2016
* http://www.smartmenus.org/
*
* Copyright Vasil Dinkov, Vadikom Web Ltd.
* http://vadikom.com
*
* Licensed MIT
*/
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'jquery.smartmenus'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
// CommonJS
module.exports = factory(require('jquery'));
} else {
// Global jQuery
factory(jQuery);
}
} (function($) {
$.extend($.SmartMenus.Bootstrap = {}, {
keydownFix: false,
init: function() {
// init all navbars that don't have the "data-sm-skip" attribute set
var $navbars = $('ul.navbar-nav:not([data-sm-skip])');
$navbars.each(function() {
var $this = $(this),
obj = $this.data('smartmenus');
// if this navbar is not initialized
if (!obj) {
$this.smartmenus({
// these are some good default options that should work for all
// you can, of course, tweak these as you like
subMenusSubOffsetX: 2,
subMenusSubOffsetY: -6,
subIndicators: false,
collapsibleShowFunction: null,
collapsibleHideFunction: null,
rightToLeftSubMenus: $this.hasClass('navbar-right'),
bottomToTopSubMenus: $this.closest('.navbar').hasClass('navbar-fixed-bottom')
})
.bind({
// set/unset proper Bootstrap classes for some menu elements
'show.smapi': function(e, menu) {
var $menu = $(menu),
$scrollArrows = $menu.dataSM('scroll-arrows');
if ($scrollArrows) {
// they inherit border-color from body, so we can use its background-color too
$scrollArrows.css('background-color', $(document.body).css('background-color'));
}
$menu.parent().addClass('open');
},
'hide.smapi': function(e, menu) {
$(menu).parent().removeClass('open');
}
});
function onInit() {
// set Bootstrap's "active" class to SmartMenus "current" items (should someone decide to enable markCurrentItem: true)
$this.find('a.current').parent().addClass('active');
// remove any Bootstrap required attributes that might cause conflicting issues with the SmartMenus script
$this.find('a.has-submenu').each(function() {
var $this = $(this);
if ($this.is('[data-toggle="dropdown"]')) {
$this.dataSM('bs-data-toggle-dropdown', true).removeAttr('data-toggle');
}
if ($this.is('[role="button"]')) {
$this.dataSM('bs-role-button', true).removeAttr('role');
}
});
}
onInit();
function onBeforeDestroy() {
$this.find('a.current').parent().removeClass('active');
$this.find('a.has-submenu').each(function() {
var $this = $(this);
if ($this.dataSM('bs-data-toggle-dropdown')) {
$this.attr('data-toggle', 'dropdown').removeDataSM('bs-data-toggle-dropdown');
}
if ($this.dataSM('bs-role-button')) {
$this.attr('role', 'button').removeDataSM('bs-role-button');
}
});
}
obj = $this.data('smartmenus');
// custom "isCollapsible" method for Bootstrap
obj.isCollapsible = function() {
return !/^(left|right)$/.test(this.$firstLink.parent().css('float'));
};
// custom "refresh" method for Bootstrap
obj.refresh = function() {
$.SmartMenus.prototype.refresh.call(this);
onInit();
// update collapsible detection
detectCollapsible(true);
};
// custom "destroy" method for Bootstrap
obj.destroy = function(refresh) {
onBeforeDestroy();
$.SmartMenus.prototype.destroy.call(this, refresh);
};
// keep Bootstrap's default behavior for parent items when the "data-sm-skip-collapsible-behavior" attribute is set to the ul.navbar-nav
// i.e. use the whole item area just as a sub menu toggle and don't customize the carets
if ($this.is('[data-sm-skip-collapsible-behavior]')) {
$this.bind({
// click the parent item to toggle the sub menus (and reset deeper levels and other branches on click)
'click.smapi': function(e, item) {
if (obj.isCollapsible()) {
var $item = $(item),
$sub = $item.parent().dataSM('sub');
if ($sub && $sub.dataSM('shown-before') && $sub.is(':visible')) {
obj.itemActivate($item);
obj.menuHide($sub);
return false;
}
}
}
});
}
// onresize detect when the navbar becomes collapsible and add it the "sm-collapsible" class
var winW;
function detectCollapsible(force) {
var newW = obj.getViewportWidth();
if (newW != winW || force) {
var $carets = $this.find('.caret');
if (obj.isCollapsible()) {
$this.addClass('sm-collapsible');
// set "navbar-toggle" class to carets (so they look like a button) if the "data-sm-skip-collapsible-behavior" attribute is not set to the ul.navbar-nav
if (!$this.is('[data-sm-skip-collapsible-behavior]')) {
$carets.addClass('navbar-toggle sub-arrow');
}
} else {
$this.removeClass('sm-collapsible');
if (!$this.is('[data-sm-skip-collapsible-behavior]')) {
$carets.removeClass('navbar-toggle sub-arrow');
}
}
winW = newW;
}
}
detectCollapsible();
$(window).bind('resize.smartmenus' + obj.rootId, detectCollapsible);
}
});
// keydown fix for Bootstrap 3.3.5+ conflict
if ($navbars.length && !$.SmartMenus.Bootstrap.keydownFix) {
// unhook BS keydown handler for all dropdowns
$(document).off('keydown.bs.dropdown.data-api', '.dropdown-menu');
// restore BS keydown handler for dropdowns that are not inside SmartMenus navbars
if ($.fn.dropdown && $.fn.dropdown.Constructor) {
$(document).on('keydown.bs.dropdown.data-api', '.dropdown-menu:not([id^="sm-"])', $.fn.dropdown.Constructor.prototype.keydown);
}
$.SmartMenus.Bootstrap.keydownFix = true;
}
}
});
// init ondomready
$($.SmartMenus.Bootstrap.init);
return $;
}));