@@ -66,7 +66,8 @@ $.fn.modal = function(parameters) {
66
66
67
67
$module = $ ( this ) ,
68
68
$context = $ ( settings . context ) ,
69
- $close = $module . find ( selector . close ) ,
69
+ $closeIcon = $module . find ( selector . closeIcon ) ,
70
+ $inputs ,
70
71
71
72
$allModals ,
72
73
$otherModals ,
@@ -92,6 +93,7 @@ $.fn.modal = function(parameters) {
92
93
module = {
93
94
94
95
initialize : function ( ) {
96
+ module . create . id ( ) ;
95
97
if ( ! $module . hasClass ( 'modal' ) ) {
96
98
module . create . modal ( ) ;
97
99
if ( ! $ . isFunction ( settings . onHidden ) ) {
@@ -116,12 +118,13 @@ $.fn.modal = function(parameters) {
116
118
$actions . empty ( ) ;
117
119
}
118
120
settings . actions . forEach ( function ( el ) {
119
- var icon = el [ fields . icon ] ? '<i class="' + module . helpers . deQuote ( el [ fields . icon ] ) + ' icon"></i>' : '' ,
121
+ var icon = el [ fields . icon ] ? '<i ' + ( el [ fields . text ] ? 'aria-hidden="true"' : '' ) + ' class="' + module . helpers . deQuote ( el [ fields . icon ] ) + ' icon"></i>' : '' ,
120
122
text = module . helpers . escape ( el [ fields . text ] || '' , settings . preserveHTML ) ,
121
123
cls = module . helpers . deQuote ( el [ fields . class ] || '' ) ,
122
124
click = el [ fields . click ] && $ . isFunction ( el [ fields . click ] ) ? el [ fields . click ] : function ( ) { } ;
123
125
$actions . append ( $ ( '<button/>' , {
124
126
html : icon + text ,
127
+ 'aria-label' : $ ( '<div>' + ( el [ fields . text ] || el [ fields . icon ] || '' ) + '</div>' ) . text ( ) ,
125
128
class : className . button + ' ' + cls ,
126
129
click : function ( ) {
127
130
if ( click . call ( element , $module ) === false ) {
@@ -135,7 +138,6 @@ $.fn.modal = function(parameters) {
135
138
module . cache = { } ;
136
139
module . verbose ( 'Initializing dimmer' , $context ) ;
137
140
138
- module . create . id ( ) ;
139
141
module . create . dimmer ( ) ;
140
142
141
143
if ( settings . allowMultiple ) {
@@ -145,11 +147,9 @@ $.fn.modal = function(parameters) {
145
147
$module . addClass ( 'top aligned' ) ;
146
148
}
147
149
module . refreshModals ( ) ;
148
-
150
+ module . refreshInputs ( ) ;
149
151
module . bind . events ( ) ;
150
- if ( settings . observeChanges ) {
151
- module . observeChanges ( ) ;
152
- }
152
+ module . observeChanges ( ) ;
153
153
module . instantiate ( ) ;
154
154
if ( settings . autoShow ) {
155
155
module . show ( ) ;
@@ -166,16 +166,20 @@ $.fn.modal = function(parameters) {
166
166
167
167
create : {
168
168
modal : function ( ) {
169
- $module = $ ( '<div/>' , { class : className . modal } ) ;
169
+ $module = $ ( '<div/>' , { class : className . modal , role : 'dialog' , 'aria-modal' : true } ) ;
170
170
if ( settings . closeIcon ) {
171
- $close = $ ( '<i/>' , { class : className . close } )
172
- $module . append ( $close ) ;
171
+ $closeIcon = $ ( '<i/>' , { class : className . close , role : 'button' , tabindex : 0 , 'aria-label' : settings . text . close } )
172
+ $module . append ( $closeIcon ) ;
173
173
}
174
174
if ( settings . title !== '' ) {
175
- $ ( '<div/>' , { class : className . title } ) . appendTo ( $module ) ;
175
+ var titleId = '_' + module . get . id ( ) + 'title' ;
176
+ $module . attr ( 'aria-labelledby' , titleId ) ;
177
+ $ ( '<div/>' , { class : className . title , id : titleId } ) . appendTo ( $module ) ;
176
178
}
177
179
if ( settings . content !== '' ) {
178
- $ ( '<div/>' , { class : className . content } ) . appendTo ( $module ) ;
180
+ var descId = '_' + module . get . id ( ) + 'desc' ;
181
+ $module . attr ( 'aria-describedby' , descId ) ;
182
+ $ ( '<div/>' , { class : className . content , id : descId } ) . appendTo ( $module ) ;
179
183
}
180
184
if ( module . has . configActions ( ) ) {
181
185
$ ( '<div/>' , { class : className . actions } ) . appendTo ( $module ) ;
@@ -228,15 +232,21 @@ $.fn.modal = function(parameters) {
228
232
;
229
233
$window . off ( elementEventNamespace ) ;
230
234
$dimmer . off ( elementEventNamespace ) ;
231
- $close . off ( eventNamespace ) ;
235
+ $closeIcon . off ( elementEventNamespace ) ;
236
+ if ( $inputs ) {
237
+ $inputs . off ( elementEventNamespace ) ;
238
+ }
232
239
$context . dimmer ( 'destroy' ) ;
233
240
} ,
234
241
235
242
observeChanges : function ( ) {
236
243
if ( 'MutationObserver' in window ) {
237
244
observer = new MutationObserver ( function ( mutations ) {
238
- module . debug ( 'DOM tree modified, refreshing' ) ;
239
- module . refresh ( ) ;
245
+ if ( settings . observeChanges ) {
246
+ module . debug ( 'DOM tree modified, refreshing' ) ;
247
+ module . refresh ( ) ;
248
+ }
249
+ module . refreshInputs ( ) ;
240
250
} ) ;
241
251
observer . observe ( element , {
242
252
childList : true ,
@@ -261,6 +271,23 @@ $.fn.modal = function(parameters) {
261
271
$allModals = $otherModals . add ( $module ) ;
262
272
} ,
263
273
274
+ refreshInputs : function ( ) {
275
+ if ( $inputs ) {
276
+ $inputs
277
+ . off ( 'keydown' + elementEventNamespace )
278
+ ;
279
+ }
280
+ $inputs = $module . find ( '[tabindex], :input' ) . filter ( ':visible' ) . filter ( function ( ) {
281
+ return $ ( this ) . closest ( '.disabled' ) . length === 0 ;
282
+ } ) ;
283
+ $inputs . first ( )
284
+ . on ( 'keydown' + elementEventNamespace , module . event . inputKeyDown . first )
285
+ ;
286
+ $inputs . last ( )
287
+ . on ( 'keydown' + elementEventNamespace , module . event . inputKeyDown . last )
288
+ ;
289
+ } ,
290
+
264
291
attachEvents : function ( selector , event ) {
265
292
var
266
293
$toggle = $ ( selector )
@@ -289,6 +316,9 @@ $.fn.modal = function(parameters) {
289
316
. on ( 'click' + eventNamespace , selector . approve , module . event . approve )
290
317
. on ( 'click' + eventNamespace , selector . deny , module . event . deny )
291
318
;
319
+ $closeIcon
320
+ . on ( 'keyup' + elementEventNamespace , module . event . closeKeyUp )
321
+ ;
292
322
$window
293
323
. on ( 'resize' + elementEventNamespace , module . event . resize )
294
324
;
@@ -307,7 +337,7 @@ $.fn.modal = function(parameters) {
307
337
308
338
get : {
309
339
id : function ( ) {
310
- return ( Math . random ( ) . toString ( 16 ) + '000000000' ) . substr ( 2 , 8 ) ;
340
+ return id ;
311
341
} ,
312
342
element : function ( ) {
313
343
return $module ;
@@ -346,10 +376,38 @@ $.fn.modal = function(parameters) {
346
376
close : function ( ) {
347
377
module . hide ( ) ;
348
378
} ,
379
+ closeKeyUp : function ( event ) {
380
+ var
381
+ keyCode = event . which
382
+ ;
383
+ if ( ( keyCode === settings . keys . enter || keyCode === settings . keys . space ) && $module . hasClass ( className . front ) ) {
384
+ module . hide ( ) ;
385
+ }
386
+ } ,
387
+ inputKeyDown : {
388
+ first : function ( event ) {
389
+ var
390
+ keyCode = event . which
391
+ ;
392
+ if ( keyCode === settings . keys . tab && event . shiftKey ) {
393
+ $inputs . last ( ) . focus ( ) ;
394
+ event . preventDefault ( ) ;
395
+ }
396
+ } ,
397
+ last : function ( event ) {
398
+ var
399
+ keyCode = event . which
400
+ ;
401
+ if ( keyCode === settings . keys . tab && ! event . shiftKey ) {
402
+ $inputs . first ( ) . focus ( ) ;
403
+ event . preventDefault ( ) ;
404
+ }
405
+ }
406
+ } ,
349
407
mousedown : function ( event ) {
350
408
var
351
409
$target = $ ( event . target ) ,
352
- isRtl = module . is . rtl ( ) ;
410
+ isRtl = module . is . rtl ( )
353
411
;
354
412
initialMouseDownInModal = ( $target . closest ( selector . modal ) . length > 0 ) ;
355
413
if ( initialMouseDownInModal ) {
@@ -397,10 +455,9 @@ $.fn.modal = function(parameters) {
397
455
} ,
398
456
keyboard : function ( event ) {
399
457
var
400
- keyCode = event . which ,
401
- escapeKey = 27
458
+ keyCode = event . which
402
459
;
403
- if ( keyCode == escapeKey ) {
460
+ if ( keyCode === settings . keys . escape ) {
404
461
if ( settings . closable ) {
405
462
module . debug ( 'Escape key pressed hiding modal' ) ;
406
463
if ( $module . hasClass ( className . front ) ) {
@@ -900,13 +957,10 @@ $.fn.modal = function(parameters) {
900
957
set : {
901
958
autofocus : function ( ) {
902
959
var
903
- $inputs = $module . find ( '[tabindex], :input' ) . filter ( ':visible' ) . filter ( function ( ) {
904
- return $ ( this ) . closest ( '.disabled' ) . length === 0 ;
905
- } ) ,
906
960
$autofocus = $inputs . filter ( '[autofocus]' ) ,
907
961
$input = ( $autofocus . length > 0 )
908
962
? $autofocus . first ( )
909
- : $inputs . first ( )
963
+ : ( $inputs . length > 1 ? $inputs . filter ( ':not(i.close)' ) : $inputs ) . first ( )
910
964
;
911
965
if ( $input . length > 0 ) {
912
966
$input . focus ( ) ;
@@ -1323,11 +1377,19 @@ $.fn.modal.settings = {
1323
1377
// called after deny selector match
1324
1378
onDeny : function ( ) { return true ; } ,
1325
1379
1380
+ keys : {
1381
+ space : 32 ,
1382
+ enter : 13 ,
1383
+ escape : 27 ,
1384
+ tab : 9 ,
1385
+ } ,
1386
+
1326
1387
selector : {
1327
1388
title : '> .header' ,
1328
1389
content : '> .content' ,
1329
1390
actions : '> .actions' ,
1330
1391
close : '> .close' ,
1392
+ closeIcon : '> .close' ,
1331
1393
approve : '.actions .positive, .actions .approve, .actions .ok' ,
1332
1394
deny : '.actions .negative, .actions .deny, .actions .cancel' ,
1333
1395
modal : '.ui.modal' ,
@@ -1363,7 +1425,8 @@ $.fn.modal.settings = {
1363
1425
} ,
1364
1426
text : {
1365
1427
ok : 'Ok' ,
1366
- cancel : 'Cancel'
1428
+ cancel : 'Cancel' ,
1429
+ close : 'Close'
1367
1430
}
1368
1431
} ;
1369
1432
0 commit comments