-
Notifications
You must be signed in to change notification settings - Fork 0
/
navAccordion.js
243 lines (219 loc) · 8.91 KB
/
navAccordion.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/* Nav Accordion Plugin v1.1.2
************************************/
(function($){
$.fn.navAccordion = function(options, callback){
this.each(function(){
//Options
var settings = $.extend({
expandButtonText : "+", //Text inside of expand button
collapseButtonText: "-", //Text inside of collapse button
selectedExpand: "true", //Expand the selected channel
selectedClass: "selected", //Class that will be used to detect the currently selected channel - this will check the "parentElement" for this class (the parent <li> by default)
multipleLevels: "true", //Apply accordion to all levels - setting this to false will apply the accordion only to the first level
buttonWidth: "20%", //Width of accordion expand/collapse button as a percentage or pixels
buttonPosition: "right", //Position of button - 'right' is default - you can also choose 'left'
slideSpeed: "fast", //Speed of slide animation - "fast", "slow", or number in milliseconds such as 500
parentElement: "li", //Parent element type, class or ID - you don't need to change this if you're using a ul > li > ul pattern
childElement: "ul", //Child element type, class or ID - you don't need to change this if you're using a ul > li > ul pattern
headersOnly: false, //False is default - setting to true will make any link with sub-nav behave as if it were set to header only, making the link inaccessible - this option is useful if you are using the plugin for a non-navigation area
headersOnlyCheck: false, // False is default - set to true to apply the accordion only to links that are set as "header only" (have no href)
delayLink: false, //Delay following the href of links until after the accordion the has expanded
delayAmount: null //Time in milliseconds to delay before following href - will use "slideSpeed" by default if nothing else is set
}, options);
var container = this,
//Multiple levels variable
multi = settings.multipleLevels ? '': ' > ' + settings.childElement + ' > ';
//Add class to container
$(container)
.addClass('accordion-nav');
//Apply has-subnav class to lis with uls - also add accordion buttons with styles
$(multi + settings.parentElement, container).each(function(){
if ( ($(this).contents(settings.childElement).length > 0
&& settings.headersOnlyCheck == false) || (!($('> a', this).attr('href'))
&& settings.headersOnlyCheck == true) )
{
//Apply Class and styles to parent item
$(this).addClass('has-subnav')
.css('position', 'relative')
.find('>a')
.css('margin-' + settings.buttonPosition, settings.buttonWidth);
//Add expand button elements
$(' > ' + settings.childElement, this)
.before('<span class="accordion-btn-wrap"><span class="accordion-btn accordion-collapsed">'
+ settings.expandButtonText + '</span><span class="accordion-btn accordion-expanded">'
+ settings.collapseButtonText + '</span></span>');
//Apply Styles to expand button
$('.accordion-btn-wrap', this)
.css({
'width': settings.buttonWidth,
'position': 'absolute',
'top': 0,
'text-align': 'center',
'cursor': 'pointer',
'display': 'inline-block'
})
.css(settings.buttonPosition, 0);
$('.accordion-btn ', this)
.css({
'display': 'inline-block',
'width': '100%'
});
$('.accordion-expanded', this)
.css('display', 'none');
}
//Apply styles to <a> tags that are set to header only
if (!($('> a', this).attr('href')) || settings.headersOnly){
$(this)
.addClass('accordion-header-only')
.find('.accordion-btn-wrap')
.css({
'width': '100%',
'text-align': settings.buttonPosition
})
.find('.accordion-btn ')
.css({
'width': settings.buttonWidth,
'text-align': 'center'
});
}
//Delay Link Mode
if (settings.delayLink && !settings.headersOnly) {
var currentThis = this,
speed = settings.delayAmount != null ? settings.delayAmount : settings.slideSpeed;
if (speed == "fast") {
speed = 200;
} else if (speed == "slow") {
speed = 600;
}
$('> a', currentThis).on('click',function(e){
if (!$('> .accordion-btn-wrap', currentThis).hasClass("accordion-active")) {
e.preventDefault();
var href = $(this).attr('href');
clickToggle($('> .accordion-btn-wrap', currentThis));
//Go to link after delay
setTimeout(function(){
window.location = href;
}, speed)
}
})
}
});
var selectedNavAccordion = $(settings.parentElement + '.' + settings.selectedClass + ' > .accordion-btn-wrap', container);
//Debounced Button height event listener
var buttonheightResize = debounce(function(){
//Run button height
buttonheight();
//Expand Selected Channel
expandSelected();
}, 250);
$(window).on('resize', buttonheightResize);
//Set button heights
buttonheight();
//Expand Selected Channel
expandSelected();
//On click function
$(container).on('click', '.accordion-btn-wrap', function(e) {
e.preventDefault();
clickToggle(this);
});
//Callback
if (typeof callback == "function") {
callback();
}
/* Functions
*******************************/
//Click Toggle function
function clickToggle(element) {
var nextChild = $(element).next(settings.childElement),
currentExpandBtn = $('.accordion-expanded', element),
currentCollapseBtn = $('.accordion-collapsed', element),
parentObj = $(element).closest(settings.parentElement);
if (nextChild.is(':visible')) {
nextChild
.slideUp(settings.slideSpeed);
$(element)
.removeClass('accordion-active');
currentExpandBtn
.css('display', 'none');
currentCollapseBtn
.css('display', 'inline-block');
parentObj.add(parentObj.siblings('.active')).add(parentObj.find('.active')).removeClass('active');
} else {
$(element).closest(settings.childElement).find('.accordion-active')
.removeClass('accordion-active')
.next(settings.childElement)
.slideUp(settings.slideSpeed).prev()
.find('.accordion-expanded')
.css('display', 'none')
.parent().find('.accordion-collapsed')
.css('display', 'inline-block');
parentObj.add(parentObj.siblings('.active')).add(parentObj.find('.active')).removeClass('active');
$(element)
.addClass('accordion-active');
nextChild
.slideToggle(settings.slideSpeed);
currentExpandBtn
.css('display', 'inline-block');
currentCollapseBtn
.css('display', 'none');
parentObj.addClass('active');
}
}
//Expand Selected Channel Function
function expandSelected(){
if(settings.selectedExpand){
if(!settings.headersOnlyCheck){
selectedNavAccordion.find('.accordion-expanded')
.css('display', 'inline-block');
selectedNavAccordion.find('.accordion-collapsed')
.css('display', 'none');
selectedNavAccordion.addClass('accordion-active')
.next(settings.childElement)
.css('display', 'block');
selectedNavAccordion.closest(settings.parentElement)
.addClass('active');
} else {
$(settings.parentElement + '.' + settings.selectedClass + ' > ' + settings.childElement, container)
.css('display', 'block');
$(settings.parentElement + '.' + settings.selectedClass).addClass('active');
}
}
}
//Accordion Button Height Function
function buttonheight(){
$('.accordion-btn', container).each(function(){
//Show uls so heights are calculated correctly
$(settings.parentElement + '.has-subnav > ' + settings.childElement, container)
.css('display', 'block');
//Calculate and set heights
var parentItem = $(this).closest(settings.parentElement),
lineheight = $('> a', parentItem).innerHeight();
$(this)
.css({'line-height': lineheight + 'px', 'height': lineheight});
//Hide uls under lis and reset expand/collapse buttons
$(settings.parentElement + ((settings.headersOnlyCheck) ? ' ' : '.has-subnav > ') + settings.childElement, container)
.css('display', 'none');
$('.accordion-expanded')
.css('display', 'none');
$('.accordion-collapsed')
.css('display', 'inline-block');
})
}
//Debounce function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
});
}
})(jQuery);