PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / trunk
Jetpack – WP Security, Backup, Speed, & Growth vtrunk
16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / videopress / js / videopress-media-new.js
jetpack / modules / videopress / js Last commit date
editor-view.js 9 months ago gutenberg-video-upload.js 6 months ago media-video-widget-extensions.js 6 years ago videopress-add-resumable-upload-support.js 4 years ago videopress-media-new.js 1 month ago videopress-plupload.js 8 months ago videopress-uploader.js 2 months ago
videopress-media-new.js
345 lines
1 /* global plupload, pluploadL10n, ajaxurl, wpUploaderInit, uploadSuccess, wpFileError, wpQueueError, videoPressMediaNew */
2
3 /**
4 * Routes video uploads from wp-admin/media-new.php to VideoPress.
5 *
6 * The classic uploader (plupload-handlers) creates a raw plupload.Uploader
7 * rather than wp.Uploader, so the override in videopress-plupload.js never
8 * engages there. This shim registers the same videopress_check_uploads file
9 * filter and re-targets video uploads to VideoPress, then hands the local
10 * attachment ID created during the upload back to the stock uploadSuccess
11 * handler so the classic UI renders the media item as usual.
12 */
13 ( function ( $ ) {
14 if ( typeof plupload === 'undefined' ) {
15 return;
16 }
17
18 var originalOptions = {};
19
20 // Videos accepted for VideoPress upload since the page loaded, used to
21 // enforce the free plan's single-video limit within an upload session.
22 var acceptedVideoCount = 0;
23
24 // Video files in the selection currently being added to the uploader,
25 // recorded before the file filters run so the free-plan gate can block a
26 // multi-video selection before any upload starts.
27 var pendingBatchVideoCount = 0;
28
29 /**
30 * Counts the video files in an addFile() argument.
31 *
32 * @param {Array|FileList|object} file What was passed to addFile: a single
33 * file or an array-like of files.
34 * @return {number} How many of them are videos.
35 */
36 function countVideoFiles( file ) {
37 var files = file && typeof file.length === 'number' ? file : [ file ];
38 var count = 0;
39
40 for ( var i = 0; i < files.length; i++ ) {
41 var type = files[ i ] && files[ i ].type;
42
43 if ( type && type.split( '/' )[ 0 ] === 'video' ) {
44 count++;
45 }
46 }
47
48 return count;
49 }
50
51 /**
52 * Returns the upload limit data localized by the module.
53 *
54 * @return {object} The limit data.
55 */
56 function getUploadLimits() {
57 return typeof videoPressMediaNew !== 'undefined' ? videoPressMediaNew : {};
58 }
59
60 // Class of the container the upgrade notice renders in.
61 var NOTICE_CLASS = 'videopress-media-new-notice';
62
63 /**
64 * Removes any previously rendered upgrade notice.
65 */
66 function removeUpgradeNotice() {
67 var notices = document.querySelectorAll( '.' + NOTICE_CLASS );
68
69 for ( var i = 0; i < notices.length; i++ ) {
70 notices[ i ].parentNode.removeChild( notices[ i ] );
71 }
72 }
73
74 /**
75 * Shows the free-plan upgrade notice above the upload queue.
76 *
77 * The message is pre-escaped HTML built server-side, containing the link
78 * to the upgrade path. It renders in a container of its own next to the
79 * stock #media-upload-error area rather than inside it: the stock
80 * FilesAdded handler empties #media-upload-error as soon as any file of
81 * the selection is accepted, which would wipe a notice rendered there
82 * before the user could read it.
83 *
84 * @param {string} message The notice HTML.
85 */
86 function showUpgradeNotice( message ) {
87 if ( ! message ) {
88 return;
89 }
90
91 var anchor = document.getElementById( 'media-upload-error' );
92
93 if ( ! anchor || ! anchor.parentNode ) {
94 // The stock error area is better than no notice at all.
95 if ( typeof wpQueueError === 'function' ) {
96 wpQueueError( message );
97 }
98 return;
99 }
100
101 removeUpgradeNotice();
102
103 var notice = document.createElement( 'div' );
104 notice.className = 'notice notice-warning ' + NOTICE_CLASS;
105
106 var paragraph = document.createElement( 'p' );
107 // The message is localized server-side and passed through wp_kses;
108 // it only contains the upgrade link markup.
109 paragraph.innerHTML = message;
110
111 notice.appendChild( paragraph );
112 anchor.parentNode.insertBefore( notice, anchor.nextSibling );
113 }
114
115 /**
116 * Free-plan gate for a video file: the free plan includes a single video
117 * upload, so reject every video once the site already has a VideoPress
118 * video, and allow only one video per upload session otherwise.
119 *
120 * @param {plupload.File} file The video file being queued.
121 * @param {Function} cb The file filter continuation callback.
122 * @return {boolean} Whether the file was rejected.
123 */
124 function rejectedByFreePlanLimits( file, cb ) {
125 var limits = getUploadLimits();
126 var strings = limits.strings || {};
127
128 if ( limits.hasVideoPressPurchase ) {
129 return false;
130 }
131
132 if ( limits.hasUsedVideo ) {
133 showUpgradeNotice( strings.usedVideoUpload );
134 cb( false );
135 return true;
136 }
137
138 // A selection with more than one video is blocked entirely — including
139 // its first video — so no upload starts until the user upgrades.
140 if ( pendingBatchVideoCount > 1 ) {
141 showUpgradeNotice( strings.multipleVideosSelected );
142 cb( false );
143 return true;
144 }
145
146 if ( acceptedVideoCount >= 1 ) {
147 showUpgradeNotice( strings.multipleVideos );
148 cb( false );
149 return true;
150 }
151
152 return false;
153 }
154
155 /**
156 * Restores the stock upload settings saved before a VideoPress upload.
157 *
158 * @param {plupload.Uploader} up Uploader instance.
159 */
160 function restoreOriginalOptions( up ) {
161 if ( typeof originalOptions.url === 'undefined' ) {
162 return;
163 }
164
165 up.setOption( 'url', originalOptions.url );
166 up.setOption( 'file_data_name', originalOptions.file_data_name );
167 up.setOption( 'headers', originalOptions.headers );
168
169 originalOptions = {};
170 }
171
172 /**
173 * For video files, fetch a VideoPress upload token and attach it to the
174 * file before it is queued. Mirrors the videopress_check_uploads filter in
175 * videopress-uploader.js without depending on wp.media, which is not
176 * loaded on media-new.php. Non-video files get the stock max_file_size
177 * behavior this filter replaces.
178 */
179 plupload.addFileFilter( 'videopress_check_uploads', function ( maxSize, file, cb ) {
180 var self = this;
181
182 /**
183 * Rejects the file with an uploader error.
184 *
185 * @param {string} [message] Error message to display.
186 */
187 function fail( message ) {
188 self.trigger( 'Error', {
189 code: plupload.HTTP_ERROR,
190 message:
191 message ||
192 plupload.translate( 'Could not get the VideoPress token needed for uploading' ),
193 file: file,
194 } );
195 cb( false );
196 }
197
198 if ( file.type && file.type.split( '/' )[ 0 ] === 'video' ) {
199 if ( rejectedByFreePlanLimits( file, cb ) ) {
200 return;
201 }
202
203 $.post( ajaxurl, { action: 'videopress-get-upload-token', filename: file.name } )
204 .done( function ( response ) {
205 if (
206 ! response ||
207 ! response.success ||
208 ! response.data ||
209 ! response.data.upload_action_url
210 ) {
211 fail( response && response.data && response.data.message );
212 return;
213 }
214
215 file.videopress = response.data;
216 acceptedVideoCount++;
217 cb( true );
218 } )
219 .fail( function () {
220 fail();
221 } );
222
223 return;
224 }
225
226 // Handles the stock max_file_size functionality for non-video files.
227 if (
228 typeof file.size !== 'undefined' &&
229 maxSize &&
230 file.size > plupload.parseSize( maxSize )
231 ) {
232 this.trigger( 'Error', {
233 code: plupload.FILE_SIZE_ERROR,
234 message: pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name ),
235 file: file,
236 } );
237 cb( false );
238 return;
239 }
240
241 cb( true );
242 } );
243
244 $( function () {
245 // plupload-handlers is a dependency of this script, so its ready
246 // callback ran first and the global `uploader` already exists.
247 if (
248 typeof wpUploaderInit === 'undefined' ||
249 typeof window.uploader === 'undefined' ||
250 ! window.uploader
251 ) {
252 return;
253 }
254
255 var uploader = window.uploader;
256
257 /**
258 * Record how many videos each selection contains before plupload runs
259 * the file filters, so the free-plan gate can reject every video of a
260 * multi-video selection. Both the file selector and drag-and-drop
261 * funnel their whole selection through a single addFile() call.
262 */
263 var stockAddFile = uploader.addFile;
264
265 uploader.addFile = function ( file, fileName ) {
266 // Each selection starts clean: a notice about a previous
267 // selection no longer applies to this one.
268 removeUpgradeNotice();
269 pendingBatchVideoCount = countVideoFiles( file );
270 return stockAddFile.call( this, file, fileName );
271 };
272
273 /**
274 * Re-target VideoPress files right before each upload starts and
275 * restore the stock settings for everything else, so mixed batches
276 * of videos and other media both land in the right place.
277 */
278 uploader.bind( 'BeforeUpload', function ( up, file ) {
279 if ( typeof file.videopress === 'undefined' ) {
280 restoreOriginalOptions( up );
281 return;
282 }
283
284 if ( typeof originalOptions.url === 'undefined' ) {
285 originalOptions.url = up.getOption( 'url' );
286 originalOptions.file_data_name = up.getOption( 'file_data_name' );
287 originalOptions.headers = up.getOption( 'headers' );
288 }
289
290 up.setOption( 'url', file.videopress.upload_action_url );
291 up.setOption( 'file_data_name', 'media[]' );
292 up.setOption( 'headers', {
293 Authorization:
294 'X_UPLOAD_TOKEN token="' +
295 file.videopress.upload_token +
296 '" blog_id="' +
297 file.videopress.upload_blog_id +
298 '"',
299 } );
300 } );
301
302 uploader.bind( 'Error', function ( up ) {
303 restoreOriginalOptions( up );
304 } );
305
306 uploader.bind( 'UploadComplete', function ( up ) {
307 restoreOriginalOptions( up );
308 } );
309
310 /**
311 * The stock FileUploaded handler calls the global uploadSuccess with
312 * the raw server response, which for VideoPress uploads is the REST
313 * API media response instead of the attachment ID async-upload.php
314 * returns. Wrap uploadSuccess to translate the former into the
315 * latter; the stock handler then loads the media item row from
316 * async-upload.php as it would for any other upload.
317 */
318 var stockUploadSuccess = uploadSuccess;
319
320 window.uploadSuccess = function ( fileObj, serverData ) {
321 if ( typeof fileObj.videopress === 'undefined' ) {
322 return stockUploadSuccess( fileObj, serverData );
323 }
324
325 var response = null;
326
327 try {
328 response = JSON.parse( serverData );
329 } catch {
330 // Handled below.
331 }
332
333 var media = response && response.media && response.media[ 0 ];
334
335 if ( ! media || ! media.ID ) {
336 var message = response && ( response.message || response.error );
337 wpFileError( fileObj, message || pluploadL10n.default_error );
338 return;
339 }
340
341 return stockUploadSuccess( fileObj, String( media.ID ) );
342 };
343 } );
344 } )( jQuery );
345