omf_web 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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);
|