wp/wp-admin/js/widgets/media-gallery-widget.js
changeset 7 cf61fcea0001
child 9 177826044cd9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wp/wp-admin/js/widgets/media-gallery-widget.js	Mon Oct 14 17:39:30 2019 +0200
@@ -0,0 +1,340 @@
+/* eslint consistent-this: [ "error", "control" ] */
+(function( component ) {
+	'use strict';
+
+	var GalleryWidgetModel, GalleryWidgetControl, GalleryDetailsMediaFrame;
+
+	/**
+	 * Custom gallery details frame.
+	 *
+	 * @since 4.9.0
+	 * @class GalleryDetailsMediaFrame
+	 * @constructor
+	 */
+	GalleryDetailsMediaFrame = wp.media.view.MediaFrame.Post.extend( {
+
+		/**
+		 * Create the default states.
+		 *
+		 * @since 4.9.0
+		 * @returns {void}
+		 */
+		createStates: function createStates() {
+			this.states.add([
+				new wp.media.controller.Library({
+					id:         'gallery',
+					title:      wp.media.view.l10n.createGalleryTitle,
+					priority:   40,
+					toolbar:    'main-gallery',
+					filterable: 'uploaded',
+					multiple:   'add',
+					editable:   true,
+
+					library:  wp.media.query( _.defaults({
+						type: 'image'
+					}, this.options.library ) )
+				}),
+
+				// Gallery states.
+				new wp.media.controller.GalleryEdit({
+					library: this.options.selection,
+					editing: this.options.editing,
+					menu:    'gallery'
+				}),
+
+				new wp.media.controller.GalleryAdd()
+			]);
+		}
+	} );
+
+	/**
+	 * Gallery widget model.
+	 *
+	 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
+	 *
+	 * @since 4.9.0
+	 * @class GalleryWidgetModel
+	 * @constructor
+	 */
+	GalleryWidgetModel = component.MediaWidgetModel.extend( {} );
+
+	/**
+	 * Gallery widget control.
+	 *
+	 * See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
+	 *
+	 * @since 4.9.0
+	 * @class GalleryWidgetControl
+	 * @constructor
+	 */
+	GalleryWidgetControl = component.MediaWidgetControl.extend( {
+
+		/**
+		 * View events.
+		 *
+		 * @since 4.9.0
+		 * @type {object}
+		 */
+		events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
+			'click .media-widget-gallery-preview': 'editMedia'
+		} ),
+
+		/**
+		 * Initialize.
+		 *
+		 * @since 4.9.0
+		 * @param {Object}         options - Options.
+		 * @param {Backbone.Model} options.model - Model.
+		 * @param {jQuery}         options.el - Control field container element.
+		 * @param {jQuery}         options.syncContainer - Container element where fields are synced for the server.
+		 * @returns {void}
+		 */
+		initialize: function initialize( options ) {
+			var control = this;
+
+			component.MediaWidgetControl.prototype.initialize.call( control, options );
+
+			_.bindAll( control, 'updateSelectedAttachments', 'handleAttachmentDestroy' );
+			control.selectedAttachments = new wp.media.model.Attachments();
+			control.model.on( 'change:ids', control.updateSelectedAttachments );
+			control.selectedAttachments.on( 'change', control.renderPreview );
+			control.selectedAttachments.on( 'reset', control.renderPreview );
+			control.updateSelectedAttachments();
+
+			/*
+			 * Refresh a Gallery widget partial when the user modifies one of the selected attachments.
+			 * This ensures that when an attachment's caption is updated in the media modal the Gallery
+			 * widget in the preview will then be refreshed to show the change. Normally doing this
+			 * would not be necessary because all of the state should be contained inside the changeset,
+			 * as everything done in the Customizer should not make a change to the site unless the
+			 * changeset itself is published. Attachments are a current exception to this rule.
+			 * For a proposal to include attachments in the customized state, see #37887.
+			 */
+			if ( wp.customize && wp.customize.previewer ) {
+				control.selectedAttachments.on( 'change', function() {
+					wp.customize.previewer.send( 'refresh-widget-partial', control.model.get( 'widget_id' ) );
+				} );
+			}
+		},
+
+		/**
+		 * Update the selected attachments if necessary.
+		 *
+		 * @since 4.9.0
+		 * @returns {void}
+		 */
+		updateSelectedAttachments: function updateSelectedAttachments() {
+			var control = this, newIds, oldIds, removedIds, addedIds, addedQuery;
+
+			newIds = control.model.get( 'ids' );
+			oldIds = _.pluck( control.selectedAttachments.models, 'id' );
+
+			removedIds = _.difference( oldIds, newIds );
+			_.each( removedIds, function( removedId ) {
+				control.selectedAttachments.remove( control.selectedAttachments.get( removedId ) );
+			});
+
+			addedIds = _.difference( newIds, oldIds );
+			if ( addedIds.length ) {
+				addedQuery = wp.media.query({
+					order: 'ASC',
+					orderby: 'post__in',
+					perPage: -1,
+					post__in: newIds,
+					query: true,
+					type: 'image'
+				});
+				addedQuery.more().done( function() {
+					control.selectedAttachments.reset( addedQuery.models );
+				});
+			}
+		},
+
+		/**
+		 * Render preview.
+		 *
+		 * @since 4.9.0
+		 * @returns {void}
+		 */
+		renderPreview: function renderPreview() {
+			var control = this, previewContainer, previewTemplate, data;
+
+			previewContainer = control.$el.find( '.media-widget-preview' );
+			previewTemplate = wp.template( 'wp-media-widget-gallery-preview' );
+
+			data = control.previewTemplateProps.toJSON();
+			data.attachments = {};
+			control.selectedAttachments.each( function( attachment ) {
+				data.attachments[ attachment.id ] = attachment.toJSON();
+			} );
+
+			previewContainer.html( previewTemplate( data ) );
+		},
+
+		/**
+		 * Determine whether there are selected attachments.
+		 *
+		 * @since 4.9.0
+		 * @returns {boolean} Selected.
+		 */
+		isSelected: function isSelected() {
+			var control = this;
+
+			if ( control.model.get( 'error' ) ) {
+				return false;
+			}
+
+			return control.model.get( 'ids' ).length > 0;
+		},
+
+		/**
+		 * Open the media select frame to edit images.
+		 *
+		 * @since 4.9.0
+		 * @returns {void}
+		 */
+		editMedia: function editMedia() {
+			var control = this, selection, mediaFrame, mediaFrameProps;
+
+			selection = new wp.media.model.Selection( control.selectedAttachments.models, {
+				multiple: true
+			});
+
+			mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
+			selection.gallery = new Backbone.Model( mediaFrameProps );
+			if ( mediaFrameProps.size ) {
+				control.displaySettings.set( 'size', mediaFrameProps.size );
+			}
+			mediaFrame = new GalleryDetailsMediaFrame({
+				frame: 'manage',
+				text: control.l10n.add_to_widget,
+				selection: selection,
+				mimeType: control.mime_type,
+				selectedDisplaySettings: control.displaySettings,
+				showDisplaySettings: control.showDisplaySettings,
+				metadata: mediaFrameProps,
+				editing:   true,
+				multiple:  true,
+				state: 'gallery-edit'
+			});
+			wp.media.frame = mediaFrame; // See wp.media().
+
+			// Handle selection of a media item.
+			mediaFrame.on( 'update', function onUpdate( newSelection ) {
+				var state = mediaFrame.state(), resultSelection;
+
+				resultSelection = newSelection || state.get( 'selection' );
+				if ( ! resultSelection ) {
+					return;
+				}
+
+				// Copy orderby_random from gallery state.
+				if ( resultSelection.gallery ) {
+					control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
+				}
+
+				// Directly update selectedAttachments to prevent needing to do additional request.
+				control.selectedAttachments.reset( resultSelection.models );
+
+				// Update models in the widget instance.
+				control.model.set( {
+					ids: _.pluck( resultSelection.models, 'id' )
+				} );
+			} );
+
+			mediaFrame.$el.addClass( 'media-widget' );
+			mediaFrame.open();
+
+			if ( selection ) {
+				selection.on( 'destroy', control.handleAttachmentDestroy );
+			}
+		},
+
+		/**
+		 * Open the media select frame to chose an item.
+		 *
+		 * @since 4.9.0
+		 * @returns {void}
+		 */
+		selectMedia: function selectMedia() {
+			var control = this, selection, mediaFrame, mediaFrameProps;
+			selection = new wp.media.model.Selection( control.selectedAttachments.models, {
+				multiple: true
+			});
+
+			mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
+			if ( mediaFrameProps.size ) {
+				control.displaySettings.set( 'size', mediaFrameProps.size );
+			}
+			mediaFrame = new GalleryDetailsMediaFrame({
+				frame: 'select',
+				text: control.l10n.add_to_widget,
+				selection: selection,
+				mimeType: control.mime_type,
+				selectedDisplaySettings: control.displaySettings,
+				showDisplaySettings: control.showDisplaySettings,
+				metadata: mediaFrameProps,
+				state: 'gallery'
+			});
+			wp.media.frame = mediaFrame; // See wp.media().
+
+			// Handle selection of a media item.
+			mediaFrame.on( 'update', function onUpdate( newSelection ) {
+				var state = mediaFrame.state(), resultSelection;
+
+				resultSelection = newSelection || state.get( 'selection' );
+				if ( ! resultSelection ) {
+					return;
+				}
+
+				// Copy orderby_random from gallery state.
+				if ( resultSelection.gallery ) {
+					control.model.set( control.mapMediaToModelProps( resultSelection.gallery.toJSON() ) );
+				}
+
+				// Directly update selectedAttachments to prevent needing to do additional request.
+				control.selectedAttachments.reset( resultSelection.models );
+
+				// Update widget instance.
+				control.model.set( {
+					ids: _.pluck( resultSelection.models, 'id' )
+				} );
+			} );
+
+			mediaFrame.$el.addClass( 'media-widget' );
+			mediaFrame.open();
+
+			if ( selection ) {
+				selection.on( 'destroy', control.handleAttachmentDestroy );
+			}
+
+			/*
+			 * Make sure focus is set inside of modal so that hitting Esc will close
+			 * the modal and not inadvertently cause the widget to collapse in the customizer.
+			 */
+			mediaFrame.$el.find( ':focusable:first' ).focus();
+		},
+
+		/**
+		 * Clear the selected attachment when it is deleted in the media select frame.
+		 *
+		 * @since 4.9.0
+		 * @param {wp.media.models.Attachment} attachment - Attachment.
+		 * @returns {void}
+		 */
+		handleAttachmentDestroy: function handleAttachmentDestroy( attachment ) {
+			var control = this;
+			control.model.set( {
+				ids: _.difference(
+					control.model.get( 'ids' ),
+					[ attachment.id ]
+				)
+			} );
+		}
+	} );
+
+	// Exports.
+	component.controlConstructors.media_gallery = GalleryWidgetControl;
+	component.modelConstructors.media_gallery = GalleryWidgetModel;
+
+})( wp.mediaWidgets );