omf_web 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/omf-web/content/content_proxy.rb +28 -15
- data/lib/omf-web/content/file_repository.rb +16 -57
- data/lib/omf-web/content/git_repository.rb +2 -121
- data/lib/omf-web/content/irods_repository.rb +2 -0
- data/lib/omf-web/content/repository.rb +121 -10
- data/lib/omf-web/content/static_repository.rb +3 -3
- data/lib/omf-web/rack/content_handler.rb +8 -6
- data/lib/omf-web/theme.rb +16 -2
- data/lib/omf-web/thin/logging.rb +13 -4
- data/lib/omf-web/version.rb +1 -1
- data/lib/omf-web/widget/text/maruku/output/to_html.rb +29 -23
- data/lib/omf-web/widget/text/maruku.rb +20 -5
- data/omf_web.gemspec +1 -1
- data/share/htdocs/graph/js/code_mirror.js +2 -1
- data/share/htdocs/vendor/VERSION_MAP.yaml +1 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/LICENSE-MIT +22 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/README.md +26 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.css +103 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.js +72 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.min.js +3 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/addons/keyboard/jquery.smartmenus.keyboard.js +192 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/addons/keyboard/jquery.smartmenus.keyboard.min.js +3 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/current-item-bg.png +0 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/main-item-hover-bg.png +0 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/main-menu-bg.png +0 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/sub-item-hover-bg.png +0 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/vertical-main-item-bg.png +0 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/sm-blue.css +409 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-clean/sm-clean.css +315 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-core-css.css +23 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-mint/sm-mint.css +320 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-simple/sm-simple.css +218 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/jquery.smartmenus.js +1041 -0
- data/share/htdocs/vendor/smartmenus-0.9.6/jquery.smartmenus.min.js +3 -0
- metadata +218 -229
@@ -0,0 +1,1041 @@
|
|
1
|
+
/*!
|
2
|
+
* SmartMenus jQuery Plugin - v0.9.6 - March 27, 2014
|
3
|
+
* http://www.smartmenus.org/
|
4
|
+
*
|
5
|
+
* Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
|
6
|
+
* http://vadikom.com
|
7
|
+
*
|
8
|
+
* Licensed MIT
|
9
|
+
*/
|
10
|
+
|
11
|
+
(function($) {
|
12
|
+
|
13
|
+
var menuTrees = [],
|
14
|
+
IE = !!window.createPopup, // we need to detect it, unfortunately
|
15
|
+
IElt9 = IE && !document.defaultView,
|
16
|
+
IElt8 = IE && !document.querySelector,
|
17
|
+
IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
|
18
|
+
mouse = false, // optimize for touch by default - we will detect for mouse input
|
19
|
+
mouseDetectionEnabled = false;
|
20
|
+
|
21
|
+
// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
|
22
|
+
function initMouseDetection(disable) {
|
23
|
+
if (!mouseDetectionEnabled && !disable) {
|
24
|
+
// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
|
25
|
+
// in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events)
|
26
|
+
var firstTime = true,
|
27
|
+
lastMove = null;
|
28
|
+
$(document).bind({
|
29
|
+
'mousemove.smartmenus_mouse': function(e) {
|
30
|
+
var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
|
31
|
+
if (lastMove) {
|
32
|
+
var deltaX = Math.abs(lastMove.x - thisMove.x),
|
33
|
+
deltaY = Math.abs(lastMove.y - thisMove.y);
|
34
|
+
if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
|
35
|
+
mouse = true;
|
36
|
+
// if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes
|
37
|
+
if (firstTime) {
|
38
|
+
var $a = $(e.target).closest('a');
|
39
|
+
if ($a.is('a')) {
|
40
|
+
$.each(menuTrees, function() {
|
41
|
+
if ($.contains(this.$root[0], $a[0])) {
|
42
|
+
this.itemEnter({ currentTarget: $a[0] });
|
43
|
+
return false;
|
44
|
+
}
|
45
|
+
});
|
46
|
+
}
|
47
|
+
firstTime = false;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
lastMove = thisMove;
|
52
|
+
},
|
53
|
+
'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
|
54
|
+
if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) {
|
55
|
+
mouse = false;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
});
|
59
|
+
mouseDetectionEnabled = true;
|
60
|
+
} else if (mouseDetectionEnabled && disable) {
|
61
|
+
$(document).unbind('.smartmenus_mouse');
|
62
|
+
mouseDetectionEnabled = false;
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
$.SmartMenus = function(elm, options) {
|
67
|
+
this.$root = $(elm);
|
68
|
+
this.opts = options;
|
69
|
+
this.rootId = ''; // internal
|
70
|
+
this.$subArrow = null;
|
71
|
+
this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted)
|
72
|
+
this.activatedItems = []; // stores last activated A's for each level
|
73
|
+
this.visibleSubMenus = []; // stores visible sub menus UL's
|
74
|
+
this.showTimeout = 0;
|
75
|
+
this.hideTimeout = 0;
|
76
|
+
this.scrollTimeout = 0;
|
77
|
+
this.clickActivated = false;
|
78
|
+
this.zIndexInc = 0;
|
79
|
+
this.$firstLink = null; // we'll use these for some tests
|
80
|
+
this.$firstSub = null; // at runtime so we'll cache them
|
81
|
+
this.disabled = false;
|
82
|
+
this.$disableOverlay = null;
|
83
|
+
this.init();
|
84
|
+
};
|
85
|
+
|
86
|
+
$.extend($.SmartMenus, {
|
87
|
+
hideAll: function() {
|
88
|
+
$.each(menuTrees, function() {
|
89
|
+
this.menuHideAll();
|
90
|
+
});
|
91
|
+
},
|
92
|
+
destroy: function() {
|
93
|
+
while (menuTrees.length) {
|
94
|
+
menuTrees[0].destroy();
|
95
|
+
}
|
96
|
+
initMouseDetection(true);
|
97
|
+
},
|
98
|
+
prototype: {
|
99
|
+
init: function(refresh) {
|
100
|
+
var self = this;
|
101
|
+
|
102
|
+
if (!refresh) {
|
103
|
+
menuTrees.push(this);
|
104
|
+
|
105
|
+
this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
|
106
|
+
|
107
|
+
if (this.$root.hasClass('sm-rtl')) {
|
108
|
+
this.opts.rightToLeftSubMenus = true;
|
109
|
+
}
|
110
|
+
|
111
|
+
// init root (main menu)
|
112
|
+
this.$root
|
113
|
+
.data('smartmenus', this)
|
114
|
+
.attr('data-smartmenus-id', this.rootId)
|
115
|
+
.dataSM('level', 1)
|
116
|
+
.bind({
|
117
|
+
'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
|
118
|
+
'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
|
119
|
+
})
|
120
|
+
.delegate('a', {
|
121
|
+
'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
|
122
|
+
'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
|
123
|
+
'mousedown.smartmenus': $.proxy(this.itemDown, this),
|
124
|
+
'focus.smartmenus': $.proxy(this.itemFocus, this),
|
125
|
+
'blur.smartmenus': $.proxy(this.itemBlur, this),
|
126
|
+
'click.smartmenus': $.proxy(this.itemClick, this),
|
127
|
+
'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
|
128
|
+
});
|
129
|
+
|
130
|
+
var eNamespace = '.smartmenus' + this.rootId;
|
131
|
+
// hide menus on tap or click outside the root UL
|
132
|
+
if (this.opts.hideOnClick) {
|
133
|
+
$(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
|
134
|
+
.bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
|
135
|
+
.bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
|
136
|
+
// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
|
137
|
+
.bind('click' + eNamespace, $.proxy(this.docClick, this));
|
138
|
+
}
|
139
|
+
// hide sub menus on resize
|
140
|
+
$(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
|
141
|
+
|
142
|
+
if (this.opts.subIndicators) {
|
143
|
+
this.$subArrow = $('<span/>').addClass('sub-arrow');
|
144
|
+
if (this.opts.subIndicatorsText) {
|
145
|
+
this.$subArrow.html(this.opts.subIndicatorsText);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
// make sure mouse detection is enabled
|
150
|
+
initMouseDetection();
|
151
|
+
}
|
152
|
+
|
153
|
+
// init sub menus
|
154
|
+
this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
|
155
|
+
|
156
|
+
this.$firstLink = this.$root.find('a').eq(0);
|
157
|
+
|
158
|
+
// find current item
|
159
|
+
if (this.opts.markCurrentItem) {
|
160
|
+
var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
|
161
|
+
reHash = /#.*/,
|
162
|
+
locHref = window.location.href.replace(reDefaultDoc, ''),
|
163
|
+
locHrefNoHash = locHref.replace(reHash, '');
|
164
|
+
this.$root.find('a').each(function() {
|
165
|
+
var href = this.href.replace(reDefaultDoc, ''),
|
166
|
+
$this = $(this);
|
167
|
+
if (href == locHref || href == locHrefNoHash) {
|
168
|
+
$this.addClass('current');
|
169
|
+
if (self.opts.markCurrentTree) {
|
170
|
+
$this.parents('li').each(function() {
|
171
|
+
var $this = $(this);
|
172
|
+
if ($this.dataSM('sub')) {
|
173
|
+
$this.children('a').addClass('current');
|
174
|
+
}
|
175
|
+
});
|
176
|
+
}
|
177
|
+
}
|
178
|
+
});
|
179
|
+
}
|
180
|
+
},
|
181
|
+
destroy: function() {
|
182
|
+
this.menuHideAll();
|
183
|
+
this.$root
|
184
|
+
.removeData('smartmenus')
|
185
|
+
.removeAttr('data-smartmenus-id')
|
186
|
+
.removeDataSM('level')
|
187
|
+
.unbind('.smartmenus')
|
188
|
+
.undelegate('.smartmenus');
|
189
|
+
var eNamespace = '.smartmenus' + this.rootId;
|
190
|
+
$(document).unbind(eNamespace);
|
191
|
+
$(window).unbind(eNamespace);
|
192
|
+
if (this.opts.subIndicators) {
|
193
|
+
this.$subArrow = null;
|
194
|
+
}
|
195
|
+
var self = this;
|
196
|
+
$.each(this.subMenus, function() {
|
197
|
+
if (this.hasClass('mega-menu')) {
|
198
|
+
this.find('ul').removeDataSM('in-mega');
|
199
|
+
}
|
200
|
+
if (this.dataSM('shown-before')) {
|
201
|
+
if (IElt8) {
|
202
|
+
this.children().css({ styleFloat: '', width: '' });
|
203
|
+
}
|
204
|
+
if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
|
205
|
+
if (!IE6) {
|
206
|
+
this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
|
207
|
+
} else {
|
208
|
+
this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
|
209
|
+
}
|
210
|
+
}
|
211
|
+
if (this.dataSM('scroll-arrows')) {
|
212
|
+
this.dataSM('scroll-arrows').remove();
|
213
|
+
}
|
214
|
+
this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
|
215
|
+
}
|
216
|
+
if (self.opts.subIndicators) {
|
217
|
+
this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
|
218
|
+
}
|
219
|
+
this.removeDataSM('shown-before')
|
220
|
+
.removeDataSM('ie-shim')
|
221
|
+
.removeDataSM('scroll-arrows')
|
222
|
+
.removeDataSM('parent-a')
|
223
|
+
.removeDataSM('level')
|
224
|
+
.removeDataSM('beforefirstshowfired')
|
225
|
+
.parent().removeDataSM('sub');
|
226
|
+
});
|
227
|
+
if (this.opts.markCurrentItem) {
|
228
|
+
this.$root.find('a.current').removeClass('current');
|
229
|
+
}
|
230
|
+
this.$root = null;
|
231
|
+
this.$firstLink = null;
|
232
|
+
this.$firstSub = null;
|
233
|
+
if (this.$disableOverlay) {
|
234
|
+
this.$disableOverlay.remove();
|
235
|
+
this.$disableOverlay = null;
|
236
|
+
}
|
237
|
+
menuTrees.splice($.inArray(this, menuTrees), 1);
|
238
|
+
},
|
239
|
+
disable: function(noOverlay) {
|
240
|
+
if (!this.disabled) {
|
241
|
+
this.menuHideAll();
|
242
|
+
// display overlay over the menu to prevent interaction
|
243
|
+
if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
|
244
|
+
var pos = this.$root.offset();
|
245
|
+
this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
|
246
|
+
position: 'absolute',
|
247
|
+
top: pos.top,
|
248
|
+
left: pos.left,
|
249
|
+
width: this.$root.outerWidth(),
|
250
|
+
height: this.$root.outerHeight(),
|
251
|
+
zIndex: this.getStartZIndex() + 1,
|
252
|
+
opacity: 0
|
253
|
+
}).appendTo(document.body);
|
254
|
+
}
|
255
|
+
this.disabled = true;
|
256
|
+
}
|
257
|
+
},
|
258
|
+
docClick: function(e) {
|
259
|
+
// hide on any click outside the menu or on a menu link
|
260
|
+
if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
|
261
|
+
this.menuHideAll();
|
262
|
+
}
|
263
|
+
},
|
264
|
+
docTouchEnd: function(e) {
|
265
|
+
if (!this.lastTouch) {
|
266
|
+
return;
|
267
|
+
}
|
268
|
+
if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) {
|
269
|
+
if (this.hideTimeout) {
|
270
|
+
clearTimeout(this.hideTimeout);
|
271
|
+
this.hideTimeout = 0;
|
272
|
+
}
|
273
|
+
// hide with a delay to prevent triggering accidental unwanted click on some page element
|
274
|
+
var self = this;
|
275
|
+
this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, 350);
|
276
|
+
}
|
277
|
+
this.lastTouch = null;
|
278
|
+
},
|
279
|
+
docTouchMove: function(e) {
|
280
|
+
if (!this.lastTouch) {
|
281
|
+
return;
|
282
|
+
}
|
283
|
+
var touchPoint = e.originalEvent.touches[0];
|
284
|
+
this.lastTouch.x2 = touchPoint.pageX;
|
285
|
+
this.lastTouch.y2 = touchPoint.pageY;
|
286
|
+
},
|
287
|
+
docTouchStart: function(e) {
|
288
|
+
var touchPoint = e.originalEvent.touches[0];
|
289
|
+
this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
|
290
|
+
},
|
291
|
+
enable: function() {
|
292
|
+
if (this.disabled) {
|
293
|
+
if (this.$disableOverlay) {
|
294
|
+
this.$disableOverlay.remove();
|
295
|
+
this.$disableOverlay = null;
|
296
|
+
}
|
297
|
+
this.disabled = false;
|
298
|
+
}
|
299
|
+
},
|
300
|
+
getHeight: function($elm) {
|
301
|
+
return this.getOffset($elm, true);
|
302
|
+
},
|
303
|
+
// returns precise width/height float values in IE9+, FF4+, recent WebKit
|
304
|
+
// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
|
305
|
+
getOffset: function($elm, height) {
|
306
|
+
var old;
|
307
|
+
if ($elm.css('display') == 'none') {
|
308
|
+
old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
|
309
|
+
$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
|
310
|
+
}
|
311
|
+
var defaultView = $elm[0].ownerDocument.defaultView,
|
312
|
+
compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
|
313
|
+
val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
|
314
|
+
if (val) {
|
315
|
+
val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
|
316
|
+
+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
|
317
|
+
+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
|
318
|
+
+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
|
319
|
+
} else {
|
320
|
+
val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
|
321
|
+
}
|
322
|
+
if (old) {
|
323
|
+
$elm.hide().css(old);
|
324
|
+
}
|
325
|
+
return val;
|
326
|
+
},
|
327
|
+
getWidth: function($elm) {
|
328
|
+
return this.getOffset($elm);
|
329
|
+
},
|
330
|
+
getStartZIndex: function() {
|
331
|
+
var zIndex = parseInt(this.$root.css('z-index'));
|
332
|
+
return !isNaN(zIndex) ? zIndex : 1;
|
333
|
+
},
|
334
|
+
handleEvents: function() {
|
335
|
+
return !this.disabled && this.isCSSOn();
|
336
|
+
},
|
337
|
+
handleItemEvents: function($a) {
|
338
|
+
return this.handleEvents() && !this.isLinkInMegaMenu($a);
|
339
|
+
},
|
340
|
+
isCollapsible: function() {
|
341
|
+
return this.$firstSub.css('position') == 'static';
|
342
|
+
},
|
343
|
+
isCSSOn: function() {
|
344
|
+
return this.$firstLink.css('display') == 'block';
|
345
|
+
},
|
346
|
+
isFixed: function() {
|
347
|
+
return this.$root.css('position') == 'fixed';
|
348
|
+
},
|
349
|
+
isLinkInMegaMenu: function($a) {
|
350
|
+
return !$a.parent().parent().dataSM('level');
|
351
|
+
},
|
352
|
+
isTouchMode: function() {
|
353
|
+
return !mouse || this.isCollapsible();
|
354
|
+
},
|
355
|
+
itemActivate: function($a) {
|
356
|
+
var $li = $a.parent(),
|
357
|
+
$ul = $li.parent(),
|
358
|
+
level = $ul.dataSM('level');
|
359
|
+
// if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first
|
360
|
+
if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
|
361
|
+
var self = this;
|
362
|
+
$($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
|
363
|
+
self.itemActivate($(this).dataSM('parent-a'));
|
364
|
+
});
|
365
|
+
}
|
366
|
+
// hide any visible deeper level sub menus
|
367
|
+
if (this.visibleSubMenus.length > level) {
|
368
|
+
for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) {
|
369
|
+
this.menuHide(this.visibleSubMenus[i]);
|
370
|
+
}
|
371
|
+
}
|
372
|
+
// save new active item and sub menu for this level
|
373
|
+
this.activatedItems[level - 1] = $a;
|
374
|
+
this.visibleSubMenus[level - 1] = $ul;
|
375
|
+
if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
|
376
|
+
return;
|
377
|
+
}
|
378
|
+
// show the sub menu if this item has one
|
379
|
+
var $sub = $li.dataSM('sub');
|
380
|
+
if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
|
381
|
+
this.menuShow($sub);
|
382
|
+
}
|
383
|
+
},
|
384
|
+
itemBlur: function(e) {
|
385
|
+
var $a = $(e.currentTarget);
|
386
|
+
if (!this.handleItemEvents($a)) {
|
387
|
+
return;
|
388
|
+
}
|
389
|
+
this.$root.triggerHandler('blur.smapi', $a[0]);
|
390
|
+
},
|
391
|
+
itemClick: function(e) {
|
392
|
+
var $a = $(e.currentTarget);
|
393
|
+
if (!this.handleItemEvents($a)) {
|
394
|
+
return;
|
395
|
+
}
|
396
|
+
$a.removeDataSM('mousedown');
|
397
|
+
if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
|
398
|
+
return false;
|
399
|
+
}
|
400
|
+
var $sub = $a.parent().dataSM('sub');
|
401
|
+
if (this.isTouchMode()) {
|
402
|
+
// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
|
403
|
+
if ($a.dataSM('href')) {
|
404
|
+
$a.attr('href', $a.dataSM('href')).removeDataSM('href');
|
405
|
+
}
|
406
|
+
// if the sub is not visible
|
407
|
+
if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
|
408
|
+
// try to activate the item and show the sub
|
409
|
+
this.itemActivate($a);
|
410
|
+
// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
|
411
|
+
// if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded
|
412
|
+
if ($sub.is(':visible')) {
|
413
|
+
return false;
|
414
|
+
}
|
415
|
+
}
|
416
|
+
} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
|
417
|
+
this.clickActivated = true;
|
418
|
+
this.menuShow($sub);
|
419
|
+
return false;
|
420
|
+
}
|
421
|
+
if ($a.hasClass('disabled')) {
|
422
|
+
return false;
|
423
|
+
}
|
424
|
+
if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
|
425
|
+
return false;
|
426
|
+
}
|
427
|
+
},
|
428
|
+
itemDown: function(e) {
|
429
|
+
var $a = $(e.currentTarget);
|
430
|
+
if (!this.handleItemEvents($a)) {
|
431
|
+
return;
|
432
|
+
}
|
433
|
+
$a.dataSM('mousedown', true);
|
434
|
+
},
|
435
|
+
itemEnter: function(e) {
|
436
|
+
var $a = $(e.currentTarget);
|
437
|
+
if (!this.handleItemEvents($a)) {
|
438
|
+
return;
|
439
|
+
}
|
440
|
+
if (!this.isTouchMode()) {
|
441
|
+
if (this.showTimeout) {
|
442
|
+
clearTimeout(this.showTimeout);
|
443
|
+
this.showTimeout = 0;
|
444
|
+
}
|
445
|
+
var self = this;
|
446
|
+
this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
|
447
|
+
}
|
448
|
+
this.$root.triggerHandler('mouseenter.smapi', $a[0]);
|
449
|
+
},
|
450
|
+
itemFocus: function(e) {
|
451
|
+
var $a = $(e.currentTarget);
|
452
|
+
if (!this.handleItemEvents($a)) {
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
// fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus
|
456
|
+
if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
|
457
|
+
this.itemActivate($a);
|
458
|
+
}
|
459
|
+
this.$root.triggerHandler('focus.smapi', $a[0]);
|
460
|
+
},
|
461
|
+
itemLeave: function(e) {
|
462
|
+
var $a = $(e.currentTarget);
|
463
|
+
if (!this.handleItemEvents($a)) {
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
if (!this.isTouchMode()) {
|
467
|
+
if ($a[0].blur) {
|
468
|
+
$a[0].blur();
|
469
|
+
}
|
470
|
+
if (this.showTimeout) {
|
471
|
+
clearTimeout(this.showTimeout);
|
472
|
+
this.showTimeout = 0;
|
473
|
+
}
|
474
|
+
}
|
475
|
+
$a.removeDataSM('mousedown');
|
476
|
+
this.$root.triggerHandler('mouseleave.smapi', $a[0]);
|
477
|
+
},
|
478
|
+
itemTouchEnd: function(e) {
|
479
|
+
var $a = $(e.currentTarget);
|
480
|
+
if (!this.handleItemEvents($a)) {
|
481
|
+
return;
|
482
|
+
}
|
483
|
+
// prevent the address bar on iPhone from sliding down when expanding a sub menu
|
484
|
+
var $sub = $a.parent().dataSM('sub');
|
485
|
+
if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
|
486
|
+
$a.dataSM('href', $a.attr('href'));
|
487
|
+
$a.attr('href', '#');
|
488
|
+
}
|
489
|
+
},
|
490
|
+
menuFixLayout: function($ul) {
|
491
|
+
// fixes a menu that is being shown for the first time
|
492
|
+
if (!$ul.dataSM('shown-before')) {
|
493
|
+
$ul.hide().dataSM('shown-before', true);
|
494
|
+
// fix the layout of the items in IE<8
|
495
|
+
if (IElt8) {
|
496
|
+
$ul.children().css({ styleFloat: 'left', width: '100%' });
|
497
|
+
}
|
498
|
+
}
|
499
|
+
},
|
500
|
+
menuHide: function($sub) {
|
501
|
+
if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
$sub.stop(true, true);
|
505
|
+
if ($sub.is(':visible')) {
|
506
|
+
var complete = function() {
|
507
|
+
// unset z-index
|
508
|
+
if (IElt9) {
|
509
|
+
$sub.parent().css('z-index', '');
|
510
|
+
} else {
|
511
|
+
$sub.css('z-index', '');
|
512
|
+
}
|
513
|
+
};
|
514
|
+
// if sub is collapsible (mobile view)
|
515
|
+
if (this.isCollapsible()) {
|
516
|
+
if (this.opts.collapsibleHideFunction) {
|
517
|
+
this.opts.collapsibleHideFunction.call(this, $sub, complete);
|
518
|
+
} else {
|
519
|
+
$sub.hide(this.opts.collapsibleHideDuration, complete);
|
520
|
+
}
|
521
|
+
} else {
|
522
|
+
if (this.opts.hideFunction) {
|
523
|
+
this.opts.hideFunction.call(this, $sub, complete);
|
524
|
+
} else {
|
525
|
+
$sub.hide(this.opts.hideDuration, complete);
|
526
|
+
}
|
527
|
+
}
|
528
|
+
// remove IE iframe shim
|
529
|
+
if ($sub.dataSM('ie-shim')) {
|
530
|
+
$sub.dataSM('ie-shim').remove();
|
531
|
+
}
|
532
|
+
// deactivate scrolling if it is activated for this sub
|
533
|
+
if ($sub.dataSM('scroll')) {
|
534
|
+
$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
|
535
|
+
}
|
536
|
+
// unhighlight parent item
|
537
|
+
$sub.dataSM('parent-a').removeClass('highlighted');
|
538
|
+
var level = $sub.dataSM('level');
|
539
|
+
this.activatedItems.splice(level - 1, 1);
|
540
|
+
this.visibleSubMenus.splice(level - 1, 1);
|
541
|
+
this.$root.triggerHandler('hide.smapi', $sub[0]);
|
542
|
+
}
|
543
|
+
},
|
544
|
+
menuHideAll: function() {
|
545
|
+
if (this.showTimeout) {
|
546
|
+
clearTimeout(this.showTimeout);
|
547
|
+
this.showTimeout = 0;
|
548
|
+
}
|
549
|
+
// hide all subs
|
550
|
+
for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
|
551
|
+
this.menuHide(this.visibleSubMenus[i]);
|
552
|
+
}
|
553
|
+
// hide root if it's popup
|
554
|
+
if (this.opts.isPopup) {
|
555
|
+
this.$root.stop(true, true);
|
556
|
+
if (this.$root.is(':visible')) {
|
557
|
+
if (this.opts.hideFunction) {
|
558
|
+
this.opts.hideFunction.call(this, this.$root);
|
559
|
+
} else {
|
560
|
+
this.$root.hide(this.opts.hideDuration);
|
561
|
+
}
|
562
|
+
// remove IE iframe shim
|
563
|
+
if (this.$root.dataSM('ie-shim')) {
|
564
|
+
this.$root.dataSM('ie-shim').remove();
|
565
|
+
}
|
566
|
+
}
|
567
|
+
}
|
568
|
+
this.activatedItems = [];
|
569
|
+
this.visibleSubMenus = [];
|
570
|
+
this.clickActivated = false;
|
571
|
+
// reset z-index increment
|
572
|
+
this.zIndexInc = 0;
|
573
|
+
},
|
574
|
+
menuIframeShim: function($ul) {
|
575
|
+
// create iframe shim for the menu
|
576
|
+
if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
|
577
|
+
$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
|
578
|
+
.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
|
579
|
+
);
|
580
|
+
}
|
581
|
+
},
|
582
|
+
menuInit: function($ul) {
|
583
|
+
if (!$ul.dataSM('in-mega')) {
|
584
|
+
this.subMenus.push($ul);
|
585
|
+
// mark UL's in mega drop downs (if any) so we can neglect them
|
586
|
+
if ($ul.hasClass('mega-menu')) {
|
587
|
+
$ul.find('ul').dataSM('in-mega', true);
|
588
|
+
}
|
589
|
+
// get level (much faster than, for example, using parentsUntil)
|
590
|
+
var level = 2,
|
591
|
+
par = $ul[0];
|
592
|
+
while ((par = par.parentNode.parentNode) != this.$root[0]) {
|
593
|
+
level++;
|
594
|
+
}
|
595
|
+
// cache stuff
|
596
|
+
$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
|
597
|
+
.dataSM('level', level)
|
598
|
+
.parent().dataSM('sub', $ul);
|
599
|
+
// add sub indicator to parent item
|
600
|
+
if (this.opts.subIndicators) {
|
601
|
+
$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
|
602
|
+
}
|
603
|
+
}
|
604
|
+
},
|
605
|
+
menuPosition: function($sub) {
|
606
|
+
var $a = $sub.dataSM('parent-a'),
|
607
|
+
$ul = $sub.parent().parent(),
|
608
|
+
level = $sub.dataSM('level'),
|
609
|
+
subW = this.getWidth($sub),
|
610
|
+
subH = this.getHeight($sub),
|
611
|
+
itemOffset = $a.offset(),
|
612
|
+
itemX = itemOffset.left,
|
613
|
+
itemY = itemOffset.top,
|
614
|
+
itemW = this.getWidth($a),
|
615
|
+
itemH = this.getHeight($a),
|
616
|
+
$win = $(window),
|
617
|
+
winX = $win.scrollLeft(),
|
618
|
+
winY = $win.scrollTop(),
|
619
|
+
winW = $win.width(),
|
620
|
+
winH = $win.height(),
|
621
|
+
horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
|
622
|
+
subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
|
623
|
+
subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
|
624
|
+
x, y;
|
625
|
+
if (horizontalParent) {
|
626
|
+
x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
|
627
|
+
y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
|
628
|
+
} else {
|
629
|
+
x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX;
|
630
|
+
y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
|
631
|
+
}
|
632
|
+
if (this.opts.keepInViewport && !this.isCollapsible()) {
|
633
|
+
if (this.isFixed()) {
|
634
|
+
itemX -= winX;
|
635
|
+
itemY -= winY;
|
636
|
+
winX = winY = 0;
|
637
|
+
}
|
638
|
+
var absX = itemX + x,
|
639
|
+
absY = itemY + y;
|
640
|
+
if (this.opts.rightToLeftSubMenus && absX < winX) {
|
641
|
+
x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
|
642
|
+
} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + winW) {
|
643
|
+
x = horizontalParent ? winX + winW - subW - absX + x : subOffsetX - subW;
|
644
|
+
}
|
645
|
+
if (!horizontalParent) {
|
646
|
+
if (subH < winH && absY + subH > winY + winH) {
|
647
|
+
y += winY + winH - subH - absY;
|
648
|
+
} else if (subH >= winH || absY < winY) {
|
649
|
+
y += winY - absY;
|
650
|
+
}
|
651
|
+
}
|
652
|
+
// do we need scrolling?
|
653
|
+
// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
|
654
|
+
if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
|
655
|
+
var self = this;
|
656
|
+
if (!$sub.dataSM('scroll-arrows')) {
|
657
|
+
$sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]])
|
658
|
+
.bind({
|
659
|
+
mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
|
660
|
+
mouseleave: function(e) {
|
661
|
+
self.menuScrollStop($sub);
|
662
|
+
self.menuScrollOut($sub, e);
|
663
|
+
},
|
664
|
+
'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
|
665
|
+
})
|
666
|
+
.insertAfter($sub)
|
667
|
+
);
|
668
|
+
}
|
669
|
+
// bind events to show/hide arrows on hover and save scrolling data for this sub
|
670
|
+
var vportY = winY - (itemY + itemH);
|
671
|
+
$sub.dataSM('scroll', {
|
672
|
+
vportY: vportY,
|
673
|
+
subH: subH,
|
674
|
+
winH: winH,
|
675
|
+
step: 1
|
676
|
+
})
|
677
|
+
.bind({
|
678
|
+
'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
|
679
|
+
'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
|
680
|
+
'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
|
681
|
+
})
|
682
|
+
.dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: this.getWidth($sub) - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: this.getStartZIndex() + this.zIndexInc })
|
683
|
+
.eq(0).css('margin-top', vportY).end()
|
684
|
+
.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
|
685
|
+
.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
|
686
|
+
}
|
687
|
+
}
|
688
|
+
$sub.css({ top: 'auto', left: '0', marginLeft: x, marginTop: y - itemH });
|
689
|
+
// IE iframe shim
|
690
|
+
this.menuIframeShim($sub);
|
691
|
+
if ($sub.dataSM('ie-shim')) {
|
692
|
+
$sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH });
|
693
|
+
}
|
694
|
+
},
|
695
|
+
menuScroll: function($sub, up, wheel) {
|
696
|
+
var y = parseFloat($sub.css('margin-top')),
|
697
|
+
scroll = $sub.dataSM('scroll'),
|
698
|
+
end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
|
699
|
+
step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
|
700
|
+
$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
|
701
|
+
y = parseFloat($sub.css('margin-top'));
|
702
|
+
// show opposite arrow if appropriate
|
703
|
+
if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
|
704
|
+
$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
|
705
|
+
}
|
706
|
+
// accelerate when not using mousewheel to scroll
|
707
|
+
if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
|
708
|
+
$sub.dataSM('scroll').step += 0.5;
|
709
|
+
}
|
710
|
+
// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
|
711
|
+
if (Math.abs(y - end) < 1) {
|
712
|
+
$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
|
713
|
+
$sub.dataSM('scroll').step = 1;
|
714
|
+
} else if (!wheel) {
|
715
|
+
var self = this;
|
716
|
+
this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
|
717
|
+
}
|
718
|
+
},
|
719
|
+
menuScrollMousewheel: function($sub, e) {
|
720
|
+
var $closestSub = $(e.target).closest('ul');
|
721
|
+
while ($closestSub.dataSM('in-mega')) {
|
722
|
+
$closestSub = $closestSub.parent().closest('ul');
|
723
|
+
}
|
724
|
+
if ($closestSub[0] == $sub[0]) {
|
725
|
+
var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
|
726
|
+
if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
|
727
|
+
this.menuScroll($sub, up, true);
|
728
|
+
}
|
729
|
+
}
|
730
|
+
e.preventDefault();
|
731
|
+
},
|
732
|
+
menuScrollOut: function($sub, e) {
|
733
|
+
var reClass = /^scroll-(up|down)/,
|
734
|
+
$closestSub = $(e.relatedTarget).closest('ul');
|
735
|
+
while ($closestSub.dataSM('in-mega')) {
|
736
|
+
$closestSub = $closestSub.parent().closest('ul');
|
737
|
+
}
|
738
|
+
if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
|
739
|
+
$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
|
740
|
+
}
|
741
|
+
},
|
742
|
+
menuScrollOver: function($sub, e) {
|
743
|
+
var reClass = /^scroll-(up|down)/,
|
744
|
+
$closestSub = $(e.target).closest('ul');
|
745
|
+
while ($closestSub.dataSM('in-mega')) {
|
746
|
+
$closestSub = $closestSub.parent().closest('ul');
|
747
|
+
}
|
748
|
+
if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
|
749
|
+
$sub.dataSM('scroll-arrows').css('visibility', 'visible');
|
750
|
+
}
|
751
|
+
},
|
752
|
+
menuScrollStop: function($sub) {
|
753
|
+
if (this.scrollTimeout) {
|
754
|
+
clearTimeout(this.scrollTimeout);
|
755
|
+
this.scrollTimeout = 0;
|
756
|
+
$sub.dataSM('scroll').step = 1;
|
757
|
+
}
|
758
|
+
},
|
759
|
+
menuShow: function($sub) {
|
760
|
+
if (!$sub.dataSM('beforefirstshowfired')) {
|
761
|
+
$sub.dataSM('beforefirstshowfired', true);
|
762
|
+
if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
|
763
|
+
return;
|
764
|
+
}
|
765
|
+
}
|
766
|
+
if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
|
767
|
+
return;
|
768
|
+
}
|
769
|
+
this.menuFixLayout($sub);
|
770
|
+
$sub.stop(true, true);
|
771
|
+
if (!$sub.is(':visible')) {
|
772
|
+
// set z-index - for IE < 9 set it to the parent LI
|
773
|
+
var zIndex = this.getStartZIndex() + (++this.zIndexInc);
|
774
|
+
if (IElt9) {
|
775
|
+
$sub.parent().css('z-index', zIndex);
|
776
|
+
} else {
|
777
|
+
$sub.css('z-index', zIndex);
|
778
|
+
}
|
779
|
+
// highlight parent item
|
780
|
+
if (this.opts.keepHighlighted || this.isCollapsible()) {
|
781
|
+
$sub.dataSM('parent-a').addClass('highlighted');
|
782
|
+
}
|
783
|
+
// min/max-width fix - no way to rely purely on CSS as all UL's are nested
|
784
|
+
if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
|
785
|
+
if (!IElt8) {
|
786
|
+
$sub.css({ width: 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
|
787
|
+
if (this.opts.subMenusMinWidth) {
|
788
|
+
$sub.css('min-width', this.opts.subMenusMinWidth);
|
789
|
+
}
|
790
|
+
if (this.opts.subMenusMaxWidth) {
|
791
|
+
var noMaxWidth = this.getWidth($sub);
|
792
|
+
$sub.css('max-width', this.opts.subMenusMaxWidth);
|
793
|
+
if (noMaxWidth > this.getWidth($sub)) {
|
794
|
+
$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
|
795
|
+
}
|
796
|
+
}
|
797
|
+
// IE6,7
|
798
|
+
} else {
|
799
|
+
$sub.children().css('styleFloat', 'none');
|
800
|
+
if (IE6) {
|
801
|
+
$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
|
802
|
+
.children().children('a').css('white-space', 'nowrap');
|
803
|
+
} else { // IE7
|
804
|
+
$sub.css({ width: 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
|
805
|
+
if (this.opts.subMenusMinWidth) {
|
806
|
+
$sub.css('min-width', this.opts.subMenusMinWidth);
|
807
|
+
}
|
808
|
+
}
|
809
|
+
if (this.opts.subMenusMaxWidth) {
|
810
|
+
var noMaxWidth = $sub.width();
|
811
|
+
if (IE6) {
|
812
|
+
var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
|
813
|
+
if (noMaxWidth > maxWidth) {
|
814
|
+
$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
|
815
|
+
} else {
|
816
|
+
$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
|
817
|
+
}
|
818
|
+
} else { // IE7
|
819
|
+
$sub.css('max-width', this.opts.subMenusMaxWidth);
|
820
|
+
if (noMaxWidth > $sub.width()) {
|
821
|
+
$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
|
822
|
+
} else {
|
823
|
+
$sub.width(noMaxWidth);
|
824
|
+
}
|
825
|
+
}
|
826
|
+
} else {
|
827
|
+
$sub.width($sub.width());
|
828
|
+
}
|
829
|
+
$sub.children().css('styleFloat', 'left');
|
830
|
+
}
|
831
|
+
}
|
832
|
+
this.menuPosition($sub);
|
833
|
+
// insert IE iframe shim
|
834
|
+
if ($sub.dataSM('ie-shim')) {
|
835
|
+
$sub.dataSM('ie-shim').insertBefore($sub);
|
836
|
+
}
|
837
|
+
var complete = function() {
|
838
|
+
// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
|
839
|
+
$sub.css('overflow', '');
|
840
|
+
};
|
841
|
+
// if sub is collapsible (mobile view)
|
842
|
+
if (this.isCollapsible()) {
|
843
|
+
if (this.opts.collapsibleShowFunction) {
|
844
|
+
this.opts.collapsibleShowFunction.call(this, $sub, complete);
|
845
|
+
} else {
|
846
|
+
$sub.show(this.opts.collapsibleShowDuration, complete);
|
847
|
+
}
|
848
|
+
} else {
|
849
|
+
if (this.opts.showFunction) {
|
850
|
+
this.opts.showFunction.call(this, $sub, complete);
|
851
|
+
} else {
|
852
|
+
$sub.show(this.opts.showDuration, complete);
|
853
|
+
}
|
854
|
+
}
|
855
|
+
// save new sub menu for this level
|
856
|
+
this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
|
857
|
+
this.$root.triggerHandler('show.smapi', $sub[0]);
|
858
|
+
}
|
859
|
+
},
|
860
|
+
popupHide: function(noHideTimeout) {
|
861
|
+
if (this.hideTimeout) {
|
862
|
+
clearTimeout(this.hideTimeout);
|
863
|
+
this.hideTimeout = 0;
|
864
|
+
}
|
865
|
+
var self = this;
|
866
|
+
this.hideTimeout = setTimeout(function() {
|
867
|
+
self.menuHideAll();
|
868
|
+
}, noHideTimeout ? 1 : this.opts.hideTimeout);
|
869
|
+
},
|
870
|
+
popupShow: function(left, top) {
|
871
|
+
if (!this.opts.isPopup) {
|
872
|
+
alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
|
873
|
+
return;
|
874
|
+
}
|
875
|
+
if (this.hideTimeout) {
|
876
|
+
clearTimeout(this.hideTimeout);
|
877
|
+
this.hideTimeout = 0;
|
878
|
+
}
|
879
|
+
this.menuFixLayout(this.$root);
|
880
|
+
this.$root.stop(true, true);
|
881
|
+
if (!this.$root.is(':visible')) {
|
882
|
+
this.$root.css({ left: left, top: top });
|
883
|
+
// IE iframe shim
|
884
|
+
this.menuIframeShim(this.$root);
|
885
|
+
if (this.$root.dataSM('ie-shim')) {
|
886
|
+
this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left: left, top: top }).insertBefore(this.$root);
|
887
|
+
}
|
888
|
+
// show menu
|
889
|
+
if (this.opts.showFunction) {
|
890
|
+
this.opts.showFunction.call(this, this.$root);
|
891
|
+
} else {
|
892
|
+
this.$root.show(this.opts.showDuration);
|
893
|
+
}
|
894
|
+
this.visibleSubMenus[0] = this.$root;
|
895
|
+
}
|
896
|
+
},
|
897
|
+
refresh: function() {
|
898
|
+
this.menuHideAll();
|
899
|
+
this.$root.find('ul').each(function() {
|
900
|
+
var $this = $(this);
|
901
|
+
if ($this.dataSM('scroll-arrows')) {
|
902
|
+
$this.dataSM('scroll-arrows').remove();
|
903
|
+
}
|
904
|
+
})
|
905
|
+
.removeDataSM('in-mega')
|
906
|
+
.removeDataSM('shown-before')
|
907
|
+
.removeDataSM('ie-shim')
|
908
|
+
.removeDataSM('scroll-arrows')
|
909
|
+
.removeDataSM('parent-a')
|
910
|
+
.removeDataSM('level')
|
911
|
+
.removeDataSM('beforefirstshowfired');
|
912
|
+
this.$root.find('a.has-submenu').removeClass('has-submenu')
|
913
|
+
.parent().removeDataSM('sub');
|
914
|
+
if (this.opts.subIndicators) {
|
915
|
+
this.$root.find('span.sub-arrow').remove();
|
916
|
+
}
|
917
|
+
if (this.opts.markCurrentItem) {
|
918
|
+
this.$root.find('a.current').removeClass('current');
|
919
|
+
}
|
920
|
+
this.subMenus = [];
|
921
|
+
this.init(true);
|
922
|
+
},
|
923
|
+
rootOut: function(e) {
|
924
|
+
if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
|
925
|
+
return;
|
926
|
+
}
|
927
|
+
if (this.hideTimeout) {
|
928
|
+
clearTimeout(this.hideTimeout);
|
929
|
+
this.hideTimeout = 0;
|
930
|
+
}
|
931
|
+
if (!this.opts.showOnClick || !this.opts.hideOnClick) {
|
932
|
+
var self = this;
|
933
|
+
this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
|
934
|
+
}
|
935
|
+
},
|
936
|
+
rootOver: function(e) {
|
937
|
+
if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
|
938
|
+
return;
|
939
|
+
}
|
940
|
+
if (this.hideTimeout) {
|
941
|
+
clearTimeout(this.hideTimeout);
|
942
|
+
this.hideTimeout = 0;
|
943
|
+
}
|
944
|
+
},
|
945
|
+
winResize: function(e) {
|
946
|
+
if (!this.handleEvents()) {
|
947
|
+
// we still need to resize the disable overlay if it's visible
|
948
|
+
if (this.$disableOverlay) {
|
949
|
+
var pos = this.$root.offset();
|
950
|
+
this.$disableOverlay.css({
|
951
|
+
top: pos.top,
|
952
|
+
left: pos.left,
|
953
|
+
width: this.$root.outerWidth(),
|
954
|
+
height: this.$root.outerHeight()
|
955
|
+
});
|
956
|
+
}
|
957
|
+
return;
|
958
|
+
}
|
959
|
+
// hide sub menus on resize - on mobile do it only on orientation change
|
960
|
+
if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
|
961
|
+
if (this.activatedItems.length) {
|
962
|
+
this.activatedItems[this.activatedItems.length - 1][0].blur();
|
963
|
+
}
|
964
|
+
this.menuHideAll();
|
965
|
+
}
|
966
|
+
}
|
967
|
+
}
|
968
|
+
});
|
969
|
+
|
970
|
+
$.fn.dataSM = function(key, val) {
|
971
|
+
if (val) {
|
972
|
+
return this.data(key + '_smartmenus', val);
|
973
|
+
}
|
974
|
+
return this.data(key + '_smartmenus');
|
975
|
+
}
|
976
|
+
|
977
|
+
$.fn.removeDataSM = function(key) {
|
978
|
+
return this.removeData(key + '_smartmenus');
|
979
|
+
}
|
980
|
+
|
981
|
+
$.fn.smartmenus = function(options) {
|
982
|
+
if (typeof options == 'string') {
|
983
|
+
var args = arguments,
|
984
|
+
method = options;
|
985
|
+
Array.prototype.shift.call(args);
|
986
|
+
return this.each(function() {
|
987
|
+
var smartmenus = $(this).data('smartmenus');
|
988
|
+
if (smartmenus && smartmenus[method]) {
|
989
|
+
smartmenus[method].apply(smartmenus, args);
|
990
|
+
}
|
991
|
+
});
|
992
|
+
}
|
993
|
+
var opts = $.extend({}, $.fn.smartmenus.defaults, options);
|
994
|
+
return this.each(function() {
|
995
|
+
new $.SmartMenus(this, opts);
|
996
|
+
});
|
997
|
+
}
|
998
|
+
|
999
|
+
// default settings
|
1000
|
+
$.fn.smartmenus.defaults = {
|
1001
|
+
isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
|
1002
|
+
mainMenuSubOffsetX: 0, // pixels offset from default position
|
1003
|
+
mainMenuSubOffsetY: 0, // pixels offset from default position
|
1004
|
+
subMenusSubOffsetX: 0, // pixels offset from default position
|
1005
|
+
subMenusSubOffsetY: 0, // pixels offset from default position
|
1006
|
+
subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
|
1007
|
+
subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
|
1008
|
+
subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A
|
1009
|
+
subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append')
|
1010
|
+
subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
|
1011
|
+
scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height
|
1012
|
+
scrollInterval: 30, // interval between each scrolling step
|
1013
|
+
scrollAccelerate: true, // accelerate scrolling or use a fixed step
|
1014
|
+
showTimeout: 250, // timeout before showing the sub menus
|
1015
|
+
hideTimeout: 500, // timeout before hiding the sub menus
|
1016
|
+
showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null
|
1017
|
+
showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show')
|
1018
|
+
// don't forget to call complete() at the end of whatever you do
|
1019
|
+
// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
|
1020
|
+
hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
|
1021
|
+
hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide')
|
1022
|
+
// don't forget to call complete() at the end of whatever you do
|
1023
|
+
// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
|
1024
|
+
collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
|
1025
|
+
collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu
|
1026
|
+
// (i.e. when mobile styles are used to make the sub menus collapsible)
|
1027
|
+
collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
|
1028
|
+
collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu
|
1029
|
+
// (i.e. when mobile styles are used to make the sub menus collapsible)
|
1030
|
+
showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
|
1031
|
+
hideOnClick: true, // hide the sub menus on click/tap anywhere on the page
|
1032
|
+
keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport
|
1033
|
+
keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
|
1034
|
+
markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL
|
1035
|
+
markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item
|
1036
|
+
rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position)
|
1037
|
+
bottomToTopSubMenus: false, // bottom to top display of the sub menus
|
1038
|
+
overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
|
1039
|
+
};
|
1040
|
+
|
1041
|
+
})(jQuery);
|