├── .gitignore ├── .github └── FUNDING.yml ├── scss ├── sidebar-bootstrap.scss ├── sidebar.scss ├── _mixins.scss ├── _sidebar-vendor-prefixes.scss ├── _variables-bootstrap.scss ├── _variables.scss ├── _sidebar-theme.scss ├── _sidebar-core.scss └── _wrapper.scss ├── js ├── utils │ ├── const.js │ ├── events.js │ ├── window.js │ ├── toggle.js │ ├── storage.js │ ├── actions.js │ ├── css.js │ ├── scrollbar.js │ └── touch.js └── sidebar.js ├── webpack.config.js ├── examples ├── index.html ├── examples.css ├── main.js ├── navbar-static.html ├── navbar-fixed.html ├── basic.html ├── navbar-mini.html ├── navbar-mini-fluid.html ├── navbar-fixed-fluid.html ├── navbar-fixed-full-locked-fluid.html └── navbar-static-fluid.html ├── README.md ├── LICENSE ├── rollup.config.js ├── package.json ├── doc └── index.md └── dist ├── sidebar-bootstrap.css ├── sidebar.css └── sidebar.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | node_modules/ 4 | package-lock.json 5 | yarn.lock 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [francoispluchino] 2 | custom: ['https://paypal.me/francoispluchino'] 3 | -------------------------------------------------------------------------------- /scss/sidebar-bootstrap.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Sidebar Bootstrap 3 | // -------------------------------------------------- 4 | 5 | @import 'variables-bootstrap'; 6 | @import 'variables'; 7 | @import 'wrapper'; 8 | -------------------------------------------------------------------------------- /scss/sidebar.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Sidebar 3 | // -------------------------------------------------- 4 | 5 | @import 'variables-bootstrap'; 6 | @import 'variables'; 7 | @import 'mixins'; 8 | @import 'sidebar-core'; 9 | @import 'sidebar-vendor-prefixes'; 10 | @import 'sidebar-theme'; 11 | -------------------------------------------------------------------------------- /scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Mixins 3 | // -------------------------------------------------- 4 | 5 | @mixin box-shadow($shadow) { 6 | -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 7 | box-shadow: $shadow; 8 | } 9 | 10 | @mixin transition($transition) { 11 | -webkit-transition: #{$transition}; 12 | -o-transition: #{$transition}; 13 | transition: #{$transition}; 14 | } 15 | -------------------------------------------------------------------------------- /scss/_sidebar-vendor-prefixes.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Sidebar Vendor Prefixes 3 | // -------------------------------------------------- 4 | 5 | .fxp-sidebar { 6 | -ms-touch-action: none; 7 | } 8 | 9 | .fxp-sidebar-swipe { 10 | -ms-touch-action: none; 11 | } 12 | 13 | .fxp-sidebar-menu { 14 | &, 15 | & ul, 16 | & li, 17 | & span, 18 | & a { 19 | -ms-touch-action: pan-y; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /js/utils/const.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | /** 11 | * Left position. 12 | */ 13 | export const POSITION_LEFT = 'left'; 14 | 15 | /** 16 | * Right position. 17 | */ 18 | export const POSITION_RIGHT = 'right'; 19 | 20 | /** 21 | * Not force toggle. 22 | */ 23 | export const FORCE_TOGGLE_NO = false; 24 | 25 | /** 26 | * Force toggle. 27 | */ 28 | export const FORCE_TOGGLE = true; 29 | 30 | /** 31 | * Always force toggle. 32 | */ 33 | export const FORCE_TOGGLE_ALWAYS = 'always'; 34 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | const Encore = require('@symfony/webpack-encore'); 11 | 12 | const config = Encore 13 | .setOutputPath('build/') 14 | .setPublicPath('/build') 15 | .disableSingleRuntimeChunk() 16 | .autoProvidejQuery() 17 | .enableSourceMaps(!Encore.isProduction()) 18 | .cleanupOutputBeforeBuild() 19 | .enableSassLoader() 20 | .addEntry('main', './examples/main.js') 21 | .copyFiles({ 22 | from: './examples', 23 | to: '[name].[ext]', 24 | pattern: /.html$/ 25 | }) 26 | .getWebpackConfig() 27 | ; 28 | 29 | module.exports = config; 30 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fxp Jquery Sidebar Demo 7 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fxp Jquery Sidebar 2 | ================== 3 | 4 | This jquery plugin is a responsive Drawer with Hammerjs. 5 | 6 | Documentation 7 | ------------- 8 | 9 | The bulk of the documentation is stored in the `doc/index.md` 10 | file in this component: 11 | 12 | [Read the Documentation](doc/index.md) 13 | 14 | Installation 15 | ------------ 16 | 17 | All the installation instructions are located in [documentation](doc/index.md). 18 | 19 | License 20 | ------- 21 | 22 | This javascript component is under the MIT license. See the complete license: 23 | 24 | [LICENSE](LICENSE) 25 | 26 | About 27 | ----- 28 | 29 | Fxp Jquery Sidebar is a [François Pluchino](https://github.com/francoispluchino) initiative. 30 | See also the list of [contributors](https://github.com/fxpio/fxp-jquery-sidebar/graphs/contributors). 31 | 32 | Reporting an issue or a feature request 33 | --------------------------------------- 34 | 35 | Issues and feature requests are tracked in the [Github issue tracker](https://github.com/fxpio/fxp-jquery-sidebar/issues). 36 | -------------------------------------------------------------------------------- /scss/_variables-bootstrap.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | // TWITTER BOOTSTRAP VARIABLES 6 | // -------------------------------------------------- 7 | 8 | $white: #fff !default; 9 | 10 | $gray-200: #e9ecef !default; 11 | $gray-900: #212529 !default; 12 | 13 | $blue: #0d6efd !default; 14 | 15 | $primary: $blue !default; 16 | 17 | $font-size-base: 1rem !default; // Assumes the browser default, typically `16px` 18 | 19 | $h3-font-size: $font-size-base * 1.75 !default; 20 | 21 | $headings-font-family: null !default; 22 | 23 | $zindex-fixed: 1030 !default; 24 | 25 | $navbar-dark-color: rgba($white, .55) !default; 26 | 27 | $grid-gutter-width: 1.5rem !default; 28 | 29 | $container-padding-x: $grid-gutter-width / 2 !default; 30 | 31 | $grid-breakpoints: ( 32 | xs: 0, 33 | sm: 576px, 34 | md: 768px, 35 | lg: 992px, 36 | xl: 1200px, 37 | xxl: 1400px 38 | ) !default; 39 | 40 | $container-max-widths: ( 41 | sm: 540px, 42 | md: 720px, 43 | lg: 960px, 44 | xl: 1140px, 45 | xxl: 1320px 46 | ) !default; 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2018 François Pluchino 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /examples/examples.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | .container-main { 4 | height: 100%; 5 | width: 100%; 6 | margin: 0; 7 | } 8 | 9 | .container-main { 10 | overflow-y: auto; 11 | -webkit-overflow-scrolling: touch; 12 | } 13 | 14 | .container-main.container-fixed-top { 15 | padding-top: 70px; 16 | } 17 | 18 | .container-main.container-fixed-bottom { 19 | padding-bottom: 70px; 20 | } 21 | 22 | .navbar-toggle.fxp-sidebar-btn-toggle-left { 23 | float: left; 24 | margin-left: 15px; 25 | } 26 | 27 | .navbar-toggle.fxp-sidebar-btn-toggle-left, 28 | .navbar-toggle.fxp-sidebar-btn-toggle-right { 29 | margin-top: 5px; 30 | margin-bottom: 5px; 31 | } 32 | 33 | .fxp-sidebar .fxp-sidebar-menu.text-right { 34 | text-align: right; 35 | } 36 | 37 | @media (min-width: 768px) { 38 | .navbar-header { 39 | width: 100%; 40 | } 41 | 42 | .navbar-toggle.fxp-sidebar-btn-toggle-left, 43 | .navbar-toggle.fxp-sidebar-btn-toggle-right { 44 | display: inline-block; 45 | } 46 | 47 | .navbar-toggle.fxp-sidebar-btn-toggle-left.sidebar-locked-toggle:not(.keep-visible), 48 | .navbar-toggle.fxp-sidebar-btn-toggle-right.sidebar-locked-toggle:not(.keep-visible) { 49 | display: none; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import 'bootstrap/dist/css/bootstrap.css'; 11 | import '@fortawesome/fontawesome-free/css/all.css'; 12 | import '@fxp/jquery-scroller/scss/scroller.scss'; 13 | import '../scss/sidebar.scss'; 14 | import '../scss/sidebar-bootstrap.scss'; 15 | import './examples.css'; 16 | import 'hammerjs'; 17 | import '@fxp/jquery-scroller'; 18 | import '@fxp/jquery-scroller/js/sticky-header'; 19 | import '../js/sidebar'; 20 | 21 | $(document).ready(function() { 22 | var $miniSidebars = $('.fxp-sidebar-mini'); 23 | 24 | if ($miniSidebars.length > 0) { 25 | $miniSidebars.each(function (index) { 26 | var $miniSidebar = $miniSidebars.eq(index); 27 | 28 | $miniSidebar.on('mouseenter', null, null, function () { 29 | $miniSidebar.sidebar('open'); 30 | }); 31 | 32 | $miniSidebar.on('mouseleave', null, null, function () { 33 | $miniSidebar.sidebar('close'); 34 | }); 35 | }); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /js/utils/events.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import $ from 'jquery'; 11 | 12 | /** 13 | * Add browser prefix on event name for jquery. 14 | * 15 | * @param {String} name The event name 16 | * @param {String} [namespace] The namespace of jquery event 17 | * 18 | * @returns {String} 19 | */ 20 | export function prefixedEvent(name, namespace) { 21 | let pfx = ['webkit', 'moz', 'ms', 'o', ''], 22 | names = ''; 23 | 24 | for (let p = 0; p < pfx.length; p++) { 25 | if (!pfx[p]) { 26 | name = name.toLowerCase(); 27 | } 28 | 29 | names += ' ' + pfx[p] + name; 30 | 31 | if (undefined !== namespace) { 32 | names += '.' + namespace; 33 | } 34 | } 35 | 36 | return names; 37 | } 38 | 39 | /** 40 | * Trigger the event. 41 | * 42 | * @param {String} type The event type 43 | * @param {Sidebar} self The sidebar instance 44 | * @param {*} [data] The data 45 | */ 46 | export function triggerEvent(type, self, data) { 47 | $.event.trigger({ 48 | type: 'sidebar:' + type + '.fxp.sidebar', 49 | sidebar: self, 50 | eventData: data, 51 | time: new Date() 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /js/utils/window.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import {isOverMinWidth, changeTransition} from "./css"; 11 | import {lockBodyScroll, unlockBodyScroll} from "./scrollbar"; 12 | 13 | /** 14 | * Close the sidebar or reopen the locked sidebar on window resize event. 15 | * 16 | * @param {Event} event The event 17 | * 18 | * @typedef {Sidebar} Event.data The sidebar instance 19 | */ 20 | export function onResizeWindow(event) { 21 | let self = event.data, 22 | isForceOpened = false, 23 | isOver = isOverMinWidth(self); 24 | 25 | changeTransition(self.$element, 'none'); 26 | 27 | if (isOver && self.isLocked()) { 28 | self.forceOpen(); 29 | unlockBodyScroll(self); 30 | isForceOpened = true; 31 | } 32 | 33 | if (undefined === self.resizeDelay) { 34 | self.resizeDelay = window.setTimeout(function () { 35 | delete self.resizeDelay; 36 | changeTransition(self.$element, ''); 37 | 38 | if (!isForceOpened && self.isLocked()) { 39 | if (!isOver && self.isOpen()) { 40 | lockBodyScroll(self); 41 | } else { 42 | unlockBodyScroll(self); 43 | } 44 | } 45 | }, 500); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /js/utils/toggle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | /** 11 | * Action to detach toggle button. 12 | * 13 | * @param {Sidebar} self The sidebar instance 14 | * @param {jQuery} $toggle The toggle 15 | */ 16 | export function doDetachToggle(self, $toggle) { 17 | $toggle 18 | .off('mouseover.fxp.sidebar' + self.guid, $.proxy(self.open, self)) 19 | .off(self.eventType + '.fxp.sidebar' + self.guid, self.toggle) 20 | .removeClass(self.options.classLocked + '-toggle') 21 | .removeClass(self.options.classForceOpen + '-toggle') 22 | .removeClass(self.options.classOpen + '-toggle'); 23 | 24 | if (!self.enabled) { 25 | $toggle.removeClass('disabled'); 26 | } 27 | } 28 | 29 | /** 30 | * Add css classname in toggle buttons. 31 | * 32 | * @param {Sidebar} self The sidebar instance 33 | * @param {String} classname The css classname 34 | */ 35 | export function addClassToggles(self, classname) { 36 | self.$toggles.each(function (index, $toggle) { 37 | $toggle.addClass(classname); 38 | }); 39 | } 40 | 41 | /** 42 | * Add css classname in toggle buttons. 43 | * 44 | * @param {Sidebar} self The sidebar instance 45 | * @param {String} classname The css classname 46 | */ 47 | export function removeClassToggles(self, classname) { 48 | self.$toggles.each(function (index, $toggle) { 49 | $toggle.removeClass(classname); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import babel from 'rollup-plugin-babel'; 11 | import commonjs from 'rollup-plugin-commonjs'; 12 | import resolve from 'rollup-plugin-node-resolve'; 13 | import {uglify} from 'rollup-plugin-uglify'; 14 | 15 | const baseConfig = { 16 | input: 'js/sidebar.js', 17 | external: [ 18 | 'jquery' 19 | ], 20 | plugins: [ 21 | resolve(), 22 | commonjs({ 23 | include: 'node_modules/@fxp/jquery-pluginify/**' 24 | }), 25 | babel({ 26 | presets: [ 27 | '@babel/preset-env' 28 | ] 29 | }) 30 | ] 31 | }; 32 | 33 | const iifeConfig = { 34 | ...baseConfig, 35 | output: { 36 | format: 'iife', 37 | name: 'FxpSidebar', 38 | exports: 'named', 39 | globals: { 40 | jquery: 'jQuery' 41 | } 42 | } 43 | }; 44 | 45 | const uglifyConfig = { 46 | warnings: false, 47 | compress: { 48 | pure_getters: true, 49 | unsafe: true, 50 | unsafe_comps: true 51 | } 52 | }; 53 | 54 | export default [ 55 | { 56 | ...iifeConfig, 57 | output: { 58 | ...iifeConfig.output, 59 | file: 'dist/sidebar.js' 60 | } 61 | }, 62 | { 63 | ...iifeConfig, 64 | plugins: [...baseConfig.plugins, uglify(uglifyConfig)], 65 | output: { 66 | ...iifeConfig.output, 67 | file: 'dist/sidebar.min.js' 68 | } 69 | } 70 | ]; 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fxp/jquery-sidebar", 3 | "version": "1.2.5", 4 | "license": "MIT", 5 | "author": "François Pluchino ", 6 | "contributors": [], 7 | "description": "A jquery responsive sidebar with hammerjs", 8 | "keywords": [ 9 | "sidebar", 10 | "drawer", 11 | "responsive", 12 | "hammerjs", 13 | "hammer scroll", 14 | "jquery" 15 | ], 16 | "homepage": "https://github.com/fxpio/fxp-jquery-sidebar", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/fxpio/fxp-jquery-sidebar.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/fxpio/fxp-jquery-sidebar/issues" 23 | }, 24 | "scripts": { 25 | "dev": "encore dev", 26 | "serve": "encore dev-server --port 9000", 27 | "build:style": "sass --no-source-map scss/sidebar.scss dist/sidebar.css", 28 | "build:style:bootstrap": "sass --no-source-map scss/sidebar-bootstrap.scss dist/sidebar-bootstrap.css", 29 | "build:module": "rollup -c", 30 | "build": "yarn run build:module && yarn run build:style && yarn run build:style:bootstrap" 31 | }, 32 | "engines": {}, 33 | "main": "js/sidebar.js", 34 | "dependencies": { 35 | "@fxp/jquery-pluginify": "github:fxpio/fxp-jquery-pluginify#semver:^1.0.0", 36 | "hammerjs": "^2.0.0", 37 | "jquery": "^2.2.0||^3.2.0" 38 | }, 39 | "devDependencies": { 40 | "@fortawesome/fontawesome-free": "^5.15.2", 41 | "@fxp/jquery-scroller": "github:fxpio/fxp-jquery-scroller#semver:^1.0.0", 42 | "@symfony/webpack-encore": "^1.1.0", 43 | "bootstrap": "^5.1.0", 44 | "file-loader": "^6.0.0", 45 | "rollup": "^1.25.2", 46 | "rollup-plugin-babel": "^4.3.3", 47 | "rollup-plugin-commonjs": "^10.1.0", 48 | "rollup-plugin-node-resolve": "^5.2.0", 49 | "rollup-plugin-uglify": "^6.0.3", 50 | "sass": "^1.32.7", 51 | "sass-loader": "^11.0.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /js/utils/storage.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import {changeTransition} from "./css"; 11 | 12 | /** 13 | * Set the value in local storage. 14 | * 15 | * @param {Sidebar} self The sidebar instance 16 | * @param {String} key The key 17 | * @param {String|Boolean} value The value 18 | */ 19 | export function setLocalStorage(self, key, value) { 20 | if (self.options.saveConfig && 'localStorage' in window) { 21 | try { 22 | window.localStorage.setItem(self.$element.prop('id') + '/' + key, value); 23 | } catch (e) {} 24 | } 25 | } 26 | 27 | /** 28 | * Get the value in local storage. 29 | * 30 | * @param {Sidebar} self The sidebar instance 31 | * @param {String} key The key 32 | * @param {String|Boolean} [defaultValue] The default value 33 | * 34 | * @return {String|null} 35 | */ 36 | export function getLocalStorage(self, key, defaultValue) { 37 | let value = undefined === defaultValue ? null : defaultValue, 38 | itemValue = null; 39 | 40 | if (self.options.saveConfig && 'localStorage' in window) { 41 | itemValue = window.localStorage.getItem(self.$element.prop('id') + '/' + key); 42 | } 43 | 44 | return null !== itemValue ? itemValue : value; 45 | } 46 | 47 | /** 48 | * Init the sidebar options with the locale storage. 49 | * 50 | * @param {Sidebar} self The sidebar instance 51 | */ 52 | export function initWithLocalStorage(self) { 53 | let storageLocked = getLocalStorage(self, self.options.storageLockedKey); 54 | 55 | if (null !== storageLocked && self.options.toggleOnClick) { 56 | self.options.locked = storageLocked === 'true'; 57 | 58 | if (!self.options.locked) { 59 | changeTransition(self.$element, 'none'); 60 | self.forceClose(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /js/utils/actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import {isOverMinWidth} from "./css"; 11 | 12 | /** 13 | * Binding actions of keyboard. 14 | * 15 | * @param {jQuery.Event|Event} event 16 | */ 17 | export function keyboardAction(event) { 18 | if (!(event instanceof jQuery.Event)) { 19 | return; 20 | } 21 | 22 | if (event.data.options.disabledKeyboard) { 23 | return; 24 | } 25 | 26 | let self = event.data, 27 | kbe = self.options.keyboardEvent; 28 | 29 | if (event.shiftKey === kbe.shiftKey && 30 | event.ctrlKey === kbe.ctrlKey && 31 | event.altKey === kbe.altKey && 32 | event.keyCode === kbe.keyCode) { 33 | self.toggle(event); 34 | } 35 | } 36 | 37 | /** 38 | * Close the sidebar since external action. 39 | * 40 | * @param {Event} event The event 41 | * 42 | * @typedef {Sidebar} Event.data The sidebar instance 43 | */ 44 | export function closeExternal(event) { 45 | let self = event.data; 46 | 47 | event.stopPropagation(); 48 | event.preventDefault(); 49 | 50 | if (isOverMinWidth(self)) { 51 | self.close(); 52 | 53 | } else { 54 | self.forceClose(); 55 | } 56 | } 57 | 58 | /** 59 | * Close the sidebar when an item is selected. 60 | * 61 | * @param {Event} event The event 62 | * 63 | * @typedef {Sidebar} Event.data The sidebar instance 64 | */ 65 | export function closeOnSelect(event) { 66 | let self = event.data; 67 | 68 | if (self.options.closeOnSelectDelay > 0) { 69 | self.closeDelay = window.setTimeout(function () { 70 | self.close(); 71 | }, self.options.closeOnSelectDelay * 1000); 72 | } else { 73 | self.close(); 74 | } 75 | } 76 | 77 | /** 78 | * Clean the close delay. 79 | * 80 | * @param {Sidebar} self The sidebar instance 81 | */ 82 | export function cleanCloseDelay(self) { 83 | if (null !== self.closeDelay) { 84 | window.clearTimeout(self.closeDelay); 85 | self.closeDelay = null; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =============== 3 | 4 | Prerequisites 5 | ------------- 6 | 7 | This library require: 8 | 9 | - jquery 10 | - hammerjs 11 | - font-awesome (optional, for toggle button) 12 | - fxp-hammer-scroll (optional) 13 | - bootstrap (optional) 14 | 15 | Installation 16 | ------------ 17 | 18 | ``` 19 | npm install @fxp/jquery-sidebar --save 20 | ``` 21 | 22 | Dev installation 23 | ---------------- 24 | 25 | ### Use NPM 26 | 27 | ``` 28 | npm install 29 | ``` 30 | 31 | ### Use Webpack Encore 32 | 33 | ``` 34 | $ encore dev-server --port 9000 35 | ``` 36 | 37 | Open the URL `http://localhost:9000/build` in your browser. 38 | 39 | ### Twitter Bootstrap 40 | 41 | You can use the specific stylesheet for twitter bootstrap (optional): `less/sidebar-bootstrap.less`. 42 | 43 | ##### For fixed navbar: 44 | 45 | You must used: 46 | - `.sidebar-fixed-top` class on sidebar element (`.sidebar`) 47 | - `.container-fixed-top` class on content container element (`.container-main`) for top navbar 48 | - `.container-fixed-bottom` class on content container element (`.container-main`) for bottom navbar 49 | 50 | ##### For static navbar: 51 | 52 | You must used: 53 | - `.sidebar-static-top` class on sidebar element (`.sidebar`) 54 | - `.container-static-top` class on content container element (`.container-main`) for top navbar 55 | - `.container-static-bottom` class on content container element (`.container-main`) for bottom navbar 56 | 57 | ##### For sidebar force open option: 58 | 59 | You must used: 60 | 61 | - `.sidebar-force-open` and `.sidebar-open-init` (optional) classes on sidebar element (`.sidebar`) 62 | - `.container-force-open-left` class on content container element (`.container-main`) for the left position 63 | - `.container-force-open-right` class on content container element (`.container-main`) for the right position 64 | 65 | ##### For sidebar locked option: 66 | 67 | You must used: 68 | 69 | - `.sidebar-locked` and `.sidebar-open-init` (optional) classes on sidebar element (`.sidebar`) 70 | - `.container-force-open-left` class on content container element (`.container-main`) for the left position 71 | - `.container-force-open-right` class on content container element (`.container-main`) for the right position 72 | - `.sidebar-locked-toggle` class on toggle button element (optional) 73 | -------------------------------------------------------------------------------- /js/utils/css.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | /*global CSSMatrix*/ 11 | /*global WebKitCSSMatrix*/ 12 | /*global MSCSSMatrix*/ 13 | 14 | /** 15 | * Changes the css transition configuration on target element. 16 | * 17 | * @param {jQuery} $target The element to edited 18 | * @param {string} transition The css transition configuration of target 19 | */ 20 | export function changeTransition($target, transition) { 21 | $target.css('-webkit-transition', transition); 22 | $target.css('transition', transition); 23 | } 24 | 25 | /** 26 | * Changes the css transform configuration on target element. 27 | * 28 | * @param {jQuery} $target The element to edited 29 | * @param {string} transform The css transform configuration of target 30 | */ 31 | export function changeTransform($target, transform) { 32 | $target.css('-webkit-transform', transform); 33 | $target.css('transform', transform); 34 | } 35 | 36 | /** 37 | * Translate the jquery element with Translate 3D CSS. 38 | * 39 | * @param {jQuery } $target The jquery element 40 | * @param {Number} delta The delta of translate 41 | */ 42 | export function changeTranslate($target, delta) { 43 | let trans = delta + 'px, 0px, 0px'; 44 | 45 | changeTransform($target, 'translate3d(' + trans + ')'); 46 | } 47 | 48 | /** 49 | * Get the horizontal position of target element. 50 | * 51 | * @param {jQuery} $target The jquery target 52 | * 53 | * @return {number} 54 | */ 55 | export function getTargetPosition($target) { 56 | let transformCss = $target.css('transform'), 57 | transform = {e: 0, f: 0}, 58 | reMatrix, 59 | match; 60 | 61 | if (transformCss) { 62 | if ('function' === typeof CSSMatrix) { 63 | transform = new CSSMatrix(transformCss); 64 | 65 | } else if ('function' === typeof WebKitCSSMatrix) { 66 | transform = new WebKitCSSMatrix(transformCss); 67 | 68 | } else if ('function' === typeof MSCSSMatrix) { 69 | transform = new MSCSSMatrix(transformCss); 70 | 71 | } else { 72 | reMatrix = /matrix\(\s*-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?\s*,\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\)/; 73 | match = transformCss.match(reMatrix); 74 | 75 | if (match) { 76 | transform.e = parseInt(match[1], 10); 77 | transform.f = parseInt(match[2], 10); 78 | } 79 | } 80 | } 81 | 82 | return transform.e; 83 | } 84 | 85 | /** 86 | * Checks if the window width is wider than the minimum width defined in 87 | * options. 88 | * 89 | * @param {Sidebar} self The sidebar instance 90 | * 91 | * @returns {boolean} 92 | */ 93 | export function isOverMinWidth(self) { 94 | let $window = $(window), 95 | windowWidth = $window.innerWidth(); 96 | 97 | if (self.$body.height() > $window.innerHeight()) { 98 | windowWidth += self.nativeScrollWidth; 99 | } 100 | 101 | return windowWidth >= self.options.minLockWidth; 102 | } 103 | -------------------------------------------------------------------------------- /js/utils/scrollbar.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import {POSITION_RIGHT} from "./const"; 11 | import {triggerEvent} from "./events"; 12 | 13 | let nativeScrollWidth = null; 14 | 15 | /** 16 | * Get the width of native scrollbar. 17 | * 18 | * @returns {Number} 19 | */ 20 | export function getNativeScrollWidth() { 21 | let sbDiv = document.createElement("div"), 22 | size; 23 | sbDiv.style.width = '100px'; 24 | sbDiv.style.height = '100px'; 25 | sbDiv.style.overflow = 'scroll'; 26 | sbDiv.style.position = 'absolute'; 27 | sbDiv.style.top = '-9999px'; 28 | document.body.appendChild(sbDiv); 29 | size = sbDiv.offsetWidth - sbDiv.clientWidth; 30 | document.body.removeChild(sbDiv); 31 | 32 | return size; 33 | } 34 | 35 | /** 36 | * Check if is a mobile device. 37 | * 38 | * @returns {boolean} 39 | * 40 | * @private 41 | */ 42 | export function mobileCheck() { 43 | if (null === nativeScrollWidth) { 44 | nativeScrollWidth = getNativeScrollWidth(); 45 | } 46 | 47 | return 0 === nativeScrollWidth; 48 | } 49 | 50 | /** 51 | * Init the scroller instance. 52 | * 53 | * @param {Sidebar} self The sidebar instance 54 | * 55 | * @private 56 | */ 57 | export function initScroller(self) { 58 | let options = { 59 | scrollbarInverse: POSITION_RIGHT === self.options.position 60 | }; 61 | 62 | if ($.fn.scroller && self.options.useScroller) { 63 | self.$element.scroller($.extend({}, options, self.options.scroller)); 64 | self.$element.on('scrolling.fxp.scroller.fxp.sidebar', null, self, resetScrolling); 65 | } 66 | } 67 | 68 | /** 69 | * Destroy the hammer scroll configuration. 70 | * 71 | * @param {Sidebar} self The sidebar instance 72 | */ 73 | export function destroyScroller(self) { 74 | if ($.fn.scroller && self.options.useScroller) { 75 | self.$element.scroller('destroy'); 76 | self.$element.off('scrolling.fxp.scroller.fxp.sidebar', resetScrolling); 77 | } 78 | } 79 | 80 | /** 81 | * Lock the scroll of body. 82 | * 83 | * @param {Sidebar} self The sidebar instance 84 | */ 85 | export function lockBodyScroll(self) { 86 | let bodyPad = parseInt((self.$body.css('padding-right') || 0), 10), 87 | hasScrollbar = self.$body.get(0).scrollHeight > document.documentElement.clientHeight && 88 | 'hidden' !== self.$body.css('overflow-y'); 89 | 90 | if (hasScrollbar) { 91 | self.originalBodyPad = document.body.style.paddingRight || ''; 92 | self.originalBodyOverflowY = document.body.style.overflowY || ''; 93 | 94 | self.$body.css({ 95 | 'padding-right': (bodyPad + self.nativeScrollWidth) + 'px', 96 | 'overflow-y': 'hidden' 97 | }); 98 | 99 | triggerEvent('lock-body-scroll', self, self.nativeScrollWidth); 100 | } 101 | } 102 | 103 | /** 104 | * Unlock the scroll of body. 105 | * 106 | * @param {Sidebar} self The sidebar instance 107 | */ 108 | export function unlockBodyScroll(self) { 109 | if (null !== self.originalBodyPad || null !== self.originalBodyOverflowY) { 110 | self.$body.css({ 111 | 'padding-right': self.originalBodyPad, 112 | 'overflow-y': self.originalBodyOverflowY 113 | }); 114 | 115 | self.originalBodyPad = null; 116 | self.originalBodyOverflowY = null; 117 | triggerEvent('unlock-body-scroll', self, self.nativeScrollWidth); 118 | } 119 | } 120 | 121 | /** 122 | * Reset the scrolling locker. 123 | * 124 | * @param {Event} event The event 125 | * 126 | * @typedef {Sidebar} Event.data The sidebar instance 127 | * 128 | * @private 129 | */ 130 | function resetScrolling(event) { 131 | let self = event.data; 132 | 133 | self.resetScrolling = window.setTimeout(function () { 134 | self.resetScrolling = null; 135 | }, self.options.resetScrollDelay * 1000); 136 | } 137 | -------------------------------------------------------------------------------- /scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | 6 | // COMPONENT VARIABLES 7 | // -------------------------------------------------- 8 | 9 | // Text 10 | // ------------------------- 11 | 12 | $sidebar-headings-font-family: $headings-font-family !default; 13 | 14 | // Z-index master list 15 | // ------------------------- 16 | 17 | $zindex-sidebar: $zindex-fixed + 2 !default; 18 | $zindex-sidebar-fixed: $zindex-fixed + 1 !default; 19 | $zindex-sidebar-static: 0 !default; 20 | 21 | $zindex-sidebar-swipe: $zindex-sidebar - 1 !default; 22 | $zindex-sidebar-swipe-fixed: $zindex-sidebar-fixed - 1 !default; 23 | $zindex-sidebar-swipe-static: $zindex-sidebar-static - 1 !default; 24 | 25 | $zindex-sidebar-obfuscator: $zindex-sidebar - 1 !default; 26 | $zindex-sidebar-obfuscator-fixed: $zindex-sidebar-fixed - 1 !default; 27 | $zindex-sidebar-obfuscator-static: $zindex-sidebar-static - 1 !default; 28 | 29 | // Grid 30 | // ------------------------- 31 | 32 | $sidebar-grid-gutter-width: $grid-gutter-width !default; 33 | 34 | $sidebar-container-padding-x: $sidebar-grid-gutter-width / 2 !default; 35 | 36 | $sidebar-grid-breakpoints: $grid-breakpoints !default; 37 | 38 | $sidebar-container-max-widths: $container-max-widths !default; 39 | 40 | $sidebar-force-open-breakpoint: 'lg' !default; 41 | $sidebar-mobile-breakpoint: 'md' !default; 42 | 43 | // Custom Sidebar 44 | // ------------------------- 45 | 46 | $sidebar-prefix: 'fxp-' !default; 47 | $sidebar-width: 210px !default; 48 | $sidebar-mini-width: round($sidebar-width / 3) !default; 49 | $sidebar-right-width: $sidebar-width !default; 50 | $sidebar-right-mini-width: round($sidebar-right-width / 3) !default; 51 | $sidebar-mobile-width: 80% !default; 52 | $sidebar-right-mobile-width: $sidebar-mobile-width !default; 53 | $sidebar-clickable-swipe-bg: fade($primary, 23%) !default; 54 | $sidebar-obfuscator-bg: rgba(0, 0, 0, 0.5) !default; 55 | $sidebar-obfuscator-duration: '0.3s' !default; 56 | $sidebar-navbar-height: 56px !default; 57 | 58 | $sidebar-default-font-size: $font-size-base !default; 59 | $sidebar-default-color: $gray-900 !default; 60 | $sidebar-default-bg: #fff !default; 61 | $sidebar-default-border-color: $gray-200 !default; 62 | $sidebar-default-group-color: darken($sidebar-default-bg, 14%) !default; 63 | $sidebar-default-group-size: $h3-font-size !default; 64 | $sidebar-default-link-color: $gray-900 !default; 65 | $sidebar-default-link-mini-color: lighten($sidebar-default-link-color, 14%) !default; 66 | $sidebar-default-link-bg: transprent !default; 67 | $sidebar-default-link-hover-color: null !default; 68 | $sidebar-default-link-hover-bg: $gray-200 !default; 69 | $sidebar-default-link-active-color: $primary !default; 70 | $sidebar-default-link-active-bg: $sidebar-default-link-bg !default; 71 | $sidebar-default-icon-color: $sidebar-default-link-color !default; 72 | $sidebar-default-icon-bg: $primary !default; 73 | $sidebar-default-scrollbar-bg: #555 !default; 74 | $sidebar-default-shadow-open-left: none !default; 75 | $sidebar-default-shadow-open-right: $sidebar-default-shadow-open-left !default; 76 | 77 | $sidebar-inverse-color: $navbar-dark-color !default; 78 | $sidebar-inverse-bg: #2a3542 !default; 79 | $sidebar-inverse-border-color: lighten($sidebar-inverse-bg, 5%) !default; 80 | $sidebar-inverse-group-color: lighten($sidebar-inverse-bg, 14%) !default; 81 | $sidebar-inverse-link-color: $sidebar-inverse-color !default; 82 | $sidebar-inverse-link-mini-color: lighten($sidebar-inverse-link-color, 14%) !default; 83 | $sidebar-inverse-link-bg: $sidebar-inverse-bg !default; 84 | $sidebar-inverse-link-hover-color: null !default; 85 | $sidebar-inverse-link-hover-bg: lighten($sidebar-inverse-link-bg, 5%) !default; 86 | $sidebar-inverse-link-active-color: lighten($primary, 46%) !default; 87 | $sidebar-inverse-link-active-bg: $sidebar-inverse-link-bg !default; 88 | $sidebar-inverse-icon-color: $sidebar-inverse-link-active-color !default; 89 | $sidebar-inverse-icon-bg: lighten($primary, 46%) !default; 90 | $sidebar-inverse-scrollbar-bg: lighten($sidebar-inverse-bg, 70%) !default; 91 | $sidebar-inverse-shadow-open-left: $sidebar-default-shadow-open-left !default; 92 | $sidebar-inverse-shadow-open-right: $sidebar-inverse-shadow-open-left !default; 93 | -------------------------------------------------------------------------------- /scss/_sidebar-theme.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Sidebar Theme 3 | // -------------------------------------------------- 4 | 5 | .fxp-sidebar { 6 | &.fxp-sidebar-default { 7 | color: $sidebar-default-color; 8 | background-color: $sidebar-default-bg; 9 | 10 | .fxp-sidebar-group { 11 | > span { 12 | color: $sidebar-default-group-color; 13 | border-top-color: $sidebar-default-border-color; 14 | } 15 | 16 | &.sticky-header > span { 17 | background-color: $sidebar-default-bg; 18 | } 19 | 20 | + .fxp-sidebar-item { 21 | border-top-color: $sidebar-default-border-color; 22 | } 23 | } 24 | 25 | .fxp-sidebar-divider-item { 26 | border-top-color: $sidebar-default-border-color; 27 | } 28 | 29 | .fxp-sidebar-item { 30 | > a { 31 | color: $sidebar-default-link-color; 32 | background-color: $sidebar-default-link-bg; 33 | 34 | &:hover, 35 | &:focus { 36 | color: $sidebar-default-link-hover-color; 37 | background-color: $sidebar-default-link-hover-bg; 38 | } 39 | 40 | &.active { 41 | color: $sidebar-default-link-active-color; 42 | background-color: $sidebar-default-link-active-bg; 43 | } 44 | } 45 | 46 | &.fxp-sidebar-item-mini > a { 47 | color: $sidebar-default-link-mini-color; 48 | 49 | &.active { 50 | color: $sidebar-default-link-active-color; 51 | background-color: $sidebar-default-link-active-bg; 52 | } 53 | } 54 | } 55 | 56 | .hammer-scrollbar { 57 | background-color: $sidebar-default-scrollbar-bg; 58 | } 59 | } 60 | 61 | &.fxp-sidebar-inverse { 62 | color: $sidebar-inverse-color; 63 | background-color: $sidebar-inverse-bg; 64 | 65 | .fxp-sidebar-group { 66 | > span { 67 | color: $sidebar-inverse-group-color; 68 | border-top-color: $sidebar-inverse-border-color; 69 | } 70 | 71 | &.sticky-header > span { 72 | background-color: $sidebar-inverse-bg; 73 | } 74 | 75 | + .fxp-sidebar-item { 76 | border-top-color: $sidebar-inverse-border-color; 77 | } 78 | } 79 | 80 | .fxp-sidebar-divider-item { 81 | border-top-color: $sidebar-inverse-border-color; 82 | } 83 | 84 | .fxp-sidebar-item { 85 | > a { 86 | color: $sidebar-inverse-link-color; 87 | background-color: $sidebar-inverse-link-bg; 88 | 89 | &:hover, 90 | &:focus { 91 | color: $sidebar-inverse-link-hover-color; 92 | background-color: $sidebar-inverse-link-hover-bg; 93 | } 94 | 95 | &.active { 96 | color: $sidebar-inverse-link-active-color; 97 | background-color: $sidebar-inverse-link-active-bg; 98 | } 99 | } 100 | 101 | &.fxp-sidebar-item-mini > a { 102 | color: $sidebar-inverse-link-mini-color; 103 | 104 | &.active { 105 | color: $sidebar-inverse-link-active-color; 106 | background-color: $sidebar-inverse-link-active-bg; 107 | } 108 | } 109 | } 110 | 111 | .hammer-scrollbar { 112 | background-color: $sidebar-inverse-scrollbar-bg; 113 | } 114 | } 115 | 116 | &[data-clickable-swipe="true"] { 117 | + .fxp-sidebar-swipe { 118 | &.mouse-hover { 119 | background-color: $sidebar-clickable-swipe-bg; 120 | } 121 | } 122 | } 123 | } 124 | 125 | .fxp-sidebar-obfuscator.show { 126 | background-color: $sidebar-obfuscator-bg; 127 | } 128 | 129 | // Responsive 130 | // ------------------------- 131 | 132 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 133 | .fxp-sidebar.fxp-sidebar-locked { 134 | &.fxp-sidebar-default { 135 | border-color: $sidebar-default-border-color; 136 | } 137 | 138 | &.fxp-sidebar-inverse { 139 | border-color: $sidebar-inverse-border-color; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /examples/navbar-static.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Static example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 | 13 |
15 | 45 |
46 | 47 |
48 | 49 | 58 | 59 | 60 |
61 |
62 |
63 |

