var $ = jQuery,
Modal;
/**
* wp.media.view.Modal
*
* A modal view, which the media modal uses as its default container.
*
* @memberOf wp.media.view
*
* @class
* @augments wp.media.View
* @augments wp.Backbone.View
* @augments Backbone.View
*/
Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
tagName: 'div',
template: wp.template('media-modal'),
events: {
'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
'keydown': 'keydown'
},
clickedOpenerEl: null,
initialize: function() {
_.defaults( this.options, {
container: document.body,
title: '',
propagate: true,
hasCloseButton: true
});
this.focusManager = new wp.media.view.FocusManager({
el: this.el
});
},
/**
* @return {Object}
*/
prepare: function() {
return {
title: this.options.title,
hasCloseButton: this.options.hasCloseButton
};
},
/**
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
attach: function() {
if ( this.views.attached ) {
return this;
}
if ( ! this.views.rendered ) {
this.render();
}
this.$el.appendTo( this.options.container );
// Manually mark the view as attached and trigger ready.
this.views.attached = true;
this.views.ready();
return this.propagate('attach');
},
/**
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
detach: function() {
if ( this.$el.is(':visible') ) {
this.close();
}
this.$el.detach();
this.views.attached = false;
return this.propagate('detach');
},
/**
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
open: function() {
var $el = this.$el,
mceEditor;
if ( $el.is(':visible') ) {
return this;
}
this.clickedOpenerEl = document.activeElement;
if ( ! this.views.attached ) {
this.attach();
}
// Disable page scrolling.
$( 'body' ).addClass( 'modal-open' );
$el.show();
// Try to close the onscreen keyboard.
if ( 'ontouchend' in document ) {
if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
mceEditor.iframeElement.focus();
mceEditor.iframeElement.blur();
setTimeout( function() {
mceEditor.iframeElement.blur();
}, 100 );
}
}
// Set initial focus on the content instead of this view element, to avoid page scrolling.
this.$( '.media-modal' ).focus();
// Hide the page content from assistive technologies.
this.focusManager.setAriaHiddenOnBodyChildren( $el );
return this.propagate('open');
},
/**
* @param {Object} options
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
close: function( options ) {
if ( ! this.views.attached || ! this.$el.is(':visible') ) {
return this;
}
// Enable page scrolling.
$( 'body' ).removeClass( 'modal-open' );
// Hide modal and remove restricted media modal tab focus once it's closed.
this.$el.hide().undelegate( 'keydown' );
/*
* Make visible again to assistive technologies all body children that
* have been made hidden when the modal opened.
*/
this.focusManager.removeAriaHiddenFromBodyChildren();
// Move focus back in useful location once modal is closed.
if ( null !== this.clickedOpenerEl ) {
// Move focus back to the element that opened the modal.
this.clickedOpenerEl.focus();
} else {
// Fallback to the admin page main element.
$( '#wpbody-content' )
.attr( 'tabindex', '-1' )
.focus();
}
this.propagate('close');
if ( options && options.escape ) {
this.propagate('escape');
}
return this;
},
/**
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
escape: function() {
return this.close({ escape: true });
},
/**
* @param {Object} event
*/
escapeHandler: function( event ) {
event.preventDefault();
this.escape();
},
/**
* @param {Array|Object} content Views to register to '.media-modal-content'
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
content: function( content ) {
this.views.set( '.media-modal-content', content );
return this;
},
/**
* Triggers a modal event and if the `propagate` option is set,
* forwards events to the modal's controller.
*
* @param {string} id
* @return {wp.media.view.Modal} Returns itself to allow chaining.
*/
propagate: function( id ) {
this.trigger( id );
if ( this.options.propagate ) {
this.controller.trigger( id );
}
return this;
},
/**
* @param {Object} event
*/
keydown: function( event ) {
// Close the modal when escape is pressed.
if ( 27 === event.which && this.$el.is(':visible') ) {
this.escape();
event.stopImmediatePropagation();
}
}
});
module.exports = Modal;