summaryrefslogtreecommitdiffstats
path: root/jquery
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2016-05-01 08:05:39 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2016-05-05 19:40:39 (GMT)
commit8480d35beef57ed08139b58972bfb83a3b37422c (patch)
tree13d486ed244ee6382a88d5d3312f0ea01b5131be /jquery
parent33915cdce6b66af7e0f8d3e98d741df6e9cc5e32 (diff)
downloadDoxygen-8480d35beef57ed08139b58972bfb83a3b37422c.zip
Doxygen-8480d35beef57ed08139b58972bfb83a3b37422c.tar.gz
Doxygen-8480d35beef57ed08139b58972bfb83a3b37422c.tar.bz2
Applied responsive design to menu bar using smartmenus
Diffstat (limited to 'jquery')
-rw-r--r--jquery/.gitignore4
-rw-r--r--jquery/Makefile25
-rw-r--r--jquery/README8
-rw-r--r--jquery/jquery.smartmenus-1.0.0.js1214
-rw-r--r--jquery/jquery.ui-0.2.3.touch-punch.js180
-rw-r--r--jquery/sass/_round-corners-last-item.scss23
-rw-r--r--jquery/sass/_sm-dox.scss594
-rw-r--r--jquery/sass/_sub-items-indentation.scss15
-rw-r--r--jquery/sass/sm-dox.scss5
-rw-r--r--jquery/sm-core-css.css10
10 files changed, 2070 insertions, 8 deletions
diff --git a/jquery/.gitignore b/jquery/.gitignore
new file mode 100644
index 0000000..8436b24
--- /dev/null
+++ b/jquery/.gitignore
@@ -0,0 +1,4 @@
+.sass-cache
+*-min.js
+doxmenu*.css
+jquery.js
diff --git a/jquery/Makefile b/jquery/Makefile
index 996f472..02cdd34 100644
--- a/jquery/Makefile
+++ b/jquery/Makefile
@@ -3,6 +3,8 @@ JQUERY_UI_VERSION = 1.8.18
HASHCHANGE_VERSION = 1.3
SCROLL_VERSION = 1.4.2
POWERTIP_VERSION = 1.2.0
+TOUCHPUNCH_VERSION = 0.2.3
+SMARTMENUS_VERSION = 1.0.0
MINIFIER ?= /usr/local/bin/yuicompressor-2.4.7
SCRIPTS = jquery-$(JQUERY_VERSION).js \
@@ -12,23 +14,36 @@ SCRIPTS = jquery-$(JQUERY_VERSION).js \
jquery.ui-$(JQUERY_UI_VERSION).resizable.js \
jquery.ba-$(HASHCHANGE_VERSION)-hashchange.js \
jquery.scrollTo-$(SCROLL_VERSION).js \
- jquery.powertip-$(POWERTIP_VERSION).js
-RESULTS = jquery.js
+ jquery.powertip-$(POWERTIP_VERSION).js \
+ jquery.ui-$(TOUCHPUNCH_VERSION).touch-punch.js \
+ jquery.smartmenus-$(SMARTMENUS_VERSION).js
+RESULTS = jquery.js doxmenu-min.css
SCRIPTS_MIN = $(SCRIPTS:%.js=%-min.js)
all: $(RESULTS)
install: $(RESULTS)
- cp $(RESULTS) ../templates/html/
+ cp jquery.js ../templates/html/jquery.js
+ cp doxmenu-min.css ../templates/html/tabs.css
-jquery.js: scripts
+jquery.js: $(SCRIPTS_MIN)
cat $(SCRIPTS_MIN) > jquery.js
+doxmenu-min.css: sm-core-css.css \
+ sass/sm-dox.scss \
+ sass/_round-corners-last-item.scss \
+ sass/_sm-dox.scss \
+ sass/_sub-items-indentation.scss
+ compass compile --css-dir . --force sass/sm-dox.scss
+ cat sm-core-css.css sm-dox.css > doxmenu.css
+ java -jar $(MINIFIER).jar doxmenu.css > doxmenu-min.css
+ rm -f sm-dox.css doxmenu.css
+
scripts: $(SCRIPTS_MIN)
clean:
- rm -f $(SCRIPTS_MIN) $(RESULTS)
+ rm -rf $(SCRIPTS_MIN) $(RESULTS) doxmenu.css .sass-cache jquery.js
%-min.js: %.js
java -jar $(MINIFIER).jar $^ > $@
diff --git a/jquery/README b/jquery/README
index 5e385a5..21590ff 100644
--- a/jquery/README
+++ b/jquery/README
@@ -7,8 +7,10 @@ packages:
- jquery.ui.widget
- jquery.ui.mouse
- jquery.ui.resizable
-- jquery.hashchange: 1.3: http://benalman.com/projects/jquery-hashchange-plugin/
-- jquery.scrollTo: 1.4.2: https://github.com/flesler/jquery.scrollTo
-- jquery.powertip: 1.2.0: http://stevenbenner.github.io/jquery-powertip/
+- jquery.hashchange: 1.3: http://benalman.com/projects/jquery-hashchange-plugin/
+- jquery.scrollTo: 1.4.2: https://github.com/flesler/jquery.scrollTo
+- jquery.powertip: 1.2.0: http://stevenbenner.github.io/jquery-powertip/
+- jquery.touchpunch: 0.2.3: http://touchpunch.furf.com/
+- jquery.smartmenus: 1.0.0: http://www.smartmenus.org/
The Makefile will built the jquery.js files used by doxygen.
diff --git a/jquery/jquery.smartmenus-1.0.0.js b/jquery/jquery.smartmenus-1.0.0.js
new file mode 100644
index 0000000..9c3a494
--- /dev/null
+++ b/jquery/jquery.smartmenus-1.0.0.js
@@ -0,0 +1,1214 @@
+/*!
+ * SmartMenus jQuery Plugin - v1.0.0 - January 27, 2016
+ * http://www.smartmenus.org/
+ *
+ * Copyright Vasil Dinkov, Vadikom Web Ltd.
+ * http://vadikom.com
+ *
+ * Licensed MIT
+ */
+
+(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && typeof module.exports === 'object') {
+ // CommonJS
+ module.exports = factory(require('jquery'));
+ } else {
+ // Global jQuery
+ factory(jQuery);
+ }
+} (function($) {
+
+ var menuTrees = [],
+ IE = !!window.createPopup, // detect it for the iframe shim
+ mouse = false, // optimize for touch by default - we will detect for mouse input
+ touchEvents = 'ontouchstart' in window, // we use this just to choose between toucn and pointer events, not for touch screen detection
+ mouseDetectionEnabled = false,
+ requestAnimationFrame = window.requestAnimationFrame || function(callback) { return setTimeout(callback, 1000 / 60); },
+ cancelAnimationFrame = window.cancelAnimationFrame || function(id) { clearTimeout(id); };
+
+ // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
+ function initMouseDetection(disable) {
+ var eNS = '.smartmenus_mouse';
+ if (!mouseDetectionEnabled && !disable) {
+ // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
+ // 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)
+ var firstTime = true,
+ lastMove = null;
+ $(document).bind(getEventsNS([
+ ['mousemove', function(e) {
+ var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
+ if (lastMove) {
+ var deltaX = Math.abs(lastMove.x - thisMove.x),
+ deltaY = Math.abs(lastMove.y - thisMove.y);
+ if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
+ mouse = true;
+ // 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
+ if (firstTime) {
+ var $a = $(e.target).closest('a');
+ if ($a.is('a')) {
+ $.each(menuTrees, function() {
+ if ($.contains(this.$root[0], $a[0])) {
+ this.itemEnter({ currentTarget: $a[0] });
+ return false;
+ }
+ });
+ }
+ firstTime = false;
+ }
+ }
+ }
+ lastMove = thisMove;
+ }],
+ [touchEvents ? 'touchstart' : 'pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut', function(e) {
+ if (isTouchEvent(e.originalEvent)) {
+ mouse = false;
+ }
+ }]
+ ], eNS));
+ mouseDetectionEnabled = true;
+ } else if (mouseDetectionEnabled && disable) {
+ $(document).unbind(eNS);
+ mouseDetectionEnabled = false;
+ }
+ }
+
+ function isTouchEvent(e) {
+ return !/^(4|mouse)$/.test(e.pointerType);
+ }
+
+ // returns a jQuery bind() ready object
+ function getEventsNS(defArr, eNS) {
+ if (!eNS) {
+ eNS = '';
+ }
+ var obj = {};
+ $.each(defArr, function(index, value) {
+ obj[value[0].split(' ').join(eNS + ' ') + eNS] = value[1];
+ });
+ return obj;
+ }
+
+ $.SmartMenus = function(elm, options) {
+ this.$root = $(elm);
+ this.opts = options;
+ this.rootId = ''; // internal
+ this.accessIdPrefix = '';
+ this.$subArrow = null;
+ this.activatedItems = []; // stores last activated A's for each level
+ this.visibleSubMenus = []; // stores visible sub menus UL's (might be in no particular order)
+ this.showTimeout = 0;
+ this.hideTimeout = 0;
+ this.scrollTimeout = 0;
+ this.clickActivated = false;
+ this.focusActivated = false;
+ this.zIndexInc = 0;
+ this.idInc = 0;
+ this.$firstLink = null; // we'll use these for some tests
+ this.$firstSub = null; // at runtime so we'll cache them
+ this.disabled = false;
+ this.$disableOverlay = null;
+ this.$touchScrollingSub = null;
+ this.cssTransforms3d = 'perspective' in elm.style || 'webkitPerspective' in elm.style;
+ this.wasCollapsible = false;
+ this.init();
+ };
+
+ $.extend($.SmartMenus, {
+ hideAll: function() {
+ $.each(menuTrees, function() {
+ this.menuHideAll();
+ });
+ },
+ destroy: function() {
+ while (menuTrees.length) {
+ menuTrees[0].destroy();
+ }
+ initMouseDetection(true);
+ },
+ prototype: {
+ init: function(refresh) {
+ var self = this;
+
+ if (!refresh) {
+ menuTrees.push(this);
+
+ this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
+ this.accessIdPrefix = 'sm-' + this.rootId + '-';
+
+ if (this.$root.hasClass('sm-rtl')) {
+ this.opts.rightToLeftSubMenus = true;
+ }
+
+ // init root (main menu)
+ var eNS = '.smartmenus';
+ this.$root
+ .data('smartmenus', this)
+ .attr('data-smartmenus-id', this.rootId)
+ .dataSM('level', 1)
+ .bind(getEventsNS([
+ ['mouseover focusin', $.proxy(this.rootOver, this)],
+ ['mouseout focusout', $.proxy(this.rootOut, this)],
+ ['keydown', $.proxy(this.rootKeyDown, this)]
+ ], eNS))
+ .delegate('a', getEventsNS([
+ ['mouseenter', $.proxy(this.itemEnter, this)],
+ ['mouseleave', $.proxy(this.itemLeave, this)],
+ ['mousedown', $.proxy(this.itemDown, this)],
+ ['focus', $.proxy(this.itemFocus, this)],
+ ['blur', $.proxy(this.itemBlur, this)],
+ ['click', $.proxy(this.itemClick, this)]
+ ], eNS));
+
+ // hide menus on tap or click outside the root UL
+ eNS += this.rootId;
+ if (this.opts.hideOnClick) {
+ $(document).bind(getEventsNS([
+ ['touchstart', $.proxy(this.docTouchStart, this)],
+ ['touchmove', $.proxy(this.docTouchMove, this)],
+ ['touchend', $.proxy(this.docTouchEnd, this)],
+ // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
+ ['click', $.proxy(this.docClick, this)]
+ ], eNS));
+ }
+ // hide sub menus on resize
+ $(window).bind(getEventsNS([['resize orientationchange', $.proxy(this.winResize, this)]], eNS));
+
+ if (this.opts.subIndicators) {
+ this.$subArrow = $('<span/>').addClass('sub-arrow');
+ if (this.opts.subIndicatorsText) {
+ this.$subArrow.html(this.opts.subIndicatorsText);
+ }
+ }
+
+ // make sure mouse detection is enabled
+ initMouseDetection();
+ }
+
+ // init sub menus
+ this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
+
+ this.$firstLink = this.$root.find('a').eq(0);
+
+ // find current item
+ if (this.opts.markCurrentItem) {
+ var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
+ reHash = /#.*/,
+ locHref = window.location.href.replace(reDefaultDoc, ''),
+ locHrefNoHash = locHref.replace(reHash, '');
+ this.$root.find('a').each(function() {
+ var href = this.href.replace(reDefaultDoc, ''),
+ $this = $(this);
+ if (href == locHref || href == locHrefNoHash) {
+ $this.addClass('current');
+ if (self.opts.markCurrentTree) {
+ $this.parentsUntil('[data-smartmenus-id]', 'ul').each(function() {
+ $(this).dataSM('parent-a').addClass('current');
+ });
+ }
+ }
+ });
+ }
+
+ // save initial state
+ this.wasCollapsible = this.isCollapsible();
+ },
+ destroy: function(refresh) {
+ if (!refresh) {
+ var eNS = '.smartmenus';
+ this.$root
+ .removeData('smartmenus')
+ .removeAttr('data-smartmenus-id')
+ .removeDataSM('level')
+ .unbind(eNS)
+ .undelegate(eNS);
+ eNS += this.rootId;
+ $(document).unbind(eNS);
+ $(window).unbind(eNS);
+ if (this.opts.subIndicators) {
+ this.$subArrow = null;
+ }
+ }
+ this.menuHideAll();
+ var self = this;
+ this.$root.find('ul').each(function() {
+ var $this = $(this);
+ if ($this.dataSM('scroll-arrows')) {
+ $this.dataSM('scroll-arrows').remove();
+ }
+ if ($this.dataSM('shown-before')) {
+ if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
+ $this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
+ }
+ if ($this.dataSM('scroll-arrows')) {
+ $this.dataSM('scroll-arrows').remove();
+ }
+ $this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
+ }
+ if (($this.attr('id') || '').indexOf(self.accessIdPrefix) == 0) {
+ $this.removeAttr('id');
+ }
+ })
+ .removeDataSM('in-mega')
+ .removeDataSM('shown-before')
+ .removeDataSM('ie-shim')
+ .removeDataSM('scroll-arrows')
+ .removeDataSM('parent-a')
+ .removeDataSM('level')
+ .removeDataSM('beforefirstshowfired')
+ .removeAttr('role')
+ .removeAttr('aria-hidden')
+ .removeAttr('aria-labelledby')
+ .removeAttr('aria-expanded');
+ this.$root.find('a.has-submenu').each(function() {
+ var $this = $(this);
+ if ($this.attr('id').indexOf(self.accessIdPrefix) == 0) {
+ $this.removeAttr('id');
+ }
+ })
+ .removeClass('has-submenu')
+ .removeDataSM('sub')
+ .removeAttr('aria-haspopup')
+ .removeAttr('aria-controls')
+ .removeAttr('aria-expanded')
+ .closest('li').removeDataSM('sub');
+ if (this.opts.subIndicators) {
+ this.$root.find('span.sub-arrow').remove();
+ }
+ if (this.opts.markCurrentItem) {
+ this.$root.find('a.current').removeClass('current');
+ }
+ if (!refresh) {
+ this.$root = null;
+ this.$firstLink = null;
+ this.$firstSub = null;
+ if (this.$disableOverlay) {
+ this.$disableOverlay.remove();
+ this.$disableOverlay = null;
+ }
+ menuTrees.splice($.inArray(this, menuTrees), 1);
+ }
+ },
+ disable: function(noOverlay) {
+ if (!this.disabled) {
+ this.menuHideAll();
+ // display overlay over the menu to prevent interaction
+ if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
+ var pos = this.$root.offset();
+ this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
+ position: 'absolute',
+ top: pos.top,
+ left: pos.left,
+ width: this.$root.outerWidth(),
+ height: this.$root.outerHeight(),
+ zIndex: this.getStartZIndex(true),
+ opacity: 0
+ }).appendTo(document.body);
+ }
+ this.disabled = true;
+ }
+ },
+ docClick: function(e) {
+ if (this.$touchScrollingSub) {
+ this.$touchScrollingSub = null;
+ return;
+ }
+ // hide on any click outside the menu or on a menu link
+ if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
+ this.menuHideAll();
+ }
+ },
+ docTouchEnd: function(e) {
+ if (!this.lastTouch) {
+ return;
+ }
+ 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))) {
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ this.hideTimeout = 0;
+ }
+ // hide with a delay to prevent triggering accidental unwanted click on some page element
+ var self = this;
+ this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, 350);
+ }
+ this.lastTouch = null;
+ },
+ docTouchMove: function(e) {
+ if (!this.lastTouch) {
+ return;
+ }
+ var touchPoint = e.originalEvent.touches[0];
+ this.lastTouch.x2 = touchPoint.pageX;
+ this.lastTouch.y2 = touchPoint.pageY;
+ },
+ docTouchStart: function(e) {
+ var touchPoint = e.originalEvent.touches[0];
+ this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
+ },
+ enable: function() {
+ if (this.disabled) {
+ if (this.$disableOverlay) {
+ this.$disableOverlay.remove();
+ this.$disableOverlay = null;
+ }
+ this.disabled = false;
+ }
+ },
+ getClosestMenu: function(elm) {
+ var $closestMenu = $(elm).closest('ul');
+ while ($closestMenu.dataSM('in-mega')) {
+ $closestMenu = $closestMenu.parent().closest('ul');
+ }
+ return $closestMenu[0] || null;
+ },
+ getHeight: function($elm) {
+ return this.getOffset($elm, true);
+ },
+ // returns precise width/height float values
+ getOffset: function($elm, height) {
+ var old;
+ if ($elm.css('display') == 'none') {
+ old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
+ $elm.css({ position: 'absolute', visibility: 'hidden' }).show();
+ }
+ var box = $elm[0].getBoundingClientRect && $elm[0].getBoundingClientRect(),
+ val = box && (height ? box.height || box.bottom - box.top : box.width || box.right - box.left);
+ if (!val && val !== 0) {
+ val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
+ }
+ if (old) {
+ $elm.hide().css(old);
+ }
+ return val;
+ },
+ getStartZIndex: function(root) {
+ var zIndex = parseInt(this[root ? '$root' : '$firstSub'].css('z-index'));
+ if (!root && isNaN(zIndex)) {
+ zIndex = parseInt(this.$root.css('z-index'));
+ }
+ return !isNaN(zIndex) ? zIndex : 1;
+ },
+ getTouchPoint: function(e) {
+ return e.touches && e.touches[0] || e.changedTouches && e.changedTouches[0] || e;
+ },
+ getViewport: function(height) {
+ var name = height ? 'Height' : 'Width',
+ val = document.documentElement['client' + name],
+ val2 = window['inner' + name];
+ if (val2) {
+ val = Math.min(val, val2);
+ }
+ return val;
+ },
+ getViewportHeight: function() {
+ return this.getViewport(true);
+ },
+ getViewportWidth: function() {
+ return this.getViewport();
+ },
+ getWidth: function($elm) {
+ return this.getOffset($elm);
+ },
+ handleEvents: function() {
+ return !this.disabled && this.isCSSOn();
+ },
+ handleItemEvents: function($a) {
+ return this.handleEvents() && !this.isLinkInMegaMenu($a);
+ },
+ isCollapsible: function() {
+ return this.$firstSub.css('position') == 'static';
+ },
+ isCSSOn: function() {
+ return this.$firstLink.css('display') == 'block';
+ },
+ isFixed: function() {
+ var isFixed = this.$root.css('position') == 'fixed';
+ if (!isFixed) {
+ this.$root.parentsUntil('body').each(function() {
+ if ($(this).css('position') == 'fixed') {
+ isFixed = true;
+ return false;
+ }
+ });
+ }
+ return isFixed;
+ },
+ isLinkInMegaMenu: function($a) {
+ return $(this.getClosestMenu($a[0])).hasClass('mega-menu');
+ },
+ isTouchMode: function() {
+ return !mouse || this.opts.noMouseOver || this.isCollapsible();
+ },
+ itemActivate: function($a, focus) {
+ var $ul = $a.closest('ul'),
+ level = $ul.dataSM('level');
+ // 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
+ if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
+ var self = this;
+ $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
+ self.itemActivate($(this).dataSM('parent-a'));
+ });
+ }
+ // hide any visible deeper level sub menus
+ if (!this.isCollapsible() || focus) {
+ this.menuHideSubMenus(!this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level);
+ }
+ // save new active item for this level
+ this.activatedItems[level - 1] = $a;
+ if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
+ return;
+ }
+ // show the sub menu if this item has one
+ var $sub = $a.dataSM('sub');
+ if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
+ this.menuShow($sub);
+ }
+ },
+ itemBlur: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ this.$root.triggerHandler('blur.smapi', $a[0]);
+ },
+ itemClick: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ if (this.$touchScrollingSub && this.$touchScrollingSub[0] == $a.closest('ul')[0]) {
+ this.$touchScrollingSub = null;
+ e.stopPropagation();
+ return false;
+ }
+ if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
+ return false;
+ }
+ var subArrowClicked = $(e.target).is('span.sub-arrow'),
+ $sub = $a.dataSM('sub'),
+ firstLevelSub = $sub ? $sub.dataSM('level') == 2 : false;
+ // if the sub is not visible
+ if ($sub && !$sub.is(':visible')) {
+ if (this.opts.showOnClick && firstLevelSub) {
+ this.clickActivated = true;
+ }
+ // try to activate the item and show the sub
+ this.itemActivate($a);
+ // if "itemActivate" showed the sub, prevent the click so that the link is not loaded
+ // 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
+ if ($sub.is(':visible')) {
+ this.focusActivated = true;
+ return false;
+ }
+ } else if (this.isCollapsible() && subArrowClicked) {
+ this.itemActivate($a);
+ this.menuHide($sub);
+ return false;
+ }
+ if (this.opts.showOnClick && firstLevelSub || $a.hasClass('disabled') || this.$root.triggerHandler('select.smapi', $a[0]) === false) {
+ return false;
+ }
+ },
+ itemDown: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ $a.dataSM('mousedown', true);
+ },
+ itemEnter: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ if (!this.isTouchMode()) {
+ if (this.showTimeout) {
+ clearTimeout(this.showTimeout);
+ this.showTimeout = 0;
+ }
+ var self = this;
+ this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.closest('ul').dataSM('level') == 1 ? 1 : this.opts.showTimeout);
+ }
+ this.$root.triggerHandler('mouseenter.smapi', $a[0]);
+ },
+ itemFocus: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ // 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
+ if (this.focusActivated && (!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
+ this.itemActivate($a, true);
+ }
+ this.$root.triggerHandler('focus.smapi', $a[0]);
+ },
+ itemLeave: function(e) {
+ var $a = $(e.currentTarget);
+ if (!this.handleItemEvents($a)) {
+ return;
+ }
+ if (!this.isTouchMode()) {
+ $a[0].blur();
+ if (this.showTimeout) {
+ clearTimeout(this.showTimeout);
+ this.showTimeout = 0;
+ }
+ }
+ $a.removeDataSM('mousedown');
+ this.$root.triggerHandler('mouseleave.smapi', $a[0]);
+ },
+ menuHide: function($sub) {
+ if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
+ return;
+ }
+ $sub.stop(true, true);
+ if ($sub.css('display') != 'none') {
+ var complete = function() {
+ // unset z-index
+ $sub.css('z-index', '');
+ };
+ // if sub is collapsible (mobile view)
+ if (this.isCollapsible()) {
+ if (this.opts.collapsibleHideFunction) {
+ this.opts.collapsibleHideFunction.call(this, $sub, complete);
+ } else {
+ $sub.hide(this.opts.collapsibleHideDuration, complete);
+ }
+ } else {
+ if (this.opts.hideFunction) {
+ this.opts.hideFunction.call(this, $sub, complete);
+ } else {
+ $sub.hide(this.opts.hideDuration, complete);
+ }
+ }
+ // remove IE iframe shim
+ if ($sub.dataSM('ie-shim')) {
+ $sub.dataSM('ie-shim').remove().css({ '-webkit-transform': '', transform: '' });
+ }
+ // deactivate scrolling if it is activated for this sub
+ if ($sub.dataSM('scroll')) {
+ this.menuScrollStop($sub);
+ $sub.css({ 'touch-action': '', '-ms-touch-action': '', '-webkit-transform': '', transform: '' })
+ .unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
+ }
+ // unhighlight parent item + accessibility
+ $sub.dataSM('parent-a').removeClass('highlighted').attr('aria-expanded', 'false');
+ $sub.attr({
+ 'aria-expanded': 'false',
+ 'aria-hidden': 'true'
+ });
+ var level = $sub.dataSM('level');
+ this.activatedItems.splice(level - 1, 1);
+ this.visibleSubMenus.splice($.inArray($sub, this.visibleSubMenus), 1);
+ this.$root.triggerHandler('hide.smapi', $sub[0]);
+ }
+ },
+ menuHideAll: function() {
+ if (this.showTimeout) {
+ clearTimeout(this.showTimeout);
+ this.showTimeout = 0;
+ }
+ // hide all subs
+ // if it's a popup, this.visibleSubMenus[0] is the root UL
+ var level = this.opts.isPopup ? 1 : 0;
+ for (var i = this.visibleSubMenus.length - 1; i >= level; i--) {
+ this.menuHide(this.visibleSubMenus[i]);
+ }
+ // hide root if it's popup
+ if (this.opts.isPopup) {
+ this.$root.stop(true, true);
+ if (this.$root.is(':visible')) {
+ if (this.opts.hideFunction) {
+ this.opts.hideFunction.call(this, this.$root);
+ } else {
+ this.$root.hide(this.opts.hideDuration);
+ }
+ // remove IE iframe shim
+ if (this.$root.dataSM('ie-shim')) {
+ this.$root.dataSM('ie-shim').remove();
+ }
+ }
+ }
+ this.activatedItems = [];
+ this.visibleSubMenus = [];
+ this.clickActivated = false;
+ this.focusActivated = false;
+ // reset z-index increment
+ this.zIndexInc = 0;
+ this.$root.triggerHandler('hideAll.smapi');
+ },
+ menuHideSubMenus: function(level) {
+ for (var i = this.activatedItems.length - 1; i >= level; i--) {
+ var $sub = this.activatedItems[i].dataSM('sub');
+ if ($sub) {
+ this.menuHide($sub);
+ }
+ }
+ },
+ menuIframeShim: function($ul) {
+ // create iframe shim for the menu
+ if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
+ $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
+ .css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
+ );
+ }
+ },
+ menuInit: function($ul) {
+ if (!$ul.dataSM('in-mega')) {
+ // mark UL's in mega drop downs (if any) so we can neglect them
+ if ($ul.hasClass('mega-menu')) {
+ $ul.find('ul').dataSM('in-mega', true);
+ }
+ // get level (much faster than, for example, using parentsUntil)
+ var level = 2,
+ par = $ul[0];
+ while ((par = par.parentNode.parentNode) != this.$root[0]) {
+ level++;
+ }
+ // cache stuff for quick access
+ var $a = $ul.prevAll('a').eq(-1);
+ // if the link is nested (e.g. in a heading)
+ if (!$a.length) {
+ $a = $ul.prevAll().find('a').eq(-1);
+ }
+ $a.addClass('has-submenu').dataSM('sub', $ul);
+ $ul.dataSM('parent-a', $a)
+ .dataSM('level', level)
+ .parent().dataSM('sub', $ul);
+ // accessibility
+ var aId = $a.attr('id') || this.accessIdPrefix + (++this.idInc),
+ ulId = $ul.attr('id') || this.accessIdPrefix + (++this.idInc);
+ $a.attr({
+ id: aId,
+ 'aria-haspopup': 'true',
+ 'aria-controls': ulId,
+ 'aria-expanded': 'false'
+ });
+ $ul.attr({
+ id: ulId,
+ 'role': 'group',
+ 'aria-hidden': 'true',
+ 'aria-labelledby': aId,
+ 'aria-expanded': 'false'
+ });
+ // add sub indicator to parent item
+ if (this.opts.subIndicators) {
+ $a[this.opts.subIndicatorsPos](this.$subArrow.clone());
+ }
+ }
+ },
+ menuPosition: function($sub) {
+ var $a = $sub.dataSM('parent-a'),
+ $li = $a.closest('li'),
+ $ul = $li.parent(),
+ level = $sub.dataSM('level'),
+ subW = this.getWidth($sub),
+ subH = this.getHeight($sub),
+ itemOffset = $a.offset(),
+ itemX = itemOffset.left,
+ itemY = itemOffset.top,
+ itemW = this.getWidth($a),
+ itemH = this.getHeight($a),
+ $win = $(window),
+ winX = $win.scrollLeft(),
+ winY = $win.scrollTop(),
+ winW = this.getViewportWidth(),
+ winH = this.getViewportHeight(),
+ horizontalParent = $ul.parent().is('[data-sm-horizontal-sub]') || level == 2 && !$ul.hasClass('sm-vertical'),
+ rightToLeft = this.opts.rightToLeftSubMenus && !$li.is('[data-sm-reverse]') || !this.opts.rightToLeftSubMenus && $li.is('[data-sm-reverse]'),
+ subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
+ subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
+ x, y;
+ if (horizontalParent) {
+ x = rightToLeft ? itemW - subW - subOffsetX : subOffsetX;
+ y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
+ } else {
+ x = rightToLeft ? subOffsetX - subW : itemW - subOffsetX;
+ y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
+ }
+ if (this.opts.keepInViewport) {
+ var absX = itemX + x,
+ absY = itemY + y;
+ if (rightToLeft && absX < winX) {
+ x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
+ } else if (!rightToLeft && absX + subW > winX + winW) {
+ x = horizontalParent ? winX + winW - subW - absX + x : subOffsetX - subW;
+ }
+ if (!horizontalParent) {
+ if (subH < winH && absY + subH > winY + winH) {
+ y += winY + winH - subH - absY;
+ } else if (subH >= winH || absY < winY) {
+ y += winY - absY;
+ }
+ }
+ // do we need scrolling?
+ // 0.49 used for better precision when dealing with float values
+ if (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49) {
+ var self = this;
+ if (!$sub.dataSM('scroll-arrows')) {
+ $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]])
+ .bind({
+ mouseenter: function() {
+ $sub.dataSM('scroll').up = $(this).hasClass('scroll-up');
+ self.menuScroll($sub);
+ },
+ mouseleave: function(e) {
+ self.menuScrollStop($sub);
+ self.menuScrollOut($sub, e);
+ },
+ 'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
+ })
+ .insertAfter($sub)
+ );
+ }
+ // bind scroll events and save scroll data for this sub
+ var eNS = '.smartmenus_scroll';
+ $sub.dataSM('scroll', {
+ y: this.cssTransforms3d ? 0 : y - itemH,
+ step: 1,
+ // cache stuff for faster recalcs later
+ itemH: itemH,
+ subH: subH,
+ arrowDownH: this.getHeight($sub.dataSM('scroll-arrows').eq(1))
+ })
+ .bind(getEventsNS([
+ ['mouseover', function(e) { self.menuScrollOver($sub, e); }],
+ ['mouseout', function(e) { self.menuScrollOut($sub, e); }],
+ ['mousewheel DOMMouseScroll', function(e) { self.menuScrollMousewheel($sub, e); }]
+ ], eNS))
+ .dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: subW - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: $sub.css('z-index') })
+ .eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
+ // when a menu tree is fixed positioned we allow scrolling via touch too
+ // since there is no other way to access such long sub menus if no mouse is present
+ if (this.isFixed()) {
+ $sub.css({ 'touch-action': 'none', '-ms-touch-action': 'none' })
+ .bind(getEventsNS([
+ [touchEvents ? 'touchstart touchmove touchend' : 'pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp', function(e) {
+ self.menuScrollTouch($sub, e);
+ }]
+ ], eNS));
+ }
+ }
+ }
+ $sub.css({ top: 'auto', left: '0', marginLeft: x, marginTop: y - itemH });
+ // IE iframe shim
+ this.menuIframeShim($sub);
+ if ($sub.dataSM('ie-shim')) {
+ $sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH });
+ }
+ },
+ menuScroll: function($sub, once, step) {
+ var data = $sub.dataSM('scroll'),
+ $arrows = $sub.dataSM('scroll-arrows'),
+ end = data.up ? data.upEnd : data.downEnd,
+ diff;
+ if (!once && data.momentum) {
+ data.momentum *= 0.92;
+ diff = data.momentum;
+ if (diff < 0.5) {
+ this.menuScrollStop($sub);
+ return;
+ }
+ } else {
+ diff = step || (once || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor(data.step));
+ }
+ // hide any visible deeper level sub menus
+ var level = $sub.dataSM('level');
+ if (this.activatedItems[level - 1] && this.activatedItems[level - 1].dataSM('sub') && this.activatedItems[level - 1].dataSM('sub').is(':visible')) {
+ this.menuHideSubMenus(level - 1);
+ }
+ data.y = data.up && end <= data.y || !data.up && end >= data.y ? data.y : (Math.abs(end - data.y) > diff ? data.y + (data.up ? diff : -diff) : end);
+ $sub.add($sub.dataSM('ie-shim')).css(this.cssTransforms3d ? { '-webkit-transform': 'translate3d(0, ' + data.y + 'px, 0)', transform: 'translate3d(0, ' + data.y + 'px, 0)' } : { marginTop: data.y });
+ // show opposite arrow if appropriate
+ if (mouse && (data.up && data.y > data.downEnd || !data.up && data.y < data.upEnd)) {
+ $arrows.eq(data.up ? 1 : 0).show();
+ }
+ // if we've reached the end
+ if (data.y == end) {
+ if (mouse) {
+ $arrows.eq(data.up ? 0 : 1).hide();
+ }
+ this.menuScrollStop($sub);
+ } else if (!once) {
+ if (this.opts.scrollAccelerate && data.step < this.opts.scrollStep) {
+ data.step += 0.2;
+ }
+ var self = this;
+ this.scrollTimeout = requestAnimationFrame(function() { self.menuScroll($sub); });
+ }
+ },
+ menuScrollMousewheel: function($sub, e) {
+ if (this.getClosestMenu(e.target) == $sub[0]) {
+ e = e.originalEvent;
+ var up = (e.wheelDelta || -e.detail) > 0;
+ if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
+ $sub.dataSM('scroll').up = up;
+ this.menuScroll($sub, true);
+ }
+ }
+ e.preventDefault();
+ },
+ menuScrollOut: function($sub, e) {
+ if (mouse) {
+ if (!/^scroll-(up|down)/.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || this.getClosestMenu(e.relatedTarget) != $sub[0])) {
+ $sub.dataSM('scroll-arrows').css('visibility', 'hidden');
+ }
+ }
+ },
+ menuScrollOver: function($sub, e) {
+ if (mouse) {
+ if (!/^scroll-(up|down)/.test(e.target.className) && this.getClosestMenu(e.target) == $sub[0]) {
+ this.menuScrollRefreshData($sub);
+ var data = $sub.dataSM('scroll'),
+ upEnd = $(window).scrollTop() - $sub.dataSM('parent-a').offset().top - data.itemH;
+ $sub.dataSM('scroll-arrows').eq(0).css('margin-top', upEnd).end()
+ .eq(1).css('margin-top', upEnd + this.getViewportHeight() - data.arrowDownH).end()
+ .css('visibility', 'visible');
+ }
+ }
+ },
+ menuScrollRefreshData: function($sub) {
+ var data = $sub.dataSM('scroll'),
+ upEnd = $(window).scrollTop() - $sub.dataSM('parent-a').offset().top - data.itemH;
+ if (this.cssTransforms3d) {
+ upEnd = -(parseFloat($sub.css('margin-top')) - upEnd);
+ }
+ $.extend(data, {
+ upEnd: upEnd,
+ downEnd: upEnd + this.getViewportHeight() - data.subH
+ });
+ },
+ menuScrollStop: function($sub) {
+ if (this.scrollTimeout) {
+ cancelAnimationFrame(this.scrollTimeout);
+ this.scrollTimeout = 0;
+ $sub.dataSM('scroll').step = 1;
+ return true;
+ }
+ },
+ menuScrollTouch: function($sub, e) {
+ e = e.originalEvent;
+ if (isTouchEvent(e)) {
+ var touchPoint = this.getTouchPoint(e);
+ // neglect event if we touched a visible deeper level sub menu
+ if (this.getClosestMenu(touchPoint.target) == $sub[0]) {
+ var data = $sub.dataSM('scroll');
+ if (/(start|down)$/i.test(e.type)) {
+ if (this.menuScrollStop($sub)) {
+ // if we were scrolling, just stop and don't activate any link on the first touch
+ e.preventDefault();
+ this.$touchScrollingSub = $sub;
+ } else {
+ this.$touchScrollingSub = null;
+ }
+ // update scroll data since the user might have zoomed, etc.
+ this.menuScrollRefreshData($sub);
+ // extend it with the touch properties
+ $.extend(data, {
+ touchStartY: touchPoint.pageY,
+ touchStartTime: e.timeStamp
+ });
+ } else if (/move$/i.test(e.type)) {
+ var prevY = data.touchY !== undefined ? data.touchY : data.touchStartY;
+ if (prevY !== undefined && prevY != touchPoint.pageY) {
+ this.$touchScrollingSub = $sub;
+ var up = prevY < touchPoint.pageY;
+ // changed direction? reset...
+ if (data.up !== undefined && data.up != up) {
+ $.extend(data, {
+ touchStartY: touchPoint.pageY,
+ touchStartTime: e.timeStamp
+ });
+ }
+ $.extend(data, {
+ up: up,
+ touchY: touchPoint.pageY
+ });
+ this.menuScroll($sub, true, Math.abs(touchPoint.pageY - prevY));
+ }
+ e.preventDefault();
+ } else { // touchend/pointerup
+ if (data.touchY !== undefined) {
+ if (data.momentum = Math.pow(Math.abs(touchPoint.pageY - data.touchStartY) / (e.timeStamp - data.touchStartTime), 2) * 15) {
+ this.menuScrollStop($sub);
+ this.menuScroll($sub);
+ e.preventDefault();
+ }
+ delete data.touchY;
+ }
+ }
+ }
+ }
+ },
+ menuShow: function($sub) {
+ if (!$sub.dataSM('beforefirstshowfired')) {
+ $sub.dataSM('beforefirstshowfired', true);
+ if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
+ return;
+ }
+ }
+ if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
+ return;
+ }
+ $sub.dataSM('shown-before', true)
+ .stop(true, true);
+ if (!$sub.is(':visible')) {
+ // highlight parent item
+ var $a = $sub.dataSM('parent-a');
+ if (this.opts.keepHighlighted || this.isCollapsible()) {
+ $a.addClass('highlighted');
+ }
+ if (this.isCollapsible()) {
+ $sub.removeClass('sm-nowrap').css({ zIndex: '', width: 'auto', minWidth: '', maxWidth: '', top: '', left: '', marginLeft: '', marginTop: '' });
+ } else {
+ // set z-index
+ $sub.css('z-index', this.zIndexInc = (this.zIndexInc || this.getStartZIndex()) + 1);
+ // min/max-width fix - no way to rely purely on CSS as all UL's are nested
+ if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
+ $sub.css({ width: 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
+ if (this.opts.subMenusMinWidth) {
+ $sub.css('min-width', this.opts.subMenusMinWidth);
+ }
+ if (this.opts.subMenusMaxWidth) {
+ var noMaxWidth = this.getWidth($sub);
+ $sub.css('max-width', this.opts.subMenusMaxWidth);
+ if (noMaxWidth > this.getWidth($sub)) {
+ $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
+ }
+ }
+ }
+ this.menuPosition($sub);
+ // insert IE iframe shim
+ if ($sub.dataSM('ie-shim')) {
+ $sub.dataSM('ie-shim').insertBefore($sub);
+ }
+ }
+ var complete = function() {
+ // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
+ $sub.css('overflow', '');
+ };
+ // if sub is collapsible (mobile view)
+ if (this.isCollapsible()) {
+ if (this.opts.collapsibleShowFunction) {
+ this.opts.collapsibleShowFunction.call(this, $sub, complete);
+ } else {
+ $sub.show(this.opts.collapsibleShowDuration, complete);
+ }
+ } else {
+ if (this.opts.showFunction) {
+ this.opts.showFunction.call(this, $sub, complete);
+ } else {
+ $sub.show(this.opts.showDuration, complete);
+ }
+ }
+ // accessibility
+ $a.attr('aria-expanded', 'true');
+ $sub.attr({
+ 'aria-expanded': 'true',
+ 'aria-hidden': 'false'
+ });
+ // store sub menu in visible array
+ this.visibleSubMenus.push($sub);
+ this.$root.triggerHandler('show.smapi', $sub[0]);
+ }
+ },
+ popupHide: function(noHideTimeout) {
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ this.hideTimeout = 0;
+ }
+ var self = this;
+ this.hideTimeout = setTimeout(function() {
+ self.menuHideAll();
+ }, noHideTimeout ? 1 : this.opts.hideTimeout);
+ },
+ popupShow: function(left, top) {
+ if (!this.opts.isPopup) {
+ alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
+ return;
+ }
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ this.hideTimeout = 0;
+ }
+ this.$root.dataSM('shown-before', true)
+ .stop(true, true);
+ if (!this.$root.is(':visible')) {
+ this.$root.css({ left: left, top: top });
+ // IE iframe shim
+ this.menuIframeShim(this.$root);
+ if (this.$root.dataSM('ie-shim')) {
+ 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);
+ }
+ // show menu
+ var self = this,
+ complete = function() {
+ self.$root.css('overflow', '');
+ };
+ if (this.opts.showFunction) {
+ this.opts.showFunction.call(this, this.$root, complete);
+ } else {
+ this.$root.show(this.opts.showDuration, complete);
+ }
+ this.visibleSubMenus[0] = this.$root;
+ }
+ },
+ refresh: function() {
+ this.destroy(true);
+ this.init(true);
+ },
+ rootKeyDown: function(e) {
+ if (!this.handleEvents()) {
+ return;
+ }
+ switch (e.keyCode) {
+ case 27: // reset on Esc
+ var $activeTopItem = this.activatedItems[0];
+ if ($activeTopItem) {
+ this.menuHideAll();
+ $activeTopItem[0].focus();
+ var $sub = $activeTopItem.dataSM('sub');
+ if ($sub) {
+ this.menuHide($sub);
+ }
+ }
+ break;
+ case 32: // activate item's sub on Space
+ var $target = $(e.target);
+ if ($target.is('a') && this.handleItemEvents($target)) {
+ var $sub = $target.dataSM('sub');
+ if ($sub && !$sub.is(':visible')) {
+ this.itemClick({ currentTarget: e.target });
+ e.preventDefault();
+ }
+ }
+ break;
+ }
+ },
+ rootOut: function(e) {
+ if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
+ return;
+ }
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ this.hideTimeout = 0;
+ }
+ if (!this.opts.showOnClick || !this.opts.hideOnClick) {
+ var self = this;
+ this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
+ }
+ },
+ rootOver: function(e) {
+ if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
+ return;
+ }
+ if (this.hideTimeout) {
+ clearTimeout(this.hideTimeout);
+ this.hideTimeout = 0;
+ }
+ },
+ winResize: function(e) {
+ if (!this.handleEvents()) {
+ // we still need to resize the disable overlay if it's visible
+ if (this.$disableOverlay) {
+ var pos = this.$root.offset();
+ this.$disableOverlay.css({
+ top: pos.top,
+ left: pos.left,
+ width: this.$root.outerWidth(),
+ height: this.$root.outerHeight()
+ });
+ }
+ return;
+ }
+ // hide sub menus on resize - on mobile do it only on orientation change
+ if (!('onorientationchange' in window) || e.type == 'orientationchange') {
+ var isCollapsible = this.isCollapsible();
+ // if it was collapsible before resize and still is, don't do it
+ if (!(this.wasCollapsible && isCollapsible)) {
+ if (this.activatedItems.length) {
+ this.activatedItems[this.activatedItems.length - 1][0].blur();
+ }
+ this.menuHideAll();
+ }
+ this.wasCollapsible = isCollapsible;
+ }
+ }
+ }
+ });
+
+ $.fn.dataSM = function(key, val) {
+ if (val) {
+ return this.data(key + '_smartmenus', val);
+ }
+ return this.data(key + '_smartmenus');
+ }
+
+ $.fn.removeDataSM = function(key) {
+ return this.removeData(key + '_smartmenus');
+ }
+
+ $.fn.smartmenus = function(options) {
+ if (typeof options == 'string') {
+ var args = arguments,
+ method = options;
+ Array.prototype.shift.call(args);
+ return this.each(function() {
+ var smartmenus = $(this).data('smartmenus');
+ if (smartmenus && smartmenus[method]) {
+ smartmenus[method].apply(smartmenus, args);
+ }
+ });
+ }
+ var opts = $.extend({}, $.fn.smartmenus.defaults, options);
+ return this.each(function() {
+ new $.SmartMenus(this, opts);
+ });
+ }
+
+ // default settings
+ $.fn.smartmenus.defaults = {
+ isPopup: false, // is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
+ mainMenuSubOffsetX: 0, // pixels offset from default position
+ mainMenuSubOffsetY: 0, // pixels offset from default position
+ subMenusSubOffsetX: 0, // pixels offset from default position
+ subMenusSubOffsetY: 0, // pixels offset from default position
+ subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
+ subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
+ subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A
+ subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append')
+ subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
+ scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height
+ scrollAccelerate: true, // accelerate scrolling or use a fixed step
+ showTimeout: 250, // timeout before showing the sub menus
+ hideTimeout: 500, // timeout before hiding the sub menus
+ showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null
+ showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show')
+ // don't forget to call complete() at the end of whatever you do
+ // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
+ hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
+ hideFunction: function($ul, complete) { $ul.fadeOut(200, complete); }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide')
+ // don't forget to call complete() at the end of whatever you do
+ // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
+ collapsibleShowDuration:0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
+ collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); }, // custom function to use when showing a collapsible sub menu
+ // (i.e. when mobile styles are used to make the sub menus collapsible)
+ collapsibleHideDuration:0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
+ collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); }, // custom function to use when hiding a collapsible sub menu
+ // (i.e. when mobile styles are used to make the sub menus collapsible)
+ showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (i.e. mimic desktop app menus) (matters only for mouse input)
+ hideOnClick: true, // hide the sub menus on click/tap anywhere on the page
+ noMouseOver: false, // disable sub menus activation onmouseover (i.e. behave like in touch mode - use just mouse clicks) (matters only for mouse input)
+ keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport
+ keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
+ markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL
+ markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item
+ rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position)
+ bottomToTopSubMenus: false, // bottom to top display of the sub menus
+ overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
+ };
+
+ return $;
+}));
diff --git a/jquery/jquery.ui-0.2.3.touch-punch.js b/jquery/jquery.ui-0.2.3.touch-punch.js
new file mode 100644
index 0000000..16ce41d
--- /dev/null
+++ b/jquery/jquery.ui-0.2.3.touch-punch.js
@@ -0,0 +1,180 @@
+/*!
+ * jQuery UI Touch Punch 0.2.3
+ *
+ * Copyright 2011–2014, Dave Furfero
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ */
+(function ($) {
+
+ // Detect touch support
+ $.support.touch = 'ontouchend' in document;
+
+ // Ignore browsers without touch support
+ if (!$.support.touch) {
+ return;
+ }
+
+ var mouseProto = $.ui.mouse.prototype,
+ _mouseInit = mouseProto._mouseInit,
+ _mouseDestroy = mouseProto._mouseDestroy,
+ touchHandled;
+
+ /**
+ * Simulate a mouse event based on a corresponding touch event
+ * @param {Object} event A touch event
+ * @param {String} simulatedType The corresponding mouse event
+ */
+ function simulateMouseEvent (event, simulatedType) {
+
+ // Ignore multi-touch events
+ if (event.originalEvent.touches.length > 1) {
+ return;
+ }
+
+ event.preventDefault();
+
+ var touch = event.originalEvent.changedTouches[0],
+ simulatedEvent = document.createEvent('MouseEvents');
+
+ // Initialize the simulated mouse event using the touch event's coordinates
+ simulatedEvent.initMouseEvent(
+ simulatedType, // type
+ true, // bubbles
+ true, // cancelable
+ window, // view
+ 1, // detail
+ touch.screenX, // screenX
+ touch.screenY, // screenY
+ touch.clientX, // clientX
+ touch.clientY, // clientY
+ false, // ctrlKey
+ false, // altKey
+ false, // shiftKey
+ false, // metaKey
+ 0, // button
+ null // relatedTarget
+ );
+
+ // Dispatch the simulated event to the target element
+ event.target.dispatchEvent(simulatedEvent);
+ }
+
+ /**
+ * Handle the jQuery UI widget's touchstart events
+ * @param {Object} event The widget element's touchstart event
+ */
+ mouseProto._touchStart = function (event) {
+
+ var self = this;
+
+ // Ignore the event if another widget is already being handled
+ if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
+ return;
+ }
+
+ // Set the flag to prevent other widgets from inheriting the touch event
+ touchHandled = true;
+
+ // Track movement to determine if interaction was a click
+ self._touchMoved = false;
+
+ // Simulate the mouseover event
+ simulateMouseEvent(event, 'mouseover');
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+
+ // Simulate the mousedown event
+ simulateMouseEvent(event, 'mousedown');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchmove events
+ * @param {Object} event The document's touchmove event
+ */
+ mouseProto._touchMove = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Interaction was not a click
+ this._touchMoved = true;
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchend events
+ * @param {Object} event The document's touchend event
+ */
+ mouseProto._touchEnd = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Simulate the mouseup event
+ simulateMouseEvent(event, 'mouseup');
+
+ // Simulate the mouseout event
+ simulateMouseEvent(event, 'mouseout');
+
+ // If the touch interaction did not move, it should trigger a click
+ if (!this._touchMoved) {
+
+ // Simulate the click event
+ simulateMouseEvent(event, 'click');
+ }
+
+ // Unset the flag to allow other widgets to inherit the touch event
+ touchHandled = false;
+ };
+
+ /**
+ * A duck punch of the $.ui.mouse _mouseInit method to support touch events.
+ * This method extends the widget with bound touch event handlers that
+ * translate touch events to mouse events and pass them to the widget's
+ * original mouse event handling methods.
+ */
+ mouseProto._mouseInit = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.bind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse init method
+ _mouseInit.call(self);
+ };
+
+ /**
+ * Remove the touch event handlers
+ */
+ mouseProto._mouseDestroy = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.unbind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse destroy method
+ _mouseDestroy.call(self);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/jquery/sass/_round-corners-last-item.scss b/jquery/sass/_round-corners-last-item.scss
new file mode 100644
index 0000000..70a8391
--- /dev/null
+++ b/jquery/sass/_round-corners-last-item.scss
@@ -0,0 +1,23 @@
+// Generate rules to round the corners of the last collapsible item
+
+@mixin sm-dox__round-corners-last-item($amount, $chainable: 'ul > li:last-child > ', $level: 4, $chain_prefix: '> li:last-child > ', $chain: '', $selector: '') {
+ $chain: $chain_prefix;
+ $selector: $chain + 'a, ' + $chain + '*:not(ul) a, ' + $chain + 'ul';
+ @for $i from 1 through $level {
+ $chain: $chain + $chainable;
+ $selector: $selector + ', ' + $chain + ' a, ' + $chain + '*:not(ul) a, ' + $chain + ' ul';
+ }
+ #{$selector} {
+ @include border-radius(0 0 $amount $amount);
+ }
+ // highlighted items, don't need rounding since their sub is open
+ $chain: $chain_prefix;
+ $selector: $chain + 'a.highlighted, ' + $chain + '*:not(ul) a.highlighted';
+ @for $i from 1 through $level {
+ $chain: $chain + $chainable;
+ $selector: $selector + ', ' + $chain + ' a.highlighted, ' + $chain + '*:not(ul) a.highlighted';
+ }
+ #{$selector} {
+ @include border-radius(0);
+ }
+}
diff --git a/jquery/sass/_sm-dox.scss b/jquery/sass/_sm-dox.scss
new file mode 100644
index 0000000..81a4e74
--- /dev/null
+++ b/jquery/sass/_sm-dox.scss
@@ -0,0 +1,594 @@
+@import 'compass';
+
+// This file is best viewed with Tab size 4 code indentation
+
+
+// -----------------------------------------------------------------------------------------------------------------
+// 1. Theme Quick Settings (Variables)
+// (for further control, you will need to dig into the actual CSS in 2.)
+// -----------------------------------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------
+// :: 1.1. Colors
+// ----------------------------------------------------------
+
+$sm-dox__white: #fff !default;
+$sm-dox__gray: darken($sm-dox__white, 6.5%) !default;
+$sm-dox__gray-dark: darken($sm-dox__white, 26.5%) !default;
+$sm-dox__gray-darker: darken($sm-dox__white, 66.5%) !default;
+$sm-dox__red: #D23600 !default;
+
+$sm-dox__box-shadow: rgba(0, 0, 0, 0.2) !default;
+
+
+// ----------------------------------------------------------
+// :: 1.2. Breakpoints
+// ----------------------------------------------------------
+
+$sm-dox__desktop-vp: 768px !default; // switch from collapsible to desktop
+
+
+// ----------------------------------------------------------
+// :: 1.3. Typography
+// ----------------------------------------------------------
+
+$sm-dox__font-family: "Lucida Grande", "Geneva", "Helvetica", Arial, sans-serif !default;
+$sm-dox__font-size-base: 13px !default;
+$sm-dox__font-size-small: 12px !default;
+$sm-dox__line-height: 15px !default;
+
+
+// ----------------------------------------------------------
+// :: 1.4. Borders
+// ----------------------------------------------------------
+
+$sm-dox__border-width: 1px !default;
+$sm-dox__border-radius: 5px !default;
+
+
+// ----------------------------------------------------------
+// :: 1.5. Collapsible main menu
+// ----------------------------------------------------------
+
+// Menu box
+//$sm-dox__collapsible-bg: $sm-dox__gray !default;
+$sm-dox__collapsible-bg: url('tab_b.png') !default;
+$sm-dox__collapsible-border-radius: $sm-dox__border-radius !default;
+
+// Items
+$sm-dox__collapsible-item-color: $sm-dox__gray-darker !default;
+$sm-dox__collapsible-item-current-color: $sm-dox__red !default;
+$sm-dox__collapsible-item-disabled-color: darken($sm-dox__gray, 20%) !default;
+$sm-dox__collapsible-item-padding-vertical: 0px !default;
+$sm-dox__collapsible-item-padding-horizontal: 12px !default;
+
+// Items separators
+$sm-dox__collapsible-separators-color: rgba(0, 0, 0, 0.05) !default;
+
+// Toggle button (sub menu indicators)
+$sm-dox__collapsible-toggle-bg: rgba(255, 255, 255, 0.5) !default;
+
+
+// ----------------------------------------------------------
+// :: 1.6. Collapsible sub menus
+// ----------------------------------------------------------
+
+// Menu box
+$sm-dox__collapsible-sub-bg: rgba(darken($sm-dox__gray, 30%), 0.1) !default;
+
+// Items text indentation for deeper levels
+$sm-dox__collapsible-sub-item-indentation: 8px !default;
+
+
+// ----------------------------------------------------------
+// :: 1.7. Desktop main menu
+// ----------------------------------------------------------
+
+// Menu box
+//$sm-dox__desktop-bg: $sm-dox__gray !default;
+$sm-dox__desktop-bg: url('tab_b.png') !default;
+//$sm-dox__desktop-border-radius: 100px !default;
+$sm-dox__desktop-padding-horizontal: 10px !default;
+
+// Items
+$sm-dox__desktop-item-color: $sm-dox__gray_darker !default;
+$sm-dox__desktop-item-hover-color: $sm-dox__red !default;
+$sm-dox__desktop-item-current-color: $sm-dox__red !default;
+$sm-dox__desktop-item-disabled-color: darken($sm-dox__gray, 20%) !default;
+$sm-dox__desktop-item-padding-vertical: 0px !default;
+$sm-dox__desktop-item-padding-horizontal: 12px !default;
+
+// Sub menu indicators
+$sm-dox__desktop-arrow-size: 4px !default; // border-width
+$sm-dox__desktop-arrow-color: $sm-dox__gray-darker !default;
+$sm-dox__desktop-arrow-spacing: 4px !default;
+
+// Vertical menu box
+$sm-dox__desktop-vertical-border-radius: $sm-dox__border-radius !default;
+$sm-dox__desktop-vertical-padding-vertical: 10px !default;
+
+// Vertical items
+$sm-dox__desktop-vertical-item-hover-bg: $sm-dox__white !default;
+$sm-dox__desktop-vertical-item-padding-vertical: 10px !default;
+$sm-dox__desktop-vertical-item-padding-horizontal: 20px !default;
+
+$sm-dox__main-text-color: #283A5D !default;
+$sm-dox__main-highlight-color: white !default;
+
+// ----------------------------------------------------------
+// :: 1.8. Desktop sub menus
+// ----------------------------------------------------------
+
+// Menu box
+$sm-dox__desktop-sub-bg: $sm-dox__white !default;
+$sm-dox__desktop-sub-border-color: $sm-dox__gray-dark !default;
+$sm-dox__desktop-sub-border-radius: $sm-dox__border-radius !default;
+$sm-dox__desktop-sub-box-shadow: 0 5px 9px $sm-dox__box-shadow !default;
+$sm-dox__desktop-sub-padding-vertical: 5px !default;
+$sm-dox__desktop-sub-padding-horizontal: 0 !default;
+
+// Items
+$sm-dox__desktop-sub-item-color: $sm-dox__gray_darker !default;
+$sm-dox__desktop-sub-item-hover-color: $sm-dox__red !default;
+$sm-dox__desktop-sub-item-hover-bg: $sm-dox__gray !default;
+$sm-dox__desktop-sub-item-current-color: $sm-dox__red !default;
+$sm-dox__desktop-sub-item-disabled-color: darken($sm-dox__white, 20%) !default;
+$sm-dox__desktop-sub-item-padding-vertical: 10px !default;
+$sm-dox__desktop-sub-item-padding-horizontal: 20px !default;
+
+// Sub menu indicators
+$sm-dox__desktop-sub-arrow-size: 5px !default; // border-width
+
+// Sub menu carets
+$sm-dox__desktop-sub-caret-size: 8px !default; // border-width
+$sm-dox__desktop-sub-caret-left: 30px !default;
+
+$sm-dox__main-row-height: 36px !default;
+
+// -----------------------------------------------------------------------------------------------------------------
+// 2. Theme CSS
+// -----------------------------------------------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------
+// :: 2.1. Collapsible mode (mobile first)
+// ----------------------------------------------------------
+
+// calc item height and sub menus toggle button size
+$sm-dox__item-height: $sm-dox__line-height + $sm-dox__collapsible-item-padding-vertical * 2;
+// set toggle button size to 80% of item height
+$sm-dox__toggle-size: floor($sm-dox__main-row-height * 0.8);
+$sm-dox__toggle-spacing: floor($sm-dox__main-row-height * 0.1);
+
+// Main menu box
+.sm-dox {
+ background-image: $sm-dox__collapsible-bg;
+ //@include border-radius($sm-dox__collapsible-border-radius);
+
+ // Main menu items
+ a {
+ &,
+ &:focus,
+ &:hover,
+ &:active {
+ padding: $sm-dox__collapsible-item-padding-vertical $sm-dox__collapsible-item-padding-horizontal;
+ /* make room for the toggle button (sub indicator) */
+ padding-right: $sm-dox__collapsible-item-padding-horizontal + $sm-dox__toggle-size + $sm-dox__toggle-spacing;
+ /* color: $sm-dox__collapsible-item-color; */
+ font-family: $sm-dox__font-family;
+ font-size: $sm-dox__font-size-base;
+ font-weight: bold;
+ line-height: 36px; //$sm-dox__line-height;
+ text-decoration: none;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ color: $sm-dox__main-text-color;
+ outline: none;
+ }
+
+ &:hover {
+ background-image: url('tab_a.png');
+ background-repeat:repeat-x;
+ color: $sm-dox__main-highlight-color;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ }
+
+ &.current {
+ color: $sm-dox__collapsible-item-current-color;
+ }
+
+ &.disabled {
+ color: $sm-dox__collapsible-item-disabled-color;
+ }
+
+ // Toggle buttons (sub menu indicators)
+ span.sub-arrow {
+ position: absolute;
+ top: 50%;
+ margin-top: -(ceil($sm-dox__toggle-size / 2));
+ left: auto;
+ right: $sm-dox__toggle-spacing;
+ width: $sm-dox__toggle-size;
+ height: $sm-dox__toggle-size;
+ overflow: hidden;
+ font: bold #{$sm-dox__font-size-small}/#{$sm-dox__toggle-size} monospace !important;
+ text-align: center;
+ text-shadow: none;
+ background: $sm-dox__collapsible-toggle-bg;
+ @include border-radius($sm-dox__border-radius);
+ }
+ // Change + to - on sub menu expand
+ &.highlighted span.sub-arrow:before {
+ display: block;
+ content: '-';
+ }
+ }
+
+ // round the corners of the first item
+ > li:first-child > a, > li:first-child > :not(ul) a {
+ @include border-radius($sm-dox__collapsible-border-radius $sm-dox__collapsible-border-radius 0 0);
+ }
+ // round the corners of the last item
+ @include sm-dox__round-corners-last-item($sm-dox__collapsible-border-radius);
+
+ // Main menu items separators
+ //li {
+ // /*border-top: 1px solid $sm-dox__collapsible-separators-color;*/
+ // border-top: 0;
+ //}
+ //> li:first-child {
+ // border-top: 0;
+ //}
+
+ // Sub menus box
+ ul {
+ background: $sm-dox__collapsible-sub-bg;
+
+ // Sub menus items
+ a {
+ &,
+ &:focus,
+ &:hover,
+ &:active {
+ font-size: $sm-dox__font-size-small;
+ // add indentation for sub menus text
+ border-left: $sm-dox__collapsible-sub-item-indentation solid transparent;
+ //line-height: $sm-dox__line-height;
+ line-height: $sm-dox__main-row-height;
+ text-shadow: none;
+ background-color: white;
+ background-image: none;
+ }
+
+ &:hover {
+ // color: $sm-dox__collapsible-item-current-color;
+ // background-color: $sm-dox__gray;
+ background-image: url('tab_a.png');
+ background-repeat:repeat-x;
+ color: $sm-dox__main-highlight-color;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ }
+
+ }
+
+ // Add indentation for sub menus text for deeper levels
+ @include sm-dox__sub-items-indentation($sm-dox__collapsible-sub-item-indentation);
+ }
+}
+
+
+// ----------------------------------------------------------
+// :: 2.2. Desktop mode
+// ----------------------------------------------------------
+
+@media (min-width: $sm-dox__desktop-vp) {
+
+ /* Switch to desktop layout
+ -----------------------------------------------
+ These transform the menu tree from
+ collapsible to desktop (navbar + dropdowns)
+ -----------------------------------------------*/
+ /* start... (it's not recommended editing these rules) */
+ .sm-dox ul{position:absolute;width:12em;}
+ .sm-dox li{float:left;}
+ .sm-dox.sm-rtl li{float:right;}
+ .sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none;}
+ .sm-dox a{white-space:nowrap;}
+ .sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal;}
+ .sm-dox .sm-nowrap > li > a,.sm-dox .sm-nowrap > li > :not(ul) a{white-space:nowrap;}
+ /* ...end */
+
+ // Main menu box
+ .sm-dox {
+ padding: 0 $sm-dox__desktop-padding-horizontal;
+ background-image: $sm-dox__desktop-bg;
+ line-height: 36px;
+ //@include border-radius($sm-dox__desktop-border-radius);
+
+ // Main menu items
+ a {
+ // Sub menu indicators
+ span.sub-arrow {
+ top: 50%;
+ margin-top: -(ceil($sm-dox__desktop-arrow-size / 2));
+ right: $sm-dox__desktop-item-padding-horizontal;
+ width: 0;
+ height: 0;
+ border-width: $sm-dox__desktop-arrow-size;
+ border-style: solid dashed dashed dashed;
+ border-color: $sm-dox__main-text-color transparent transparent transparent;
+ background: transparent;
+ @include border-radius(0);
+ }
+
+ &,
+ &:focus,
+ &:active,
+ &:hover,
+ &.highlighted {
+ padding: $sm-dox__desktop-item-padding-vertical $sm-dox__desktop-item-padding-horizontal;
+ /*color: $sm-dox__desktop-item-color;*/
+ background-image:url('tab_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ @include border-radius(0 !important);
+ }
+ &:hover {
+ background-image: url('tab_a.png');
+ background-repeat:repeat-x;
+ color: $sm-dox__main-highlight-color;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ span.sub-arrow {
+ border-color: $sm-dox__main-highlight-color transparent transparent transparent;
+ }
+ }
+
+ // Make room for the sub arrows
+ &.has-submenu {
+ padding-right: $sm-dox__desktop-item-padding-horizontal + $sm-dox__desktop-arrow-size * 2 + $sm-dox__desktop-arrow-spacing;
+ }
+ }
+
+ // No main menu items separators
+ li {
+ border-top: 0;
+ }
+
+ // First sub level carets
+ > li > ul:before,
+ > li > ul:after {
+ content: '';
+ position: absolute;
+ top: -($sm-dox__desktop-sub-caret-size * 2 + $sm-dox__border-width * 2);
+ left: $sm-dox__desktop-sub-caret-left;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ border-width: ($sm-dox__desktop-sub-caret-size + $sm-dox__border-width);
+ border-style: dashed dashed solid dashed;
+ border-color: transparent transparent $sm-dox__gray-dark transparent;
+ }
+ > li > ul:after {
+ top: -($sm-dox__desktop-sub-caret-size * 2);
+ left: ($sm-dox__desktop-sub-caret-left + $sm-dox__border-width);
+ border-width: $sm-dox__desktop-sub-caret-size;
+ border-color: transparent transparent $sm-dox__desktop-sub-bg transparent;
+ }
+
+ // Sub menus box
+ ul {
+ border: $sm-dox__border-width solid $sm-dox__gray-dark;
+ padding: $sm-dox__desktop-sub-padding-vertical $sm-dox__desktop-sub-padding-horizontal;
+ background: $sm-dox__desktop-sub-bg;
+ @include border-radius($sm-dox__desktop-sub-border-radius !important);
+ @include box-shadow($sm-dox__desktop-sub-box-shadow);
+
+ // Sub menus items
+ a {
+ span.sub-arrow {
+ right: 8px;
+ top: 50%;
+ margin-top: -$sm-dox__desktop-sub-arrow-size;
+ border-width: $sm-dox__desktop-sub-arrow-size;
+ border-color: transparent transparent transparent $sm-dox__desktop-sub-item-color;
+ border-style: dashed dashed dashed solid;
+ }
+
+ &,
+ &:hover,
+ &:focus,
+ &:active,
+ &.highlighted {
+ color: $sm-dox__desktop-sub-item-color;
+ background-image:none;
+ border: 0 !important;
+ color: $sm-dox__desktop-sub-item-color;
+ background-image:none;
+ }
+
+ &:hover {
+ background-image: url('tab_a.png');
+ background-repeat:repeat-x;
+ color: $sm-dox__main-highlight-color;
+ text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
+ span.sub-arrow {
+ border-color: transparent transparent transparent $sm-dox__main-highlight-color;
+ }
+ }
+ }
+ }
+
+ // Scrolling arrows containers for tall sub menus - test sub menu: "Sub test" -> "more..." in the default download package
+ span.scroll-up,
+ span.scroll-down {
+ position: absolute;
+ display: none;
+ visibility: hidden;
+ overflow: hidden;
+ background: $sm-dox__desktop-sub-bg;
+ height: 36px;
+ // width and position will be set automatically by the script
+
+ &:hover {
+ background: $sm-dox__desktop-sub-item-hover-bg;
+ }
+ }
+ span.scroll-up:hover span.scroll-up-arrow {
+ border-color: transparent transparent $sm-dox__desktop-sub-item-hover-color transparent;
+ }
+ span.scroll-down:hover span.scroll-down-arrow {
+ border-color: $sm-dox__desktop-sub-item-hover-color transparent transparent transparent;
+ }
+ span.scroll-up-arrow {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ margin-left: -6px;
+ // we will use one-side border to create a triangle so that we don't use a real background image, of course, you can use a real image if you like too
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ border-width: 6px; // tweak size of the arrow
+ border-style: dashed dashed solid dashed;
+ border-color: transparent transparent $sm-dox__desktop-sub-item-color transparent;
+ }
+ span.scroll-down-arrow {
+ @extend span.scroll-up-arrow;
+ top: 8px;
+ border-style: solid dashed dashed dashed;
+ border-color: $sm-dox__desktop-sub-item-color transparent transparent transparent;
+ }
+
+
+ // Rigth-to-left
+
+ // Main menu box
+ &.sm-rtl {
+
+ // Main menu items
+ a {
+
+ // Make room for the sub arrows
+ &.has-submenu {
+ padding-right: $sm-dox__desktop-item-padding-horizontal;
+ padding-left: $sm-dox__desktop-item-padding-horizontal + $sm-dox__desktop-arrow-size * 2 + $sm-dox__desktop-arrow-spacing;
+ }
+
+ // Sub menu indicators
+ span.sub-arrow {
+ right: auto;
+ left: $sm-dox__desktop-item-padding-horizontal;
+ }
+ }
+
+ // Vertical main menu items
+ &.sm-vertical {
+ a {
+
+ // No need for additional room for the sub arrows
+ &.has-submenu {
+ padding: $sm-dox__desktop-vertical-item-padding-vertical $sm-dox__desktop-vertical-item-padding-horizontal;
+ }
+
+ // Sub menu indicators
+ span.sub-arrow {
+ right: auto;
+ left: 8px;
+ border-style: dashed solid dashed dashed;
+ border-color: transparent $sm-dox__desktop-arrow-color transparent transparent;
+ }
+ }
+ }
+
+ // First sub level carets
+ > li > ul:before {
+ left: auto;
+ right: $sm-dox__desktop-sub-caret-left;
+ }
+ > li > ul:after {
+ left: auto;
+ right: ($sm-dox__desktop-sub-caret-left + $sm-dox__border-width);
+ }
+
+ // Sub menus box
+ ul {
+ a {
+
+ // No need for additional room for the sub arrows
+ &.has-submenu {
+ padding: $sm-dox__desktop-sub-item-padding-vertical $sm-dox__desktop-sub-item-padding-horizontal !important;
+ }
+
+ // Sub menu indicators
+ span.sub-arrow {
+ right: auto;
+ left: 8px;
+ border-style: dashed solid dashed dashed;
+ border-color: transparent $sm-dox__desktop-arrow-color transparent transparent;
+ }
+ }
+ }
+ }
+
+
+ // Vertical main menu
+
+ // Main menu box
+ &.sm-vertical {
+ padding: $sm-dox__desktop-vertical-padding-vertical 0;
+ @include border-radius($sm-dox__desktop-vertical-border-radius);
+
+ // Main menu items
+ a {
+ padding: $sm-dox__desktop-vertical-item-padding-vertical $sm-dox__desktop-vertical-item-padding-horizontal;
+
+ &:hover,
+ &:focus,
+ &:active,
+ &.highlighted {
+ background: $sm-dox__desktop-vertical-item-hover-bg;
+ }
+
+ &.disabled {
+ background-image: $sm-dox__desktop-bg;
+ }
+
+ // Sub menu indicators
+ span.sub-arrow {
+ right: 8px;
+ top: 50%;
+ margin-top: -$sm-dox__desktop-sub-arrow-size;
+ border-width: $sm-dox__desktop-sub-arrow-size;
+ border-style: dashed dashed dashed solid;
+ border-color: transparent transparent transparent $sm-dox__desktop-arrow-color;
+ }
+ }
+
+ // No sub level carets
+ > li > ul:before,
+ > li > ul:after {
+ display: none;
+ }
+
+ // Sub menus box
+ ul {
+
+ // Sub menus items
+ a {
+ padding: $sm-dox__desktop-sub-item-padding-vertical $sm-dox__desktop-sub-item-padding-horizontal;
+
+ &:hover,
+ &:focus,
+ &:active,
+ &.highlighted {
+ background: $sm-dox__desktop-sub-item-hover-bg;
+ }
+
+ &.disabled {
+ background: $sm-dox__desktop-sub-bg;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/jquery/sass/_sub-items-indentation.scss b/jquery/sass/_sub-items-indentation.scss
new file mode 100644
index 0000000..5e43999
--- /dev/null
+++ b/jquery/sass/_sub-items-indentation.scss
@@ -0,0 +1,15 @@
+// Generate rules to indent sub menus text
+//
+// We'll use left border to avoid messing with the padding.
+
+@mixin sm-dox__sub-items-indentation($amount, $chainable: 'ul ', $level: 4, $chain: '') {
+ @for $i from 1 through $level {
+ $chain: $chain + $chainable;
+ #{$chain} a,
+ #{$chain} a:hover,
+ #{$chain} a:focus,
+ #{$chain} a:active {
+ border-left: ($amount * ($i + 1)) solid transparent;
+ }
+ }
+}
diff --git a/jquery/sass/sm-dox.scss b/jquery/sass/sm-dox.scss
new file mode 100644
index 0000000..19fb444
--- /dev/null
+++ b/jquery/sass/sm-dox.scss
@@ -0,0 +1,5 @@
+@import '_sub-items-indentation.scss';
+@import '_round-corners-last-item.scss';
+
+// the variables + the CSS
+@import '_sm-dox.scss';
diff --git a/jquery/sm-core-css.css b/jquery/sm-core-css.css
new file mode 100644
index 0000000..c586599
--- /dev/null
+++ b/jquery/sm-core-css.css
@@ -0,0 +1,10 @@
+.sm{position:relative;z-index:9999;}
+.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0);}
+.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right;}
+.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0;}
+.sm ul{display:none;}
+.sm li,.sm a{position:relative;}
+.sm a{display:block;}
+.sm a.disabled{cursor:not-allowed;}
+.sm:after{content:"\00a0";display:block;height:0;font:0px/0 serif;clear:both;visibility:hidden;overflow:hidden;}
+.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}