plugin-install.js
6.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/**
* @file Functionality for the plugin install screens.
*
* @output wp-admin/js/plugin-install.js
*/
/* global tb_click, tb_remove, tb_position */
jQuery( function( $ ) {
var tbWindow,
$iframeBody,
$tabbables,
$firstTabbable,
$lastTabbable,
$focusedBefore = $(),
$uploadViewToggle = $( '.upload-view-toggle' ),
$wrap = $ ( '.wrap' ),
$body = $( document.body );
window.tb_position = function() {
var width = $( window ).width(),
H = $( window ).height() - ( ( 792 < width ) ? 60 : 20 ),
W = ( 792 < width ) ? 772 : width - 20;
tbWindow = $( '#TB_window' );
if ( tbWindow.length ) {
tbWindow.width( W ).height( H );
$( '#TB_iframeContent' ).width( W ).height( H );
tbWindow.css({
'margin-left': '-' + parseInt( ( W / 2 ), 10 ) + 'px'
});
if ( typeof document.body.style.maxWidth !== 'undefined' ) {
tbWindow.css({
'top': '30px',
'margin-top': '0'
});
}
}
return $( 'a.thickbox' ).each( function() {
var href = $( this ).attr( 'href' );
if ( ! href ) {
return;
}
href = href.replace( /&width=[0-9]+/g, '' );
href = href.replace( /&height=[0-9]+/g, '' );
$(this).attr( 'href', href + '&width=' + W + '&height=' + ( H ) );
});
};
$( window ).on( 'resize', function() {
tb_position();
});
/*
* Custom events: when a Thickbox iframe has loaded and when the Thickbox
* modal gets removed from the DOM.
*/
$body
.on( 'thickbox:iframe:loaded', tbWindow, function() {
/*
* Return if it's not the modal with the plugin details iframe. Other
* thickbox instances might want to load an iframe with content from
* an external domain. Avoid to access the iframe contents when we're
* not sure the iframe loads from the same domain.
*/
if ( ! tbWindow.hasClass( 'plugin-details-modal' ) ) {
return;
}
iframeLoaded();
})
.on( 'thickbox:removed', function() {
// Set focus back to the element that opened the modal dialog.
// Note: IE 8 would need this wrapped in a fake setTimeout `0`.
$focusedBefore.trigger( 'focus' );
});
function iframeLoaded() {
var $iframe = tbWindow.find( '#TB_iframeContent' );
// Get the iframe body.
$iframeBody = $iframe.contents().find( 'body' );
// Get the tabbable elements and handle the keydown event on first load.
handleTabbables();
// Set initial focus on the "Close" button.
$firstTabbable.trigger( 'focus' );
/*
* When the "Install" button is disabled (e.g. the Plugin is already installed)
* then we can't predict where the last focusable element is. We need to get
* the tabbable elements and handle the keydown event again and again,
* each time the active tab panel changes.
*/
$( '#plugin-information-tabs a', $iframeBody ).on( 'click', function() {
handleTabbables();
});
// Close the modal when pressing Escape.
$iframeBody.on( 'keydown', function( event ) {
if ( 27 !== event.which ) {
return;
}
tb_remove();
});
}
/*
* Get the tabbable elements and detach/attach the keydown event.
* Called after the iframe has fully loaded so we have all the elements we need.
* Called again each time a Tab gets clicked.
* @todo Consider to implement a WordPress general utility for this and don't use jQuery UI.
*/
function handleTabbables() {
var $firstAndLast;
// Get all the tabbable elements.
$tabbables = $( ':tabbable', $iframeBody );
// Our first tabbable element is always the "Close" button.
$firstTabbable = tbWindow.find( '#TB_closeWindowButton' );
// Get the last tabbable element.
$lastTabbable = $tabbables.last();
// Make a jQuery collection.
$firstAndLast = $firstTabbable.add( $lastTabbable );
// Detach any previously attached keydown event.
$firstAndLast.off( 'keydown.wp-plugin-details' );
// Attach again the keydown event on the first and last focusable elements.
$firstAndLast.on( 'keydown.wp-plugin-details', function( event ) {
constrainTabbing( event );
});
}
// Constrain tabbing within the plugin modal dialog.
function constrainTabbing( event ) {
if ( 9 !== event.which ) {
return;
}
if ( $lastTabbable[0] === event.target && ! event.shiftKey ) {
event.preventDefault();
$firstTabbable.trigger( 'focus' );
} else if ( $firstTabbable[0] === event.target && event.shiftKey ) {
event.preventDefault();
$lastTabbable.trigger( 'focus' );
}
}
/*
* Open the Plugin details modal. The event is delegated to get also the links
* in the plugins search tab, after the Ajax search rebuilds the HTML. It's
* delegated on the closest ancestor and not on the body to avoid conflicts
* with other handlers, see Trac ticket #43082.
*/
$( '.wrap' ).on( 'click', '.thickbox.open-plugin-details-modal', function( e ) {
// The `data-title` attribute is used only in the Plugin screens.
var title = $( this ).data( 'title' ) ?
wp.i18n.sprintf(
// translators: %s: Plugin name.
wp.i18n.__( 'Plugin: %s' ),
$( this ).data( 'title' )
) :
wp.i18n.__( 'Plugin details' );
e.preventDefault();
e.stopPropagation();
// Store the element that has focus before opening the modal dialog, i.e. the control which opens it.
$focusedBefore = $( this );
tb_click.call(this);
// Set ARIA role, ARIA label, and add a CSS class.
tbWindow
.attr({
'role': 'dialog',
'aria-label': wp.i18n.__( 'Plugin details' )
})
.addClass( 'plugin-details-modal' );
// Set title attribute on the iframe.
tbWindow.find( '#TB_iframeContent' ).attr( 'title', title );
});
/* Plugin install related JS */
$( '#plugin-information-tabs a' ).on( 'click', function( event ) {
var tab = $( this ).attr( 'name' );
event.preventDefault();
// Flip the tab.
$( '#plugin-information-tabs a.current' ).removeClass( 'current' );
$( this ).addClass( 'current' );
// Only show the fyi box in the description section, on smaller screen,
// where it's otherwise always displayed at the top.
if ( 'description' !== tab && $( window ).width() < 772 ) {
$( '#plugin-information-content' ).find( '.fyi' ).hide();
} else {
$( '#plugin-information-content' ).find( '.fyi' ).show();
}
// Flip the content.
$( '#section-holder div.section' ).hide(); // Hide 'em all.
$( '#section-' + tab ).show();
});
/*
* When a user presses the "Upload Plugin" button, show the upload form in place
* rather than sending them to the devoted upload plugin page.
* The `?tab=upload` page still exists for no-js support and for plugins that
* might access it directly. When we're in this page, let the link behave
* like a link. Otherwise we're in the normal plugin installer pages and the
* link should behave like a toggle button.
*/
if ( ! $wrap.hasClass( 'plugin-install-tab-upload' ) ) {
$uploadViewToggle
.attr({
role: 'button',
'aria-expanded': 'false'
})
.on( 'click', function( event ) {
event.preventDefault();
$body.toggleClass( 'show-upload-view' );
$uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
});
}
});