This is a paragraph.

64 | 65 |

This is a paragraph.

66 | 67 |

This is a paragraph.

68 | 69 |

This is a paragraph.

70 | 71 |

This is a paragraph.

72 | 73 |

This is a paragraph.

74 | 75 |

This is a paragraph.

76 | 77 |

This is a paragraph.

78 | 79 |

This is a paragraph.

80 | 81 |

This is a paragraph.

82 | 83 |

This is a paragraph.

84 | 85 |

This is a paragraph.

86 | 87 |

This is a paragraph.

88 | 89 |

This is a paragraph.

90 | 91 |

This is a paragraph.

92 | 93 |

This is a paragraph.

94 | 95 |

This is a paragraph.

96 | 97 |

This is a paragraph.

98 | 99 |

This is a paragraph.

100 | 101 |

This is a paragraph.

102 | 103 |

This is a paragraph.

104 | 105 |

This is a paragraph.

106 | 107 |

This is a paragraph.

108 | 109 |

This is a paragraph.

110 | 111 |

This is a paragraph.

112 | 113 |

This is a paragraph.

114 | 115 |

This is a paragraph.

116 | 117 |

This is a paragraph.

118 | 119 |

This is a paragraph.

120 | 121 |

This is a paragraph.

122 | 123 |

This is a paragraph.

