This repository has been archived by the owner on Apr 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 106
/
Copy pathjquery.mobilemenu.js
259 lines (188 loc) · 6.2 KB
/
jquery.mobilemenu.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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
(function($){
//plugin's default options
var settings = {
combine: true, //combine multiple menus into a single select
groupPageText: 'Main', //optgroup's aren't selectable, make an option for it
nested: true, //create optgroups by default
prependTo: 'body', //insert at top of page by default
switchWidth: 480, //width at which to switch to select, and back again
topOptionText: 'Select a page' //default "unselected" state
},
//used to store original matched menus
$menus,
//used as a unique index for each menu if no ID exists
menuCount = 0,
//used to store unique list items for combining lists
uniqueLinks = [];
//go to page
function goTo(url){
document.location.href = url;
}
//does menu exist?
function menuExists(){
return ($('.mnav').length) ? true : false;
}
//validate selector's matched list(s)
function isList($this){
var pass = true;
$this.each(function(){
if(!$(this).is('ul') && !$(this).is('ol')){
pass=false;
}
});
return pass;
}//isList()
//function to decide if mobile or not
function isMobile(){
return ($(window).width() < settings.switchWidth);
}
//function to get text value of element, but not it's children
function getText($item){
return $.trim($item.clone().children('ul, ol').remove().end().text());
}
//function to check if URL is unique
function isUrlUnique(url){
return ($.inArray(url, uniqueLinks) === -1) ? true : false;
}
//function to do duplicate checking for combined list
function checkForDuplicates($menu){
$menu.find(' > li').each(function(){
var $li = $(this),
link = $li.find('a').attr('href'),
parentLink = function(){
if($li.parent().parent().is('li')){
return $li.parent().parent().find('a').attr('href');
} else {
return null;
}
};
//check nested <li>s before checking current one
if($li.find(' ul, ol').length){
checkForDuplicates($li.find('> ul, > ol'));
}
//remove empty UL's if any are left by LI removals
if(!$li.find(' > ul li, > ol li').length){
$li.find('ul, ol').remove();
}
//if parent <li> has a link, and it's not unique, append current <li> to the "unique parent" detected earlier
if(!isUrlUnique(parentLink(), uniqueLinks) && isUrlUnique(link, uniqueLinks)){
$li.appendTo(
$menu.closest('ul#mmnav').find('li:has(a[href="'+parentLink()+'"]):first ul')
);
}
//otherwise, check if the current <li> is unique, if it is, add it to the unique list
else if(isUrlUnique(link)){
uniqueLinks.push(link);
}
//if it isn't, remove it. Simples.
else{
$li.remove();
}
});
}
//function to combine lists into one
function combineLists(){
//create a new list
var $menu = $('<ul id="mmnav" />');
//loop through each menu and extract the list's child items
//then append them to the new list
$menus.each(function(){
$(this).children().clone().appendTo($menu);
});
//de-duplicate any repeated items
checkForDuplicates($menu);
//return new combined list
return $menu;
}//combineLists()
//function to create options in the select menu
function createOption($item, $container, text){
//if no text param is passed, use list item's text, otherwise use settings.groupPageText
if(!text){
$('<option value="'+$item.find('a:first').attr('href')+'">'+$.trim(getText($item))+'</option>').appendTo($container);
} else {
$('<option value="'+$item.find('a:first').attr('href')+'">'+text+'</option>').appendTo($container);
}
}//createOption()
//function to create option groups
function createOptionGroup($group, $container){
//create <optgroup> for sub-nav items
var $optgroup = $('<optgroup label="'+$.trim(getText($group))+'" />');
//append top option to it (current list item's text)
createOption($group,$optgroup, settings.groupPageText);
//loop through each sub-nav list
$group.children('ul, ol').each(function(){
//loop through each list item and create an <option> for it
$(this).children('li').each(function(){
createOption($(this), $optgroup);
});
});
//append to select element
$optgroup.appendTo($container);
}//createOptionGroup()
//function to create <select> menu
function createSelect($menu){
//create <select> to insert into the page
var $select = $('<select id="mm'+menuCount+'" class="mnav" />');
menuCount++;
//create default option if the text is set (set to null for no option)
if(settings.topOptionText){
createOption($('<li>'+settings.topOptionText+'</li>'), $select);
}
//loop through first list items
$menu.children('li').each(function(){
var $li = $(this);
//if nested select is wanted, and has sub-nav, add optgroup element with child options
if($li.children('ul, ol').length && settings.nested){
createOptionGroup($li, $select);
}
//otherwise it's a single level select menu, so build option
else {
createOption($li, $select);
}
});
//add change event and prepend menu to set element
$select
.change(function(){goTo($(this).val());})
.prependTo(settings.prependTo);
}//createSelect()
//function to run plugin functionality
function runPlugin(){
//menu doesn't exist
if(isMobile() && !menuExists()){
//if user wants to combine menus, create a single <select>
if(settings.combine){
var $menu = combineLists();
createSelect($menu);
}
//otherwise, create a select for each matched list
else{
$menus.each(function(){
createSelect($(this));
});
}
}
//menu exists, and browser is mobile width
if(isMobile() && menuExists()){
$('.mnav').show();
$menus.hide();
}
//otherwise, hide the mobile menu
if(!isMobile() && menuExists()){
$('.mnav').hide();
$menus.show();
}
}//runPlugin()
//plugin definition
$.fn.mobileMenu = function(options){
//override the default settings if user provides some
if(options){$.extend(settings, options);}
//check if user has run the plugin against list element(s)
if(isList($(this))){
$menus = $(this);
runPlugin();
$(window).resize(function(){runPlugin();});
} else {
alert('mobileMenu only works with <ul>/<ol>');
}
};//mobileMenu()
})(jQuery);