PluginProbe
Gutenberg / 20.0.1
Gutenberg v20.0.1
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / build / media-utils / index.js

index.js in Gutenberg 20.0.1, at build/media-utils/index.js

1,061 lines 30.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ "use strict";
3 /******/ // The require scope
4 /******/ var __webpack_require__ = {};
5 /******/
6 /************************************************************************/
7 /******/ /* webpack/runtime/compat get default export */
8 /******/ (() => {
9 /******/ // getDefaultExport function for compatibility with non-harmony modules
10 /******/ __webpack_require__.n = (module) => {
11 /******/ var getter = module && module.__esModule ?
12 /******/ () => (module['default']) :
13 /******/ () => (module);
14 /******/ __webpack_require__.d(getter, { a: getter });
15 /******/ return getter;
16 /******/ };
17 /******/ })();
18 /******/
19 /******/ /* webpack/runtime/define property getters */
20 /******/ (() => {
21 /******/ // define getter functions for harmony exports
22 /******/ __webpack_require__.d = (exports, definition) => {
23 /******/ for(var key in definition) {
24 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
25 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
26 /******/ }
27 /******/ }
28 /******/ };
29 /******/ })();
30 /******/
31 /******/ /* webpack/runtime/hasOwnProperty shorthand */
32 /******/ (() => {
33 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
34 /******/ })();
35 /******/
36 /******/ /* webpack/runtime/make namespace object */
37 /******/ (() => {
38 /******/ // define __esModule on exports
39 /******/ __webpack_require__.r = (exports) => {
40 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
41 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
42 /******/ }
43 /******/ Object.defineProperty(exports, '__esModule', { value: true });
44 /******/ };
45 /******/ })();
46 /******/
47 /************************************************************************/
48 var __webpack_exports__ = {};
49 // ESM COMPAT FLAG
50 __webpack_require__.r(__webpack_exports__);
51
52 // EXPORTS
53 __webpack_require__.d(__webpack_exports__, {
54 MediaUpload: () => (/* reexport */ media_upload),
55 privateApis: () => (/* reexport */ privateApis),
56 transformAttachment: () => (/* reexport */ transformAttachment),
57 uploadMedia: () => (/* reexport */ uploadMedia),
58 validateFileSize: () => (/* reexport */ validateFileSize),
59 validateMimeType: () => (/* reexport */ validateMimeType),
60 validateMimeTypeForUser: () => (/* reexport */ validateMimeTypeForUser)
61 });
62
63 ;// external ["wp","element"]
64 const external_wp_element_namespaceObject = window["wp"]["element"];
65 ;// external ["wp","i18n"]
66 const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
67 ;// ./packages/media-utils/build-module/components/media-upload/index.js
68 /* wp:polyfill */
69 /**
70 * WordPress dependencies
71 */
72
73
74 const DEFAULT_EMPTY_GALLERY = [];
75
76 /**
77 * Prepares the Featured Image toolbars and frames.
78 *
79 * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.
80 */
81 const getFeaturedImageMediaFrame = () => {
82 const {
83 wp
84 } = window;
85 return wp.media.view.MediaFrame.Select.extend({
86 /**
87 * Enables the Set Featured Image Button.
88 *
89 * @param {Object} toolbar toolbar for featured image state
90 * @return {void}
91 */
92 featuredImageToolbar(toolbar) {
93 this.createSelectToolbar(toolbar, {
94 text: wp.media.view.l10n.setFeaturedImage,
95 state: this.options.state
96 });
97 },
98 /**
99 * Handle the edit state requirements of selected media item.
100 *
101 * @return {void}
102 */
103 editState() {
104 const selection = this.state('featured-image').get('selection');
105 const view = new wp.media.view.EditImage({
106 model: selection.single(),
107 controller: this
108 }).render();
109
110 // Set the view to the EditImage frame using the selected image.
111 this.content.set(view);
112
113 // After bringing in the frame, load the actual editor via an ajax call.
114 view.loadEditor();
115 },
116 /**
117 * Create the default states.
118 *
119 * @return {void}
120 */
121 createStates: function createStates() {
122 this.on('toolbar:create:featured-image', this.featuredImageToolbar, this);
123 this.on('content:render:edit-image', this.editState, this);
124 this.states.add([new wp.media.controller.FeaturedImage(), new wp.media.controller.EditImage({
125 model: this.options.editImage
126 })]);
127 }
128 });
129 };
130
131 /**
132 * Prepares the default frame for selecting a single media item.
133 *
134 * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.
135 */
136 const getSingleMediaFrame = () => {
137 const {
138 wp
139 } = window;
140
141 // Extend the default Select frame, and use the same `createStates` method as in core,
142 // but with the addition of `filterable: 'uploaded'` to the Library state, so that
143 // the user can filter the media library by uploaded media.
144 return wp.media.view.MediaFrame.Select.extend({
145 /**
146 * Create the default states on the frame.
147 */
148 createStates() {
149 const options = this.options;
150 if (this.options.states) {
151 return;
152 }
153
154 // Add the default states.
155 this.states.add([
156 // Main states.
157 new wp.media.controller.Library({
158 library: wp.media.query(options.library),
159 multiple: options.multiple,
160 title: options.title,
161 priority: 20,
162 filterable: 'uploaded' // Allow filtering by uploaded images.
163 }), new wp.media.controller.EditImage({
164 model: options.editImage
165 })]);
166 }
167 });
168 };
169
170 /**
171 * Prepares the Gallery toolbars and frames.
172 *
173 * @return {window.wp.media.view.MediaFrame.Post} The default media workflow.
174 */
175 const getGalleryDetailsMediaFrame = () => {
176 const {
177 wp
178 } = window;
179 /**
180 * Custom gallery details frame.
181 *
182 * @see https://github.com/xwp/wp-core-media-widgets/blob/905edbccfc2a623b73a93dac803c5335519d7837/wp-admin/js/widgets/media-gallery-widget.js
183 * @class GalleryDetailsMediaFrame
184 * @class
185 */
186 return wp.media.view.MediaFrame.Post.extend({
187 /**
188 * Set up gallery toolbar.
189 *
190 * @return {void}
191 */
192 galleryToolbar() {
193 const editing = this.state().get('editing');
194 this.toolbar.set(new wp.media.view.Toolbar({
195 controller: this,
196 items: {
197 insert: {
198 style: 'primary',
199 text: editing ? wp.media.view.l10n.updateGallery : wp.media.view.l10n.insertGallery,
200 priority: 80,
201 requires: {
202 library: true
203 },
204 /**
205 * @fires wp.media.controller.State#update
206 */
207 click() {
208 const controller = this.controller,
209 state = controller.state();
210 controller.close();
211 state.trigger('update', state.get('library'));
212
213 // Restore and reset the default state.
214 controller.setState(controller.options.state);
215 controller.reset();
216 }
217 }
218 }
219 }));
220 },
221 /**
222 * Handle the edit state requirements of selected media item.
223 *
224 * @return {void}
225 */
226 editState() {
227 const selection = this.state('gallery').get('selection');
228 const view = new wp.media.view.EditImage({
229 model: selection.single(),
230 controller: this
231 }).render();
232
233 // Set the view to the EditImage frame using the selected image.
234 this.content.set(view);
235
236 // After bringing in the frame, load the actual editor via an ajax call.
237 view.loadEditor();
238 },
239 /**
240 * Create the default states.
241 *
242 * @return {void}
243 */
244 createStates: function createStates() {
245 this.on('toolbar:create:main-gallery', this.galleryToolbar, this);
246 this.on('content:render:edit-image', this.editState, this);
247 this.states.add([new wp.media.controller.Library({
248 id: 'gallery',
249 title: wp.media.view.l10n.createGalleryTitle,
250 priority: 40,
251 toolbar: 'main-gallery',
252 filterable: 'uploaded',
253 multiple: 'add',
254 editable: false,
255 library: wp.media.query({
256 type: 'image',
257 ...this.options.library
258 })
259 }), new wp.media.controller.EditImage({
260 model: this.options.editImage
261 }), new wp.media.controller.GalleryEdit({
262 library: this.options.selection,
263 editing: this.options.editing,
264 menu: 'gallery',
265 displaySettings: false,
266 multiple: true
267 }), new wp.media.controller.GalleryAdd()]);
268 }
269 });
270 };
271
272 // The media library image object contains numerous attributes
273 // we only need this set to display the image in the library.
274 const slimImageObject = img => {
275 const attrSet = ['sizes', 'mime', 'type', 'subtype', 'id', 'url', 'alt', 'link', 'caption'];
276 return attrSet.reduce((result, key) => {
277 if (img?.hasOwnProperty(key)) {
278 result[key] = img[key];
279 }
280 return result;
281 }, {});
282 };
283 const getAttachmentsCollection = ids => {
284 const {
285 wp
286 } = window;
287 return wp.media.query({
288 order: 'ASC',
289 orderby: 'post__in',
290 post__in: ids,
291 posts_per_page: -1,
292 query: true,
293 type: 'image'
294 });
295 };
296 class MediaUpload extends external_wp_element_namespaceObject.Component {
297 constructor() {
298 super(...arguments);
299 this.openModal = this.openModal.bind(this);
300 this.onOpen = this.onOpen.bind(this);
301 this.onSelect = this.onSelect.bind(this);
302 this.onUpdate = this.onUpdate.bind(this);
303 this.onClose = this.onClose.bind(this);
304 }
305 initializeListeners() {
306 // When an image is selected in the media frame...
307 this.frame.on('select', this.onSelect);
308 this.frame.on('update', this.onUpdate);
309 this.frame.on('open', this.onOpen);
310 this.frame.on('close', this.onClose);
311 }
312
313 /**
314 * Sets the Gallery frame and initializes listeners.
315 *
316 * @return {void}
317 */
318 buildAndSetGalleryFrame() {
319 const {
320 addToGallery = false,
321 allowedTypes,
322 multiple = false,
323 value = DEFAULT_EMPTY_GALLERY
324 } = this.props;
325
326 // If the value did not changed there is no need to rebuild the frame,
327 // we can continue to use the existing one.
328 if (value === this.lastGalleryValue) {
329 return;
330 }
331 const {
332 wp
333 } = window;
334 this.lastGalleryValue = value;
335
336 // If a frame already existed remove it.
337 if (this.frame) {
338 this.frame.remove();
339 }
340 let currentState;
341 if (addToGallery) {
342 currentState = 'gallery-library';
343 } else {
344 currentState = value && value.length ? 'gallery-edit' : 'gallery';
345 }
346 if (!this.GalleryDetailsMediaFrame) {
347 this.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();
348 }
349 const attachments = getAttachmentsCollection(value);
350 const selection = new wp.media.model.Selection(attachments.models, {
351 props: attachments.props.toJSON(),
352 multiple
353 });
354 this.frame = new this.GalleryDetailsMediaFrame({
355 mimeType: allowedTypes,
356 state: currentState,
357 multiple,
358 selection,
359 editing: !!value?.length
360 });
361 wp.media.frame = this.frame;
362 this.initializeListeners();
363 }
364
365 /**
366 * Initializes the Media Library requirements for the featured image flow.
367 *
368 * @return {void}
369 */
370 buildAndSetFeatureImageFrame() {
371 const {
372 wp
373 } = window;
374 const {
375 value: featuredImageId,
376 multiple,
377 allowedTypes
378 } = this.props;
379 const featuredImageFrame = getFeaturedImageMediaFrame();
380 const attachments = getAttachmentsCollection(featuredImageId);
381 const selection = new wp.media.model.Selection(attachments.models, {
382 props: attachments.props.toJSON()
383 });
384 this.frame = new featuredImageFrame({
385 mimeType: allowedTypes,
386 state: 'featured-image',
387 multiple,
388 selection,
389 editing: featuredImageId
390 });
391 wp.media.frame = this.frame;
392 // In order to select the current featured image when opening
393 // the media library we have to set the appropriate settings.
394 // Currently they are set in php for the post editor, but
395 // not for site editor.
396 wp.media.view.settings.post = {
397 ...wp.media.view.settings.post,
398 featuredImageId: featuredImageId || -1
399 };
400 }
401
402 /**
403 * Initializes the Media Library requirements for the single image flow.
404 *
405 * @return {void}
406 */
407 buildAndSetSingleMediaFrame() {
408 const {
409 wp
410 } = window;
411 const {
412 allowedTypes,
413 multiple = false,
414 title = (0,external_wp_i18n_namespaceObject.__)('Select or Upload Media'),
415 value
416 } = this.props;
417 const frameConfig = {
418 title,
419 multiple
420 };
421 if (!!allowedTypes) {
422 frameConfig.library = {
423 type: allowedTypes
424 };
425 }
426
427 // If a frame already exists, remove it.
428 if (this.frame) {
429 this.frame.remove();
430 }
431 const singleImageFrame = getSingleMediaFrame();
432 const attachments = getAttachmentsCollection(value);
433 const selection = new wp.media.model.Selection(attachments.models, {
434 props: attachments.props.toJSON()
435 });
436 this.frame = new singleImageFrame({
437 mimeType: allowedTypes,
438 multiple,
439 selection,
440 ...frameConfig
441 });
442 wp.media.frame = this.frame;
443 }
444 componentWillUnmount() {
445 this.frame?.remove();
446 }
447 onUpdate(selections) {
448 const {
449 onSelect,
450 multiple = false
451 } = this.props;
452 const state = this.frame.state();
453 const selectedImages = selections || state.get('selection');
454 if (!selectedImages || !selectedImages.models.length) {
455 return;
456 }
457 if (multiple) {
458 onSelect(selectedImages.models.map(model => slimImageObject(model.toJSON())));
459 } else {
460 onSelect(slimImageObject(selectedImages.models[0].toJSON()));
461 }
462 }
463 onSelect() {
464 const {
465 onSelect,
466 multiple = false
467 } = this.props;
468 // Get media attachment details from the frame state.
469 const attachment = this.frame.state().get('selection').toJSON();
470 onSelect(multiple ? attachment : attachment[0]);
471 }
472 onOpen() {
473 const {
474 wp
475 } = window;
476 const {
477 value
478 } = this.props;
479 this.updateCollection();
480
481 //Handle active tab in media model on model open.
482 if (this.props.mode) {
483 this.frame.content.mode(this.props.mode);
484 }
485
486 // Handle both this.props.value being either (number[]) multiple ids
487 // (for galleries) or a (number) singular id (e.g. image block).
488 const hasMedia = Array.isArray(value) ? !!value?.length : !!value;
489 if (!hasMedia) {
490 return;
491 }
492 const isGallery = this.props.gallery;
493 const selection = this.frame.state().get('selection');
494 const valueArray = Array.isArray(value) ? value : [value];
495 if (!isGallery) {
496 valueArray.forEach(id => {
497 selection.add(wp.media.attachment(id));
498 });
499 }
500
501 // Load the images so they are available in the media modal.
502 const attachments = getAttachmentsCollection(valueArray);
503
504 // Once attachments are loaded, set the current selection.
505 attachments.more().done(function () {
506 if (isGallery && attachments?.models?.length) {
507 selection.add(attachments.models);
508 }
509 });
510 }
511 onClose() {
512 const {
513 onClose
514 } = this.props;
515 if (onClose) {
516 onClose();
517 }
518 this.frame.detach();
519 }
520 updateCollection() {
521 const frameContent = this.frame.content.get();
522 if (frameContent && frameContent.collection) {
523 const collection = frameContent.collection;
524
525 // Clean all attachments we have in memory.
526 collection.toArray().forEach(model => model.trigger('destroy', model));
527
528 // Reset has more flag, if library had small amount of items all items may have been loaded before.
529 collection.mirroring._hasMore = true;
530
531 // Request items.
532 collection.more();
533 }
534 }
535 openModal() {
536 const {
537 gallery = false,
538 unstableFeaturedImageFlow = false,
539 modalClass
540 } = this.props;
541 if (gallery) {
542 this.buildAndSetGalleryFrame();
543 } else {
544 this.buildAndSetSingleMediaFrame();
545 }
546 if (modalClass) {
547 this.frame.$el.addClass(modalClass);
548 }
549 if (unstableFeaturedImageFlow) {
550 this.buildAndSetFeatureImageFrame();
551 }
552 this.initializeListeners();
553 this.frame.open();
554 }
555 render() {
556 return this.props.render({
557 open: this.openModal
558 });
559 }
560 }
561 /* harmony default export */ const media_upload = (MediaUpload);
562
563 ;// ./packages/media-utils/build-module/components/index.js
564
565
566 ;// external ["wp","blob"]
567 const external_wp_blob_namespaceObject = window["wp"]["blob"];
568 ;// external ["wp","apiFetch"]
569 const external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"];
570 var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
571 ;// ./packages/media-utils/build-module/utils/flatten-form-data.js
572 /**
573 * Determines whether the passed argument appears to be a plain object.
574 *
575 * @param data The object to inspect.
576 */
577 function isPlainObject(data) {
578 return data !== null && typeof data === 'object' && Object.getPrototypeOf(data) === Object.prototype;
579 }
580
581 /**
582 * Recursively flatten data passed to form data, to allow using multi-level objects.
583 *
584 * @param {FormData} formData Form data object.
585 * @param {string} key Key to amend to form data object
586 * @param {string|Object} data Data to be amended to form data.
587 */
588 function flattenFormData(formData, key, data) {
589 if (isPlainObject(data)) {
590 for (const [name, value] of Object.entries(data)) {
591 flattenFormData(formData, `${key}[${name}]`, value);
592 }
593 } else if (data !== undefined) {
594 formData.append(key, String(data));
595 }
596 }
597
598 ;// ./packages/media-utils/build-module/utils/transform-attachment.js
599 /**
600 * Internal dependencies
601 */
602
603 /**
604 * Transforms an attachment object from the REST API shape into the shape expected by the block editor and other consumers.
605 *
606 * @param attachment REST API attachment object.
607 */
608 function transformAttachment(attachment) {
609 var _attachment$caption$r;
610 // eslint-disable-next-line camelcase
611 const {
612 alt_text,
613 source_url,
614 ...savedMediaProps
615 } = attachment;
616 return {
617 ...savedMediaProps,
618 alt: attachment.alt_text,
619 caption: (_attachment$caption$r = attachment.caption?.raw) !== null && _attachment$caption$r !== void 0 ? _attachment$caption$r : '',
620 title: attachment.title.raw,
621 url: attachment.source_url,
622 poster: attachment._embedded?.['wp:featuredmedia']?.[0]?.source_url || undefined
623 };
624 }
625
626 ;// ./packages/media-utils/build-module/utils/upload-to-server.js
627 /**
628 * WordPress dependencies
629 */
630
631
632 /**
633 * Internal dependencies
634 */
635
636
637 async function uploadToServer(file, additionalData = {}, signal) {
638 // Create upload payload.
639 const data = new FormData();
640 data.append('file', file, file.name || file.type.replace('/', '.'));
641 for (const [key, value] of Object.entries(additionalData)) {
642 flattenFormData(data, key, value);
643 }
644 return transformAttachment(await external_wp_apiFetch_default()({
645 // This allows the video block to directly get a video's poster image.
646 path: '/wp/v2/media?_embed=wp:featuredmedia',
647 body: data,
648 method: 'POST',
649 signal
650 }));
651 }
652
653 ;// ./packages/media-utils/build-module/utils/upload-error.js
654 /**
655 * MediaError class.
656 *
657 * Small wrapper around the `Error` class
658 * to hold an error code and a reference to a file object.
659 */
660 class UploadError extends Error {
661 constructor({
662 code,
663 message,
664 file,
665 cause
666 }) {
667 super(message, {
668 cause
669 });
670 Object.setPrototypeOf(this, new.target.prototype);
671 this.code = code;
672 this.file = file;
673 }
674 }
675
676 ;// ./packages/media-utils/build-module/utils/validate-mime-type.js
677 /* wp:polyfill */
678 /**
679 * WordPress dependencies
680 */
681
682
683 /**
684 * Internal dependencies
685 */
686
687
688 /**
689 * Verifies if the caller (e.g. a block) supports this mime type.
690 *
691 * @param file File object.
692 * @param allowedTypes List of allowed mime types.
693 */
694 function validateMimeType(file, allowedTypes) {
695 if (!allowedTypes) {
696 return;
697 }
698
699 // Allowed type specified by consumer.
700 const isAllowedType = allowedTypes.some(allowedType => {
701 // If a complete mimetype is specified verify if it matches exactly the mime type of the file.
702 if (allowedType.includes('/')) {
703 return allowedType === file.type;
704 }
705 // Otherwise a general mime type is used, and we should verify if the file mimetype starts with it.
706 return file.type.startsWith(`${allowedType}/`);
707 });
708 if (file.type && !isAllowedType) {
709 throw new UploadError({
710 code: 'MIME_TYPE_NOT_SUPPORTED',
711 message: (0,external_wp_i18n_namespaceObject.sprintf)(
712 // translators: %s: file name.
713 (0,external_wp_i18n_namespaceObject.__)('%s: Sorry, this file type is not supported here.'), file.name),
714 file
715 });
716 }
717 }
718
719 ;// ./packages/media-utils/build-module/utils/get-mime-types-array.js
720 /* wp:polyfill */
721 /**
722 * Browsers may use unexpected mime types, and they differ from browser to browser.
723 * This function computes a flexible array of mime types from the mime type structured provided by the server.
724 * Converts { jpg|jpeg|jpe: "image/jpeg" } into [ "image/jpeg", "image/jpg", "image/jpeg", "image/jpe" ]
725 *
726 * @param {?Object} wpMimeTypesObject Mime type object received from the server.
727 * Extensions are keys separated by '|' and values are mime types associated with an extension.
728 *
729 * @return An array of mime types or null
730 */
731 function getMimeTypesArray(wpMimeTypesObject) {
732 if (!wpMimeTypesObject) {
733 return null;
734 }
735 return Object.entries(wpMimeTypesObject).flatMap(([extensionsString, mime]) => {
736 const [type] = mime.split('/');
737 const extensions = extensionsString.split('|');
738 return [mime, ...extensions.map(extension => `${type}/${extension}`)];
739 });
740 }
741
742 ;// ./packages/media-utils/build-module/utils/validate-mime-type-for-user.js
743 /**
744 * WordPress dependencies
745 */
746
747
748 /**
749 * Internal dependencies
750 */
751
752
753
754 /**
755 * Verifies if the user is allowed to upload this mime type.
756 *
757 * @param file File object.
758 * @param wpAllowedMimeTypes List of allowed mime types and file extensions.
759 */
760 function validateMimeTypeForUser(file, wpAllowedMimeTypes) {
761 // Allowed types for the current WP_User.
762 const allowedMimeTypesForUser = getMimeTypesArray(wpAllowedMimeTypes);
763 if (!allowedMimeTypesForUser) {
764 return;
765 }
766 const isAllowedMimeTypeForUser = allowedMimeTypesForUser.includes(file.type);
767 if (file.type && !isAllowedMimeTypeForUser) {
768 throw new UploadError({
769 code: 'MIME_TYPE_NOT_ALLOWED_FOR_USER',
770 message: (0,external_wp_i18n_namespaceObject.sprintf)(
771 // translators: %s: file name.
772 (0,external_wp_i18n_namespaceObject.__)('%s: Sorry, you are not allowed to upload this file type.'), file.name),
773 file
774 });
775 }
776 }
777
778 ;// ./packages/media-utils/build-module/utils/validate-file-size.js
779 /**
780 * WordPress dependencies
781 */
782
783
784 /**
785 * Internal dependencies
786 */
787
788
789 /**
790 * Verifies whether the file is within the file upload size limits for the site.
791 *
792 * @param file File object.
793 * @param maxUploadFileSize Maximum upload size in bytes allowed for the site.
794 */
795 function validateFileSize(file, maxUploadFileSize) {
796 // Don't allow empty files to be uploaded.
797 if (file.size <= 0) {
798 throw new UploadError({
799 code: 'EMPTY_FILE',
800 message: (0,external_wp_i18n_namespaceObject.sprintf)(
801 // translators: %s: file name.
802 (0,external_wp_i18n_namespaceObject.__)('%s: This file is empty.'), file.name),
803 file
804 });
805 }
806 if (maxUploadFileSize && file.size > maxUploadFileSize) {
807 throw new UploadError({
808 code: 'SIZE_ABOVE_LIMIT',
809 message: (0,external_wp_i18n_namespaceObject.sprintf)(
810 // translators: %s: file name.
811 (0,external_wp_i18n_namespaceObject.__)('%s: This file exceeds the maximum upload size for this site.'), file.name),
812 file
813 });
814 }
815 }
816
817 ;// ./packages/media-utils/build-module/utils/upload-media.js
818 /**
819 * WordPress dependencies
820 */
821
822
823
824 /**
825 * Internal dependencies
826 */
827
828
829
830
831
832
833 /**
834 * Upload a media file when the file upload button is activated
835 * or when adding a file to the editor via drag & drop.
836 *
837 * @param $0 Parameters object passed to the function.
838 * @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.
839 * @param $0.additionalData Additional data to include in the request.
840 * @param $0.filesList List of files.
841 * @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.
842 * @param $0.onError Function called when an error happens.
843 * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.
844 * @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.
845 * @param $0.signal Abort signal.
846 */
847 function uploadMedia({
848 wpAllowedMimeTypes,
849 allowedTypes,
850 additionalData = {},
851 filesList,
852 maxUploadFileSize,
853 onError,
854 onFileChange,
855 signal
856 }) {
857 const validFiles = [];
858 const filesSet = [];
859 const setAndUpdateFiles = (index, value) => {
860 // For client-side media processing, this is handled by the upload-media package.
861 if (!window.__experimentalMediaProcessing) {
862 if (filesSet[index]?.url) {
863 (0,external_wp_blob_namespaceObject.revokeBlobURL)(filesSet[index].url);
864 }
865 }
866 filesSet[index] = value;
867 onFileChange?.(filesSet.filter(attachment => attachment !== null));
868 };
869 for (const mediaFile of filesList) {
870 // Verify if user is allowed to upload this mime type.
871 // Defer to the server when type not detected.
872 try {
873 validateMimeTypeForUser(mediaFile, wpAllowedMimeTypes);
874 } catch (error) {
875 onError?.(error);
876 continue;
877 }
878
879 // Check if the caller (e.g. a block) supports this mime type.
880 // Defer to the server when type not detected.
881 try {
882 validateMimeType(mediaFile, allowedTypes);
883 } catch (error) {
884 onError?.(error);
885 continue;
886 }
887
888 // Verify if file is greater than the maximum file upload size allowed for the site.
889 try {
890 validateFileSize(mediaFile, maxUploadFileSize);
891 } catch (error) {
892 onError?.(error);
893 continue;
894 }
895 validFiles.push(mediaFile);
896
897 // For client-side media processing, this is handled by the upload-media package.
898 if (!window.__experimentalMediaProcessing) {
899 // Set temporary URL to create placeholder media file, this is replaced
900 // with final file from media gallery when upload is `done` below.
901 filesSet.push({
902 url: (0,external_wp_blob_namespaceObject.createBlobURL)(mediaFile)
903 });
904 onFileChange?.(filesSet);
905 }
906 }
907 validFiles.map(async (file, index) => {
908 try {
909 const attachment = await uploadToServer(file, additionalData, signal);
910 setAndUpdateFiles(index, attachment);
911 } catch (error) {
912 // Reset to empty on failure.
913 setAndUpdateFiles(index, null);
914 let message;
915 if (error instanceof Error) {
916 message = error.message;
917 } else {
918 message = (0,external_wp_i18n_namespaceObject.sprintf)(
919 // translators: %s: file name
920 (0,external_wp_i18n_namespaceObject.__)('Error while uploading file %s to the media library.'), file.name);
921 }
922 onError?.(new UploadError({
923 code: 'GENERAL',
924 message,
925 file,
926 cause: error instanceof Error ? error : undefined
927 }));
928 }
929 });
930 }
931
932 ;// ./packages/media-utils/build-module/utils/sideload-to-server.js
933 /**
934 * WordPress dependencies
935 */
936
937
938 /**
939 * Internal dependencies
940 */
941
942
943
944
945 /**
946 * Uploads a file to the server without creating an attachment.
947 *
948 * @param file Media File to Save.
949 * @param attachmentId Parent attachment ID.
950 * @param additionalData Additional data to include in the request.
951 * @param signal Abort signal.
952 *
953 * @return The saved attachment.
954 */
955 async function sideloadToServer(file, attachmentId, additionalData = {}, signal) {
956 // Create upload payload.
957 const data = new FormData();
958 data.append('file', file, file.name || file.type.replace('/', '.'));
959 for (const [key, value] of Object.entries(additionalData)) {
960 flattenFormData(data, key, value);
961 }
962 return transformAttachment(await external_wp_apiFetch_default()({
963 path: `/wp/v2/media/${attachmentId}/sideload`,
964 body: data,
965 method: 'POST',
966 signal
967 }));
968 }
969
970 ;// ./packages/media-utils/build-module/utils/sideload-media.js
971 /**
972 * WordPress dependencies
973 */
974
975
976 /**
977 * Internal dependencies
978 */
979
980
981
982 const noop = () => {};
983 /**
984 * Uploads a file to the server without creating an attachment.
985 *
986 * @param $0 Parameters object passed to the function.
987 * @param $0.file Media File to Save.
988 * @param $0.attachmentId Parent attachment ID.
989 * @param $0.additionalData Additional data to include in the request.
990 * @param $0.signal Abort signal.
991 * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.
992 * @param $0.onError Function called when an error happens.
993 */
994 async function sideloadMedia({
995 file,
996 attachmentId,
997 additionalData = {},
998 signal,
999 onFileChange,
1000 onError = noop
1001 }) {
1002 try {
1003 const attachment = await sideloadToServer(file, attachmentId, additionalData, signal);
1004 onFileChange?.([attachment]);
1005 } catch (error) {
1006 let message;
1007 if (error instanceof Error) {
1008 message = error.message;
1009 } else {
1010 message = (0,external_wp_i18n_namespaceObject.sprintf)(
1011 // translators: %s: file name
1012 (0,external_wp_i18n_namespaceObject.__)('Error while sideloading file %s to the server.'), file.name);
1013 }
1014 onError(new UploadError({
1015 code: 'GENERAL',
1016 message,
1017 file,
1018 cause: error instanceof Error ? error : undefined
1019 }));
1020 }
1021 }
1022
1023 ;// external ["wp","privateApis"]
1024 const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
1025 ;// ./packages/media-utils/build-module/lock-unlock.js
1026 /**
1027 * WordPress dependencies
1028 */
1029
1030 const {
1031 lock,
1032 unlock
1033 } = (0,external_wp_privateApis_namespaceObject.__dangerousOptInToUnstableAPIsOnlyForCoreModules)('I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.', '@wordpress/media-utils');
1034
1035 ;// ./packages/media-utils/build-module/private-apis.js
1036 /**
1037 * Internal dependencies
1038 */
1039
1040
1041
1042 /**
1043 * Private @wordpress/media-utils APIs.
1044 */
1045 const privateApis = {};
1046 lock(privateApis, {
1047 sideloadMedia: sideloadMedia
1048 });
1049
1050 ;// ./packages/media-utils/build-module/index.js
1051
1052
1053
1054
1055
1056
1057
1058
1059 (window.wp = window.wp || {}).mediaUtils = __webpack_exports__;
1060 /******/ })()
1061 ;