124 | 125 |

This is a paragraph.

126 | 127 |

This is a paragraph.

128 | 129 |

This is a paragraph.

130 | 131 |

This is a paragraph.

132 | 133 |

This is a paragraph.

134 | 135 |

This is a paragraph.

136 | 137 |

This is a paragraph.

138 | 139 |

This is a paragraph.

140 | 141 |

This is a paragraph.

142 | 143 |

This is a paragraph.

144 | 145 |

This is a paragraph.

146 | 147 |

This is a paragraph.

148 | 149 |

This is a paragraph.

150 | 151 |

This is a paragraph.

152 | 153 |

This is a paragraph.

154 | 155 |

This is a paragraph.

156 | 157 |

This is a paragraph.

158 |
159 |
160 |
161 |
162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /examples/navbar-fixed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Fixed example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
14 | 44 |
45 | 46 |
47 | 48 | 57 | 58 | 59 |
60 |
61 |
62 |

This is a paragraph. start.

63 | 64 |

This is a paragraph.

65 | 66 |

This is a paragraph.

67 | 68 |

This is a paragraph.

69 | 70 |

This is a paragraph.

71 | 72 |

This is a paragraph.

73 | 74 |

This is a paragraph.

75 | 76 |

This is a paragraph.

77 | 78 |

This is a paragraph.

79 | 80 |

This is a paragraph.

81 | 82 |

This is a paragraph.

83 | 84 |

This is a paragraph.

85 | 86 |

This is a paragraph.

87 | 88 |

This is a paragraph.

89 | 90 |

This is a paragraph.

91 | 92 |

This is a paragraph.

93 | 94 |

This is a paragraph.

95 | 96 |

This is a paragraph.

97 | 98 |

This is a paragraph.

99 | 100 |

This is a paragraph.

101 | 102 |

This is a paragraph.

103 | 104 |

This is a paragraph.

105 | 106 |

This is a paragraph.

107 | 108 |

This is a paragraph.

109 | 110 |

This is a paragraph.

111 | 112 |

This is a paragraph.

113 | 114 |

This is a paragraph.

115 | 116 |

This is a paragraph.

117 | 118 |

This is a paragraph.

119 | 120 |

This is a paragraph.

121 | 122 |

This is a paragraph.

123 | 124 |

This is a paragraph.

125 | 126 |

This is a paragraph.

127 | 128 |

This is a paragraph.

129 | 130 |

This is a paragraph.

131 | 132 |

This is a paragraph.

133 | 134 |

This is a paragraph.

135 | 136 |

This is a paragraph.

137 | 138 |

This is a paragraph.

139 | 140 |

This is a paragraph.

141 | 142 |

This is a paragraph.

143 | 144 |

This is a paragraph.

145 | 146 |

This is a paragraph.

147 | 148 |

This is a paragraph.

149 | 150 |

This is a paragraph.

151 | 152 |

This is a paragraph.

153 | 154 |

This is a paragraph.

155 | 156 |

This is a paragraph. end.

157 |
158 |
159 |
160 |
161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /examples/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
13 | 43 |
44 | 45 | 46 |
48 | 78 |
79 | 80 |
81 | 82 | 95 | 96 | 97 |
98 |
99 |
100 |

This is a paragraph. start.

101 | 102 |

This is a paragraph.

103 | 104 |

This is a paragraph.

105 | 106 |

This is a paragraph.

107 | 108 |

This is a paragraph.

109 | 110 |

This is a paragraph.

111 | 112 |

This is a paragraph.

113 | 114 |

This is a paragraph.

115 | 116 |

This is a paragraph.

117 | 118 |

This is a paragraph.

119 | 120 |

This is a paragraph.

121 | 122 |

This is a paragraph.

123 | 124 |

This is a paragraph.

125 | 126 |

This is a paragraph.

127 | 128 |

This is a paragraph.

129 | 130 |

This is a paragraph.

131 | 132 |

This is a paragraph.

133 | 134 |

This is a paragraph.

135 | 136 |

This is a paragraph.

137 | 138 |

This is a paragraph.

139 | 140 |

This is a paragraph.

141 | 142 |

This is a paragraph.

143 | 144 |

This is a paragraph.

145 | 146 |

This is a paragraph.

147 | 148 |

This is a paragraph.

149 | 150 |

This is a paragraph.

151 | 152 |

This is a paragraph.

153 | 154 |

This is a paragraph.

155 | 156 |

This is a paragraph.

157 | 158 |

This is a paragraph.

159 | 160 |

This is a paragraph.

161 | 162 |

This is a paragraph.

163 | 164 |

This is a paragraph.

165 | 166 |

This is a paragraph.

167 | 168 |

This is a paragraph.

169 | 170 |

This is a paragraph.

171 | 172 |

This is a paragraph.

173 | 174 |

This is a paragraph.

175 | 176 |

This is a paragraph.

177 | 178 |

This is a paragraph.

179 | 180 |

This is a paragraph.

181 | 182 |

This is a paragraph.

183 | 184 |

This is a paragraph.

185 | 186 |

This is a paragraph.

187 | 188 |

This is a paragraph.

189 | 190 |

This is a paragraph.

191 | 192 |

This is a paragraph.

193 | 194 |

This is a paragraph. end.

195 |
196 |
197 |
198 |
199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /examples/navbar-mini.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Fixed Mini Fluid example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
14 | 44 |
45 | 46 | 47 |
49 | 79 |
80 | 81 |
82 | 83 | 96 | 97 | 98 |
99 |
100 |
101 |

This is a paragraph. start.

102 | 103 |

This is a paragraph.

104 | 105 |

This is a paragraph.

106 | 107 |

This is a paragraph.

108 | 109 |

This is a paragraph.

110 | 111 |

This is a paragraph.

112 | 113 |

This is a paragraph.

114 | 115 |

This is a paragraph.

116 | 117 |

This is a paragraph.

118 | 119 |

This is a paragraph.

120 | 121 |

This is a paragraph.

122 | 123 |

This is a paragraph.

124 | 125 |

This is a paragraph.

126 | 127 |

This is a paragraph.

128 | 129 |

This is a paragraph.

130 | 131 |

This is a paragraph.

132 | 133 |

This is a paragraph.

134 | 135 |

This is a paragraph.

136 | 137 |

This is a paragraph.

138 | 139 |

This is a paragraph.

140 | 141 |

This is a paragraph.

142 | 143 |

This is a paragraph.

144 | 145 |

This is a paragraph.

146 | 147 |

This is a paragraph.

148 | 149 |

This is a paragraph.

150 | 151 |

This is a paragraph.

152 | 153 |

This is a paragraph.

154 | 155 |

This is a paragraph.

156 | 157 |

This is a paragraph.

158 | 159 |

This is a paragraph.

160 | 161 |

This is a paragraph.

162 | 163 |

This is a paragraph.

164 | 165 |

This is a paragraph.

166 | 167 |

This is a paragraph.

168 | 169 |

This is a paragraph.

170 | 171 |

This is a paragraph.

172 | 173 |

This is a paragraph.

174 | 175 |

This is a paragraph.

176 | 177 |

This is a paragraph.

178 | 179 |

This is a paragraph.

180 | 181 |

This is a paragraph.

182 | 183 |

This is a paragraph.

184 | 185 |

This is a paragraph.

186 | 187 |

This is a paragraph.

188 | 189 |

This is a paragraph.

190 | 191 |

This is a paragraph.

192 | 193 |

This is a paragraph.

194 | 195 |

This is a paragraph. end.

196 |
197 |
198 |
199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /examples/navbar-mini-fluid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Fixed Mini Fluid example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
14 | 44 |
45 | 46 | 47 |
49 | 79 |
80 | 81 |
82 | 83 | 96 | 97 | 98 |
99 |
100 |
101 |

This is a paragraph. start.

102 | 103 |

This is a paragraph.

104 | 105 |

This is a paragraph.

106 | 107 |

This is a paragraph.

108 | 109 |

This is a paragraph.

110 | 111 |

This is a paragraph.

112 | 113 |

This is a paragraph.

114 | 115 |

This is a paragraph.

116 | 117 |

This is a paragraph.

118 | 119 |

This is a paragraph.

120 | 121 |

This is a paragraph.

122 | 123 |

This is a paragraph.

124 | 125 |

This is a paragraph.

126 | 127 |

This is a paragraph.

128 | 129 |

This is a paragraph.

130 | 131 |

This is a paragraph.

132 | 133 |

This is a paragraph.

134 | 135 |

This is a paragraph.

136 | 137 |

This is a paragraph.

138 | 139 |

This is a paragraph.

140 | 141 |

This is a paragraph.

142 | 143 |

This is a paragraph.

144 | 145 |

This is a paragraph.

146 | 147 |

This is a paragraph.

148 | 149 |

This is a paragraph.

150 | 151 |

This is a paragraph.

152 | 153 |

This is a paragraph.

154 | 155 |

This is a paragraph.

156 | 157 |

This is a paragraph.

158 | 159 |

This is a paragraph.

160 | 161 |

This is a paragraph.

162 | 163 |

This is a paragraph.

164 | 165 |

This is a paragraph.

166 | 167 |

This is a paragraph.

168 | 169 |

This is a paragraph.

170 | 171 |

This is a paragraph.

172 | 173 |

This is a paragraph.

174 | 175 |

This is a paragraph.

176 | 177 |

This is a paragraph.

178 | 179 |

This is a paragraph.

180 | 181 |

This is a paragraph.

182 | 183 |

This is a paragraph.

184 | 185 |

This is a paragraph.

186 | 187 |

This is a paragraph.

188 | 189 |

This is a paragraph.

190 | 191 |

This is a paragraph.

192 | 193 |

This is a paragraph.

194 | 195 |

This is a paragraph. end.

196 |
197 |
198 |
199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /examples/navbar-fixed-fluid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Fixed Fluid example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
14 | 44 |
45 | 46 | 47 |
49 | 79 |
80 | 81 |
82 | 83 | 96 | 97 | 98 |
99 |
100 |
101 |

This is a paragraph. start.

102 | 103 |

This is a paragraph.

104 | 105 |

This is a paragraph.

106 | 107 |

This is a paragraph.

108 | 109 |

This is a paragraph.

110 | 111 |

This is a paragraph.

112 | 113 |

This is a paragraph.

114 | 115 |

This is a paragraph.

116 | 117 |

This is a paragraph.

118 | 119 |

This is a paragraph.

120 | 121 |

This is a paragraph.

122 | 123 |

This is a paragraph.

124 | 125 |

This is a paragraph.

126 | 127 |

This is a paragraph.

128 | 129 |

This is a paragraph.

130 | 131 |

This is a paragraph.

132 | 133 |

This is a paragraph.

134 | 135 |

This is a paragraph.

136 | 137 |

This is a paragraph.

138 | 139 |

This is a paragraph.

140 | 141 |

This is a paragraph.

142 | 143 |

This is a paragraph.

144 | 145 |

This is a paragraph.

146 | 147 |

This is a paragraph.

148 | 149 |

This is a paragraph.

150 | 151 |

This is a paragraph.

152 | 153 |

This is a paragraph.

154 | 155 |

This is a paragraph.

156 | 157 |

This is a paragraph.

158 | 159 |

This is a paragraph.

160 | 161 |

This is a paragraph.

162 | 163 |

This is a paragraph.

164 | 165 |

This is a paragraph.

166 | 167 |

This is a paragraph.

168 | 169 |

This is a paragraph.

170 | 171 |

This is a paragraph.

172 | 173 |

This is a paragraph.

174 | 175 |

This is a paragraph.

176 | 177 |

This is a paragraph.

178 | 179 |

This is a paragraph.

180 | 181 |

This is a paragraph.

182 | 183 |

This is a paragraph.

184 | 185 |

This is a paragraph.

186 | 187 |

This is a paragraph.

188 | 189 |

This is a paragraph.

190 | 191 |

This is a paragraph.

192 | 193 |

This is a paragraph.

194 | 195 |

This is a paragraph. end.

196 |
197 |
198 |
199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /examples/navbar-fixed-full-locked-fluid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Fixed Full Locked Fluid example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 |
14 | 44 |
45 | 46 | 47 |
49 | 79 |
80 | 81 |
82 | 83 | 96 | 97 | 98 |
99 |
100 |
101 |

This is a paragraph. start.

102 | 103 |

This is a paragraph.

104 | 105 |

This is a paragraph.

106 | 107 |

This is a paragraph.

108 | 109 |

This is a paragraph.

110 | 111 |

This is a paragraph.

112 | 113 |

This is a paragraph.

114 | 115 |

This is a paragraph.

116 | 117 |

This is a paragraph.

118 | 119 |

This is a paragraph.

120 | 121 |

This is a paragraph.

122 | 123 |

This is a paragraph.

124 | 125 |

This is a paragraph.

126 | 127 |

This is a paragraph.

128 | 129 |

This is a paragraph.

130 | 131 |

This is a paragraph.

132 | 133 |

This is a paragraph.

134 | 135 |

This is a paragraph.

136 | 137 |

This is a paragraph.

138 | 139 |

This is a paragraph.

140 | 141 |

This is a paragraph.

142 | 143 |

This is a paragraph.

144 | 145 |

This is a paragraph.

146 | 147 |

This is a paragraph.

148 | 149 |

This is a paragraph.

150 | 151 |

This is a paragraph.

