Révision 560c3060
Ajouté par Julien Enselme il y a plus de 8 ans
drupal7/sites/all/modules/ctools/js/modal.js | ||
---|---|---|
48 | 48 |
modalOptions: { |
49 | 49 |
opacity: .55, |
50 | 50 |
background: '#fff' |
51 |
} |
|
51 |
}, |
|
52 |
modalClass: 'default' |
|
52 | 53 |
}; |
53 | 54 |
|
54 | 55 |
var settings = {}; |
... | ... | |
97 | 98 |
resize(); |
98 | 99 |
|
99 | 100 |
$('span.modal-title', Drupal.CTools.Modal.modal).html(Drupal.CTools.Modal.currentSettings.loadingText); |
100 |
Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed); |
|
101 |
$('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme)); |
|
101 |
Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed, settings.modalClass);
|
|
102 |
$('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme)).addClass('ctools-modal-loading');
|
|
102 | 103 |
|
103 | 104 |
// Position autocomplete results based on the scroll position of the modal. |
104 | 105 |
$('#modalContent .modal-content').delegate('input.form-autocomplete', 'keyup', function() { |
... | ... | |
299 | 300 |
// Attach behaviors within a modal dialog. |
300 | 301 |
var settings = response.settings || ajax.settings || Drupal.settings; |
301 | 302 |
Drupal.attachBehaviors('#modalContent', settings); |
303 |
|
|
304 |
if ($('#modal-content').hasClass('ctools-modal-loading')) { |
|
305 |
$('#modal-content').removeClass('ctools-modal-loading'); |
|
306 |
} |
|
307 |
else { |
|
308 |
// If the modal was already shown, and we are simply replacing its |
|
309 |
// content, then focus on the first focusable element in the modal. |
|
310 |
// (When first showing the modal, focus will be placed on the close |
|
311 |
// button by the show() function called above.) |
|
312 |
$('#modal-content :focusable:first').focus(); |
|
313 |
} |
|
302 | 314 |
} |
303 | 315 |
|
304 | 316 |
/** |
... | ... | |
349 | 361 |
* @param css obj of css attributes |
350 | 362 |
* @param animation (fadeIn, slideDown, show) |
351 | 363 |
* @param speed (valid animation speeds slow, medium, fast or # in ms) |
364 |
* @param modalClass class added to div#modalContent |
|
352 | 365 |
*/ |
353 |
Drupal.CTools.Modal.modalContent = function(content, css, animation, speed) { |
|
366 |
Drupal.CTools.Modal.modalContent = function(content, css, animation, speed, modalClass) {
|
|
354 | 367 |
// If our animation isn't set, make it just show/pop |
355 | 368 |
if (!animation) { |
356 | 369 |
animation = 'show'; |
... | ... | |
402 | 415 |
if( docHeight < winHeight ) docHeight = winHeight; |
403 | 416 |
|
404 | 417 |
// Create our divs |
405 |
$('body').append('<div id="modalBackdrop" style="z-index: 1000; display: none;"></div><div id="modalContent" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>'); |
|
418 |
$('body').append('<div id="modalBackdrop" class="backdrop-' + modalClass + '" style="z-index: 1000; display: none;"></div><div id="modalContent" class="modal-' + modalClass + '" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>'); |
|
419 |
|
|
420 |
// Get a list of the tabbable elements in the modal content. |
|
421 |
var getTabbableElements = function () { |
|
422 |
var tabbableElements = $('#modalContent :tabbable'), |
|
423 |
radioButtons = tabbableElements.filter('input[type="radio"]'); |
|
424 |
|
|
425 |
// The list of tabbable elements from jQuery is *almost* right. The |
|
426 |
// exception is with groups of radio buttons. The list from jQuery will |
|
427 |
// include all radio buttons, when in fact, only the selected radio button |
|
428 |
// is tabbable, and if no radio buttons in a group are selected, then only |
|
429 |
// the first is tabbable. |
|
430 |
if (radioButtons.length > 0) { |
|
431 |
// First, build up an index of which groups have an item selected or not. |
|
432 |
var anySelected = {}; |
|
433 |
radioButtons.each(function () { |
|
434 |
var name = this.name; |
|
435 |
|
|
436 |
if (typeof anySelected[name] === 'undefined') { |
|
437 |
anySelected[name] = radioButtons.filter('input[name="' + name + '"]:checked').length !== 0; |
|
438 |
} |
|
439 |
}); |
|
440 |
|
|
441 |
// Next filter out the radio buttons that aren't really tabbable. |
|
442 |
var found = {}; |
|
443 |
tabbableElements = tabbableElements.filter(function () { |
|
444 |
var keep = true; |
|
445 |
|
|
446 |
if (this.type == 'radio') { |
|
447 |
if (anySelected[this.name]) { |
|
448 |
// Only keep the selected one. |
|
449 |
keep = this.checked; |
|
450 |
} |
|
451 |
else { |
|
452 |
// Only keep the first one. |
|
453 |
if (found[this.name]) { |
|
454 |
keep = false; |
|
455 |
} |
|
456 |
found[this.name] = true; |
|
457 |
} |
|
458 |
} |
|
406 | 459 |
|
407 |
// Keyboard and focus event handler ensures focus stays on modal elements only |
|
460 |
return keep; |
|
461 |
}); |
|
462 |
} |
|
463 |
|
|
464 |
return tabbableElements.get(); |
|
465 |
}; |
|
466 |
|
|
467 |
// Keyboard and focus event handler ensures only modal elements gain focus. |
|
408 | 468 |
modalEventHandler = function( event ) { |
409 | 469 |
target = null; |
410 | 470 |
if ( event ) { //Mozilla |
... | ... | |
428 | 488 |
return true; |
429 | 489 |
} |
430 | 490 |
else { |
431 |
$('#modalContent').focus();
|
|
491 |
getTabbableElements()[0].focus();
|
|
432 | 492 |
} |
433 | 493 |
|
434 | 494 |
event.preventDefault(); |
... | ... | |
436 | 496 |
$('body').bind( 'focus', modalEventHandler ); |
437 | 497 |
$('body').bind( 'keypress', modalEventHandler ); |
438 | 498 |
|
499 |
// Keypress handler Ensures you can only TAB to elements within the modal. |
|
500 |
// Based on the psuedo-code from WAI-ARIA 1.0 Authoring Practices section |
|
501 |
// 3.3.1 "Trapping Focus". |
|
502 |
modalTabTrapHandler = function (evt) { |
|
503 |
// We only care about the TAB key. |
|
504 |
if (evt.which != 9) { |
|
505 |
return true; |
|
506 |
} |
|
507 |
|
|
508 |
var tabbableElements = getTabbableElements(), |
|
509 |
firstTabbableElement = tabbableElements[0], |
|
510 |
lastTabbableElement = tabbableElements[tabbableElements.length - 1], |
|
511 |
singleTabbableElement = firstTabbableElement == lastTabbableElement, |
|
512 |
node = evt.target; |
|
513 |
|
|
514 |
// If this is the first element and the user wants to go backwards, then |
|
515 |
// jump to the last element. |
|
516 |
if (node == firstTabbableElement && evt.shiftKey) { |
|
517 |
if (!singleTabbableElement) { |
|
518 |
lastTabbableElement.focus(); |
|
519 |
} |
|
520 |
return false; |
|
521 |
} |
|
522 |
// If this is the last element and the user wants to go forwards, then |
|
523 |
// jump to the first element. |
|
524 |
else if (node == lastTabbableElement && !evt.shiftKey) { |
|
525 |
if (!singleTabbableElement) { |
|
526 |
firstTabbableElement.focus(); |
|
527 |
} |
|
528 |
return false; |
|
529 |
} |
|
530 |
// If this element isn't in the dialog at all, then jump to the first |
|
531 |
// or last element to get the user into the game. |
|
532 |
else if ($.inArray(node, tabbableElements) == -1) { |
|
533 |
// Make sure the node isn't in another modal (ie. WYSIWYG modal). |
|
534 |
var parents = $(node).parents().get(); |
|
535 |
for (var i = 0; i < parents.length; ++i) { |
|
536 |
var position = $(parents[i]).css('position'); |
|
537 |
if (position == 'absolute' || position == 'fixed') { |
|
538 |
return true; |
|
539 |
} |
|
540 |
} |
|
541 |
|
|
542 |
if (evt.shiftKey) { |
|
543 |
lastTabbableElement.focus(); |
|
544 |
} |
|
545 |
else { |
|
546 |
firstTabbableElement.focus(); |
|
547 |
} |
|
548 |
} |
|
549 |
}; |
|
550 |
$('body').bind('keydown', modalTabTrapHandler); |
|
551 |
|
|
439 | 552 |
// Create our content div, get the dimensions, and hide it |
440 | 553 |
var modalContent = $('#modalContent').css('top','-1000px'); |
441 | 554 |
var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2); |
... | ... | |
457 | 570 |
|
458 | 571 |
$(document).bind('keydown', modalEventEscapeCloseHandler); |
459 | 572 |
|
573 |
// Per WAI-ARIA 1.0 Authoring Practices, initial focus should be on the |
|
574 |
// close button, but we should save the original focus to restore it after |
|
575 |
// the dialog is closed. |
|
576 |
var oldFocus = document.activeElement; |
|
577 |
$('.close').focus(); |
|
578 |
|
|
460 | 579 |
// Close the open modal content and backdrop |
461 | 580 |
function close() { |
462 | 581 |
// Unbind the events |
463 | 582 |
$(window).unbind('resize', modalContentResize); |
464 | 583 |
$('body').unbind( 'focus', modalEventHandler); |
465 | 584 |
$('body').unbind( 'keypress', modalEventHandler ); |
585 |
$('body').unbind( 'keydown', modalTabTrapHandler ); |
|
466 | 586 |
$('.close').unbind('click', modalContentClose); |
467 | 587 |
$('body').unbind('keypress', modalEventEscapeCloseHandler); |
468 | 588 |
$(document).trigger('CToolsDetachBehaviors', $('#modalContent')); |
... | ... | |
478 | 598 |
// Remove the content |
479 | 599 |
$('#modalContent').remove(); |
480 | 600 |
$('#modalBackdrop').remove(); |
601 |
|
|
602 |
// Restore focus to where it was before opening the dialog |
|
603 |
$(oldFocus).focus(); |
|
481 | 604 |
}; |
482 | 605 |
|
483 |
// Move and resize the modalBackdrop and modalContent on resize of the window
|
|
484 |
modalContentResize = function(){
|
|
606 |
// Move and resize the modalBackdrop and modalContent on window resize.
|
|
607 |
modalContentResize = function(){ |
|
485 | 608 |
|
486 |
// position code lifted from http://www.quirksmode.org/viewport/compatibility.html |
|
609 |
// Reset the backdrop height/width to get accurate document size. |
|
610 |
$('#modalBackdrop').css('height', '').css('width', ''); |
|
611 |
|
|
612 |
// Position code lifted from: |
|
613 |
// http://www.quirksmode.org/viewport/compatibility.html |
|
487 | 614 |
if (self.pageYOffset) { // all except Explorer |
488 | 615 |
var wt = self.pageYOffset; |
489 | 616 |
} else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict |
... | ... | |
509 | 636 |
modalContent.css('top', mdcTop + 'px').css('left', mdcLeft + 'px').show(); |
510 | 637 |
}; |
511 | 638 |
$(window).bind('resize', modalContentResize); |
512 |
|
|
513 |
$('#modalContent').focus(); |
|
514 | 639 |
}; |
515 | 640 |
|
516 | 641 |
/** |
... | ... | |
533 | 658 |
$(window).unbind('resize', modalContentResize); |
534 | 659 |
$('body').unbind('focus', modalEventHandler); |
535 | 660 |
$('body').unbind('keypress', modalEventHandler); |
661 |
$('body').unbind( 'keydown', modalTabTrapHandler ); |
|
536 | 662 |
$('.close').unbind('click', modalContentClose); |
663 |
$('body').unbind('keypress', modalEventEscapeCloseHandler); |
|
537 | 664 |
$(document).trigger('CToolsDetachBehaviors', $('#modalContent')); |
538 | 665 |
|
539 | 666 |
// jQuery magic loop through the instances and run the animations or removal. |
Formats disponibles : Unified diff
Update ctools 1.7 -> 1.9