UNPKG

@clayui/css

Version:

Liferay's web implementation of the Lexicon Design Language

1,090 lines (801 loc) 26.1 kB
/** * Clay 3.12.0 * * Copyright 2020, Liferay, Inc. * All rights reserved. * MIT license */ +function($) { var doc = $(document); var listenerAdded = false; // Make sure we only add one resize listener to the page, // no matter how many components we have var addResizeListener = function() { if (!listenerAdded) { $(window).on( 'resize', debounce( function(event) { doc.trigger('screenChange.lexicon.sidenav'); }, 150 ) ); listenerAdded = true; } }; var debounce = function(fn, delay) { var id; return function() { var instance = this; var args = arguments; var later = function() { id = null; fn.apply(instance, args); }; clearTimeout(id); id = setTimeout(later, delay); }; }; var getBreakpointRegion = function() { var screenXs = 480; var screenSm = 768; var screenMd = 992; var screenLg = 1200; var windowWidth = window.innerWidth; var region = ''; if (windowWidth >= screenLg) { region = 'lg'; } else if (windowWidth >= screenMd) { region = 'md'; } else if (windowWidth >= screenSm) { region = 'sm'; } else if (windowWidth >= screenXs) { region = 'xs'; } else { region = 'xxs'; } return region; }; var guid = (function() { var counter = 0; return function(toggler, ns) { var strId = toggler.attr('id'); if (!strId) { strId = (ns + counter++); toggler.attr('id', strId); } return strId; }; }()); var toInt = function(str) { return parseInt(str, 10) || 0; }; var SideNavigation = function(toggler, options) { this.init(toggler, options); }; SideNavigation.TRANSITION_DURATION = 500; SideNavigation.prototype = { init: function(toggler, options) { var instance = this; var useDataAttribute = toggler.data('toggle') === 'sidenav'; options = $.extend({}, $.fn.sideNavigation.defaults, options); options.breakpoint = toInt(options.breakpoint); options.container = options.container || toggler.data('target') || toggler.attr('href'); options.gutter = toInt(options.gutter); options.heightType = options.heightType || (options.equalHeight ? 'equalHeight' : false); options.rtl = doc.attr('dir') === 'rtl'; options.width = toInt(options.width); options.widthOriginal = options.width; // instantiate using data attribute if (useDataAttribute) { options.closedClass = toggler.data('closed-class') || 'closed'; options.content = toggler.data('content'); options.equalHeight = false; // equalHeight option is deprecated options.loadingIndicatorTPL = toggler.data('loading-indicator-tpl') || options.loadingIndicatorTPL; options.openClass = toggler.data('open-class') || 'open'; options.toggler = toggler; options.type = toggler.data('type'); options.typeMobile = toggler.data('type-mobile'); options.url = toggler.data('url'); options.useDelegate = toggler.data('use-delegate'); options.width = ''; if (options.useDelegate === undefined) { options.useDelegate = true; } } instance.toggler = toggler; instance.options = options; instance.useDataAttribute = useDataAttribute; instance._bindUI(); instance._renderUI(); }, clearStyle: function(attribute) { var instance = this; var options = instance.options; var container = $(options.container); var content = container.find(options.content).first(); var navigation = container.find(options.navigation).first(); var menu = container.find('.sidenav-menu').first(); var els = content.add(navigation).add(menu); if (Array.isArray(attribute)) { for (var i = 0; i < attribute.length; i++) { els.css(attribute[i], ''); } } else { els.css(attribute, ''); } }, destroy: function() { var instance = this; var options = instance.options; var container = $(instance.options.container); // Detach sidenav close doc.off('click.close.lexicon.sidenav', instance.closeButtonSelector); doc.data(instance.dataCloseButtonSelector, null); // Detach toggler if (options.useDelegate) { doc.off('click.lexicon.sidenav', instance.togglerSelector); doc.data(instance.dataTogglerSelector, null); } else { container.off('click.lexicon.sidenav'); } // Remove Side Navigation container.data('lexicon.sidenav', null); }, hide: function() { var instance = this; if (instance.useDataAttribute) { instance.hideSimpleSidenav(); } else { instance.toggleNavigation(false); } }, hideSidenav: function() { var instance = this; var options = instance.options; var container = $(options.container); var content = container.find(options.content).first(); var navigation = container.find(options.navigation).first(); var menu = navigation.find('.sidenav-menu').first(); var sidenavRight = instance._isSidenavRight(); var positionDirection = options.rtl ? 'right' : 'left'; if (sidenavRight) { positionDirection = options.rtl ? 'left' : 'right'; } var paddingDirection = 'padding-' + positionDirection; content.css(paddingDirection, '').css(positionDirection, ''); navigation.css('width', ''); if (sidenavRight) { menu.css(positionDirection, instance._getSidenavWidth()); } }, hideSimpleSidenav: function() { var instance = this; var options = instance.options; var simpleSidenavClosed = instance._isSimpleSidenavClosed(); if (!simpleSidenavClosed) { var content = $(options.content).first(); var sidenav = $(options.container); var closedClass = options.closedClass; var openClass = options.openClass; var toggler = instance.toggler; var target = toggler.attr('href') || toggler.attr('data-target'); sidenav.trigger({ toggler: $(instance.togglerSelector), type: 'closedStart.lexicon.sidenav' }); instance._onSidenavTransitionEnd(content, function() { sidenav.removeClass('sidenav-transition'); toggler.removeClass('sidenav-transition'); sidenav.trigger({ toggler: $(instance.togglerSelector), type: 'closed.lexicon.sidenav' }); }); if (content.hasClass(openClass)) { content.addClass('sidenav-transition').addClass(closedClass).removeClass(openClass); } sidenav.addClass('sidenav-transition'); toggler.addClass('sidenav-transition'); sidenav.addClass(closedClass).removeClass(openClass); $('[data-target="' + target + '"]').removeClass(openClass).removeClass('active'); $('[href="' + target + '"]').removeClass(openClass).removeClass('active'); } }, setEqualHeight: function() { var instance = this; var options = instance.options; var container = $(options.container); var content = options.content; var navigation = options.navigation; var type = instance.mobile ? options.typeMobile : options.type; if (type !== 'fixed' && type !== 'fixed-push') { var contentNode = container.find(content).first(); var navNode = container.find(navigation).first(); var sideNavMenuNode = container.find('.sidenav-menu').first(); var tallest = Math.max(contentNode.outerHeight(), navNode.outerHeight()); contentNode.css('min-height', tallest); navNode.css({ 'min-height': tallest, 'height': '100%' }); sideNavMenuNode.css({ 'min-height': tallest, 'height': '100%' }); } }, setFullHeight: function() { var instance = this; var options = instance.options; var container = $(options.container); var navigation = options.navigation; var type = instance.mobile ? options.typeMobile : options.type; if (type === 'relative') { var navNode = container.find(navigation).first(); var sidenavMenuNode = container.find('.sidenav-menu').first(); var minHeight = doc.innerHeight() - navNode.offset().top; if (sidenavMenuNode.innerHeight() + navNode.offset().top > doc.innerHeight()) { minHeight = sidenavMenuNode.innerHeight(); } navNode.css({ 'min-height': minHeight, 'height': '100%' }); sidenavMenuNode.css({ 'min-height': minHeight, 'height': '100%' }); } }, setHeight: function() { var instance = this; var options = instance.options; if (options.heightType === 'equalHeight') { instance.setEqualHeight(); } else if (options.heightType === 'fullHeight') { instance.setFullHeight(); } }, show: function() { var instance = this; if (instance.useDataAttribute) { instance.showSimpleSidenav(); } else { instance.toggleNavigation(true); } }, showSidenav: function() { var instance = this; var mobile = instance.mobile; var options = instance.options; var container = $(options.container); var content = container.find(options.content).first(); var navigation = container.find(options.navigation).first(); var menu = navigation.find('.sidenav-menu').first(); var sidenavRight = instance._isSidenavRight(); var width = instance._getSidenavWidth(); var offset = width + options.gutter; var url = options.url; if (url) { container.one( 'urlLoaded.lexicon.sidenav', function(event) { instance.setHeight(); } ); instance._loadUrl(menu, url, container); } navigation.css('width', width); menu.css('width', width); var positionDirection = options.rtl ? 'right' : 'left'; if (sidenavRight) { positionDirection = options.rtl ? 'left' : 'right'; } var paddingDirection = 'padding-' + positionDirection; var pushContentCssProperty = mobile ? positionDirection : paddingDirection; var type = mobile ? options.typeMobile : options.type; if (type !== 'fixed') { var navigationStartX = container.hasClass('open') ? navigation.offset().left - options.gutter : navigation.offset().left - offset; var contentStartX = content.offset().left; var contentWidth = content.innerWidth(); var padding = ''; if ((options.rtl && sidenavRight) || (!options.rtl && options.position === 'left')) { navigationStartX = navigation.offset().left + offset; if (navigationStartX > contentStartX) { padding = navigationStartX - contentStartX; } } else if ((options.rtl && options.position === 'left') || (!options.rtl && sidenavRight)) { if (navigationStartX < contentStartX + contentWidth) { padding = (contentStartX + contentWidth) - navigationStartX; if (padding >= offset) { padding = offset; } } } content.css(pushContentCssProperty, padding); } }, showSimpleSidenav: function() { var instance = this; var options = instance.options; var simpleSidenavClosed = instance._isSimpleSidenavClosed(); if (simpleSidenavClosed) { var content = $(options.content).first(); var sidenav = $(options.container); var closedClass = options.closedClass; var openClass = options.openClass; var toggler = options.toggler; var url = toggler.data('url'); if (url) { instance._loadUrl(sidenav, url); } sidenav.trigger({ toggler: $(instance.togglerSelector), type: 'openStart.lexicon.sidenav' }); instance._onSidenavTransitionEnd(content, function() { sidenav.removeClass('sidenav-transition'); toggler.removeClass('sidenav-transition'); sidenav.trigger({ toggler: $(instance.togglerSelector), type: 'open.lexicon.sidenav' }); }); content.addClass('sidenav-transition').addClass(openClass).removeClass(closedClass); sidenav.addClass('sidenav-transition'); toggler.addClass('sidenav-transition'); sidenav.addClass(openClass).removeClass(closedClass); toggler.addClass('active').addClass(openClass); } }, toggle: function() { var instance = this; if (instance.useDataAttribute) { instance.toggleSimpleSidenav(); } else { instance.toggleNavigation(); } }, toggleNavigation: function(force) { var instance = this; var options = instance.options; var container = $(options.container); var menu = container.find('.sidenav-menu').first(); var toggler = instance.toggler; var width = options.width; var closed = $.type(force) === 'boolean' ? force : container.hasClass('closed'); var sidenavRight = instance._isSidenavRight(); var widthMethod = closed ? 'showSidenav' : 'hideSidenav'; if (closed) { container.trigger({ toggler: toggler, type: 'openStart.lexicon.sidenav' }); } else { container.trigger({ toggler: toggler, type: 'closedStart.lexicon.sidenav' }); } instance._onSidenavTransitionEnd(container, function() { var menu = container.find('.sidenav-menu').first(); if (container.hasClass('closed')) { instance.clearStyle(['min-height', 'height']); toggler.removeClass('open').removeClass('sidenav-transition'); container.trigger({ toggler: toggler, type: 'closed.lexicon.sidenav' }); } else { toggler.addClass('open').removeClass('sidenav-transition'); container.trigger({ toggler: toggler, type: 'open.lexicon.sidenav' }); } if (instance.mobile) { instance._focusElement(menu); } }); if (closed) { instance.setHeight(); menu.css('width', width); var positionDirection = options.rtl ? 'left' : 'right'; if (sidenavRight) { menu.css(positionDirection, ''); } } container.addClass('sidenav-transition'); toggler.addClass('sidenav-transition'); instance[widthMethod](container); container.toggleClass('closed', !closed).toggleClass('open', closed); toggler.toggleClass('active', closed).toggleClass('open', closed); }, toggleSimpleSidenav: function() { var instance = this; var simpleSidenavClosed = instance._isSimpleSidenavClosed(); if (simpleSidenavClosed) { instance.showSimpleSidenav(); } else { instance.hideSimpleSidenav(); } }, visible: function() { var instance = this; var closed; if (instance.useDataAttribute) { closed = instance._isSimpleSidenavClosed(); } else { var container = $(instance.options.container); closed = container.hasClass('sidenav-transition') ? !container.hasClass('closed') : container.hasClass('closed'); } return !closed; }, _bindUI: function() { var instance = this; if (!instance.useDataAttribute) { addResizeListener(); instance._onScreenChange(); } if (instance.options.useDelegate) { instance._onDelegateClickTrigger(); } else { instance._onClickTrigger(); } instance._onClickSidenavClose(); }, _focusElement: function(el) { // ios 8 fixed element disappears when trying to scroll el.focus(); }, _getSidenavWidth: function() { var instance = this; var options = instance.options; var widthOriginal = options.widthOriginal; var width = widthOriginal; var winWidth = window.innerWidth; if (winWidth < widthOriginal + 40) { width = winWidth - 40; } return width; }, _getSimpleSidenavType: function() { var instance = this; var options = instance.options; var desktop = instance._isDesktop(); var type = options.type; var typeMobile = options.typeMobile; if (desktop && (type === 'fixed-push')) { return 'desktop-fixed-push'; } else if (!desktop && (typeMobile === 'fixed-push')) { return 'mobile-fixed-push'; } return 'fixed'; }, _isDesktop: function() { return window.innerWidth >= this.options.breakpoint; }, _isSidenavRight: function() { var instance = this; var options = instance.options; var container = $(options.container); var isSidenavRight = container.hasClass('sidenav-right'); return isSidenavRight; }, _isSimpleSidenavClosed: function() { var instance = this; var options = instance.options; var openClass = options.openClass; var container = $(options.container); return !container.hasClass(openClass); }, _loadUrl: function(sidenav, url, eventTarget) { var instance = this; var urlLoaded = sidenav.data('url-loaded'); var readyState = urlLoaded ? urlLoaded.readyState : 0; eventTarget = eventTarget || sidenav; var sidebarBody = sidenav.find('.sidebar-body').first(); if (!readyState && sidebarBody.length && (typeof url === 'string' || $.isPlainObject(url))) { sidebarBody.append('<div class="sidenav-loading">' + instance.options.loadingIndicatorTPL + '</div>'); urlLoaded = $.ajax(url).done( function(response) { sidebarBody.append(response); eventTarget.trigger('urlLoaded.lexicon.sidenav'); sidebarBody.find('.sidenav-loading').remove(); } ); sidenav.data('url-loaded', urlLoaded); } return urlLoaded; }, _onClickSidenavClose: function() { var instance = this; var options = instance.options; var container = $(options.container); var containerSelector = options.container; var closeButton = $(containerSelector).find('.sidenav-close').first(); var closeButtonSelector = '#' + guid(closeButton, 'generatedLexiconSidenavCloseId'); var dataCloseButtonSelector = 'lexicon.' + closeButtonSelector; if (!doc.data(dataCloseButtonSelector)) { doc.data(dataCloseButtonSelector, 'true'); doc.on('click.close.lexicon.sidenav', closeButtonSelector, function(event) { event.preventDefault(); instance.toggle(); }); } instance.closeButtonSelector = closeButtonSelector; instance.dataCloseButtonSelector = dataCloseButtonSelector; }, _onClickTrigger: function() { var instance = this; var el = instance.toggler; el.on( 'click.lexicon.sidenav', function(event) { instance.toggle(); } ); }, _onDelegateClickTrigger: function() { var instance = this; var toggler = instance.toggler; var togglerSelector = '#' + guid(toggler, 'generatedLexiconSidenavTogglerId'); var dataTogglerSelector = 'lexicon.' + togglerSelector; if (!doc.data(dataTogglerSelector)) { doc.data(dataTogglerSelector, 'true'); doc.on( 'click.lexicon.sidenav', togglerSelector, function(event) { instance.toggle(); event.preventDefault(); } ); } instance.togglerSelector = togglerSelector; instance.dataTogglerSelector = dataTogglerSelector; }, _onScreenChange: function() { var instance = this; var options = instance.options; var container = $(options.container); var toggler = instance.toggler; var screenStartDesktop = instance._setScreenSize(); doc.on('screenChange.lexicon.sidenav', function(event) { var desktop = instance._setScreenSize(); var sidenavRight = instance._isSidenavRight(); var type = desktop ? options.type : options.typeMobile; var fixedMenu = type === 'fixed' || type === 'fixed-push'; var menu = container.find('.sidenav-menu').first(); var navigation = container.find(options.navigation).first(); var menuWidth; var originalMenuWidth = options.widthOriginal; var positionDirection = options.rtl ? 'left' : 'right'; container.toggleClass('sidenav-fixed', fixedMenu); if ((!desktop && screenStartDesktop) || (desktop && !screenStartDesktop)) { instance.hideSidenav(); instance.clearStyle([ 'min-height', 'height' ]); container.addClass('closed').removeClass('open'); toggler.removeClass('active').removeClass('open'); screenStartDesktop = false; if (desktop) { if (sidenavRight) { menu.css(positionDirection, originalMenuWidth).css('width', originalMenuWidth); } screenStartDesktop = true; } } var closed = container.hasClass('closed'); if (!desktop) { menuWidth = originalMenuWidth; if (window.innerWidth <= originalMenuWidth) { menuWidth = window.innerWidth - options.gutter - 25; } if (sidenavRight) { if (closed) { menu.css(positionDirection, menuWidth); } menu.css('width', menuWidth); } screenStartDesktop = false; } if (!closed) { instance.clearStyle([ 'min-height', 'height' ]); instance.showSidenav(); instance.setHeight(); } }); }, _onSidenavTransitionEnd: function(el, fn) { var instance = this; var transitionEnd = 'bsTransitionEnd'; var complete = function() { el.removeClass('sidenav-transition'); if (fn) { fn(); } }; if (!bootstrap.Util.supportsTransitionEnd()) { complete.call(instance); } else { el.one(transitionEnd, function(event) { complete(); }) .emulateTransitionEnd(SideNavigation.TRANSITION_DURATION); } }, _renderNav: function() { var instance = this; var options = instance.options; var container = $(options.container); var slider = container.find(options.navigation).first(); var menu = slider.find('.sidenav-menu').first(); var closed = container.hasClass('closed'); var sidenavRight = instance._isSidenavRight(); var width = instance._getSidenavWidth(); if (closed) { menu.css('width', width); if (sidenavRight) { var positionDirection = options.rtl ? 'left' : 'right'; menu.css(positionDirection, width); } } else { instance.showSidenav(); instance.setHeight(); } container.removeClass('sidenav-js-fouc'); }, _renderUI: function() { var instance = this; var options = instance.options; var container = $(options.container); var toggler = instance.toggler; var mobile = instance.mobile; var type = mobile ? options.typeMobile : options.type; if (!instance.useDataAttribute) { if (mobile) { container.addClass('closed').removeClass('open'); toggler.removeClass('active').removeClass('open'); } if (options.position === 'right') { container.addClass('sidenav-right'); } if (type !== 'relative') { container.addClass('sidenav-fixed'); } instance._renderNav(); } container.css('display', ''); // Force Reflow for IE11 Browser Bug }, _setScreenSize: function() { var instance = this; var screenSize = getBreakpointRegion(); var desktop = screenSize === 'sm' || screenSize === 'md' || screenSize === 'lg'; instance.mobile = !desktop; instance.desktop = desktop; return desktop; } }; var old = $.fn.sideNavigation; var initialize = function(toggler, options, selector) { var data = toggler.data('lexicon.sidenav'); if (!data) { if (!options) { options = {}; } options.selector = selector; data = new SideNavigation(toggler, options); toggler.data('lexicon.sidenav', data); } return data; }; var Plugin = function(options) { var instance = this; var selector = instance.selector; var retVal = instance; var methodCall = typeof options === 'string'; var returnInstance = options === 'instance'; var args = $.makeArray(arguments).slice(1); if (methodCall) { this.each( function() { var $this = $(this); var data = $this.data('lexicon.sidenav'); if (data) { if (returnInstance) { retVal = data; return false; } var methodRetVal; if ($.isFunction(data[options]) && options.indexOf('_') !== 0) { methodRetVal = data[options].apply(data, args); } if (methodRetVal !== data && methodRetVal !== undefined) { if (methodRetVal.jquery) { retVal = retVal.pushStack(methodRetVal.get()); } else { retVal = methodRetVal; } return false; } } else if (returnInstance) { retVal = null; return false; } } ); } else { this.each( function() { initialize($(this), options, selector); } ); } return retVal; }; Plugin.noConflict = function() { $.fn.sideNavigation = old; return this; }; /** * Plugin options * @property {String|Number} breakpoint The window width that defines the desktop size. * @property {String} content The class or ID of the content container. * @property {String} container The class or ID of the sidenav container. * @property {String|Number} gutter The space between the sidenav-slider and the sidenav-content. * @property {String|Boolean} equalHeight The height of content and navigation should be equal. This is deprecated. * @property {String} heightType Calculates the height of sidenav when type is relative. Possible values: `fullHeight`, `equalHeight` * @property {String} navigation The class or ID of the navigation container. * @property {String} position The position of the sidenav-slider. Possible values: left, right * @property {String} type The type of sidenav in desktop. Possible values: relative, fixed, fixed-push * @property {String} typeMobile The type of sidenav in mobile. Possible values: relative, fixed, fixed-push * @property {String|Boolean} useDelegate The type of reference to use on the toggler event handler. Value false, directly binds click to the toggler. * @property {String|Object} url The URL or $.ajax config object to fetch the content to inject into .sidebar-body * @property {String|Number} width The width of the side navigation. */ Plugin.defaults = { breakpoint: 768, content: '.sidenav-content', equalHeight: true, // equalHeight option is deprecated, use heightType instead gutter: '15px', heightType: null, loadingIndicatorTPL: '<div class="loading-animation loading-animation-md"></div>', navigation: '.sidenav-menu-slider', position: 'left', type: 'relative', typeMobile: 'relative', url: null, useDelegate: true, width: '225px' }; Plugin.Constructor = SideNavigation; $.fn.sideNavigation = Plugin; $(function() { var sidenav = $('[data-toggle="sidenav"]'); Plugin.call(sidenav); }); }(jQuery);