341 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			341 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /* 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 ); |