1+ import { Sidebar } from './sidebar'
2+ import { SidebarMenuCollapse } from './sidebar-menu-collapse'
3+ import { SIDEBAR_SELECTOR , SIDEBAR_MENU_SELECTORS } from './config'
4+
5+ const DROPDOWN_SELECTOR = '[data-toggle="sidebar-dropdown"]'
6+ const CONTAINER_SELECTOR = '.sidebar-dropdown-menu'
7+ const DROPDOWN_DATA_KEY = 'bl.sidebar-dropdown'
8+ const DROPDOWN_DATA_INIT = `init.${ DROPDOWN_DATA_KEY } `
9+ const DROPDOWN_DATA_BUTTON = `button.${ DROPDOWN_DATA_KEY } `
10+ const DROPDOWN_HIDE = `hide.${ DROPDOWN_DATA_KEY } `
11+ const DROPDOWN_SHOW = `show.${ DROPDOWN_DATA_KEY } `
12+ const DROPDOWN_MOUSEENTER = `mouseenter.${ DROPDOWN_DATA_KEY } `
13+ const DROPDOWN_MOUSELEAVE = `mouseleave.${ DROPDOWN_DATA_KEY } `
14+
15+ const COLLAPSE_SELECTOR = '[data-toggle="sidebar-collapse"]'
16+
17+ export class SidebarMenuDropdown {
18+
19+ /**
20+ * SidebarMenuDropdown constructor
21+ * @return {[type] } [description]
22+ */
23+ constructor ( ) {
24+ this . sidebar = new Sidebar ( )
25+ this . sidebarMenuCollapse = new SidebarMenuCollapse ( )
26+ jQuery ( DROPDOWN_SELECTOR ) . each ( ( index , button ) => this . init ( button ) )
27+ }
28+
29+ /**
30+ * Get a jQuery element
31+ * @param {String|jQuery } elementOrSelector jQuery element or DOM selector
32+ * @return {jQuery } A jQuery element
33+ */
34+ _element ( elementOrSelector ) {
35+ return elementOrSelector instanceof jQuery ? elementOrSelector : jQuery ( elementOrSelector )
36+ }
37+
38+ /**
39+ * Get the sidebar container
40+ * @param {String|jQuery } childElement jQuery element or DOM selector
41+ */
42+ _sidebar ( childElement ) {
43+ return this . _element ( childElement ) . closest ( SIDEBAR_SELECTOR )
44+ }
45+
46+ /**
47+ * Render menu event handler
48+ * @param {MouseEvent } e The mouse event
49+ */
50+ _render ( e ) {
51+ if ( this . sidebar . SCREEN_MD_UP ) {
52+ this . _cancelHide ( )
53+ this . _show ( jQuery ( e . currentTarget ) )
54+ }
55+ }
56+
57+ /**
58+ * Show a sidebar menu
59+ * @param {String|jQuery } button jQuery element or DOM selector
60+ */
61+ _show ( button ) {
62+ const sidebar = this . _sidebar ( button )
63+ const sidebarOptions = this . sidebar . _options ( sidebar )
64+ const sidebarWidth = sidebar . width ( )
65+
66+ let ddMenu = jQuery ( CONTAINER_SELECTOR )
67+
68+ if ( ! ddMenu . length ) {
69+ ddMenu = jQuery ( `<ul class="${ CONTAINER_SELECTOR . substring ( 1 ) } dropdown-menu"></ul>` )
70+ jQuery ( 'body' ) . append ( ddMenu )
71+
72+ ddMenu . on ( DROPDOWN_MOUSEENTER , ( ) => this . _cancelHide ( ) )
73+ . on ( DROPDOWN_MOUSELEAVE , ( ) => this . _hide ( ) )
74+ }
75+
76+ if ( ddMenu . data ( DROPDOWN_DATA_BUTTON ) ) {
77+ jQuery ( ddMenu . data ( DROPDOWN_DATA_BUTTON ) ) . trigger ( DROPDOWN_HIDE , [ ddMenu ] )
78+ }
79+
80+ ddMenu . data ( DROPDOWN_DATA_BUTTON , button )
81+ button . trigger ( DROPDOWN_SHOW , [ ddMenu ] )
82+
83+ ddMenu . css ( {
84+ left : sidebarOptions . position === 'left' ? sidebarWidth : 'auto' ,
85+ right : sidebarOptions . position === 'right' ? sidebarWidth : 'auto' ,
86+ top : button . offset ( ) . top + 'px'
87+ } )
88+
89+ const submenu = button . next ( SIDEBAR_MENU_SELECTORS . submenu ) . clone ( false )
90+
91+ submenu . find ( 'li' )
92+ . removeClass ( )
93+ . find ( 'a' )
94+ . removeClass ( )
95+ . addClass ( 'dropdown-item' )
96+
97+ submenu . find ( 'ul' )
98+ . removeClass ( )
99+ . addClass ( 'sidebar-submenu' )
100+ . filter ( ( index , element ) => ! jQuery ( element ) . prev ( COLLAPSE_SELECTOR ) . length )
101+ . addClass ( sidebarOptions . position === 'left' ? 'dropdown-menu-right' : 'dropdown-menu-left' )
102+ . addClass ( 'dropdown-menu sidebar-dropdown-submenu' ) . closest ( 'li' ) . addClass ( 'dropdown' )
103+
104+ submenu . find ( 'ul' )
105+ . filter ( ( index , element ) => jQuery ( element ) . prev ( COLLAPSE_SELECTOR ) . length )
106+ . addClass ( 'sidebar-submenu-collapse' )
107+
108+ ddMenu . html ( submenu . html ( ) )
109+ ddMenu . find ( COLLAPSE_SELECTOR ) . each ( ( index , button ) => this . sidebarMenuCollapse . init ( button ) )
110+ }
111+
112+ /**
113+ * Queue hide
114+ */
115+ _hide ( ) {
116+ this . _cancelHide ( )
117+
118+ const ddMenu = jQuery ( CONTAINER_SELECTOR )
119+ if ( ddMenu . length ) {
120+ const button = ddMenu . data ( DROPDOWN_DATA_BUTTON )
121+ ddMenu . data ( DROPDOWN_HIDE , setTimeout ( ( ) => {
122+ ddMenu . remove ( )
123+ button . trigger ( DROPDOWN_HIDE , [ ddMenu ] )
124+ } , 100 ) )
125+ }
126+ }
127+
128+ /**
129+ * Clear hide
130+ */
131+ _cancelHide ( ) {
132+ const ddMenu = jQuery ( CONTAINER_SELECTOR )
133+ if ( ddMenu . length ) {
134+ const clearTimer = ddMenu . data ( DROPDOWN_HIDE )
135+ if ( clearTimer ) {
136+ clearTimeout ( clearTimer )
137+ ddMenu . removeData ( DROPDOWN_HIDE )
138+ }
139+ }
140+ }
141+
142+ /**
143+ * Initialize a sidebar menu
144+ * @param {String|jQuery } button jQuery element or DOM selector
145+ */
146+ init ( button ) {
147+ button = this . _element ( button )
148+ const sidebar = this . _sidebar ( button )
149+ const layout = this . sidebar . _layout ( sidebar )
150+
151+ const breakpointsCollapse = [ 320 , 480 , 544 ]
152+ const breakpointsDropdown = [ 768 , 992 , 1200 , 1600 ]
153+
154+ layout . on ( breakpointsDropdown . map ( b => `enterBreakpoint${ b } .${ DROPDOWN_DATA_KEY } ` ) . join ( ' ' ) , ( ) => {
155+ if ( ! button . data ( DROPDOWN_DATA_INIT ) ) {
156+ this . sidebarMenuCollapse . destroy ( button )
157+ button
158+ . on ( DROPDOWN_MOUSEENTER , e => this . _render ( e ) )
159+ . on ( DROPDOWN_MOUSELEAVE , ( ) => this . _hide ( ) )
160+ . on ( DROPDOWN_SHOW , ( e ) => jQuery ( e . currentTarget ) . parent ( ) . addClass ( 'open' ) )
161+ . on ( DROPDOWN_HIDE , ( e ) => jQuery ( e . currentTarget ) . parent ( ) . removeClass ( 'open' ) )
162+ . data ( DROPDOWN_DATA_INIT , true )
163+ }
164+ } )
165+ . on ( breakpointsCollapse . map ( b => `enterBreakpoint${ b } .${ DROPDOWN_DATA_KEY } ` ) . join ( ' ' ) , ( ) => {
166+ this . destroy ( button )
167+ this . sidebarMenuCollapse . init ( button )
168+ } )
169+ }
170+
171+ /**
172+ * Destroy a sidebar menu
173+ * @param {String|jQuery } button jQuery element or DOM selector
174+ */
175+ destroy ( button ) {
176+ button
177+ . off ( DROPDOWN_MOUSEENTER , e => this . _render ( e ) )
178+ . off ( DROPDOWN_MOUSELEAVE , ( ) => this . _hide ( ) )
179+ . off ( DROPDOWN_SHOW , ( e ) => jQuery ( e . currentTarget ) . parent ( ) . addClass ( 'open' ) )
180+ . off ( DROPDOWN_HIDE , ( e ) => jQuery ( e . currentTarget ) . parent ( ) . removeClass ( 'open' ) )
181+
182+ const sidebar = this . _sidebar ( button )
183+ const layout = this . sidebar . _layout ( sidebar )
184+
185+ layout . off ( DROPDOWN_DATA_KEY )
186+ }
187+ }
188+
189+ // EXPORT INSTANCE
190+ export let sidebarMenuDropdown = new SidebarMenuDropdown ( )
0 commit comments