diff options
Diffstat (limited to 'jquery')
-rw-r--r-- | jquery/.gitignore | 4 | ||||
-rw-r--r-- | jquery/Makefile | 25 | ||||
-rw-r--r-- | jquery/README | 8 | ||||
-rw-r--r-- | jquery/jquery.smartmenus-1.0.0.js | 1214 | ||||
-rw-r--r-- | jquery/jquery.ui-0.2.3.touch-punch.js | 180 | ||||
-rw-r--r-- | jquery/sass/_round-corners-last-item.scss | 23 | ||||
-rw-r--r-- | jquery/sass/_sm-dox.scss | 594 | ||||
-rw-r--r-- | jquery/sass/_sub-items-indentation.scss | 15 | ||||
-rw-r--r-- | jquery/sass/sm-dox.scss | 5 | ||||
-rw-r--r-- | jquery/sm-core-css.css | 10 |
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;} |