152 | 153 |

This is a paragraph.

154 | 155 |

This is a paragraph.

156 | 157 |

This is a paragraph.

158 | 159 |

This is a paragraph.

160 | 161 |

This is a paragraph.

162 | 163 |

This is a paragraph.

164 | 165 |

This is a paragraph.

166 | 167 |

This is a paragraph.

168 | 169 |

This is a paragraph.

170 | 171 |

This is a paragraph.

172 | 173 |

This is a paragraph.

174 | 175 |

This is a paragraph.

176 | 177 |

This is a paragraph.

178 | 179 |

This is a paragraph.

180 | 181 |

This is a paragraph.

182 | 183 |

This is a paragraph.

184 | 185 |

This is a paragraph.

186 | 187 |

This is a paragraph.

188 | 189 |

This is a paragraph.

190 | 191 |

This is a paragraph.

192 | 193 |

This is a paragraph.

194 | 195 |

This is a paragraph. end.

196 |
197 |
198 |
199 |
200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /examples/navbar-static-fluid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Navbar Static Fluid example - Fxp Jquery Sidebar 7 | 8 | 9 | 10 | 11 | 12 | 13 |
15 | 45 |
46 | 47 | 48 |
50 | 80 |
81 | 82 |
83 | 84 | 97 | 98 | 99 |
100 |
101 |
102 |

This is a paragraph.

103 | 104 |

This is a paragraph.

105 | 106 |

This is a paragraph.

107 | 108 |

This is a paragraph.

109 | 110 |

This is a paragraph.

111 | 112 |

This is a paragraph.

113 | 114 |

This is a paragraph.

115 | 116 |

This is a paragraph.

117 | 118 |

This is a paragraph.

119 | 120 |

This is a paragraph.

121 | 122 |

This is a paragraph.

123 | 124 |

This is a paragraph.

125 | 126 |

This is a paragraph.

127 | 128 |

This is a paragraph.

129 | 130 |

This is a paragraph.

131 | 132 |

This is a paragraph.

133 | 134 |

This is a paragraph.

135 | 136 |

This is a paragraph.

137 | 138 |

This is a paragraph.

139 | 140 |

This is a paragraph.

141 | 142 |

This is a paragraph.

143 | 144 |

This is a paragraph.

145 | 146 |

This is a paragraph.

147 | 148 |

This is a paragraph.

149 | 150 |

This is a paragraph.

151 | 152 |

This is a paragraph.

153 | 154 |

This is a paragraph.

155 | 156 |

This is a paragraph.

157 | 158 |

This is a paragraph.

159 | 160 |

This is a paragraph.

161 | 162 |

This is a paragraph.

163 | 164 |

This is a paragraph.

165 | 166 |

This is a paragraph.

167 | 168 |

This is a paragraph.

169 | 170 |

This is a paragraph.

171 | 172 |

This is a paragraph.

173 | 174 |

This is a paragraph.

175 | 176 |

This is a paragraph.

177 | 178 |

This is a paragraph.

179 | 180 |

This is a paragraph.

181 | 182 |

This is a paragraph.

183 | 184 |

This is a paragraph.

185 | 186 |

This is a paragraph.

187 | 188 |

This is a paragraph.

189 | 190 |

This is a paragraph.

191 | 192 |

This is a paragraph.

193 | 194 |

This is a paragraph.

195 | 196 |

This is a paragraph.

