1
- // jQuery() .dropdown_menu() by Daniel Upshaw 2012-2013
1
+ // jQuery.dropdown_menu() by Daniel Upshaw 2012-2013
2
2
// http://danielupshaw.com/jquery-css-dropdown-plugin/readme.html
3
3
4
4
// Beginning semi-colon for concatenated scripts and any improperly closed plugins
5
5
; ( function ( $ , window , document , undefined ) {
6
- $ . fn . extend ( {
7
- dropdown_menu : function ( options ) {
8
- var _defaults = {
9
- sub_indicator_class : 'dropdown-menu-sub-indicator' , // Class given to LI's with submenus
10
- vertical_class : 'dropdown-menu-vertical' , // Class for a vertical menu
11
- shadow_class : 'dropdown-menu-shadow' , // Class for drop shadow on submenus
12
- hover_class : 'dropdown-menu-hover' , // Class applied to hovered LI's
13
- open_delay : 150 , // Delay on menu open
14
- close_delay : 300 , // Delay on menu close
15
- animation_open : { opacity : 'show' } , // Animation for menu open
16
- speed_open : 'fast' , // Animation speed for menu open
17
- animation_close : { opacity : 'hide' } , // Animation for menu close
18
- speed_close : 'fast' , // Animation speed for menu close
19
- sub_indicators : false , // Whether to show arrows for submenus
20
- drop_shadows : false , // Whether to apply drop shadow class to submenus
21
- vertical : false , // Whether the root menu is vertically aligned
22
- viewport_overflow : 'auto' , // Handle submenu opening offscreen: "auto", "move", "scroll", or false
23
- init : function ( ) { } // Callback function applied on init
24
- } ;
25
-
26
- // Test for IE <= 7
27
- var ie7 = ( $ . browser . msie && $ . browser . version < 8 ) ;
28
-
29
- return this . each ( function ( ) {
30
- var menu = $ ( this ) ;
31
- // Needs this single/double quote precedence for JSON data
32
- // <ul data-options='{"sub_indicators":"true"}'></ul>
33
- var metadata = menu . data ( 'options' ) ;
34
- var o = $ . extend ( { } , _defaults , options , metadata ) ;
35
-
36
- // Arrow element
37
- var sub_indicator = $ ( '<span class="' + o . sub_indicator_class + '">»</span>' ) ;
38
-
39
- // Add vertical menu class
40
- if ( o . vertical ) {
41
- menu . addClass ( o . vertical_class ) ;
42
- }
43
-
44
- // Remove whitespace between inline-block elements
45
- $ ( '>li' , menu ) . css ( { 'font-size' : menu . css ( 'font-size' ) } ) ;
46
- menu . css ( { 'font-size' : '0' } ) ;
47
-
48
- menu . find ( 'li:has(ul)' ) . each ( function ( ) {
49
- // Add a class to the LI to indicate that it has a submenu
50
- $ ( this ) . addClass ( o . sub_indicator_class ) ;
51
-
52
- // Add arrow/indicator element if enabled
53
- if ( o . sub_indicators ) {
54
- $ ( '>a:first-child' , this ) . append ( sub_indicator . clone ( ) ) ;
55
- }
56
-
57
- // Get the submenu and hide it, but keep display:block so the width can be calculated
58
- var submenu = $ ( '>ul' , this ) . css ( { 'visibility' : 'hidden' , 'display' : 'block' } ) ;
59
-
60
- // Add drop shadow class if enabled
61
- if ( o . drop_shadows ) {
62
- submenu . addClass ( o . shadow_class ) ;
63
- }
64
-
65
- // IE <= 7
66
- if ( ie7 ) {
67
- // Wrap in setTimeout() else the arrow may not be included
68
- setTimeout ( function ( ) {
69
- // Lock submenu UL width in CSS so that the LI's can stretch
70
- submenu . css ( { 'width' : submenu . width ( ) } ) ;
71
- } , 0 ) ;
72
- }
73
-
74
- // Handle hover states
75
- $ ( this ) . on ( {
76
- mouseenter : function ( e ) {
77
- clearTimeout ( $ ( this ) . data ( 'close_timer' ) ) ;
78
- clearTimeout ( $ ( this ) . data ( 'open_timer' ) ) ;
79
-
80
- // If the submenu has already been opened
81
- if ( $ ( this ) . hasClass ( o . hover_class ) ) {
82
- return ;
83
- }
84
-
85
- // $.proxy() keeps "this" context
86
- $ ( this ) . data ( 'open_timer' , setTimeout ( $ . proxy ( function ( ) {
87
- $ ( this ) . addClass ( o . hover_class ) ;
88
-
89
- // For vertical menus
90
- if ( o . vertical ) {
91
- submenu . css ( { 'top' : 0 , 'left' : $ ( this ) . width ( ) } ) ;
92
- } else {
93
- submenu . css ( { 'top' : '' , 'left' : '' } ) ;
94
- }
95
-
96
- // So we can check the offset
97
- submenu . css ( { 'visibility' : 'hidden' , 'display' : 'block' } ) ;
98
-
99
- // Check if the submenu is overflowing off the page
100
- overflow_x = submenu . offset ( ) . left + submenu . width ( ) > $ ( window ) . scrollLeft ( ) + $ ( window ) . width ( ) ;
101
- overflow_y = submenu . offset ( ) . top + submenu . height ( ) > $ ( window ) . scrollTop ( ) + $ ( window ) . height ( ) ;
102
- overflow = overflow_x || overflow_y ;
103
-
104
- if ( overflow && o . viewport_overflow ) {
105
- // Padding to accomodate for drop shgadows, etc
106
- var padding = 10 ;
107
- if ( o . viewport_overflow === 'auto' ) o . viewport_overflow = ie7 ? 'scroll' : 'move' ;
108
-
109
- switch ( o . viewport_overflow ) {
110
- case 'move' :
111
- var left = overflow_x ? ( $ ( window ) . scrollLeft ( ) + $ ( window ) . width ( ) ) - submenu . width ( ) - padding : submenu . offset ( ) . left ;
112
- var top = overflow_y ? ( $ ( window ) . scrollTop ( ) + $ ( window ) . height ( ) ) - submenu . height ( ) - padding : submenu . offset ( ) . top ;
113
- submenu . offset ( { left : left , top : top } ) ;
114
- break ;
115
- case 'scroll' :
116
- if ( overflow_x ) {
117
- var scrollLeft = submenu . offset ( ) . left - $ ( window ) . width ( ) + submenu . width ( ) + padding ;
118
- $ ( 'html' ) . animate ( { scrollLeft : scrollLeft } , 'fast' ) ;
119
- //$(window).scrollLeft(scrollLeft);
120
- }
121
- if ( overflow_y ) {
122
- var scrollTop = submenu . offset ( ) . top - $ ( window ) . height ( ) + submenu . height ( ) + padding ;
123
- $ ( 'html' ) . animate ( { scrollTop : scrollTop } , 'fast' ) ;
124
- //$(window).scrollTop(scrollTop);
125
- }
126
- break ;
127
- }
128
- }
129
-
130
- // Restore display state
131
- submenu . hide ( ) . css ( { 'visibility' : 'visible' } ) ;
132
-
133
- if ( o . animation_open ) {
134
- submenu . animate ( o . animation_open , o . speed_open ) ;
135
- } else {
136
- submenu . show ( ) ;
137
- }
138
- } , this ) , o . open_delay ) ) ;
139
- } ,
140
- mouseleave : function ( e ) {
141
- clearTimeout ( $ ( this ) . data ( 'close_timer' ) ) ;
142
- clearTimeout ( $ ( this ) . data ( 'open_timer' ) ) ;
143
-
144
- $ ( this ) . data ( 'close_timer' , setTimeout ( $ . proxy ( function ( ) {
145
- $ ( this ) . removeClass ( o . hover_class ) ;
146
-
147
- if ( o . animation_close ) {
148
- submenu . animate ( o . animation_close , o . speed_close , function ( ) {
149
- submenu . css ( { 'visibility' : 'hidden' } ) ;
150
- } ) ;
151
- } else {
152
- submenu . hide ( ) . css ( { 'visibility' : 'hidden' } ) ;
153
- }
154
- } , this ) , o . close_delay ) ) ;
155
- } ,
156
- // For touch devices, disable the link if its submenu is not showing yet
157
- touchstart : function ( e ) {
158
- $ ( '>a:first-child' , this ) . one ( 'click' , $ . proxy ( function ( e ) {
159
- if ( ! $ ( this ) . hasClass ( o . hover_class ) ) {
160
- e . preventDefault ( ) ;
161
- } else {
162
- return true ;
163
- }
164
- } , this ) ) ;
165
- }
166
- } ) ;
167
- } ) ;
168
-
169
- // Wrap in setTimeout() to ensure processes have completed
170
- setTimeout ( function ( ) {
171
- // Completely hide the submenus
172
- $ ( 'ul' , menu ) . hide ( 1 )
173
- . promise ( )
174
- . done ( function ( ) {
175
- // Apply the init callback
176
- o . init . call ( menu [ 0 ] ) ;
177
- } ) ;
178
- } , 0 ) ;
179
- } ) ;
180
- }
181
- } ) ;
182
- } ) ( jQuery , window , document ) ;
6
+ $ . fn . extend ( {
7
+ dropdown_menu : function ( options ) {
8
+ var _defaults = {
9
+ sub_indicator_class : 'dropdown-menu-sub-indicator' , // Class given to LI's with submenus
10
+ vertical_class : 'dropdown-menu-vertical' , // Class for a vertical menu
11
+ shadow_class : 'dropdown-menu-shadow' , // Class for drop shadow on submenus
12
+ hover_class : 'dropdown-menu-hover' , // Class applied to hovered LI's
13
+ open_delay : 150 , // Delay on menu open
14
+ close_delay : 300 , // Delay on menu close
15
+ animation_open : { opacity : 'show' } , // Animation for menu open
16
+ speed_open : 'fast' , // Animation speed for menu open
17
+ animation_close : { opacity : 'hide' } , // Animation for menu close
18
+ speed_close : 'fast' , // Animation speed for menu close
19
+ sub_indicators : false , // Whether to show arrows for submenus
20
+ drop_shadows : false , // Whether to apply drop shadow class to submenus
21
+ vertical : false , // Whether the root menu is vertically aligned
22
+ viewport_overflow : 'auto' , // Handle submenu opening offscreen: "auto", "move", "scroll", or false
23
+ init : function ( ) { } // Callback function applied on init
24
+ } ;
25
+
26
+ // Test for IE <= 7
27
+ version = parseFloat ( navigator . appVersion . split ( "MSIE" ) [ 1 ] ) ;
28
+ var ie7 = ( version < 8 ) && ( document . body . filters ) ;
29
+
30
+ return this . each ( function ( ) {
31
+ var menu = $ ( this ) ;
32
+ // Needs this single/double quote precedence for JSON data
33
+ // <ul data-options='{"sub_indicators":"true"}'></ul>
34
+ var metadata = menu . data ( 'options' ) ;
35
+ var o = $ . extend ( { } , _defaults , options , metadata ) ;
36
+
37
+ // Arrow element
38
+ var sub_indicator = $ ( '<span class="' + o . sub_indicator_class + '">»</span>' ) ;
39
+
40
+ // Add vertical menu class
41
+ if ( o . vertical ) {
42
+ menu . addClass ( o . vertical_class ) ;
43
+ }
44
+
45
+ // Remove whitespace between inline-block elements
46
+ $ ( '>li' , menu ) . css ( { 'font-size' : menu . css ( 'font-size' ) } ) ;
47
+ menu . css ( { 'font-size' : '0' } ) ;
48
+
49
+ menu . find ( 'li:has(ul)' ) . each ( function ( ) {
50
+ // Add a class to the LI to indicate that it has a submenu
51
+ $ ( this ) . addClass ( o . sub_indicator_class ) ;
52
+
53
+ // Add arrow/indicator element if enabled
54
+ if ( o . sub_indicators ) {
55
+ $ ( '>a:first-child' , this ) . append ( sub_indicator . clone ( ) ) ;
56
+ }
57
+
58
+ // Get the submenu and hide it, but keep display:block so the width can be calculated
59
+ var submenu = $ ( '>ul' , this ) . css ( { 'visibility' : 'hidden' , 'display' : 'block' } ) ;
60
+
61
+ // Add drop shadow class if enabled
62
+ if ( o . drop_shadows ) {
63
+ submenu . addClass ( o . shadow_class ) ;
64
+ }
65
+
66
+ // IE <= 7
67
+ if ( ie7 ) {
68
+ // Wrap in setTimeout() else the arrow may not be included
69
+ setTimeout ( function ( ) {
70
+ // Lock submenu UL width in CSS so that the LI's can stretch
71
+ submenu . css ( { 'width' : submenu . width ( ) } ) ;
72
+ } , 0 ) ;
73
+ }
74
+
75
+ // Handle hover states
76
+ $ ( this ) . on ( {
77
+ mouseenter : function ( e ) {
78
+ clearTimeout ( $ ( this ) . data ( 'close_timer' ) ) ;
79
+ clearTimeout ( $ ( this ) . data ( 'open_timer' ) ) ;
80
+
81
+ // If the submenu has already been opened
82
+ if ( $ ( this ) . hasClass ( o . hover_class ) ) {
83
+ return ;
84
+ }
85
+
86
+ // $.proxy() keeps "this" context
87
+ $ ( this ) . data ( 'open_timer' , setTimeout ( $ . proxy ( function ( ) {
88
+ $ ( this ) . addClass ( o . hover_class ) ;
89
+
90
+ // For vertical menus
91
+ if ( o . vertical ) {
92
+ submenu . css ( { 'top' : 0 , 'left' : $ ( this ) . width ( ) } ) ;
93
+ } else {
94
+ submenu . css ( { 'top' : '' , 'left' : '' } ) ;
95
+ }
96
+
97
+ // So we can check the offset
98
+ submenu . css ( { 'visibility' : 'hidden' , 'display' : 'block' } ) ;
99
+
100
+ // Check if the submenu is overflowing off the page
101
+ overflow_x = submenu . offset ( ) . left + submenu . width ( ) > $ ( window ) . scrollLeft ( ) + $ ( window ) . width ( ) ;
102
+ overflow_y = submenu . offset ( ) . top + submenu . height ( ) > $ ( window ) . scrollTop ( ) + $ ( window ) . height ( ) ;
103
+ overflow = overflow_x || overflow_y ;
104
+
105
+ if ( overflow && o . viewport_overflow ) {
106
+ // Padding to accomodate for drop shadows, etc
107
+ var padding = 10 ;
108
+ if ( o . viewport_overflow === 'auto' ) o . viewport_overflow = ie7 ? 'scroll' : 'move' ;
109
+
110
+ switch ( o . viewport_overflow ) {
111
+ case 'move' :
112
+ var left = overflow_x ? ( $ ( window ) . scrollLeft ( ) + $ ( window ) . width ( ) ) - submenu . width ( ) - padding : submenu . offset ( ) . left ;
113
+ var top = overflow_y ? ( $ ( window ) . scrollTop ( ) + $ ( window ) . height ( ) ) - submenu . height ( ) - padding : submenu . offset ( ) . top ;
114
+ submenu . offset ( { left : left , top : top } ) ;
115
+ break ;
116
+ case 'scroll' :
117
+ if ( overflow_x ) {
118
+ var scrollLeft = submenu . offset ( ) . left - $ ( window ) . width ( ) + submenu . width ( ) + padding ;
119
+ $ ( 'html' ) . animate ( { scrollLeft : scrollLeft } , 'fast' ) ;
120
+ //$(window).scrollLeft(scrollLeft);
121
+ }
122
+ if ( overflow_y ) {
123
+ var scrollTop = submenu . offset ( ) . top - $ ( window ) . height ( ) + submenu . height ( ) + padding ;
124
+ $ ( 'html' ) . animate ( { scrollTop : scrollTop } , 'fast' ) ;
125
+ //$(window).scrollTop(scrollTop);
126
+ }
127
+ break ;
128
+ }
129
+ }
130
+
131
+ // Restore display state
132
+ submenu . hide ( ) . css ( { 'visibility' : 'visible' } ) ;
133
+
134
+ if ( o . animation_open ) {
135
+ submenu . animate ( o . animation_open , o . speed_open ) ;
136
+ } else {
137
+ submenu . show ( ) ;
138
+ }
139
+ } , this ) , o . open_delay ) ) ;
140
+ } ,
141
+ mouseleave : function ( e ) {
142
+ clearTimeout ( $ ( this ) . data ( 'close_timer' ) ) ;
143
+ clearTimeout ( $ ( this ) . data ( 'open_timer' ) ) ;
144
+
145
+ $ ( this ) . data ( 'close_timer' , setTimeout ( $ . proxy ( function ( ) {
146
+ $ ( this ) . removeClass ( o . hover_class ) ;
147
+
148
+ if ( o . animation_close ) {
149
+ submenu . animate ( o . animation_close , o . speed_close , function ( ) {
150
+ submenu . css ( { 'visibility' : 'hidden' } ) ;
151
+ } ) ;
152
+ } else {
153
+ submenu . hide ( ) . css ( { 'visibility' : 'hidden' } ) ;
154
+ }
155
+ } , this ) , o . close_delay ) ) ;
156
+ } ,
157
+ // For touch devices, disable the link if its submenu is not showing yet
158
+ touchstart : function ( e ) {
159
+ $ ( '>a:first-child' , this ) . one ( 'click' , $ . proxy ( function ( e ) {
160
+ if ( ! $ ( this ) . hasClass ( o . hover_class ) ) {
161
+ e . preventDefault ( ) ;
162
+ } else {
163
+ return true ;
164
+ }
165
+ } , this ) ) ;
166
+ }
167
+ } ) ;
168
+ } ) ;
169
+
170
+ // Wrap in setTimeout() to ensure processes have completed
171
+ setTimeout ( function ( ) {
172
+ // Completely hide the submenus
173
+ $ ( 'ul' , menu ) . hide ( 1 )
174
+ . promise ( )
175
+ . done ( function ( ) {
176
+ // Apply the init callback
177
+ o . init . call ( menu [ 0 ] ) ;
178
+ } ) ;
179
+ } , 0 ) ;
180
+ } ) ;
181
+ }
182
+ } ) ;
183
+ } ) ( jQuery , window , document ) ;
0 commit comments