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.
Files changed (35) hide show
  1. data/lib/omf-web/content/content_proxy.rb +28 -15
  2. data/lib/omf-web/content/file_repository.rb +16 -57
  3. data/lib/omf-web/content/git_repository.rb +2 -121
  4. data/lib/omf-web/content/irods_repository.rb +2 -0
  5. data/lib/omf-web/content/repository.rb +121 -10
  6. data/lib/omf-web/content/static_repository.rb +3 -3
  7. data/lib/omf-web/rack/content_handler.rb +8 -6
  8. data/lib/omf-web/theme.rb +16 -2
  9. data/lib/omf-web/thin/logging.rb +13 -4
  10. data/lib/omf-web/version.rb +1 -1
  11. data/lib/omf-web/widget/text/maruku/output/to_html.rb +29 -23
  12. data/lib/omf-web/widget/text/maruku.rb +20 -5
  13. data/omf_web.gemspec +1 -1
  14. data/share/htdocs/graph/js/code_mirror.js +2 -1
  15. data/share/htdocs/vendor/VERSION_MAP.yaml +1 -0
  16. data/share/htdocs/vendor/smartmenus-0.9.6/LICENSE-MIT +22 -0
  17. data/share/htdocs/vendor/smartmenus-0.9.6/README.md +26 -0
  18. data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.css +103 -0
  19. data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.js +72 -0
  20. data/share/htdocs/vendor/smartmenus-0.9.6/addons/bootstrap/jquery.smartmenus.bootstrap.min.js +3 -0
  21. data/share/htdocs/vendor/smartmenus-0.9.6/addons/keyboard/jquery.smartmenus.keyboard.js +192 -0
  22. data/share/htdocs/vendor/smartmenus-0.9.6/addons/keyboard/jquery.smartmenus.keyboard.min.js +3 -0
  23. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/current-item-bg.png +0 -0
  24. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/main-item-hover-bg.png +0 -0
  25. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/main-menu-bg.png +0 -0
  26. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/sub-item-hover-bg.png +0 -0
  27. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/css-gradients-fallback/vertical-main-item-bg.png +0 -0
  28. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-blue/sm-blue.css +409 -0
  29. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-clean/sm-clean.css +315 -0
  30. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-core-css.css +23 -0
  31. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-mint/sm-mint.css +320 -0
  32. data/share/htdocs/vendor/smartmenus-0.9.6/css/sm-simple/sm-simple.css +218 -0
  33. data/share/htdocs/vendor/smartmenus-0.9.6/jquery.smartmenus.js +1041 -0
  34. data/share/htdocs/vendor/smartmenus-0.9.6/jquery.smartmenus.min.js +3 -0
  35. 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);