197 |
198 |
199 |
200 |
201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /js/utils/touch.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Fxp package. 3 | * 4 | * (c) François Pluchino 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import {isOverMinWidth, getTargetPosition, changeTransition, changeTranslate, changeTransform} from "./css"; 11 | import {triggerEvent} from "./events"; 12 | import {lockBodyScroll, unlockBodyScroll} from "./scrollbar"; 13 | import {cleanCloseDelay} from "./actions"; 14 | import {FORCE_TOGGLE, FORCE_TOGGLE_ALWAYS, POSITION_LEFT, POSITION_RIGHT} from "./const"; 15 | import {addClassToggles, removeClassToggles} from "./toggle"; 16 | 17 | /** 18 | * Trigger the opened or closed event when the transition is finished. 19 | * 20 | * @param {Event} event The event 21 | * 22 | * @typedef {Sidebar} Event.data The sidebar instance 23 | */ 24 | export function onEndTransition(event) { 25 | let self = event.data, 26 | action = event.data.isOpen() ? 'opened' : 'closed'; 27 | 28 | if (event.target !== self.$element.get(0)) { 29 | return; 30 | } 31 | 32 | if (event.data.isOpen()) { 33 | addClassToggles(self, self.options.classOpen + '-toggle'); 34 | 35 | if ($.fn.scroller && self.options.useScroller) { 36 | self.$element.scroller('resizeScrollbar'); 37 | } 38 | 39 | $('a:visible:first', self.$toggles.get(0).parent()).focus(); 40 | } else { 41 | removeClassToggles(self, self.options.classOpen + '-toggle'); 42 | 43 | if ($.fn.scroller && self.options.useScroller) { 44 | self.$element.scroller('resizeScrollbar'); 45 | } 46 | } 47 | 48 | if (self.isLocked()) { 49 | if (!isOverMinWidth(self) && self.isOpen()) { 50 | lockBodyScroll(self); 51 | } else { 52 | unlockBodyScroll(self); 53 | } 54 | } 55 | 56 | triggerEvent(action, self); 57 | } 58 | 59 | /** 60 | * Action of "on drag" hammer event. 61 | * 62 | * @param {Sidebar} self The sidebar instance 63 | * @param {object} event The hammer event 64 | * 65 | * @typedef {Number} event.deltaX The hammer delta X 66 | * @typedef {Number} event.deltaY The hammer delta Y 67 | */ 68 | export function onDrag(self, event) { 69 | let delta; 70 | 71 | if (null !== self.resetScrolling || event.target === self.$obfuscator.get(0)) { 72 | return; 73 | } 74 | 75 | // drag start 76 | if (null === self.dragDirection) { 77 | if (Math.abs(event.deltaX) <= Math.abs(event.deltaY)) { 78 | return; 79 | } 80 | 81 | self.mouseDragEnd = null; 82 | self.dragDirection = event.direction; 83 | self.$element.css('user-select', 'none'); 84 | cleanCloseDelay(self); 85 | } 86 | 87 | // drag 88 | if (-1 === $.inArray(self.dragDirection, [Hammer.DIRECTION_LEFT, Hammer.DIRECTION_RIGHT]) || 89 | (self.options.locked && isOverMinWidth(self) && self.isOpen())) { 90 | return; 91 | } 92 | 93 | event.preventDefault(); 94 | 95 | if (null === self.dragStartPosition) { 96 | self.dragStartPosition = getTargetPosition(self.$element); 97 | } 98 | 99 | delta = Math.round(self.dragStartPosition + event.deltaX); 100 | 101 | if ((POSITION_LEFT === self.getPosition() && delta > 0) || 102 | (POSITION_RIGHT === self.getPosition() && delta < 0)) { 103 | delta = 0; 104 | } 105 | 106 | self.$element.addClass(self.options.classOnDragging); 107 | changeTransition(self.$element, 'none'); 108 | changeTranslate(self.$element, delta); 109 | } 110 | 111 | /** 112 | * Action of "on drag end" hammer event. 113 | * 114 | * @param {Sidebar} self The sidebar instance 115 | * @param {object} event The hammer event 116 | * 117 | * 118 | * @typedef {Number} event.deltaX The hammer delta X 119 | * @typedef {Number} event.direction The hammer direction const 120 | */ 121 | export function onDragEnd(self, event) { 122 | let closeGesture = Hammer.DIRECTION_LEFT, 123 | openGesture = Hammer.DIRECTION_RIGHT; 124 | 125 | if (null !== self.resetScrolling || event.target === self.$obfuscator.get(0)) { 126 | return; 127 | } 128 | 129 | self.dragStartPosition = null; 130 | event.preventDefault(); 131 | 132 | if (self.fixDragClick && -1 !== $.inArray(event.srcEvent.type, ['pointerup', 'mouseup'])) { 133 | self.mouseDragEnd = true; 134 | } 135 | 136 | self.$element.removeClass(self.options.classOnDragging); 137 | self.$element.css('user-select', ''); 138 | changeTransition(self.$element, ''); 139 | changeTransform(self.$element, ''); 140 | 141 | if (Math.abs(event.deltaX) <= (self.$element.innerWidth() / 4)) { 142 | self.dragDirection = null; 143 | self.$toggles.focus(); 144 | 145 | return; 146 | } 147 | 148 | if (POSITION_RIGHT === self.getPosition()) { 149 | closeGesture = Hammer.DIRECTION_RIGHT; 150 | openGesture = Hammer.DIRECTION_LEFT; 151 | } 152 | 153 | if (self.isOpen() && closeGesture === self.dragDirection) { 154 | self.forceClose(); 155 | 156 | } else if (openGesture === self.dragDirection) { 157 | self.mouseDragEnd = null; 158 | 159 | if (self.isOpen() && isOverMinWidth(self) && 160 | $.inArray(self.options.forceToggle, [FORCE_TOGGLE, FORCE_TOGGLE_ALWAYS]) >= 0) { 161 | self.forceOpen(); 162 | 163 | } else if (isOverMinWidth(self) && FORCE_TOGGLE_ALWAYS === self.options.forceToggle) { 164 | self.forceOpen(); 165 | 166 | } else { 167 | self.open(); 168 | } 169 | } 170 | 171 | self.dragDirection = null; 172 | } 173 | 174 | /** 175 | * Init the hammer instance. 176 | * 177 | * @param {Sidebar} self The sidebar instance 178 | */ 179 | export function initHammer(self) { 180 | if (!self.options.draggable || typeof Hammer !== 'function') { 181 | return; 182 | } 183 | 184 | self.$swipe = $(''); 185 | self.$element.after(self.$swipe); 186 | 187 | self.hammer = new Hammer(self.$wrapper.get(0), $.extend(true, {}, self.options.hammer)); 188 | 189 | self.hammer.get('swipe').set({ enable: false }); 190 | self.hammer.get('tap').set({ enable: false }); 191 | 192 | self.hammer.on('panstart', function (event) { 193 | onDrag(self, event); 194 | }); 195 | self.hammer.on('pan', function (event) { 196 | onDrag(self, event); 197 | }); 198 | self.hammer.on('panend', function (event) { 199 | onDragEnd(self, event); 200 | }); 201 | 202 | self.$wrapper.on('mousedown.fxp.sidebar', null, self, onItemMouseDown); 203 | self.$wrapper.on('click.fxp.sidebar', null, self, onItemClick); 204 | 205 | if (self.options.clickableSwipe) { 206 | self.$swipe 207 | .on('click.fxp.sidebar' + self.guid, null, self, swipeClick) 208 | .on('mouseenter.fxp.sidebar' + self.guid, null, self, swipeMouseEnter) 209 | .on('mouseleave.fxp.sidebar' + self.guid, null, self, swipeMouseLeave) 210 | ; 211 | } 212 | } 213 | 214 | /** 215 | * Destroy the hammer configuration. 216 | * 217 | * @param {Sidebar} self The sidebar instance 218 | */ 219 | export function destroyHammer(self) { 220 | if (!self.options.draggable || typeof Hammer !== 'function') { 221 | return; 222 | } 223 | 224 | if (self.options.clickableSwipe) { 225 | self.$swipe 226 | .off('click.fxp.sidebar' + self.guid, swipeClick) 227 | .off('mouseenter.fxp.sidebar' + self.guid, swipeMouseEnter) 228 | .off('mouseleave.fxp.sidebar' + self.guid, swipeMouseLeave) 229 | ; 230 | } 231 | 232 | self.$wrapper.off('mousedown.fxp.sidebar', onItemMouseDown); 233 | self.$wrapper.off('click.fxp.sidebar', onItemClick); 234 | self.$swipe.remove(); 235 | self.hammer.destroy(); 236 | 237 | delete self.$swipe; 238 | delete self.hammer; 239 | } 240 | 241 | 242 | 243 | /** 244 | * Action on swipe is clicked. 245 | * 246 | * @param {Event} event The event 247 | * 248 | * @typedef {Sidebar} Event.data The sidebar instance 249 | * 250 | * @private 251 | */ 252 | function swipeClick(event) { 253 | swipeMouseLeave(event); 254 | event.data.toggle(event); 255 | } 256 | 257 | /** 258 | * Action when mouse enter on sur swipe. 259 | * 260 | * @param {Event} event The event 261 | * 262 | * @typedef {Sidebar} Event.data The sidebar instance 263 | * 264 | * @private 265 | */ 266 | function swipeMouseEnter(event) { 267 | event.data.$swipe.addClass('mouse-hover'); 268 | } 269 | 270 | /** 271 | * Action when mouse leave on sur swipe. 272 | * 273 | * @param {Event} event The event 274 | * 275 | * @typedef {Sidebar} Event.data The sidebar instance 276 | * 277 | * @private 278 | */ 279 | function swipeMouseLeave(event) { 280 | event.data.$swipe.removeClass('mouse-hover'); 281 | } 282 | 283 | /** 284 | * Action on item mouse down. 285 | * 286 | * @param {Event} event The event 287 | * 288 | * @typedef {Sidebar} Event.data The sidebar instance 289 | */ 290 | function onItemMouseDown(event) { 291 | event.preventDefault(); 292 | } 293 | 294 | /** 295 | * Action on item click. 296 | * 297 | * @param {Event} event The event 298 | * 299 | * @typedef {Sidebar} Event.data The sidebar instance 300 | */ 301 | function onItemClick(event) { 302 | let self = event.data; 303 | 304 | if (true === self.mouseDragEnd) { 305 | event.preventDefault(); 306 | cleanCloseDelay(self); 307 | self.mouseDragEnd = null; 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /dist/sidebar-bootstrap.css: -------------------------------------------------------------------------------- 1 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom { 2 | z-index: 1031; 3 | } 4 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top + .fxp-sidebar-swipe, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom + .fxp-sidebar-swipe { 5 | z-index: 1030; 6 | } 7 | @media (max-width: 991px) { 8 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top.fxp-sidebar-open ~ .fxp-sidebar-obfuscator, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 9 | z-index: 1030; 10 | } 11 | } 12 | 13 | @media (max-width: 991px) { 14 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom { 15 | z-index: 1032; 16 | } 17 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top + .fxp-sidebar-swipe, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom + .fxp-sidebar-swipe { 18 | z-index: 1031; 19 | } 20 | .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top.fxp-sidebar-open ~ .fxp-sidebar-obfuscator, .fxp-sidebar:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 21 | z-index: 1031; 22 | } 23 | } 24 | @media (min-width: 992px) { 25 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top, .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-bottom { 26 | z-index: 0; 27 | } 28 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top + .fxp-sidebar-swipe, .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-bottom + .fxp-sidebar-swipe { 29 | z-index: -1; 30 | } 31 | } 32 | @media (min-width: 992px) and (max-width: 991px) { 33 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top.fxp-sidebar-open ~ .fxp-sidebar-obfuscator, .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-bottom.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 34 | z-index: -1; 35 | } 36 | } 37 | @media (min-width: 992px) { 38 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top > .sticky-header { 39 | padding-top: 57px !important; 40 | } 41 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top .fxp-sidebar-menu > .fxp-sidebar-group:first-child, 42 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-top .fxp-sidebar-menu > .fxp-sidebar-item:first-child { 43 | padding-top: 57px; 44 | } 45 | } 46 | @media (min-width: 992px) { 47 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-bottom .fxp-sidebar-menu > .fxp-sidebar-group:last-child, 48 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-static-bottom .fxp-sidebar-menu > .fxp-sidebar-item:last-child { 49 | padding-bottom: 56px; 50 | } 51 | } 52 | @media (min-width: 992px) { 53 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-top { 54 | top: 56px; 55 | } 56 | } 57 | @media (min-width: 992px) { 58 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked).fxp-sidebar-fixed-bottom { 59 | bottom: 56px; 60 | } 61 | } 62 | @media (min-width: 992px) { 63 | .fxp-sidebar.fxp-sidebar-locked ~ .fxp-sidebar-obfuscator { 64 | display: none; 65 | } 66 | } 67 | @media (min-width: 992px) { 68 | .container-main.container-force-open-left { 69 | padding-left: 210px; 70 | } 71 | .container-main.container-force-open-left > .navbar:not(.fixed-top):not(.fixed-bottom):not(.sticky-top) { 72 | margin-left: -210px; 73 | } 74 | } 75 | @media (min-width: 992px) { 76 | .container-main.container-force-open-right { 77 | padding-right: 210px; 78 | } 79 | .container-main.container-force-open-right > .navbar:not(.fixed-top):not(.fixed-bottom):not(.sticky-top) { 80 | margin-right: -210px; 81 | } 82 | } 83 | @media (min-width: 992px) { 84 | .container-main.container-force-open-left > .container, 85 | .container-main.container-force-open-left > .navbar > .container, .container-main.container-force-open-right > .container, 86 | .container-main.container-force-open-right > .navbar > .container { 87 | width: 750px; 88 | } 89 | } 90 | @media (min-width: 1200px) { 91 | .container-main.container-force-open-left > .container, 92 | .container-main.container-force-open-left > .navbar > .container, .container-main.container-force-open-right > .container, 93 | .container-main.container-force-open-right > .navbar > .container { 94 | width: 750px; 95 | } 96 | } 97 | @media (min-width: 1410px) { 98 | .container-main.container-force-open-left > .container, 99 | .container-main.container-force-open-left > .navbar > .container, .container-main.container-force-open-right > .container, 100 | .container-main.container-force-open-right > .navbar > .container { 101 | width: 960px; 102 | } 103 | } 104 | @media (min-width: 1400px) { 105 | .container-main.container-force-open-left > .container, 106 | .container-main.container-force-open-left > .navbar > .container, .container-main.container-force-open-right > .container, 107 | .container-main.container-force-open-right > .navbar > .container { 108 | width: 930px; 109 | } 110 | } 111 | @media (min-width: 1610px) { 112 | .container-main.container-force-open-left > .container, 113 | .container-main.container-force-open-left > .navbar > .container, .container-main.container-force-open-right > .container, 114 | .container-main.container-force-open-right > .navbar > .container { 115 | width: 1140px; 116 | } 117 | } 118 | @media (min-width: 992px) { 119 | .container-main.container-full-locked.container-force-open-left > .navbar > .container-fluid { 120 | padding-left: calc(210px + 0.75rem); 121 | } 122 | } 123 | @media (min-width: 992px) { 124 | .container-main.container-full-locked.container-force-open-right > .navbar > .container-fluid { 125 | padding-right: calc(210px + 0.75rem); 126 | } 127 | } 128 | @media (min-width: 992px) { 129 | .container-main.container-force-open-left.container-force-open-right > .container, 130 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 131 | width: 540px; 132 | } 133 | } 134 | @media (min-width: 1200px) { 135 | .container-main.container-force-open-left.container-force-open-right > .container, 136 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 137 | width: 540px; 138 | } 139 | } 140 | @media (min-width: 1410px) { 141 | .container-main.container-force-open-left.container-force-open-right > .container, 142 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 143 | width: 750px; 144 | } 145 | } 146 | @media (min-width: 1620px) { 147 | .container-main.container-force-open-left.container-force-open-right > .container, 148 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 149 | width: 960px; 150 | } 151 | } 152 | @media (min-width: 1400px) { 153 | .container-main.container-force-open-left.container-force-open-right > .container, 154 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 155 | width: 720px; 156 | } 157 | } 158 | @media (min-width: 1610px) { 159 | .container-main.container-force-open-left.container-force-open-right > .container, 160 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 161 | width: 930px; 162 | } 163 | } 164 | @media (min-width: 1820px) { 165 | .container-main.container-force-open-left.container-force-open-right > .container, 166 | .container-main.container-force-open-left.container-force-open-right > .navbar > .container { 167 | width: 1140px; 168 | } 169 | } 170 | @media (min-width: 992px) { 171 | .container-main.container-mini-left { 172 | padding-left: 70px; 173 | } 174 | } 175 | @media (min-width: 992px) { 176 | .container-main.container-mini-left > .navbar > .container-fluid { 177 | padding-left: calc(70px + 0.75rem); 178 | } 179 | } 180 | @media (min-width: 992px) { 181 | .container-main.container-mini-right { 182 | padding-right: 70px; 183 | } 184 | } 185 | @media (min-width: 992px) { 186 | .container-main.container-mini-right > .navbar > .container-fluid { 187 | padding-right: calc(70px + 0.75rem); 188 | } 189 | } 190 | @media (min-width: 992px) { 191 | .container-main.container-mini-left > .container, 192 | .container-main.container-mini-left > .navbar > .container, .container-main.container-mini-right > .container, 193 | .container-main.container-mini-right > .navbar > .container { 194 | width: 890px; 195 | } 196 | } 197 | @media (min-width: 1200px) { 198 | .container-main.container-mini-left > .container, 199 | .container-main.container-mini-left > .navbar > .container, .container-main.container-mini-right > .container, 200 | .container-main.container-mini-right > .navbar > .container { 201 | width: 890px; 202 | } 203 | } 204 | @media (min-width: 1270px) { 205 | .container-main.container-mini-left > .container, 206 | .container-main.container-mini-left > .navbar > .container, .container-main.container-mini-right > .container, 207 | .container-main.container-mini-right > .navbar > .container { 208 | width: 960px; 209 | } 210 | } 211 | @media (min-width: 1400px) { 212 | .container-main.container-mini-left > .container, 213 | .container-main.container-mini-left > .navbar > .container, .container-main.container-mini-right > .container, 214 | .container-main.container-mini-right > .navbar > .container { 215 | width: 1070px; 216 | } 217 | } 218 | @media (min-width: 1470px) { 219 | .container-main.container-mini-left > .container, 220 | .container-main.container-mini-left > .navbar > .container, .container-main.container-mini-right > .container, 221 | .container-main.container-mini-right > .navbar > .container { 222 | width: 1140px; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /scss/_sidebar-core.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Sidebar Core 3 | // -------------------------------------------------- 4 | 5 | .fxp-sidebar { 6 | position: fixed !important; 7 | top: 0; 8 | overflow: hidden; 9 | bottom: 0; 10 | z-index: $zindex-sidebar; 11 | width: $sidebar-width; 12 | cursor: default; 13 | -moz-user-select: none; 14 | user-select: none; 15 | border-left: none; 16 | border-right: 1px solid transparent; 17 | 18 | -webkit-transform: translate3d(-$sidebar-width, 0px, 0px); 19 | transform: translate3d(-$sidebar-width, 0px, 0px); 20 | 21 | &.fxp-sidebar-ready { 22 | -webkit-transition: -webkit-transform 0.2s; 23 | transition: transform 0.2s; 24 | } 25 | 26 | &.fxp-sidebar-open { 27 | -webkit-transform: translate3d(0px, 0px, 0px); 28 | transform: translate3d(0px, 0px, 0px); 29 | } 30 | 31 | .fxp-sidebar-menu { 32 | margin: 0; 33 | padding: 0; 34 | overflow-x: hidden; 35 | overflow-y: hidden; 36 | height: 100%; 37 | list-style: none; 38 | text-align: left; 39 | font-size: $sidebar-default-font-size; 40 | direction: ltr; 41 | 42 | &, 43 | & ul, 44 | & li, 45 | & span, 46 | & a { 47 | touch-action: pan-y; 48 | } 49 | } 50 | 51 | &.fxp-sidebar-ready { 52 | .fxp-sidebar-menu { 53 | overflow-y: auto; 54 | } 55 | } 56 | 57 | .fxp-sidebar-group-menu { 58 | padding: 0; 59 | margin: 0; 60 | } 61 | 62 | .fxp-sidebar-group, 63 | .fxp-sidebar-group-menu, 64 | .fxp-sidebar-item { 65 | display: block; 66 | } 67 | 68 | .fxp-sidebar-group > span, 69 | .fxp-sidebar-item > a { 70 | display: block; 71 | height: 100%; 72 | padding: 12px 15px; 73 | text-decoration: none; 74 | position: relative; 75 | 76 | &:empty { 77 | padding: 0; 78 | } 79 | } 80 | 81 | .fxp-sidebar-item { 82 | 83 | > a.active { 84 | border-left: 5px solid; 85 | padding: 12px 15px 12px 10px; 86 | } 87 | 88 | &.fxp-sidebar-item-mini { 89 | > a.active { 90 | padding-top: 12px; 91 | padding-bottom: 12px; 92 | } 93 | } 94 | } 95 | 96 | .fxp-sidebar-item.fxp-sidebar-item-mini { 97 | font-size: 0.85em; 98 | 99 | > a { 100 | padding-top: 12px; 101 | padding-bottom: 12px; 102 | } 103 | } 104 | 105 | .fxp-sidebar-group { 106 | > span { 107 | font-family: $sidebar-headings-font-family; 108 | font-size: $sidebar-default-group-size; 109 | border-top: 1px solid transparent; 110 | 111 | &.no-bar { 112 | border-top: none; 113 | } 114 | } 115 | 116 | &.sticky-header { 117 | position: absolute; 118 | height: auto; 119 | top: 0; 120 | left: 0; 121 | right: 0; 122 | z-index: 1; 123 | margin-top: 0; 124 | } 125 | 126 | + .fxp-sidebar-item { 127 | margin-top: 32px; 128 | border-top: 1px solid transparent; 129 | } 130 | } 131 | 132 | .fxp-sidebar-divider-item { 133 | border-top: 1px solid transparent; 134 | } 135 | 136 | .fxp-sidebar-item > a { 137 | cursor: pointer; 138 | } 139 | 140 | &[data-clickable-swipe="true"] { 141 | + .fxp-sidebar-swipe { 142 | cursor: pointer; 143 | -webkit-transition: background-color 0.3s ease; 144 | transition: background-color 0.3s ease; 145 | border-radius: 10px; 146 | } 147 | } 148 | } 149 | 150 | .fxp-sidebar-swipe { 151 | position : fixed; 152 | z-index: $zindex-sidebar-swipe; 153 | width: 10px; 154 | left: 0; 155 | top: 0; 156 | bottom: 0; 157 | background-color: #fff; 158 | opacity: 0.01; 159 | 160 | -moz-user-select: none; 161 | user-select: none; 162 | 163 | .fxp-sidebar-disabled + & { 164 | display: none; 165 | } 166 | } 167 | 168 | .fxp-sidebar-open + .fxp-sidebar-swipe, 169 | .fxp-sidebar-force-open + .fxp-sidebar-swipe { 170 | left: $sidebar-width; 171 | } 172 | 173 | .fxp-sidebar-obfuscator { 174 | position: fixed; 175 | display: block; 176 | z-index: -1; 177 | top: 0; 178 | bottom: 0; 179 | left: 0; 180 | right: 0; 181 | opacity: 0; 182 | @include transition("opacity #{$sidebar-obfuscator-duration} ease, z-index 0s linear #{$sidebar-obfuscator-duration}"); 183 | 184 | .fxp-sidebar-open ~ & { 185 | @include transition("opacity #{$sidebar-obfuscator-duration} ease"); 186 | z-index: $zindex-sidebar-obfuscator; 187 | opacity: 1; 188 | } 189 | 190 | .fxp-sidebar-force-open ~ & { 191 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 192 | z-index: -1; 193 | opacity: 0; 194 | } 195 | } 196 | } 197 | 198 | // Sidebar Right 199 | // ------------------------- 200 | 201 | .fxp-sidebar-right { 202 | &.fxp-sidebar { 203 | right: 0; 204 | border-right: none; 205 | border-left: 1px solid transparent; 206 | width: $sidebar-right-width; 207 | -webkit-transform: translate3d($sidebar-right-width, 0px, 0px); 208 | transform: translate3d($sidebar-right-width, 0px, 0px); 209 | 210 | &.fxp-sidebar-open { 211 | -webkit-transform: translate3d(0px, 0px, 0px); 212 | transform: translate3d(0px, 0px, 0px); 213 | } 214 | 215 | .fxp-sidebar-menu { 216 | direction: rtl; 217 | } 218 | 219 | .fxp-sidebar-item { 220 | > a.active { 221 | border-left: inherit; 222 | border-right: 5px solid; 223 | padding: 12px 10px 12px 15px; 224 | } 225 | 226 | &.fxp-sidebar-item-mini { 227 | > a.active { 228 | padding-top: 12px; 229 | padding-bottom: 12px; 230 | } 231 | } 232 | } 233 | } 234 | 235 | + .fxp-sidebar-swipe { 236 | left: auto; 237 | right: 0; 238 | } 239 | 240 | &.fxp-sidebar-open + .fxp-sidebar-swipe, 241 | &.fxp-sidebar-force-open + .fxp-sidebar-swipe { 242 | right: $sidebar-right-width; 243 | } 244 | } 245 | 246 | .fxp-sidebar { 247 | &.fxp-sidebar-default { 248 | &.fxp-sidebar-open, 249 | &.fxp-sidebar-dragging { 250 | @include box-shadow(3px 0 4px rgba(0, 0, 0, 0.18)); 251 | } 252 | } 253 | 254 | &.fxp-sidebar-inverse { 255 | &.fxp-sidebar-open, 256 | &.fxp-sidebar-dragging { 257 | @include box-shadow(3px 0 4px rgba(0, 0, 0, 0.32)); 258 | } 259 | } 260 | } 261 | 262 | // Sidebar Right 263 | // ------------------------- 264 | 265 | .fxp-sidebar-right { 266 | &.fxp-sidebar { 267 | &.fxp-sidebar-default { 268 | &.fxp-sidebar-open, 269 | &.fxp-sidebar-dragging { 270 | @include box-shadow(-3px 0 4px rgba(0, 0, 0, 0.18)); 271 | } 272 | } 273 | 274 | &.fxp-sidebar-inverse { 275 | &.fxp-sidebar-open, 276 | &.fxp-sidebar-dragging { 277 | @include box-shadow(-3px 0 4px rgba(0, 0, 0, 0.32)); 278 | } 279 | } 280 | } 281 | } 282 | 283 | // Responsive 284 | // ------------------------- 285 | 286 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-mobile-breakpoint) - 1)) { 287 | .fxp-sidebar { 288 | width: $sidebar-mobile-width; 289 | -webkit-transform: translate3d(-100%, 0px, 0px); 290 | transform: translate3d(-100%, 0px, 0px); 291 | } 292 | 293 | .fxp-sidebar-open + .fxp-sidebar-swipe, 294 | .fxp-sidebar-force-open.fxp-sidebar-open + .fxp-sidebar-swipe { 295 | left: $sidebar-mobile-width; 296 | } 297 | 298 | .fxp-sidebar-force-open { 299 | + .fxp-sidebar-swipe { 300 | left: 0; 301 | } 302 | } 303 | 304 | .fxp-sidebar-right { 305 | &.fxp-sidebar { 306 | width: $sidebar-right-mobile-width; 307 | -webkit-transform: translate3d(100%, 0px, 0px); 308 | transform: translate3d(100%, 0px, 0px); 309 | } 310 | 311 | &.fxp-sidebar-open + .fxp-sidebar-swipe { 312 | left: auto; 313 | right: $sidebar-right-mobile-width; 314 | } 315 | 316 | &.fxp-sidebar-force-open { 317 | + .fxp-sidebar-swipe { 318 | left: auto; 319 | right: 0; 320 | } 321 | } 322 | } 323 | } 324 | 325 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1)) { 326 | .fxp-sidebar-force-open { 327 | &.fxp-sidebar:not(.fxp-sidebar-open) + .fxp-sidebar-swipe { 328 | left: 0; 329 | } 330 | } 331 | } 332 | 333 | @media (min-width: ((map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1) + 1)) { 334 | .fxp-sidebar { 335 | &.fxp-sidebar-open-init { 336 | -webkit-transform: translate3d(0px, 0px, 0px); 337 | transform: translate3d(0px, 0px, 0px); 338 | } 339 | 340 | &.fxp-sidebar-mini:not(.fxp-sidebar-open) { 341 | -webkit-transform: translate3d((-$sidebar-width + $sidebar-mini-width), 0px, 0px); 342 | transform: translate3d((-$sidebar-width + $sidebar-mini-width), 0px, 0px); 343 | 344 | &.fxp-sidebar-right { 345 | -webkit-transform: translate3d(($sidebar-right-width - $sidebar-mini-width), 0px, 0px); 346 | transform: translate3d(($sidebar-right-width - $sidebar-mini-width), 0px, 0px); 347 | } 348 | } 349 | } 350 | 351 | .fxp-sidebar-force-open { 352 | &.fxp-sidebar.fxp-sidebar-default { 353 | &.fxp-sidebar-open, 354 | &.fxp-sidebar-dragging { 355 | @include box-shadow($sidebar-default-shadow-open-left); 356 | } 357 | } 358 | 359 | &.fxp-sidebar.fxp-sidebar-inverse { 360 | &.fxp-sidebar-open, 361 | &.fxp-sidebar-dragging { 362 | @include box-shadow($sidebar-inverse-shadow-open-left); 363 | } 364 | } 365 | } 366 | 367 | .fxp-sidebar-force-open.fxp-sidebar-right { 368 | &.fxp-sidebar.fxp-sidebar-default { 369 | &.fxp-sidebar-open, 370 | &.fxp-sidebar-dragging { 371 | @include box-shadow($sidebar-default-shadow-open-right); 372 | } 373 | } 374 | 375 | &.fxp-sidebar.fxp-sidebar-inverse { 376 | &.fxp-sidebar-open, 377 | &.fxp-sidebar-dragging { 378 | @include box-shadow($sidebar-inverse-shadow-open-right); 379 | } 380 | } 381 | } 382 | } 383 | 384 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1)) { 385 | .fxp-sidebar, 386 | .fxp-sidebar-swipe { 387 | top: 0 !important; 388 | bottom: 0 !important; 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /dist/sidebar.css: -------------------------------------------------------------------------------- 1 | .fxp-sidebar { 2 | position: fixed !important; 3 | top: 0; 4 | overflow: hidden; 5 | bottom: 0; 6 | z-index: 1032; 7 | width: 210px; 8 | cursor: default; 9 | -moz-user-select: none; 10 | user-select: none; 11 | border-left: none; 12 | border-right: 1px solid transparent; 13 | -webkit-transform: translate3d(-210px, 0px, 0px); 14 | transform: translate3d(-210px, 0px, 0px); 15 | } 16 | .fxp-sidebar.fxp-sidebar-ready { 17 | -webkit-transition: -webkit-transform 0.2s; 18 | transition: transform 0.2s; 19 | } 20 | .fxp-sidebar.fxp-sidebar-open { 21 | -webkit-transform: translate3d(0px, 0px, 0px); 22 | transform: translate3d(0px, 0px, 0px); 23 | } 24 | .fxp-sidebar .fxp-sidebar-menu { 25 | margin: 0; 26 | padding: 0; 27 | overflow-x: hidden; 28 | overflow-y: hidden; 29 | height: 100%; 30 | list-style: none; 31 | text-align: left; 32 | font-size: 1rem; 33 | direction: ltr; 34 | } 35 | .fxp-sidebar .fxp-sidebar-menu, .fxp-sidebar .fxp-sidebar-menu ul, .fxp-sidebar .fxp-sidebar-menu li, .fxp-sidebar .fxp-sidebar-menu span, .fxp-sidebar .fxp-sidebar-menu a { 36 | touch-action: pan-y; 37 | } 38 | .fxp-sidebar.fxp-sidebar-ready .fxp-sidebar-menu { 39 | overflow-y: auto; 40 | } 41 | .fxp-sidebar .fxp-sidebar-group-menu { 42 | padding: 0; 43 | margin: 0; 44 | } 45 | .fxp-sidebar .fxp-sidebar-group, 46 | .fxp-sidebar .fxp-sidebar-group-menu, 47 | .fxp-sidebar .fxp-sidebar-item { 48 | display: block; 49 | } 50 | .fxp-sidebar .fxp-sidebar-group > span, 51 | .fxp-sidebar .fxp-sidebar-item > a { 52 | display: block; 53 | height: 100%; 54 | padding: 12px 15px; 55 | text-decoration: none; 56 | position: relative; 57 | } 58 | .fxp-sidebar .fxp-sidebar-group > span:empty, 59 | .fxp-sidebar .fxp-sidebar-item > a:empty { 60 | padding: 0; 61 | } 62 | .fxp-sidebar .fxp-sidebar-item > a.active { 63 | border-left: 5px solid; 64 | padding: 12px 15px 12px 10px; 65 | } 66 | .fxp-sidebar .fxp-sidebar-item.fxp-sidebar-item-mini > a.active { 67 | padding-top: 12px; 68 | padding-bottom: 12px; 69 | } 70 | .fxp-sidebar .fxp-sidebar-item.fxp-sidebar-item-mini { 71 | font-size: 0.85em; 72 | } 73 | .fxp-sidebar .fxp-sidebar-item.fxp-sidebar-item-mini > a { 74 | padding-top: 12px; 75 | padding-bottom: 12px; 76 | } 77 | .fxp-sidebar .fxp-sidebar-group > span { 78 | font-size: 1.75rem; 79 | border-top: 1px solid transparent; 80 | } 81 | .fxp-sidebar .fxp-sidebar-group > span.no-bar { 82 | border-top: none; 83 | } 84 | .fxp-sidebar .fxp-sidebar-group.sticky-header { 85 | position: absolute; 86 | height: auto; 87 | top: 0; 88 | left: 0; 89 | right: 0; 90 | z-index: 1; 91 | margin-top: 0; 92 | } 93 | .fxp-sidebar .fxp-sidebar-group + .fxp-sidebar-item { 94 | margin-top: 32px; 95 | border-top: 1px solid transparent; 96 | } 97 | .fxp-sidebar .fxp-sidebar-divider-item { 98 | border-top: 1px solid transparent; 99 | } 100 | .fxp-sidebar .fxp-sidebar-item > a { 101 | cursor: pointer; 102 | } 103 | .fxp-sidebar[data-clickable-swipe=true] + .fxp-sidebar-swipe { 104 | cursor: pointer; 105 | -webkit-transition: background-color 0.3s ease; 106 | transition: background-color 0.3s ease; 107 | border-radius: 10px; 108 | } 109 | 110 | .fxp-sidebar-swipe { 111 | position: fixed; 112 | z-index: 1031; 113 | width: 10px; 114 | left: 0; 115 | top: 0; 116 | bottom: 0; 117 | background-color: #fff; 118 | opacity: 0.01; 119 | -moz-user-select: none; 120 | user-select: none; 121 | } 122 | .fxp-sidebar-disabled + .fxp-sidebar-swipe { 123 | display: none; 124 | } 125 | 126 | .fxp-sidebar-open + .fxp-sidebar-swipe, 127 | .fxp-sidebar-force-open + .fxp-sidebar-swipe { 128 | left: 210px; 129 | } 130 | 131 | .fxp-sidebar-obfuscator { 132 | position: fixed; 133 | display: block; 134 | z-index: -1; 135 | top: 0; 136 | bottom: 0; 137 | left: 0; 138 | right: 0; 139 | opacity: 0; 140 | -webkit-transition: "opacity 0.3s ease, z-index 0s linear 0.3s"; 141 | -o-transition: "opacity 0.3s ease, z-index 0s linear 0.3s"; 142 | transition: "opacity 0.3s ease, z-index 0s linear 0.3s"; 143 | } 144 | .fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 145 | -webkit-transition: "opacity 0.3s ease"; 146 | -o-transition: "opacity 0.3s ease"; 147 | transition: "opacity 0.3s ease"; 148 | z-index: 1031; 149 | opacity: 1; 150 | } 151 | @media (min-width: 992px) { 152 | .fxp-sidebar-force-open ~ .fxp-sidebar-obfuscator { 153 | z-index: -1; 154 | opacity: 0; 155 | } 156 | } 157 | 158 | .fxp-sidebar-right.fxp-sidebar { 159 | right: 0; 160 | border-right: none; 161 | border-left: 1px solid transparent; 162 | -webkit-transform: translate3d(210px, 0px, 0px); 163 | transform: translate3d(210px, 0px, 0px); 164 | } 165 | .fxp-sidebar-right.fxp-sidebar.fxp-sidebar-open { 166 | -webkit-transform: translate3d(0px, 0px, 0px); 167 | transform: translate3d(0px, 0px, 0px); 168 | } 169 | .fxp-sidebar-right.fxp-sidebar .fxp-sidebar-menu { 170 | direction: rtl; 171 | } 172 | .fxp-sidebar-right.fxp-sidebar .fxp-sidebar-item > a.active { 173 | border-left: inherit; 174 | border-right: 5px solid; 175 | padding: 12px 10px 12px 15px; 176 | } 177 | .fxp-sidebar-right.fxp-sidebar .fxp-sidebar-item.fxp-sidebar-item-mini > a.active { 178 | padding-top: 12px; 179 | padding-bottom: 12px; 180 | } 181 | .fxp-sidebar-right + .fxp-sidebar-swipe { 182 | left: auto; 183 | right: 0; 184 | } 185 | .fxp-sidebar-right.fxp-sidebar-open + .fxp-sidebar-swipe, .fxp-sidebar-right.fxp-sidebar-force-open + .fxp-sidebar-swipe { 186 | right: 210px; 187 | } 188 | 189 | .fxp-sidebar.fxp-sidebar-default.fxp-sidebar-open, .fxp-sidebar.fxp-sidebar-default.fxp-sidebar-dragging { 190 | -webkit-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.18); 191 | box-shadow: 3px 0 4px rgba(0, 0, 0, 0.18); 192 | } 193 | .fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-open, .fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-dragging { 194 | -webkit-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.32); 195 | box-shadow: 3px 0 4px rgba(0, 0, 0, 0.32); 196 | } 197 | 198 | .fxp-sidebar-right.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-open, .fxp-sidebar-right.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-dragging { 199 | -webkit-box-shadow: -3px 0 4px rgba(0, 0, 0, 0.18); 200 | box-shadow: -3px 0 4px rgba(0, 0, 0, 0.18); 201 | } 202 | .fxp-sidebar-right.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-open, .fxp-sidebar-right.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-dragging { 203 | -webkit-box-shadow: -3px 0 4px rgba(0, 0, 0, 0.32); 204 | box-shadow: -3px 0 4px rgba(0, 0, 0, 0.32); 205 | } 206 | 207 | @media (max-width: 767px) { 208 | .fxp-sidebar { 209 | width: 80%; 210 | -webkit-transform: translate3d(-100%, 0px, 0px); 211 | transform: translate3d(-100%, 0px, 0px); 212 | } 213 | 214 | .fxp-sidebar-open + .fxp-sidebar-swipe, 215 | .fxp-sidebar-force-open.fxp-sidebar-open + .fxp-sidebar-swipe { 216 | left: 80%; 217 | } 218 | 219 | .fxp-sidebar-force-open + .fxp-sidebar-swipe { 220 | left: 0; 221 | } 222 | 223 | .fxp-sidebar-right.fxp-sidebar { 224 | -webkit-transform: translate3d(100%, 0px, 0px); 225 | transform: translate3d(100%, 0px, 0px); 226 | } 227 | .fxp-sidebar-right.fxp-sidebar-open + .fxp-sidebar-swipe { 228 | left: auto; 229 | right: 80%; 230 | } 231 | .fxp-sidebar-right.fxp-sidebar-force-open + .fxp-sidebar-swipe { 232 | left: auto; 233 | right: 0; 234 | } 235 | } 236 | @media (max-width: 991px) { 237 | .fxp-sidebar-force-open.fxp-sidebar:not(.fxp-sidebar-open) + .fxp-sidebar-swipe { 238 | left: 0; 239 | } 240 | } 241 | @media (min-width: 992px) { 242 | .fxp-sidebar.fxp-sidebar-open-init { 243 | -webkit-transform: translate3d(0px, 0px, 0px); 244 | transform: translate3d(0px, 0px, 0px); 245 | } 246 | .fxp-sidebar.fxp-sidebar-mini:not(.fxp-sidebar-open) { 247 | -webkit-transform: translate3d(-140px, 0px, 0px); 248 | transform: translate3d(-140px, 0px, 0px); 249 | } 250 | .fxp-sidebar.fxp-sidebar-mini:not(.fxp-sidebar-open).fxp-sidebar-right { 251 | -webkit-transform: translate3d(140px, 0px, 0px); 252 | transform: translate3d(140px, 0px, 0px); 253 | } 254 | 255 | .fxp-sidebar-force-open.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-open, .fxp-sidebar-force-open.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-dragging { 256 | -webkit-box-shadow: none; 257 | box-shadow: none; 258 | } 259 | .fxp-sidebar-force-open.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-open, .fxp-sidebar-force-open.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-dragging { 260 | -webkit-box-shadow: none; 261 | box-shadow: none; 262 | } 263 | 264 | .fxp-sidebar-force-open.fxp-sidebar-right.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-open, .fxp-sidebar-force-open.fxp-sidebar-right.fxp-sidebar.fxp-sidebar-default.fxp-sidebar-dragging { 265 | -webkit-box-shadow: none; 266 | box-shadow: none; 267 | } 268 | .fxp-sidebar-force-open.fxp-sidebar-right.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-open, .fxp-sidebar-force-open.fxp-sidebar-right.fxp-sidebar.fxp-sidebar-inverse.fxp-sidebar-dragging { 269 | -webkit-box-shadow: none; 270 | box-shadow: none; 271 | } 272 | } 273 | @media (max-width: 991px) { 274 | .fxp-sidebar, 275 | .fxp-sidebar-swipe { 276 | top: 0 !important; 277 | bottom: 0 !important; 278 | } 279 | } 280 | .fxp-sidebar { 281 | -ms-touch-action: none; 282 | } 283 | 284 | .fxp-sidebar-swipe { 285 | -ms-touch-action: none; 286 | } 287 | 288 | .fxp-sidebar-menu, .fxp-sidebar-menu ul, .fxp-sidebar-menu li, .fxp-sidebar-menu span, .fxp-sidebar-menu a { 289 | -ms-touch-action: pan-y; 290 | } 291 | 292 | .fxp-sidebar.fxp-sidebar-default { 293 | color: #212529; 294 | background-color: #fff; 295 | } 296 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-group > span { 297 | color: #dbdbdb; 298 | border-top-color: #e9ecef; 299 | } 300 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-group.sticky-header > span { 301 | background-color: #fff; 302 | } 303 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-group + .fxp-sidebar-item { 304 | border-top-color: #e9ecef; 305 | } 306 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-divider-item { 307 | border-top-color: #e9ecef; 308 | } 309 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item > a { 310 | color: #212529; 311 | background-color: transprent; 312 | } 313 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item > a:hover, .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item > a:focus { 314 | background-color: #e9ecef; 315 | } 316 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item > a.active { 317 | color: #0d6efd; 318 | background-color: transprent; 319 | } 320 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item.fxp-sidebar-item-mini > a { 321 | color: #414951; 322 | } 323 | .fxp-sidebar.fxp-sidebar-default .fxp-sidebar-item.fxp-sidebar-item-mini > a.active { 324 | color: #0d6efd; 325 | background-color: transprent; 326 | } 327 | .fxp-sidebar.fxp-sidebar-default .hammer-scrollbar { 328 | background-color: #555; 329 | } 330 | .fxp-sidebar.fxp-sidebar-inverse { 331 | color: rgba(255, 255, 255, 0.55); 332 | background-color: #2a3542; 333 | } 334 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-group > span { 335 | color: #46586e; 336 | border-top-color: #344252; 337 | } 338 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-group.sticky-header > span { 339 | background-color: #2a3542; 340 | } 341 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-group + .fxp-sidebar-item { 342 | border-top-color: #344252; 343 | } 344 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-divider-item { 345 | border-top-color: #344252; 346 | } 347 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item > a { 348 | color: rgba(255, 255, 255, 0.55); 349 | background-color: #2a3542; 350 | } 351 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item > a:hover, .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item > a:focus { 352 | background-color: #344252; 353 | } 354 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item > a.active { 355 | color: #f6f9ff; 356 | background-color: #2a3542; 357 | } 358 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item.fxp-sidebar-item-mini > a { 359 | color: rgba(255, 255, 255, 0.55); 360 | } 361 | .fxp-sidebar.fxp-sidebar-inverse .fxp-sidebar-item.fxp-sidebar-item-mini > a.active { 362 | color: #f6f9ff; 363 | background-color: #2a3542; 364 | } 365 | .fxp-sidebar.fxp-sidebar-inverse .hammer-scrollbar { 366 | background-color: #e4e8ee; 367 | } 368 | .fxp-sidebar[data-clickable-swipe=true] + .fxp-sidebar-swipe.mouse-hover { 369 | background-color: fade(#0d6efd, 23%); 370 | } 371 | 372 | .fxp-sidebar-obfuscator.show { 373 | background-color: rgba(0, 0, 0, 0.5); 374 | } 375 | 376 | @media (min-width: 992px) { 377 | .fxp-sidebar.fxp-sidebar-locked.fxp-sidebar-default { 378 | border-color: #e9ecef; 379 | } 380 | .fxp-sidebar.fxp-sidebar-locked.fxp-sidebar-inverse { 381 | border-color: #344252; 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /scss/_wrapper.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Wrapper Bootstrap 3 | // -------------------------------------------------- 4 | 5 | .fxp-sidebar:not(.fxp-sidebar-full-locked) { 6 | &.fxp-sidebar-fixed-top, 7 | &.fxp-sidebar-fixed-bottom { 8 | z-index: $zindex-sidebar-fixed; 9 | 10 | + .fxp-sidebar-swipe { 11 | z-index: $zindex-sidebar-swipe-fixed; 12 | } 13 | 14 | &.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 15 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1)) { 16 | z-index: $zindex-sidebar-obfuscator-fixed; 17 | } 18 | } 19 | } 20 | } 21 | 22 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1)) { 23 | .fxp-sidebar:not(.fxp-sidebar-full-locked) { 24 | &.fxp-sidebar-fixed-top, 25 | &.fxp-sidebar-fixed-bottom { 26 | z-index: $zindex-sidebar; 27 | 28 | + .fxp-sidebar-swipe { 29 | z-index: $zindex-sidebar-swipe; 30 | } 31 | 32 | &.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 33 | z-index: $zindex-sidebar-obfuscator; 34 | } 35 | } 36 | } 37 | } 38 | 39 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 40 | .fxp-sidebar.fxp-sidebar-locked:not(.fxp-sidebar-full-locked) { 41 | &.fxp-sidebar-static-top, 42 | &.fxp-sidebar-static-bottom { 43 | z-index: $zindex-sidebar-static; 44 | 45 | + .fxp-sidebar-swipe { 46 | z-index: $zindex-sidebar-swipe-static; 47 | } 48 | 49 | &.fxp-sidebar-open ~ .fxp-sidebar-obfuscator { 50 | @media (max-width: (map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint) - 1)) { 51 | z-index: $zindex-sidebar-obfuscator-static; 52 | } 53 | } 54 | } 55 | 56 | &.fxp-sidebar-static-top { 57 | > .sticky-header { 58 | padding-top: $sidebar-navbar-height + 1 !important; 59 | } 60 | 61 | .fxp-sidebar-menu { 62 | > .fxp-sidebar-group:first-child, 63 | > .fxp-sidebar-item:first-child { 64 | padding-top: $sidebar-navbar-height + 1; 65 | } 66 | } 67 | } 68 | 69 | &.fxp-sidebar-static-bottom { 70 | .fxp-sidebar-menu { 71 | > .fxp-sidebar-group:last-child, 72 | > .fxp-sidebar-item:last-child { 73 | padding-bottom: $sidebar-navbar-height; 74 | } 75 | } 76 | } 77 | 78 | &.fxp-sidebar-fixed-top { 79 | top: $sidebar-navbar-height; 80 | } 81 | 82 | &.fxp-sidebar-fixed-bottom { 83 | bottom: $sidebar-navbar-height; 84 | } 85 | } 86 | 87 | .fxp-sidebar.fxp-sidebar-locked { 88 | ~ .fxp-sidebar-obfuscator { 89 | display: none; 90 | } 91 | } 92 | } 93 | 94 | // 95 | // Bootstrap Container Main 96 | // -------------------------------------------------- 97 | 98 | .container-main { 99 | &.container-force-open-left { 100 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 101 | padding-left: $sidebar-width; 102 | 103 | > .navbar:not(.fixed-top):not(.fixed-bottom):not(.sticky-top) { 104 | margin-left: -$sidebar-width; 105 | } 106 | } 107 | } 108 | 109 | &.container-force-open-right { 110 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 111 | padding-right: $sidebar-right-width; 112 | 113 | > .navbar:not(.fixed-top):not(.fixed-bottom):not(.sticky-top) { 114 | margin-right: -$sidebar-right-width; 115 | } 116 | } 117 | } 118 | 119 | &.container-force-open-left { 120 | > .container, 121 | > .navbar > .container { 122 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xs')) { 123 | width: map-get($sidebar-container-max-widths, 'xs') - $sidebar-width; 124 | } 125 | @media (min-width: map-get($sidebar-grid-breakpoints, 'sm')) { 126 | width: map-get($sidebar-container-max-widths, 'sm') - $sidebar-width; 127 | } 128 | @media (min-width: map-get($sidebar-grid-breakpoints, 'md')) { 129 | width: map-get($sidebar-container-max-widths, 'md') - $sidebar-width; 130 | } 131 | @media (min-width: map-get($sidebar-grid-breakpoints, 'lg')) { 132 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-width; 133 | } 134 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xl')) { 135 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-width; 136 | } 137 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xl') + $sidebar-width)) { 138 | width: map-get($sidebar-container-max-widths, 'lg'); 139 | } 140 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xxl')) { 141 | width: map-get($sidebar-container-max-widths, 'xl') - $sidebar-width; 142 | } 143 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xxl') + $sidebar-width)) { 144 | width: map-get($sidebar-container-max-widths, 'xl'); 145 | } 146 | } 147 | } 148 | 149 | &.container-force-open-right { 150 | > .container, 151 | > .navbar > .container { 152 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xs')) { 153 | width: map-get($sidebar-container-max-widths, 'xs') - $sidebar-right-width; 154 | } 155 | @media (min-width: map-get($sidebar-grid-breakpoints, 'sm')) { 156 | width: map-get($sidebar-container-max-widths, 'sm') - $sidebar-right-width; 157 | } 158 | @media (min-width: map-get($sidebar-grid-breakpoints, 'md')) { 159 | width: map-get($sidebar-container-max-widths, 'md') - $sidebar-right-width; 160 | } 161 | @media (min-width: map-get($sidebar-grid-breakpoints, 'lg')) { 162 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-right-width; 163 | } 164 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xl')) { 165 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-right-width; 166 | } 167 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xl') + $sidebar-right-width)) { 168 | width: map-get($sidebar-container-max-widths, 'lg'); 169 | } 170 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xxl')) { 171 | width: map-get($sidebar-container-max-widths, 'xl') - $sidebar-right-width; 172 | } 173 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xxl') + $sidebar-right-width)) { 174 | width: map-get($sidebar-container-max-widths, 'xl'); 175 | } 176 | } 177 | } 178 | 179 | &.container-full-locked { 180 | &.container-force-open-left { 181 | > .navbar > .container-fluid { 182 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 183 | padding-left: unquote('calc(#{$sidebar-width} + #{$sidebar-container-padding-x})'); 184 | } 185 | } 186 | } 187 | 188 | &.container-force-open-right { 189 | > .navbar > .container-fluid { 190 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 191 | padding-right: unquote('calc(#{$sidebar-right-width} + #{$sidebar-container-padding-x})'); 192 | } 193 | } 194 | } 195 | } 196 | 197 | &.container-force-open-left.container-force-open-right { 198 | > .container, 199 | > .navbar > .container { 200 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xs')) { 201 | width: map-get($sidebar-container-max-widths, 'xs') - ($sidebar-width + $sidebar-right-width); 202 | } 203 | @media (min-width: map-get($sidebar-grid-breakpoints, 'sm')) { 204 | width: map-get($sidebar-container-max-widths, 'sm') - ($sidebar-width + $sidebar-right-width); 205 | } 206 | @media (min-width: map-get($sidebar-grid-breakpoints, 'md')) { 207 | width: map-get($sidebar-container-max-widths, 'md') - ($sidebar-width + $sidebar-right-width); 208 | } 209 | @media (min-width: map-get($sidebar-grid-breakpoints, 'lg')) { 210 | width: map-get($sidebar-container-max-widths, 'lg') - ($sidebar-width + $sidebar-right-width); 211 | } 212 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xl')) { 213 | width: map-get($sidebar-container-max-widths, 'lg') - ($sidebar-width + $sidebar-right-width); 214 | } 215 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xl') + $sidebar-width)) { 216 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-width; 217 | } 218 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xl') + ($sidebar-width + $sidebar-right-width))) { 219 | width: map-get($sidebar-container-max-widths, 'lg'); 220 | } 221 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xxl')) { 222 | width: map-get($sidebar-container-max-widths, 'xl') - ($sidebar-width + $sidebar-right-width); 223 | } 224 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xxl') + $sidebar-width)) { 225 | width: map-get($sidebar-container-max-widths, 'xl') - $sidebar-width; 226 | } 227 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xxl') + ($sidebar-width + $sidebar-right-width))) { 228 | width: map-get($sidebar-container-max-widths, 'xl'); 229 | } 230 | } 231 | } 232 | 233 | &.container-mini-left { 234 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 235 | padding-left: $sidebar-mini-width; 236 | } 237 | 238 | > .navbar > .container-fluid { 239 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 240 | padding-left: unquote('calc(#{$sidebar-mini-width} + #{$sidebar-container-padding-x})'); 241 | } 242 | } 243 | } 244 | 245 | &.container-mini-right { 246 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 247 | padding-right: $sidebar-mini-width; 248 | } 249 | 250 | > .navbar > .container-fluid { 251 | @media (min-width: map-get($sidebar-grid-breakpoints, $sidebar-force-open-breakpoint)) { 252 | padding-right: unquote('calc(#{$sidebar-mini-width} + #{$sidebar-container-padding-x})'); 253 | } 254 | } 255 | } 256 | 257 | &.container-mini-left, 258 | &.container-mini-right { 259 | > .container, 260 | > .navbar > .container { 261 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xs')) { 262 | width: map-get($sidebar-container-max-widths, 'xs') - $sidebar-mini-width; 263 | } 264 | @media (min-width: map-get($sidebar-grid-breakpoints, 'sm')) { 265 | width: map-get($sidebar-container-max-widths, 'sm') - $sidebar-mini-width; 266 | } 267 | @media (min-width: map-get($sidebar-grid-breakpoints, 'md')) { 268 | width: map-get($sidebar-container-max-widths, 'md') - $sidebar-mini-width; 269 | } 270 | @media (min-width: map-get($sidebar-grid-breakpoints, 'lg')) { 271 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-mini-width; 272 | } 273 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xl')) { 274 | width: map-get($sidebar-container-max-widths, 'lg') - $sidebar-mini-width; 275 | } 276 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xl') + $sidebar-mini-width)) { 277 | width: map-get($sidebar-container-max-widths, 'lg'); 278 | } 279 | @media (min-width: map-get($sidebar-grid-breakpoints, 'xxl')) { 280 | width: map-get($sidebar-container-max-widths, 'xl') - $sidebar-mini-width; 281 | } 282 | @media (min-width: (map-get($sidebar-grid-breakpoints, 'xxl') + $sidebar-mini-width)) { 283 | width: map-get($sidebar-container-max-widths, 'xl'); 284 | } 285 | } 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /dist/sidebar.min.js: -------------------------------------------------------------------------------- 1 | var FxpSidebar=function(e,d){"use strict";function p(e){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,o){if(!(e instanceof o))throw new TypeError("Cannot call a class as a function")}function n(e,o){for(var t=0;to.innerHeight()&&(t+=e.nativeScrollWidth),e.options.minLockWidth<=t}function O(e){var o,t,n,s,s=(t=(o=e).options.storageLockedKey,s=void 0===n?null:n,(n=null)!==(n=o.options.saveConfig&&"localStorage"in window?window.localStorage.getItem(o.$element.prop("id")+"/"+t):n)?n:s);null!==s&&e.options.toggleOnClick&&(e.options.locked="true"===s,e.options.locked||(y(e.$element,"none"),e.forceClose()))}function k(e,o){for(var t=["webkit","moz","ms","o",""],n="",s=0;s<5;s++)t[s]||(e=e.toLowerCase()),n+=" "+t[s]+e,void 0!==o&&(n+="."+o);return n}function w(e,o,t){d.event.trigger({type:"sidebar:"+e+".fxp.sidebar",sidebar:o,eventData:t,time:new Date})}var C=null;function x(){var e,o=document.createElement("div");return o.style.width="100px",o.style.height="100px",o.style.overflow="scroll",o.style.position="absolute",o.style.top="-9999px",document.body.appendChild(o),e=o.offsetWidth-o.clientWidth,document.body.removeChild(o),e}function S(e){var o=parseInt(e.$body.css("padding-right")||0,10);e.$body.get(0).scrollHeight>document.documentElement.clientHeight&&"hidden"!==e.$body.css("overflow-y")&&(e.originalBodyPad=document.body.style.paddingRight||"",e.originalBodyOverflowY=document.body.style.overflowY||"",e.$body.css({"padding-right":o+e.nativeScrollWidth+"px","overflow-y":"hidden"}),w("lock-body-scroll",e,e.nativeScrollWidth))}function D(e){null===e.originalBodyPad&&null===e.originalBodyOverflowY||(e.$body.css({"padding-right":e.originalBodyPad,"overflow-y":e.originalBodyOverflowY}),e.originalBodyPad=null,e.originalBodyOverflowY=null,w("unlock-body-scroll",e,e.nativeScrollWidth))}function T(e){var o=e.data;o.resetScrolling=window.setTimeout(function(){o.resetScrolling=null},1e3*o.options.resetScrollDelay)}function L(e){var o=e.data,t=!1,n=v(o);y(o.$element,"none"),n&&o.isLocked()&&(o.forceOpen(),D(o),t=!0),void 0===o.resizeDelay&&(o.resizeDelay=window.setTimeout(function(){delete o.resizeDelay,y(o.$element,""),!t&&o.isLocked()&&(!n&&o.isOpen()?S:D)(o)},500))}function E(e){var o,t;e instanceof jQuery.Event&&(e.data.options.disabledKeyboard||e.shiftKey===(t=(o=e.data).options.keyboardEvent).shiftKey&&e.ctrlKey===t.ctrlKey&&e.altKey===t.altKey&&e.keyCode===t.keyCode&&o.toggle(e))}function P(e){var o=e.data;e.stopPropagation(),e.preventDefault(),v(o)?o.close():o.forceClose()}function I(e){var o=e.data;0'),o.$element.after(o.$swipe),o.hammer=new Hammer(o.$wrapper.get(0),$.extend(!0,{},o.options.hammer)),o.hammer.get("swipe").set({enable:!1}),o.hammer.get("tap").set({enable:!1}),o.hammer.on("panstart",function(e){j(o,e)}),o.hammer.on("pan",function(e){j(o,e)}),o.hammer.on("panend",function(e){!function(e,o){var t=Hammer.DIRECTION_LEFT,n=Hammer.DIRECTION_RIGHT;if(null===e.resetScrolling&&o.target!==e.$obfuscator.get(0)){if(e.dragStartPosition=null,o.preventDefault(),e.fixDragClick&&-1!==$.inArray(o.srcEvent.type,["pointerup","mouseup"])&&(e.mouseDragEnd=!0),e.$element.removeClass(e.options.classOnDragging),e.$element.css("user-select",""),y(e.$element,""),b(e.$element,""),Math.abs(o.deltaX)<=e.$element.innerWidth()/4)return e.dragDirection=null,e.$toggles.focus();g===e.getPosition()&&(t=Hammer.DIRECTION_RIGHT,n=Hammer.DIRECTION_LEFT),e.isOpen()&&t===e.dragDirection?e.forceClose():n===e.dragDirection&&(e.mouseDragEnd=null,e.isOpen()&&v(e)&&0<=$.inArray(e.options.forceToggle,[h,m])||v(e)&&m===e.options.forceToggle?e.forceOpen():e.open()),e.dragDirection=null}}(o,e)}),o.$wrapper.on("mousedown.fxp.sidebar",null,o,Y),o.$wrapper.on("click.fxp.sidebar",null,o,A),o.options.clickableSwipe&&o.$swipe.on("click.fxp.sidebar"+o.guid,null,o,M).on("mouseenter.fxp.sidebar"+o.guid,null,o,B).on("mouseleave.fxp.sidebar"+o.guid,null,o,z))}function M(e){z(e),e.data.toggle(e)}function B(e){e.data.$swipe.addClass("mouse-hover")}function z(e){e.data.$swipe.removeClass("mouse-hover")}function Y(e){e.preventDefault()}function A(e){var o=e.data;!0===o.mouseDragEnd&&(e.preventDefault(),F(o),o.mouseDragEnd=null)}var N=function(){!function(e,o){if("function"!=typeof o&&null!==o)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(o&&o.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),o&&t(e,o)}(s,u);var n=a(s);function s(e){var o=1'),e.$container=d("> ."+e.options.classContainer,e.$element.parent()),e.$swipe=null,e.$obfuscator=d('
'),e.$body=d("body"),e.enabled=!e.$element.hasClass("fxp-sidebar-disabled"),e.mini=e.$element.hasClass("fxp-sidebar-mini"),e.fullLocked=e.$element.hasClass(e.options.classFullLocked),e.hammer=null,e.dragStartPosition=null,e.mouseDragEnd=null,e.dragDirection=null,e.closeDelay=null,e.resetScrolling=null,e.originalBodyPad=null,e.originalBodyOverflowY=null,e.fixDragClick=!!~o.indexOf("firefox")||!!~o.indexOf("edge")||!!~o.indexOf("msie"),e.$element.before(e.$wrapper),e.$wrapper.append(e.$element),e.$wrapper.append(e.$obfuscator),e.$element.attr("data-sidebar","true"),null!==e.options.toggleId&&e.attachToggle("#"+e.options.toggleId),void 0!==e.options.scrollerStickyHeader&&(e.options.scroller.scrollerStickyHeader=e.options.scrollerStickyHeader,delete e.options.scrollerStickyHeader),void 0!==e.options.scrollerScrollbar&&(e.options.scroller.scrollbar=e.options.scrollerScrollbar,delete e.options.scrollerScrollbar),e.$element.hasClass(e.options.classLocked)&&(e.options.locked=!0),g!==e.options.position?e.options.position=f:e.$element.addClass("fxp-sidebar-right"),e.$element.hasClass("fxp-sidebar-right")&&(e.options.position=g),e.options.position===g&&(e.options.keyboardEvent.shiftKey=!0),e.enabled||e.$element.removeClass(e.options.classLocked).removeClass(e.options.classForceOpen).removeClass(e.options.classOpen).removeClass(e.options.classOpen+"-init"),e.options.locked&&(e.options.forceToggle=m,y(e.$element,"none"),e.enabled&&(e.$element.addClass(e.options.classLocked).addClass(e.options.classForceOpen).addClass(e.options.classOpen+"-init"),e.$container.addClass("container-force-open-"+e.options.position))),e.mini&&e.$container.addClass("container-mini-"+e.options.position),e.fullLocked&&e.$container.addClass("container-full-locked"),o=v(r(e)),d(window).on("keyup.fxp.sidebar"+e.guid,null,r(e),E),d(window).on("resize.fxp.sidebar"+e.guid,null,r(e),L),e.$element.hasClass(e.options.classOpen+"-init")&&(o?e.$element.addClass(e.options.classOpen):e.$element.removeClass(e.options.classOpen).removeClass(e.options.classForceOpen),e.$element.removeClass(e.options.classOpen+"-init")),(e.$element.hasClass(e.options.classOpen)&&!o?S:D)(r(e)),e.options.closeOnSelect&&e.$element.on(e.eventType+".fxp.sidebar"+e.guid,e.options.itemSelector,r(e),I),e.$element.on(k("TransitionEnd",".fxp.sidebar"+e.guid),null,r(e),W),e.$obfuscator.on(e.eventType+".fxp.sidebar"+e.guid,null,r(e),P),o=r(e),$.fn.scroller&&o.options.useScroller&&(o.$element.scroller($.extend({},{scrollbarInverse:g===o.options.position},o.options.scroller)),o.$element.on("scrolling.fxp.scroller.fxp.sidebar",null,o,T)),_(r(e)),O(r(e)),window.setTimeout(function(){y(t.$element,""),t.$element.addClass("fxp-sidebar-ready"),w("ready",t)},0),e}return o(s,[{key:"getPosition",value:function(){return this.options.position}},{key:"isLocked",value:function(){return this.options.locked}},{key:"isOpen",value:function(){return this.$element.hasClass(this.options.classOpen)}},{key:"isFullyOpened",value:function(){return this.$element.hasClass(this.options.classForceOpen)}},{key:"isClosable",value:function(){return this.enabled&&this.isOpen()&&!v(this)}},{key:"forceOpen",value:function(){!this.enabled||this.isOpen()&&this.isFullyOpened()||(F(this),this.$element.addClass(this.options.classForceOpen),this.$container.addClass("container-force-open-"+this.options.position),R(this,this.options.classForceOpen+"-toggle"),w("force-open",this),this.open())}},{key:"forceClose",value:function(){!this.enabled||!this.isOpen()||this.isLocked()&&v(this)||(F(this),K(this,this.options.classForceOpen+"-toggle"),this.$container.removeClass("container-force-open-"+this.options.position),this.$element.removeClass(this.options.classForceOpen),w("force-close",this),this.close())}},{key:"open",value:function(){this.enabled&&!this.isOpen()&&(w("open",this),F(this),d("[data-sidebar=true]").sidebar("forceClose"),this.$element.addClass(this.options.classOpen))}},{key:"close",value:function(){!this.enabled||!this.isOpen()||this.isFullyOpened()&&v(this)||(w("close",this),F(this),this.$element.removeClass(this.options.classOpen))}},{key:"toggle",value:function(e){var o=void 0!==e?e.data:this;o.enabled&&(void 0!==e&&(e.stopPropagation(),e.preventDefault()),w("toggle",this),o.options.toggleOnClick&&(o.options.locked=!o.options.locked,function(e,o,t){if(e.options.saveConfig&&"localStorage"in window)try{window.localStorage.setItem(e.$element.prop("id")+"/"+o,t)}catch(e){}}(o,o.options.storageLockedKey,o.options.locked)),o.isOpen()?o.isFullyOpened()?o.forceClose():v(o)&&0<=d.inArray(o.options.forceToggle,[h,m])?o.forceOpen():o.close():v(o)&&m===o.options.forceToggle?o.forceOpen():o.open())}},{key:"refresh",value:function(){w("refresh",this),d.fn.scroller&&this.options.useScroller&&this.$element.scroller("refresh")}},{key:"attachToggle",value:function(e){e=d(e),this.enabled||e.addClass("disabled"),this.isLocked()?e.addClass(this.options.classLocked+"-toggle"):e.removeClass(this.options.classLocked+"-toggle"),this.isFullyOpened()?e.addClass(this.options.classForceOpen+"-toggle"):e.removeClass(this.options.classForceOpen+"-toggle"),this.isOpen()?e.addClass(this.options.classOpen+"-toggle"):e.removeClass(this.options.classOpen+"-toggle"),e.on(this.eventType+".fxp.sidebar"+this.guid,null,this,this.toggle),0!==(C=null===C?x():C)&&this.options.toggleOpenOnHover&&e.on("mouseover.fxp.sidebar"+this.guid,d.proxy(this.open,this)),this.$toggles.push(e)}},{key:"detachToggle",value:function(e){var o,t=this.$toggles.length;for(e=d(e),o=0;o .fxp-sidebar-menu > .fxp-sidebar-group > span"}},hammer:{},disabledKeyboard:!1,keyboardEvent:{ctrlKey:!0,shiftKey:!1,altKey:!0,keyCode:83}},function(o,r,a,e,t,n){var e=3 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import pluginify from '@fxp/jquery-pluginify'; 11 | import BasePlugin from '@fxp/jquery-pluginify/js/plugin'; 12 | import $ from 'jquery'; 13 | import {FORCE_TOGGLE, FORCE_TOGGLE_ALWAYS, FORCE_TOGGLE_NO, POSITION_LEFT, POSITION_RIGHT} from "./utils/const"; 14 | import {changeTransition, isOverMinWidth} from "./utils/css"; 15 | import {initWithLocalStorage, setLocalStorage} from "./utils/storage"; 16 | import {onResizeWindow} from "./utils/window"; 17 | import {prefixedEvent, triggerEvent} from "./utils/events"; 18 | import {keyboardAction, closeExternal, closeOnSelect, cleanCloseDelay} from "./utils/actions"; 19 | import {destroyHammer, initHammer, onEndTransition} from "./utils/touch"; 20 | import {addClassToggles, removeClassToggles, doDetachToggle} from "./utils/toggle"; 21 | import { 22 | getNativeScrollWidth, 23 | mobileCheck, 24 | initScroller, 25 | destroyScroller, 26 | lockBodyScroll, 27 | unlockBodyScroll 28 | } from "./utils/scrollbar"; 29 | 30 | /** 31 | * Sidebar class. 32 | */ 33 | export default class Sidebar extends BasePlugin 34 | { 35 | /** 36 | * Constructor. 37 | * 38 | * @param {HTMLElement} element The DOM element 39 | * @param {object} options The options 40 | */ 41 | constructor(element, options = {}) { 42 | super(element, options); 43 | 44 | let self = this, 45 | isOver, 46 | ua = navigator.userAgent.toLowerCase(); 47 | 48 | this.eventType = 'click'; 49 | this.nativeScrollWidth = getNativeScrollWidth(); 50 | this.$toggles = $([]); 51 | this.$wrapper = $('
'); 52 | this.$container = $('> .' + this.options.classContainer, this.$element.parent()); 53 | this.$swipe = null; 54 | this.$obfuscator = $('
'); 55 | this.$body = $('body'); 56 | this.enabled = !this.$element.hasClass('fxp-sidebar-disabled'); 57 | this.mini = this.$element.hasClass('fxp-sidebar-mini'); 58 | this.fullLocked = this.$element.hasClass(this.options.classFullLocked); 59 | this.hammer = null; 60 | this.dragStartPosition = null; 61 | this.mouseDragEnd = null; 62 | this.dragDirection = null; 63 | this.closeDelay = null; 64 | this.resetScrolling = null; 65 | this.originalBodyPad = null; 66 | this.originalBodyOverflowY = null; 67 | this.fixDragClick = ua.indexOf('firefox') > -1 || ua.indexOf('edge') > -1 || ua.indexOf('msie') > -1; 68 | 69 | this.$element.before(this.$wrapper); 70 | this.$wrapper.append(this.$element); 71 | this.$wrapper.append(this.$obfuscator); 72 | this.$element.attr('data-sidebar', 'true'); 73 | 74 | if (null !== this.options.toggleId) { 75 | this.attachToggle('#' + this.options.toggleId); 76 | } 77 | 78 | if (undefined !== this.options.scrollerStickyHeader) { 79 | this.options.scroller.scrollerStickyHeader = this.options.scrollerStickyHeader; 80 | delete this.options.scrollerStickyHeader; 81 | } 82 | 83 | if (undefined !== this.options.scrollerScrollbar) { 84 | this.options.scroller.scrollbar = this.options.scrollerScrollbar; 85 | delete this.options.scrollerScrollbar; 86 | } 87 | 88 | if (this.$element.hasClass(this.options.classLocked)) { 89 | this.options.locked = true; 90 | } 91 | 92 | if (POSITION_RIGHT !== this.options.position) { 93 | this.options.position = POSITION_LEFT; 94 | 95 | } else { 96 | this.$element.addClass('fxp-sidebar-right'); 97 | } 98 | 99 | if (this.$element.hasClass('fxp-sidebar-right')) { 100 | this.options.position = POSITION_RIGHT; 101 | } 102 | 103 | if (this.options.position === POSITION_RIGHT) { 104 | this.options.keyboardEvent.shiftKey = true; 105 | } 106 | 107 | if (!this.enabled) { 108 | this.$element 109 | .removeClass(this.options.classLocked) 110 | .removeClass(this.options.classForceOpen) 111 | .removeClass(this.options.classOpen) 112 | .removeClass(this.options.classOpen + '-init'); 113 | } 114 | 115 | if (this.options.locked) { 116 | this.options.forceToggle = FORCE_TOGGLE_ALWAYS; 117 | changeTransition(this.$element, 'none'); 118 | 119 | if (this.enabled) { 120 | this.$element 121 | .addClass(this.options.classLocked) 122 | .addClass(this.options.classForceOpen) 123 | .addClass(this.options.classOpen + '-init'); 124 | 125 | this.$container.addClass('container-force-open-' + this.options.position); 126 | } 127 | } 128 | 129 | if (this.mini) { 130 | this.$container.addClass('container-mini-' + this.options.position); 131 | } 132 | 133 | if (this.fullLocked) { 134 | this.$container.addClass('container-full-locked'); 135 | } 136 | 137 | isOver = isOverMinWidth(this); 138 | 139 | $(window).on('keyup.fxp.sidebar' + this.guid, null, this, keyboardAction); 140 | $(window).on('resize.fxp.sidebar' + this.guid, null, this, onResizeWindow); 141 | 142 | if (this.$element.hasClass(this.options.classOpen + '-init')) { 143 | if (isOver) { 144 | this.$element.addClass(this.options.classOpen); 145 | 146 | } else { 147 | this.$element 148 | .removeClass(this.options.classOpen) 149 | .removeClass(this.options.classForceOpen) 150 | ; 151 | } 152 | 153 | this.$element.removeClass(this.options.classOpen + '-init'); 154 | } 155 | 156 | if (this.$element.hasClass(this.options.classOpen) && !isOver) { 157 | lockBodyScroll(this); 158 | } else { 159 | unlockBodyScroll(this); 160 | } 161 | 162 | if (this.options.closeOnSelect) { 163 | this.$element.on(this.eventType + '.fxp.sidebar' + this.guid, this.options.itemSelector, this, closeOnSelect); 164 | } 165 | 166 | this.$element.on(prefixedEvent('TransitionEnd', '.fxp.sidebar' + this.guid), null, this, onEndTransition); 167 | this.$obfuscator.on(this.eventType + '.fxp.sidebar' + this.guid, null, this, closeExternal); 168 | 169 | initScroller(this); 170 | initHammer(this); 171 | initWithLocalStorage(this); 172 | 173 | window.setTimeout(function () { 174 | changeTransition(self.$element, ''); 175 | self.$element.addClass('fxp-sidebar-ready'); 176 | triggerEvent('ready', self); 177 | }, 0); 178 | } 179 | 180 | /** 181 | * Get sidebar position. 182 | * 183 | * @returns {string} The position (left or right) 184 | */ 185 | getPosition() { 186 | return this.options.position; 187 | } 188 | 189 | /** 190 | * Checks if sidebar is locked (always open). 191 | * 192 | * @returns {boolean} 193 | */ 194 | isLocked() { 195 | return this.options.locked; 196 | } 197 | 198 | /** 199 | * Checks if sidebar is locked (always open). 200 | * 201 | * @returns {boolean} 202 | */ 203 | isOpen() { 204 | return this.$element.hasClass(this.options.classOpen); 205 | } 206 | 207 | /** 208 | * Checks if sidebar is fully opened. 209 | * 210 | * @return {boolean} 211 | */ 212 | isFullyOpened() { 213 | return this.$element.hasClass(this.options.classForceOpen); 214 | } 215 | 216 | /** 217 | * Checks if sidebar is closable. 218 | * 219 | * @return {boolean} 220 | */ 221 | isClosable() { 222 | return this.enabled && this.isOpen() && !isOverMinWidth(this); 223 | } 224 | 225 | /** 226 | * Force open the sidebar. 227 | */ 228 | forceOpen() { 229 | if (!this.enabled || (this.isOpen() && this.isFullyOpened())) { 230 | return; 231 | } 232 | 233 | cleanCloseDelay(this); 234 | this.$element.addClass(this.options.classForceOpen); 235 | this.$container.addClass('container-force-open-' + this.options.position); 236 | addClassToggles(this, this.options.classForceOpen + '-toggle'); 237 | 238 | triggerEvent('force-open', this); 239 | this.open(); 240 | } 241 | 242 | /** 243 | * Force close the sidebar. 244 | */ 245 | forceClose() { 246 | if (!this.enabled || !this.isOpen() || (this.isLocked() && isOverMinWidth(this))) { 247 | return; 248 | } 249 | 250 | cleanCloseDelay(this); 251 | removeClassToggles(this, this.options.classForceOpen + '-toggle'); 252 | this.$container.removeClass('container-force-open-' + this.options.position); 253 | this.$element.removeClass(this.options.classForceOpen); 254 | 255 | triggerEvent('force-close', this); 256 | this.close(); 257 | } 258 | 259 | /** 260 | * Open the sidebar. 261 | */ 262 | open() { 263 | if (!this.enabled || this.isOpen()) { 264 | return; 265 | } 266 | 267 | triggerEvent('open', this); 268 | cleanCloseDelay(this); 269 | $('[data-sidebar=true]').sidebar('forceClose'); 270 | this.$element.addClass(this.options.classOpen); 271 | } 272 | 273 | /** 274 | * Close open the sidebar. 275 | * 276 | * @this Sidebar 277 | */ 278 | close() { 279 | if (!this.enabled || !this.isOpen() || (this.isFullyOpened() && isOverMinWidth(this))) { 280 | return; 281 | } 282 | 283 | triggerEvent('close', this); 284 | cleanCloseDelay(this); 285 | this.$element.removeClass(this.options.classOpen); 286 | } 287 | 288 | /** 289 | * Toggle the sidebar ("close, "open", "force open"). 290 | * 291 | * @param {jQuery.Event|Event} [event] 292 | * 293 | * @typedef {Sidebar} Event.data The sidebar instance 294 | */ 295 | toggle(event) { 296 | let self = (undefined !== event) ? event.data : this; 297 | 298 | if (!self.enabled) { 299 | return; 300 | } 301 | 302 | if (undefined !== event) { 303 | event.stopPropagation(); 304 | event.preventDefault(); 305 | } 306 | 307 | triggerEvent('toggle', this); 308 | 309 | if (self.options.toggleOnClick) { 310 | self.options.locked = !self.options.locked; 311 | setLocalStorage(self, self.options.storageLockedKey, self.options.locked); 312 | } 313 | 314 | if (self.isOpen()) { 315 | if (self.isFullyOpened()) { 316 | self.forceClose(); 317 | 318 | } else if (isOverMinWidth(self) && $.inArray(self.options.forceToggle, [FORCE_TOGGLE, FORCE_TOGGLE_ALWAYS]) >= 0) { 319 | self.forceOpen(); 320 | 321 | } else { 322 | self.close(); 323 | } 324 | 325 | } else if (isOverMinWidth(self) && FORCE_TOGGLE_ALWAYS === self.options.forceToggle) { 326 | self.forceOpen(); 327 | 328 | } else { 329 | self.open(); 330 | } 331 | } 332 | 333 | /** 334 | * Refresh the scroller. 335 | */ 336 | refresh() { 337 | triggerEvent('refresh', this); 338 | 339 | if ($.fn.scroller && this.options.useScroller) { 340 | this.$element.scroller('refresh'); 341 | } 342 | } 343 | 344 | /** 345 | * Attach a toggle button. 346 | * 347 | * @param {string|HTMLElement|object|jQuery} $toggle 348 | */ 349 | attachToggle($toggle) { 350 | $toggle = $($toggle); 351 | 352 | if (!this.enabled) { 353 | $toggle.addClass('disabled'); 354 | } 355 | 356 | if (this.isLocked()) { 357 | $toggle.addClass(this.options.classLocked + '-toggle'); 358 | } else { 359 | $toggle.removeClass(this.options.classLocked + '-toggle'); 360 | } 361 | 362 | if (this.isFullyOpened()) { 363 | $toggle.addClass(this.options.classForceOpen + '-toggle'); 364 | } else { 365 | $toggle.removeClass(this.options.classForceOpen + '-toggle'); 366 | } 367 | 368 | if (this.isOpen()) { 369 | $toggle.addClass(this.options.classOpen + '-toggle'); 370 | } else { 371 | $toggle.removeClass(this.options.classOpen + '-toggle'); 372 | } 373 | 374 | $toggle.on(this.eventType + '.fxp.sidebar' + this.guid, null, this, this.toggle); 375 | 376 | if (!mobileCheck() && this.options.toggleOpenOnHover) { 377 | $toggle.on('mouseover.fxp.sidebar' + this.guid, $.proxy(this.open, this)); 378 | } 379 | 380 | this.$toggles.push($toggle); 381 | } 382 | 383 | /** 384 | * Detach a toggle button. 385 | * 386 | * @param {string|HTMLElement|object|jQuery} $toggle 387 | */ 388 | detachToggle($toggle) { 389 | let size = this.$toggles.length, 390 | i; 391 | 392 | $toggle = $($toggle); 393 | 394 | for (i = 0; i < size; ++i) { 395 | if (this.$toggles[i][0] === $toggle[0]) { 396 | doDetachToggle(this, this.$toggles[i]); 397 | this.$toggles.splice(i, 1); 398 | break; 399 | } 400 | } 401 | } 402 | 403 | /** 404 | * Detach a toggle button. 405 | */ 406 | detachToggles() { 407 | let size = this.$toggles.length, 408 | i; 409 | 410 | for (i = 0; i < size; ++i) { 411 | doDetachToggle(this, this.$toggles[i]); 412 | } 413 | 414 | this.$toggles.splice(0, size); 415 | } 416 | 417 | /** 418 | * Checks if sidebar is enabled. 419 | * 420 | * @returns {boolean} 421 | */ 422 | isEnabled() { 423 | return this.enabled; 424 | } 425 | 426 | /** 427 | * Disable the sidebar. 428 | */ 429 | disable() { 430 | let prevIsLocked = this.isLocked(); 431 | 432 | if (!this.enabled) { 433 | return; 434 | } 435 | 436 | triggerEvent('disable', this); 437 | this.options.locked = false; 438 | this.forceClose(); 439 | this.options.locked = prevIsLocked; 440 | this.$element.addClass('fxp-sidebar-disabled'); 441 | addClassToggles(this, 'disabled'); 442 | 443 | if (this.isLocked()) { 444 | addClassToggles(this, this.options.classLocked + '-toggle-disabled'); 445 | } 446 | 447 | this.enabled = false; 448 | } 449 | 450 | /** 451 | * Enable the sidebar. 452 | */ 453 | enable() { 454 | if (this.enabled) { 455 | return; 456 | } 457 | 458 | triggerEvent('enable', this); 459 | this.enabled = true; 460 | this.$element.removeClass('fxp-sidebar-disabled'); 461 | 462 | if (isOverMinWidth(this) && FORCE_TOGGLE_ALWAYS === this.options.forceToggle) { 463 | this.forceOpen(); 464 | } 465 | 466 | removeClassToggles(this, 'disabled'); 467 | 468 | if (this.isLocked()) { 469 | removeClassToggles(this, this.options.classLocked + '-toggle-disabled'); 470 | } 471 | } 472 | 473 | /** 474 | * Destroy the instance. 475 | */ 476 | destroy() { 477 | cleanCloseDelay(this); 478 | this.detachToggles(); 479 | this.forceClose(); 480 | this.$container.removeClass('container-mini-' + this.options.position); 481 | this.$container.removeClass('container-full-locked'); 482 | $(window).off('keyup.fxp.sidebar' + this.guid, keyboardAction); 483 | $(window).off('resize.fxp.sidebar' + this.guid, onResizeWindow); 484 | this.$element.off(this.eventType + '.fxp.sidebar' + this.guid, this.options.itemSelector, closeOnSelect); 485 | this.$element.off(prefixedEvent('TransitionEnd', '.fxp.sidebar' + this.guid), onEndTransition); 486 | this.$obfuscator.off(this.eventType + '.fxp.sidebar' + this.guid, closeExternal); 487 | 488 | destroyHammer(this); 489 | destroyScroller(this); 490 | unlockBodyScroll(this); 491 | 492 | this.$wrapper.before(this.$element); 493 | this.$wrapper.remove(); 494 | 495 | this.$element.removeClass('fxp-sidebar-ready'); 496 | 497 | super.destroy(); 498 | } 499 | } 500 | 501 | 502 | 503 | /** 504 | * Defaults options. 505 | */ 506 | Sidebar.defaultOptions = { 507 | classWrapper: 'fxp-sidebar-wrapper', 508 | classContainer: 'container-main', 509 | classOpen: 'fxp-sidebar-open', 510 | classLocked: 'fxp-sidebar-locked', 511 | classFullLocked: 'fxp-sidebar-full-locked', 512 | classForceOpen: 'fxp-sidebar-force-open', 513 | classOnDragging: 'fxp-sidebar-dragging', 514 | classObfuscator: 'fxp-sidebar-obfuscator', 515 | forceToggle: FORCE_TOGGLE_NO, 516 | locked: false, 517 | position: POSITION_LEFT, 518 | minLockWidth: 992, 519 | toggleId: null, 520 | toggleOpenOnHover: false, 521 | toggleOnClick: false, 522 | saveConfig: false, 523 | storageLockedKey: 'fxp/sidebar/locked', 524 | clickableSwipe: false, 525 | draggable: true, 526 | closeOnSelect: true, 527 | closeOnSelectDelay: 0.5, 528 | resetScrollDelay: 0.3, 529 | itemSelector: '.fxp-sidebar-menu a', 530 | showObfuscator: true, 531 | useScroller: true, 532 | scrollerScrollbar: undefined, 533 | scroller: { 534 | contentSelector: '.fxp-sidebar-menu', 535 | scrollerStickyHeader: true, 536 | stickyOptions: { 537 | selector: '> .fxp-sidebar-menu > .fxp-sidebar-group > span' 538 | } 539 | }, 540 | hammer: {}, 541 | disabledKeyboard: false, 542 | keyboardEvent: { 543 | ctrlKey: true, 544 | shiftKey: false, 545 | altKey: true, 546 | keyCode: 'S'.charCodeAt(0) 547 | } 548 | }; 549 | 550 | pluginify('sidebar', 'fxp.sidebar', Sidebar, true, '[data-sidebar="true"]'); 551 | --------------------------------------------------------------------------------