Skip to content

Commit 35092c2

Browse files
committed
feat: New plugin upload UI
1 parent 2de7ed3 commit 35092c2

File tree

7 files changed

+564
-12
lines changed

7 files changed

+564
-12
lines changed

Gruntfile.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ module.exports = function(grunt) {
360360
[ WORKING_DIR + 'wp-admin/js/password-strength-meter.js' ]: [ './src/js/_enqueues/wp/password-strength-meter.js' ],
361361
[ WORKING_DIR + 'wp-admin/js/password-toggle.js' ]: [ './src/js/_enqueues/admin/password-toggle.js' ],
362362
[ WORKING_DIR + 'wp-admin/js/plugin-install.js' ]: [ './src/js/_enqueues/admin/plugin-install.js' ],
363+
[ WORKING_DIR + 'wp-admin/js/plugin-upload.js' ]: [ './src/js/_enqueues/admin/plugin-upload.js' ],
363364
[ WORKING_DIR + 'wp-admin/js/post.js' ]: [ './src/js/_enqueues/admin/post.js' ],
364365
[ WORKING_DIR + 'wp-admin/js/postbox.js' ]: [ './src/js/_enqueues/admin/postbox.js' ],
365366
[ WORKING_DIR + 'wp-admin/js/revisions.js' ]: [ './src/js/_enqueues/wp/revisions.js' ],
@@ -957,6 +958,7 @@ module.exports = function(grunt) {
957958
'src/wp-admin/js/nav-menu.js': 'src/js/_enqueues/lib/nav-menu.js',
958959
'src/wp-admin/js/password-strength-meter.js': 'src/js/_enqueues/wp/password-strength-meter.js',
959960
'src/wp-admin/js/plugin-install.js': 'src/js/_enqueues/admin/plugin-install.js',
961+
'src/wp-admin/js/plugin-upload.js': 'src/js/_enqueues/admin/plugin-upload.js',
960962
'src/wp-admin/js/post.js': 'src/js/_enqueues/admin/post.js',
961963
'src/wp-admin/js/postbox.js': 'src/js/_enqueues/admin/postbox.js',
962964
'src/wp-admin/js/revisions.js': 'src/js/_enqueues/wp/revisions.js',
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
/**
2+
* @file Functionality for the plugin upload screen.
3+
*
4+
* @output wp-admin/js/plugin-upload.js
5+
*/
6+
7+
/* global plugin_upload_intl, plupload, pluginUploaderInit, ajaxurl, upload_plugin_nonce, activate_plugin_nonce, cancel_overwrite_nonce */
8+
9+
function pluginFileQueued( fileObj ) {
10+
jQuery( '#plugin-upload-list' ).append( `
11+
<div class="plugin-card" id="plugin-item-${ fileObj.id }">
12+
<div class="plugin-card-top">
13+
<div class="name column-name">
14+
<h3>${ fileObj.name }</h3>
15+
<div class="media-item"><div class="progress"><div class="percent">0%</div><div class="bar"></div></div></div>
16+
</div>
17+
<div class="action-links"><ul class="plugin-action-buttons"></ul></div>
18+
<div class="desc column-description" style="text-align: left"><p class="description"></p><p class="authors"></p></div>
19+
</div>
20+
</div>
21+
` );
22+
}
23+
24+
function buildComparisonTable( fileObj, data ) {
25+
return `
26+
<div id="plugin-modal-window-${ fileObj.id }" style="display:none;">
27+
<table class="update-from-upload-comparison">
28+
<tbody>
29+
<tr>
30+
<th></th>
31+
<th>${ plugin_upload_intl.current }</th>
32+
<th>${ plugin_upload_intl.uploaded }</th>
33+
</tr>
34+
<tr>
35+
<td class="name-label">${ plugin_upload_intl.plugin_name }</td>
36+
<td>${ data.Name[ 0 ] }</td>
37+
<td>${ data.Name[ 1 ] }</td>
38+
</tr>
39+
<tr>
40+
<td class="name-label">${ plugin_upload_intl.version }</td>
41+
<td>${ data.Version[ 0 ] }</td>
42+
<td>${ data.Version[ 1 ] }</td>
43+
</tr>
44+
<tr>
45+
<td class="name-label">${ plugin_upload_intl.author }</td>
46+
<td>${ data.Author[ 0 ] }</td>
47+
<td>${ data.Author[ 1 ] }</td>
48+
</tr>
49+
<tr>
50+
<td class="name-label">${ plugin_upload_intl.required_wordpress_version }</td>
51+
<td>${ data.RequiresWP[ 0 ] }</td>
52+
<td>${ data.RequiresWP[ 1 ] }</td>
53+
</tr>
54+
<tr>
55+
<td class="name-label">${ plugin_upload_intl.required_php_version }</td>
56+
<td>${ data.RequiresPHP[ 0 ] }</td>
57+
<td>${ data.RequiresPHP[ 1 ] }</td>
58+
</tr>
59+
</tbody>
60+
</table>
61+
</div>
62+
63+
`;
64+
}
65+
function pluginUploadProgress( up, file ) {
66+
const item = jQuery( '#plugin-item-' + file.id );
67+
68+
jQuery( '.bar', item ).width( ( 200 * file.loaded ) / file.size );
69+
if ( 100 == file.percent ) {
70+
jQuery( '.percent', item ).html(
71+
plugin_upload_intl.processing + '...'
72+
);
73+
} else {
74+
jQuery( '.percent', item ).html( file.percent + '%' );
75+
}
76+
}
77+
78+
function pluginUploadSuccess( fileObj, serverData ) {
79+
const item = jQuery( '#plugin-item-' + fileObj.id );
80+
const action_selector = jQuery( '.plugin-action-buttons', item );
81+
const description_selector = jQuery(
82+
'.column-description .description',
83+
item
84+
);
85+
const response_json = JSON.parse( serverData );
86+
const data = response_json.data;
87+
description_selector.text( data.plugin.Description );
88+
jQuery( '.column-description .authors', item ).text(
89+
'By ' + data.plugin.Author
90+
);
91+
// https://s.w.org/plugins/geopattern-icon/cf7-kofi.svg
92+
const temp_slug = data.plugin.Title.toLowerCase().replace( ' ', '-' );
93+
jQuery( '.name h3', item )
94+
.html(
95+
`${ data.plugin.Name } <img src="https://s.w.org/plugins/geopattern-icon/${ temp_slug }.svg" class="plugin-icon" alt="">`
96+
)
97+
.css( { textAlign: 'left' } );
98+
jQuery( '.media-item', item ).hide();
99+
if ( 'can_override' === data.successCode ) {
100+
if ( data.comparisonMessage.Downgrade ) {
101+
action_selector.append(
102+
`<li><button class="button activate-button overwrite-plugin" data-attachment="${ data.attachment_id }"> ${ plugin_upload_intl.downgrade } </button></li>`
103+
);
104+
} else {
105+
action_selector.append(
106+
`<li><button class="button activate-button overwrite-plugin" data-attachment="${ data.attachment_id }"> ${ plugin_upload_intl.upgrade } </button></li>`
107+
);
108+
}
109+
action_selector.append(
110+
`<li><button class="button activate-button cancel-overwrite" data-file="${fileObj.id}" data-attachment="${ data.attachment_id }"> ${ plugin_upload_intl.cancel } </button></li>`
111+
);
112+
action_selector.append(
113+
`<li><a href="#TB_inline?&inlineId=plugin-modal-window-${ fileObj.id }&width=700" class="thickbox" data-title="${ data.plugin.Name } ${ data.plugin.Version }">${ plugin_upload_intl.more_details }</a></li>`
114+
);
115+
description_selector.append(
116+
buildComparisonTable( fileObj, data.comparisonMessage )
117+
);
118+
jQuery( '.button.overwrite-plugin' )
119+
.unbind()
120+
.click( function () {
121+
const button = jQuery( this );
122+
const attachment_id = button.data( 'attachment' );
123+
overwritePlugin( attachment_id, button );
124+
} );
125+
jQuery( '.button.cancel-overwrite' )
126+
.unbind()
127+
.click( function () {
128+
const button = jQuery( this );
129+
const attachment_id = button.data( 'attachment' );
130+
const file_id = button.data( 'file' );
131+
cancelOverwritePlugin( file_id, attachment_id, button );
132+
} );
133+
} else {
134+
action_selector.append(
135+
`<li><button class="button activate-button activate-plugin button-primary" data-name="${data.plugin.Name}" data-path="${data.path}"> ${ plugin_upload_intl.activate } </button></li>`
136+
);
137+
138+
jQuery( '.button.activate-plugin' )
139+
.unbind()
140+
.click( function () {
141+
const button = jQuery( this );
142+
const path = button.data( 'path' );
143+
const name = button.data( 'name' );
144+
activatePlugin( path,name, button );
145+
} );
146+
}
147+
}
148+
149+
function pluginUploadError( fileObj, errorCode, message ) {
150+
if ( message ) {
151+
const item = jQuery( '#plugin-item-' + fileObj.id );
152+
const description_selector = jQuery(
153+
'.column-description .description',
154+
item
155+
);
156+
157+
jQuery( '.media-item', item ).hide();
158+
const responseJSON = JSON.parse( message );
159+
if (
160+
responseJSON &&
161+
responseJSON.data &&
162+
responseJSON.data.errorMessage
163+
) {
164+
description_selector.html(
165+
`<div class="notice notice-error update-nag inline">${ responseJSON.data.errorMessage }</div>`
166+
);
167+
} else {
168+
description_selector.html(
169+
`<div class="notice notice-error update-nag inline">${ plugin_upload_intl.generic_error }</div>`
170+
);
171+
}
172+
}
173+
}
174+
175+
function overwritePlugin( attachment_id, button ) {
176+
const formData = new FormData();
177+
formData.append( '_wpnonce', upload_plugin_nonce );
178+
formData.append( 'action', 'upload-plugin' );
179+
button.prop( 'disabled', true );
180+
button.text( plugin_upload_intl.processing + '...' );
181+
182+
jQuery.ajax( {
183+
type: 'POST',
184+
url: ajaxurl + '?package=' + attachment_id + '&overwrite=update-plugin',
185+
data: formData,
186+
processData: false, // Important: tell jQuery not to process the data.
187+
contentType: false, // Important: tell jQuery not to set contentType.
188+
189+
success: function ( ) {
190+
button.text( plugin_upload_intl.updated );
191+
},
192+
error: function ( ) {
193+
button.prop( 'disabled', false );
194+
button.text( plugin_upload_intl.activation_failed );
195+
},
196+
} );
197+
}
198+
199+
function cancelOverwritePlugin( file_id ,attachment_id, button ) {
200+
const formData = new FormData();
201+
formData.append( '_wpnonce', cancel_overwrite_nonce );
202+
formData.append( 'action', 'cancel-plugin-overwrite' );
203+
button.prop( 'disabled', true );
204+
button.text( plugin_upload_intl.processing + '...' );
205+
206+
jQuery.ajax( {
207+
type: 'POST',
208+
url: ajaxurl + '?package=' + attachment_id,
209+
data: formData,
210+
processData: false, // Important: tell jQuery not to process the data.
211+
contentType: false, // Important: tell jQuery not to set contentType.
212+
213+
success: function ( ) {
214+
// Remove element from the dom.
215+
jQuery( '#plugin-item-' + file_id ).remove();
216+
217+
},
218+
error: function ( ) {
219+
button.prop( 'disabled', false );
220+
button.text( plugin_upload_intl.cancel_failed );
221+
},
222+
} );
223+
}
224+
function activatePlugin( path, name, button ) {
225+
const formData = new FormData();
226+
formData.append( 'plugin', path );
227+
formData.append( 'name', name );
228+
formData.append( 'slug', name.toLowerCase().replace( / /g, '-' ) );
229+
formData.append( '_wpnonce', activate_plugin_nonce );
230+
formData.append( 'action', 'activate-plugin' );
231+
button.prop( 'disabled', true );
232+
button.text( plugin_upload_intl.processing + '...' );
233+
jQuery.ajax( {
234+
type: 'POST',
235+
url: ajaxurl,
236+
data: formData,
237+
processData: false, // Important: tell jQuery not to process the data
238+
contentType: false, // Important: tell jQuery not to set contentType
239+
240+
success: function ( ) {
241+
button.text( plugin_upload_intl.activated );
242+
},
243+
error: function ( ) {
244+
button.prop( 'disabled', false );
245+
button.text( plugin_upload_intl.failed );
246+
},
247+
} );
248+
}
249+
jQuery( function ( $ ) {
250+
const uploader_init = function () {
251+
const uploader = new plupload.Uploader( pluginUploaderInit );
252+
253+
uploader.bind( 'Init', function ( up ) {
254+
var uploaddiv = $( '#plupload-upload-ui' );
255+
256+
if (
257+
up.features.dragdrop &&
258+
! $( document.body ).hasClass( 'mobile' )
259+
) {
260+
uploaddiv.addClass( 'drag-drop' );
261+
262+
$( '#drag-drop-area' )
263+
.on( 'dragover.wp-uploader', function () {
264+
// dragenter doesn't fire right :(
265+
uploaddiv.addClass( 'drag-over' );
266+
} )
267+
.on(
268+
'dragleave.wp-uploader, drop.wp-uploader',
269+
function () {
270+
uploaddiv.removeClass( 'drag-over' );
271+
}
272+
);
273+
} else {
274+
uploaddiv.removeClass( 'drag-drop' );
275+
$( '#drag-drop-area' ).off( '.wp-uploader' );
276+
}
277+
278+
if ( up.runtime === 'html4' ) {
279+
$( '.upload-flash-bypass' ).hide();
280+
}
281+
} );
282+
283+
uploader.bind( 'postinit', function ( up ) {
284+
up.refresh();
285+
} );
286+
287+
uploader.init();
288+
289+
uploader.bind( 'FilesAdded', function ( up, files ) {
290+
plupload.each( files, function ( file ) {
291+
if ( file.type !== 'application/zip' ) {
292+
// Ignore zip files
293+
return;
294+
}
295+
296+
pluginFileQueued( file );
297+
} );
298+
299+
up.refresh();
300+
up.start();
301+
} );
302+
303+
uploader.bind( 'UploadProgress', function ( up, file ) {
304+
pluginUploadProgress( up, file );
305+
} );
306+
307+
uploader.bind( 'Error', function ( up, error ) {
308+
pluginUploadError( error.file, error.code, error.response );
309+
up.refresh();
310+
} );
311+
312+
uploader.bind( 'FileUploaded', function ( up, file, response ) {
313+
pluginUploadSuccess( file, response.response );
314+
} );
315+
};
316+
317+
uploader_init();
318+
} );

src/wp-admin/admin-ajax.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@
117117
'parse-media-shortcode',
118118
'destroy-sessions',
119119
'install-plugin',
120+
'upload-plugin',
121+
'cancel-plugin-overwrite',
120122
'activate-plugin',
121123
'update-plugin',
122124
'crop-image',

0 commit comments

Comments
 (0)