wp/wp-admin/js/widgets/media-widgets.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    43 		 * @constructs wp.mediaWidgets.PersistentDisplaySettingsLibrary
    43 		 * @constructs wp.mediaWidgets.PersistentDisplaySettingsLibrary
    44 		 * @augments   wp.media.controller.Library
    44 		 * @augments   wp.media.controller.Library
    45 		 *
    45 		 *
    46 		 * @param {Object} options - Options.
    46 		 * @param {Object} options - Options.
    47 		 *
    47 		 *
    48 		 * @returns {void}
    48 		 * @return {void}
    49 		 */
    49 		 */
    50 		initialize: function initialize( options ) {
    50 		initialize: function initialize( options ) {
    51 			_.bindAll( this, 'handleDisplaySettingChange' );
    51 			_.bindAll( this, 'handleDisplaySettingChange' );
    52 			wp.media.controller.Library.prototype.initialize.call( this, options );
    52 			wp.media.controller.Library.prototype.initialize.call( this, options );
    53 		},
    53 		},
    54 
    54 
    55 		/**
    55 		/**
    56 		 * Sync changes to the current display settings back into the current customized.
    56 		 * Sync changes to the current display settings back into the current customized.
    57 		 *
    57 		 *
    58 		 * @param {Backbone.Model} displaySettings - Modified display settings.
    58 		 * @param {Backbone.Model} displaySettings - Modified display settings.
    59 		 * @returns {void}
    59 		 * @return {void}
    60 		 */
    60 		 */
    61 		handleDisplaySettingChange: function handleDisplaySettingChange( displaySettings ) {
    61 		handleDisplaySettingChange: function handleDisplaySettingChange( displaySettings ) {
    62 			this.get( 'selectedDisplaySettings' ).set( displaySettings.attributes );
    62 			this.get( 'selectedDisplaySettings' ).set( displaySettings.attributes );
    63 		},
    63 		},
    64 
    64 
    69 		 * and an event listener is added so that changes made to the settings
    69 		 * and an event listener is added so that changes made to the settings
    70 		 * will sync back into the model storing the session's customized display
    70 		 * will sync back into the model storing the session's customized display
    71 		 * settings.
    71 		 * settings.
    72 		 *
    72 		 *
    73 		 * @param {Backbone.Model} model - Display settings model.
    73 		 * @param {Backbone.Model} model - Display settings model.
    74 		 * @returns {Backbone.Model} Display settings model.
    74 		 * @return {Backbone.Model} Display settings model.
    75 		 */
    75 		 */
    76 		display: function getDisplaySettingsModel( model ) {
    76 		display: function getDisplaySettingsModel( model ) {
    77 			var display, selectedDisplaySettings = this.get( 'selectedDisplaySettings' );
    77 			var display, selectedDisplaySettings = this.get( 'selectedDisplaySettings' );
    78 			display = wp.media.controller.Library.prototype.display.call( this, model );
    78 			display = wp.media.controller.Library.prototype.display.call( this, model );
    79 
    79 
    98 		/**
    98 		/**
    99 		 * Initialize.
    99 		 * Initialize.
   100 		 *
   100 		 *
   101 		 * @since 4.9.0
   101 		 * @since 4.9.0
   102 		 *
   102 		 *
   103 		 * @param {object} options - Options.
   103 		 * @param {Object} options - Options.
   104 		 * @returns {void}
   104 		 * @return {void}
   105 		 */
   105 		 */
   106 		initialize: function( options ) {
   106 		initialize: function( options ) {
   107 			var view = this, embedController; // eslint-disable-line consistent-this
   107 			var view = this, embedController; // eslint-disable-line consistent-this
   108 			wp.media.view.Embed.prototype.initialize.call( view, options );
   108 			wp.media.view.Embed.prototype.initialize.call( view, options );
   109 			if ( 'image' !== view.controller.options.mimeType ) {
   109 			if ( 'image' !== view.controller.options.mimeType ) {
   115 		/**
   115 		/**
   116 		 * Refresh embed view.
   116 		 * Refresh embed view.
   117 		 *
   117 		 *
   118 		 * Forked override of {wp.media.view.Embed#refresh()} to suppress irrelevant "link text" field.
   118 		 * Forked override of {wp.media.view.Embed#refresh()} to suppress irrelevant "link text" field.
   119 		 *
   119 		 *
   120 		 * @returns {void}
   120 		 * @return {void}
   121 		 */
   121 		 */
   122 		refresh: function refresh() {
   122 		refresh: function refresh() {
   123 			/**
   123 			/**
   124 			 * @class wp.mediaWidgets~Constructor
   124 			 * @class wp.mediaWidgets~Constructor
   125 			 */
   125 			 */
   134 
   134 
   135 					/**
   135 					/**
   136 					 * Set the disabled state on the Add to Widget button.
   136 					 * Set the disabled state on the Add to Widget button.
   137 					 *
   137 					 *
   138 					 * @param {boolean} disabled - Disabled.
   138 					 * @param {boolean} disabled - Disabled.
   139 					 * @returns {void}
   139 					 * @return {void}
   140 					 */
   140 					 */
   141 					setAddToWidgetButtonDisabled: function setAddToWidgetButtonDisabled( disabled ) {
   141 					setAddToWidgetButtonDisabled: function setAddToWidgetButtonDisabled( disabled ) {
   142 						this.views.parent.views.parent.views.get( '.media-frame-toolbar' )[0].$el.find( '.media-button-select' ).prop( 'disabled', disabled );
   142 						this.views.parent.views.parent.views.get( '.media-frame-toolbar' )[0].$el.find( '.media-button-select' ).prop( 'disabled', disabled );
   143 					},
   143 					},
   144 
   144 
   145 					/**
   145 					/**
   146 					 * Set or clear an error notice.
   146 					 * Set or clear an error notice.
   147 					 *
   147 					 *
   148 					 * @param {string} notice - Notice.
   148 					 * @param {string} notice - Notice.
   149 					 * @returns {void}
   149 					 * @return {void}
   150 					 */
   150 					 */
   151 					setErrorNotice: function setErrorNotice( notice ) {
   151 					setErrorNotice: function setErrorNotice( notice ) {
   152 						var embedLinkView = this, noticeContainer; // eslint-disable-line consistent-this
   152 						var embedLinkView = this, noticeContainer; // eslint-disable-line consistent-this
   153 
   153 
   154 						noticeContainer = embedLinkView.views.parent.$el.find( '> .notice:first-child' );
   154 						noticeContainer = embedLinkView.views.parent.$el.find( '> .notice:first-child' );
   173 					/**
   173 					/**
   174 					 * Update oEmbed.
   174 					 * Update oEmbed.
   175 					 *
   175 					 *
   176 					 * @since 4.9.0
   176 					 * @since 4.9.0
   177 					 *
   177 					 *
   178 					 * @returns {void}
   178 					 * @return {void}
   179 					 */
   179 					 */
   180 					updateoEmbed: function() {
   180 					updateoEmbed: function() {
   181 						var embedLinkView = this, url; // eslint-disable-line consistent-this
   181 						var embedLinkView = this, url; // eslint-disable-line consistent-this
   182 
   182 
   183 						url = embedLinkView.model.get( 'url' );
   183 						url = embedLinkView.model.get( 'url' );
   198 					},
   198 					},
   199 
   199 
   200 					/**
   200 					/**
   201 					 * Fetch media.
   201 					 * Fetch media.
   202 					 *
   202 					 *
   203 					 * @returns {void}
   203 					 * @return {void}
   204 					 */
   204 					 */
   205 					fetch: function() {
   205 					fetch: function() {
   206 						var embedLinkView = this, fetchSuccess, matches, fileExt, urlParser, url, re, youTubeEmbedMatch; // eslint-disable-line consistent-this
   206 						var embedLinkView = this, fetchSuccess, matches, fileExt, urlParser, url, re, youTubeEmbedMatch; // eslint-disable-line consistent-this
   207 						url = embedLinkView.model.get( 'url' );
   207 						url = embedLinkView.model.get( 'url' );
   208 
   208 
   274 					 *
   274 					 *
   275 					 * Overrides the {EmbedLink#renderFail()} method to prevent showing the "Link Text" field.
   275 					 * Overrides the {EmbedLink#renderFail()} method to prevent showing the "Link Text" field.
   276 					 * The element is getting display:none in the stylesheet, but the underlying method uses
   276 					 * The element is getting display:none in the stylesheet, but the underlying method uses
   277 					 * uses {jQuery.fn.show()} which adds an inline style. This avoids the need for !important.
   277 					 * uses {jQuery.fn.show()} which adds an inline style. This avoids the need for !important.
   278 					 *
   278 					 *
   279 					 * @returns {void}
   279 					 * @return {void}
   280 					 */
   280 					 */
   281 					renderFail: function renderFail() {
   281 					renderFail: function renderFail() {
   282 						var embedLinkView = this; // eslint-disable-line consistent-this
   282 						var embedLinkView = this; // eslint-disable-line consistent-this
   283 						embedLinkView.controller.$el.find( '#embed-url-field' ).addClass( 'invalid' );
   283 						embedLinkView.controller.$el.find( '#embed-url-field' ).addClass( 'invalid' );
   284 						embedLinkView.setErrorNotice( embedLinkView.controller.options.invalidEmbedTypeError || 'ERROR' );
   284 						embedLinkView.setErrorNotice( embedLinkView.controller.options.invalidEmbedTypeError || 'ERROR' );
   304 	component.MediaFrameSelect = wp.media.view.MediaFrame.Post.extend(/** @lends wp.mediaWidgets.MediaFrameSelect.prototype */{
   304 	component.MediaFrameSelect = wp.media.view.MediaFrame.Post.extend(/** @lends wp.mediaWidgets.MediaFrameSelect.prototype */{
   305 
   305 
   306 		/**
   306 		/**
   307 		 * Create the default states.
   307 		 * Create the default states.
   308 		 *
   308 		 *
   309 		 * @returns {void}
   309 		 * @return {void}
   310 		 */
   310 		 */
   311 		createStates: function createStates() {
   311 		createStates: function createStates() {
   312 			var mime = this.options.mimeType, specificMimes = [];
   312 			var mime = this.options.mimeType, specificMimes = [];
   313 			_.each( wp.media.view.settings.embedMimes, function( embedMime ) {
   313 			_.each( wp.media.view.settings.embedMimes, function( embedMime ) {
   314 				if ( 0 === embedMime.indexOf( mime ) ) {
   314 				if ( 0 === embedMime.indexOf( mime ) ) {
   356 		 *
   356 		 *
   357 		 * Forked override of {wp.media.view.MediaFrame.Post#mainInsertToolbar()} to override text.
   357 		 * Forked override of {wp.media.view.MediaFrame.Post#mainInsertToolbar()} to override text.
   358 		 *
   358 		 *
   359 		 * @param {wp.Backbone.View} view - Toolbar view.
   359 		 * @param {wp.Backbone.View} view - Toolbar view.
   360 		 * @this {wp.media.controller.Library}
   360 		 * @this {wp.media.controller.Library}
   361 		 * @returns {void}
   361 		 * @return {void}
   362 		 */
   362 		 */
   363 		mainInsertToolbar: function mainInsertToolbar( view ) {
   363 		mainInsertToolbar: function mainInsertToolbar( view ) {
   364 			var controller = this; // eslint-disable-line consistent-this
   364 			var controller = this; // eslint-disable-line consistent-this
   365 			view.set( 'insert', {
   365 			view.set( 'insert', {
   366 				style:    'primary',
   366 				style:    'primary',
   372 				 * Handle click.
   372 				 * Handle click.
   373 				 *
   373 				 *
   374 				 * @ignore
   374 				 * @ignore
   375 				 *
   375 				 *
   376 				 * @fires wp.media.controller.State#insert()
   376 				 * @fires wp.media.controller.State#insert()
   377 				 * @returns {void}
   377 				 * @return {void}
   378 				 */
   378 				 */
   379 				click: function onClick() {
   379 				click: function onClick() {
   380 					var state = controller.state(),
   380 					var state = controller.state(),
   381 						selection = state.get( 'selection' );
   381 						selection = state.get( 'selection' );
   382 
   382 
   391 		 *
   391 		 *
   392 		 * Forked override of {wp.media.view.MediaFrame.Post#mainEmbedToolbar()} to override text.
   392 		 * Forked override of {wp.media.view.MediaFrame.Post#mainEmbedToolbar()} to override text.
   393 		 *
   393 		 *
   394 		 * @param {wp.Backbone.View} toolbar - Toolbar view.
   394 		 * @param {wp.Backbone.View} toolbar - Toolbar view.
   395 		 * @this {wp.media.controller.Library}
   395 		 * @this {wp.media.controller.Library}
   396 		 * @returns {void}
   396 		 * @return {void}
   397 		 */
   397 		 */
   398 		mainEmbedToolbar: function mainEmbedToolbar( toolbar ) {
   398 		mainEmbedToolbar: function mainEmbedToolbar( toolbar ) {
   399 			toolbar.view = new wp.media.view.Toolbar.Embed({
   399 			toolbar.view = new wp.media.view.Toolbar.Embed({
   400 				controller: this,
   400 				controller: this,
   401 				text: this.options.text,
   401 				text: this.options.text,
   406 		/**
   406 		/**
   407 		 * Embed content.
   407 		 * Embed content.
   408 		 *
   408 		 *
   409 		 * Forked override of {wp.media.view.MediaFrame.Post#embedContent()} to suppress irrelevant "link text" field.
   409 		 * Forked override of {wp.media.view.MediaFrame.Post#embedContent()} to suppress irrelevant "link text" field.
   410 		 *
   410 		 *
   411 		 * @returns {void}
   411 		 * @return {void}
   412 		 */
   412 		 */
   413 		embedContent: function embedContent() {
   413 		embedContent: function embedContent() {
   414 			var view = new component.MediaEmbedView({
   414 			var view = new component.MediaEmbedView({
   415 				controller: this,
   415 				controller: this,
   416 				model:      this.state()
   416 				model:      this.state()
   417 			}).render();
   417 			}).render();
   418 
   418 
   419 			this.content.set( view );
   419 			this.content.set( view );
   420 
       
   421 			if ( ! wp.media.isTouchDevice ) {
       
   422 				view.url.focus();
       
   423 			}
       
   424 		}
   420 		}
   425 	});
   421 	});
   426 
   422 
   427 	component.MediaWidgetControl = Backbone.View.extend(/** @lends wp.mediaWidgets.MediaWidgetControl.prototype */{
   423 	component.MediaWidgetControl = Backbone.View.extend(/** @lends wp.mediaWidgets.MediaWidgetControl.prototype */{
   428 
   424 
   491 		 * @param {Object}         options - Options.
   487 		 * @param {Object}         options - Options.
   492 		 * @param {Backbone.Model} options.model - Model.
   488 		 * @param {Backbone.Model} options.model - Model.
   493 		 * @param {jQuery}         options.el - Control field container element.
   489 		 * @param {jQuery}         options.el - Control field container element.
   494 		 * @param {jQuery}         options.syncContainer - Container element where fields are synced for the server.
   490 		 * @param {jQuery}         options.syncContainer - Container element where fields are synced for the server.
   495 		 *
   491 		 *
   496 		 * @returns {void}
   492 		 * @return {void}
   497 		 */
   493 		 */
   498 		initialize: function initialize( options ) {
   494 		initialize: function initialize( options ) {
   499 			var control = this;
   495 			var control = this;
   500 
   496 
   501 			Backbone.View.prototype.initialize.call( control, options );
   497 			Backbone.View.prototype.initialize.call( control, options );
   595 		},
   591 		},
   596 
   592 
   597 		/**
   593 		/**
   598 		 * Update the selected attachment if necessary.
   594 		 * Update the selected attachment if necessary.
   599 		 *
   595 		 *
   600 		 * @returns {void}
   596 		 * @return {void}
   601 		 */
   597 		 */
   602 		updateSelectedAttachment: function updateSelectedAttachment() {
   598 		updateSelectedAttachment: function updateSelectedAttachment() {
   603 			var control = this, attachment;
   599 			var control = this, attachment;
   604 
   600 
   605 			if ( 0 === control.model.get( 'attachment_id' ) ) {
   601 			if ( 0 === control.model.get( 'attachment_id' ) ) {
   621 		},
   617 		},
   622 
   618 
   623 		/**
   619 		/**
   624 		 * Sync the model attributes to the hidden inputs, and update previewTemplateProps.
   620 		 * Sync the model attributes to the hidden inputs, and update previewTemplateProps.
   625 		 *
   621 		 *
   626 		 * @returns {void}
   622 		 * @return {void}
   627 		 */
   623 		 */
   628 		syncModelToPreviewProps: function syncModelToPreviewProps() {
   624 		syncModelToPreviewProps: function syncModelToPreviewProps() {
   629 			var control = this;
   625 			var control = this;
   630 			control.previewTemplateProps.set( control.mapModelToPreviewTemplateProps() );
   626 			control.previewTemplateProps.set( control.mapModelToPreviewTemplateProps() );
   631 		},
   627 		},
   632 
   628 
   633 		/**
   629 		/**
   634 		 * Sync the model attributes to the hidden inputs, and update previewTemplateProps.
   630 		 * Sync the model attributes to the hidden inputs, and update previewTemplateProps.
   635 		 *
   631 		 *
   636 		 * @returns {void}
   632 		 * @return {void}
   637 		 */
   633 		 */
   638 		syncModelToInputs: function syncModelToInputs() {
   634 		syncModelToInputs: function syncModelToInputs() {
   639 			var control = this;
   635 			var control = this;
   640 			control.syncContainer.find( '.media-widget-instance-property' ).each( function() {
   636 			control.syncContainer.find( '.media-widget-instance-property' ).each( function() {
   641 				var input = $( this ), value, propertyName;
   637 				var input = $( this ), value, propertyName;
   661 		},
   657 		},
   662 
   658 
   663 		/**
   659 		/**
   664 		 * Get template.
   660 		 * Get template.
   665 		 *
   661 		 *
   666 		 * @returns {Function} Template.
   662 		 * @return {Function} Template.
   667 		 */
   663 		 */
   668 		template: function template() {
   664 		template: function template() {
   669 			var control = this;
   665 			var control = this;
   670 			if ( ! $( '#tmpl-widget-media-' + control.id_base + '-control' ).length ) {
   666 			if ( ! $( '#tmpl-widget-media-' + control.id_base + '-control' ).length ) {
   671 				throw new Error( 'Missing widget control template for ' + control.id_base );
   667 				throw new Error( 'Missing widget control template for ' + control.id_base );
   674 		},
   670 		},
   675 
   671 
   676 		/**
   672 		/**
   677 		 * Render template.
   673 		 * Render template.
   678 		 *
   674 		 *
   679 		 * @returns {void}
   675 		 * @return {void}
   680 		 */
   676 		 */
   681 		render: function render() {
   677 		render: function render() {
   682 			var control = this, titleInput;
   678 			var control = this, titleInput;
   683 
   679 
   684 			if ( ! control.templateRendered ) {
   680 			if ( ! control.templateRendered ) {
   697 
   693 
   698 		/**
   694 		/**
   699 		 * Render media preview.
   695 		 * Render media preview.
   700 		 *
   696 		 *
   701 		 * @abstract
   697 		 * @abstract
   702 		 * @returns {void}
   698 		 * @return {void}
   703 		 */
   699 		 */
   704 		renderPreview: function renderPreview() {
   700 		renderPreview: function renderPreview() {
   705 			throw new Error( 'renderPreview must be implemented' );
   701 			throw new Error( 'renderPreview must be implemented' );
   706 		},
   702 		},
   707 
   703 
   708 		/**
   704 		/**
   709 		 * Whether a media item is selected.
   705 		 * Whether a media item is selected.
   710 		 *
   706 		 *
   711 		 * @returns {boolean} Whether selected and no error.
   707 		 * @return {boolean} Whether selected and no error.
   712 		 */
   708 		 */
   713 		isSelected: function isSelected() {
   709 		isSelected: function isSelected() {
   714 			var control = this;
   710 			var control = this;
   715 
   711 
   716 			if ( control.model.get( 'error' ) ) {
   712 			if ( control.model.get( 'error' ) ) {
   722 
   718 
   723 		/**
   719 		/**
   724 		 * Handle click on link to Media Library to open modal, such as the link that appears when in the missing attachment error notice.
   720 		 * Handle click on link to Media Library to open modal, such as the link that appears when in the missing attachment error notice.
   725 		 *
   721 		 *
   726 		 * @param {jQuery.Event} event - Event.
   722 		 * @param {jQuery.Event} event - Event.
   727 		 * @returns {void}
   723 		 * @return {void}
   728 		 */
   724 		 */
   729 		handleMediaLibraryLinkClick: function handleMediaLibraryLinkClick( event ) {
   725 		handleMediaLibraryLinkClick: function handleMediaLibraryLinkClick( event ) {
   730 			var control = this;
   726 			var control = this;
   731 			event.preventDefault();
   727 			event.preventDefault();
   732 			control.selectMedia();
   728 			control.selectMedia();
   733 		},
   729 		},
   734 
   730 
   735 		/**
   731 		/**
   736 		 * Open the media select frame to chose an item.
   732 		 * Open the media select frame to chose an item.
   737 		 *
   733 		 *
   738 		 * @returns {void}
   734 		 * @return {void}
   739 		 */
   735 		 */
   740 		selectMedia: function selectMedia() {
   736 		selectMedia: function selectMedia() {
   741 			var control = this, selection, mediaFrame, defaultSync, mediaFrameProps, selectionModels = [];
   737 			var control = this, selection, mediaFrame, defaultSync, mediaFrameProps, selectionModels = [];
   742 
   738 
   743 			if ( control.isSelected() && 0 !== control.model.get( 'attachment_id' ) ) {
   739 			if ( control.isSelected() && 0 !== control.model.get( 'attachment_id' ) ) {
   820 
   816 
   821 		/**
   817 		/**
   822 		 * Get the instance props from the media selection frame.
   818 		 * Get the instance props from the media selection frame.
   823 		 *
   819 		 *
   824 		 * @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame.
   820 		 * @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame.
   825 		 * @returns {Object} Props.
   821 		 * @return {Object} Props.
   826 		 */
   822 		 */
   827 		getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) {
   823 		getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) {
   828 			var control = this, state, mediaFrameProps, modelProps;
   824 			var control = this, state, mediaFrameProps, modelProps;
   829 
   825 
   830 			state = mediaFrame.state();
   826 			state = mediaFrame.state();
   869 
   865 
   870 		/**
   866 		/**
   871 		 * Map media frame props to model props.
   867 		 * Map media frame props to model props.
   872 		 *
   868 		 *
   873 		 * @param {Object} mediaFrameProps - Media frame props.
   869 		 * @param {Object} mediaFrameProps - Media frame props.
   874 		 * @returns {Object} Model props.
   870 		 * @return {Object} Model props.
   875 		 */
   871 		 */
   876 		mapMediaToModelProps: function mapMediaToModelProps( mediaFrameProps ) {
   872 		mapMediaToModelProps: function mapMediaToModelProps( mediaFrameProps ) {
   877 			var control = this, mediaFramePropToModelPropMap = {}, modelProps = {}, extension;
   873 			var control = this, mediaFramePropToModelPropMap = {}, modelProps = {}, extension;
   878 			_.each( control.model.schema, function( fieldSchema, modelProp ) {
   874 			_.each( control.model.schema, function( fieldSchema, modelProp ) {
   879 
   875 
   920 
   916 
   921 		/**
   917 		/**
   922 		 * Map model props to media frame props.
   918 		 * Map model props to media frame props.
   923 		 *
   919 		 *
   924 		 * @param {Object} modelProps - Model props.
   920 		 * @param {Object} modelProps - Model props.
   925 		 * @returns {Object} Media frame props.
   921 		 * @return {Object} Media frame props.
   926 		 */
   922 		 */
   927 		mapModelToMediaFrameProps: function mapModelToMediaFrameProps( modelProps ) {
   923 		mapModelToMediaFrameProps: function mapModelToMediaFrameProps( modelProps ) {
   928 			var control = this, mediaFrameProps = {};
   924 			var control = this, mediaFrameProps = {};
   929 
   925 
   930 			_.each( modelProps, function( value, modelProp ) {
   926 			_.each( modelProps, function( value, modelProp ) {
   944 		},
   940 		},
   945 
   941 
   946 		/**
   942 		/**
   947 		 * Map model props to previewTemplateProps.
   943 		 * Map model props to previewTemplateProps.
   948 		 *
   944 		 *
   949 		 * @returns {Object} Preview Template Props.
   945 		 * @return {Object} Preview Template Props.
   950 		 */
   946 		 */
   951 		mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() {
   947 		mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() {
   952 			var control = this, previewTemplateProps = {};
   948 			var control = this, previewTemplateProps = {};
   953 			_.each( control.model.schema, function( value, prop ) {
   949 			_.each( control.model.schema, function( value, prop ) {
   954 				if ( ! value.hasOwnProperty( 'should_preview_update' ) || value.should_preview_update ) {
   950 				if ( ! value.hasOwnProperty( 'should_preview_update' ) || value.should_preview_update ) {
   963 
   959 
   964 		/**
   960 		/**
   965 		 * Open the media frame to modify the selected item.
   961 		 * Open the media frame to modify the selected item.
   966 		 *
   962 		 *
   967 		 * @abstract
   963 		 * @abstract
   968 		 * @returns {void}
   964 		 * @return {void}
   969 		 */
   965 		 */
   970 		editMedia: function editMedia() {
   966 		editMedia: function editMedia() {
   971 			throw new Error( 'editMedia not implemented' );
   967 			throw new Error( 'editMedia not implemented' );
   972 		}
   968 		}
   973 	});
   969 	});
  1011 		},
  1007 		},
  1012 
  1008 
  1013 		/**
  1009 		/**
  1014 		 * Get default attribute values.
  1010 		 * Get default attribute values.
  1015 		 *
  1011 		 *
  1016 		 * @returns {Object} Mapping of property names to their default values.
  1012 		 * @return {Object} Mapping of property names to their default values.
  1017 		 */
  1013 		 */
  1018 		defaults: function() {
  1014 		defaults: function() {
  1019 			var defaults = {};
  1015 			var defaults = {};
  1020 			_.each( this.schema, function( fieldSchema, field ) {
  1016 			_.each( this.schema, function( fieldSchema, field ) {
  1021 				defaults[ field ] = fieldSchema['default'];
  1017 				defaults[ field ] = fieldSchema['default'];
  1031 		 * the appropriate data types (integers or booleans).
  1027 		 * the appropriate data types (integers or booleans).
  1032 		 *
  1028 		 *
  1033 		 * @param {string|Object} key - Attribute name or attribute pairs.
  1029 		 * @param {string|Object} key - Attribute name or attribute pairs.
  1034 		 * @param {mixed|Object}  [val] - Attribute value or options object.
  1030 		 * @param {mixed|Object}  [val] - Attribute value or options object.
  1035 		 * @param {Object}        [options] - Options when attribute name and value are passed separately.
  1031 		 * @param {Object}        [options] - Options when attribute name and value are passed separately.
  1036 		 * @returns {wp.mediaWidgets.MediaWidgetModel} This model.
  1032 		 * @return {wp.mediaWidgets.MediaWidgetModel} This model.
  1037 		 */
  1033 		 */
  1038 		set: function set( key, val, options ) {
  1034 		set: function set( key, val, options ) {
  1039 			var model = this, attrs, opts, castedAttrs; // eslint-disable-line consistent-this
  1035 			var model = this, attrs, opts, castedAttrs; // eslint-disable-line consistent-this
  1040 			if ( null === key ) {
  1036 			if ( null === key ) {
  1041 				return model;
  1037 				return model;
  1085 		},
  1081 		},
  1086 
  1082 
  1087 		/**
  1083 		/**
  1088 		 * Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment).
  1084 		 * Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment).
  1089 		 *
  1085 		 *
  1090 		 * @returns {Object} Reset/override props.
  1086 		 * @return {Object} Reset/override props.
  1091 		 */
  1087 		 */
  1092 		getEmbedResetProps: function getEmbedResetProps() {
  1088 		getEmbedResetProps: function getEmbedResetProps() {
  1093 			return {
  1089 			return {
  1094 				id: 0
  1090 				id: 0
  1095 			};
  1091 			};
  1122 	 * @memberOf wp.mediaWidgets
  1118 	 * @memberOf wp.mediaWidgets
  1123 	 *
  1119 	 *
  1124 	 * @param {jQuery.Event} event - Event.
  1120 	 * @param {jQuery.Event} event - Event.
  1125 	 * @param {jQuery}       widgetContainer - Widget container element.
  1121 	 * @param {jQuery}       widgetContainer - Widget container element.
  1126 	 *
  1122 	 *
  1127 	 * @returns {void}
  1123 	 * @return {void}
  1128 	 */
  1124 	 */
  1129 	component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) {
  1125 	component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) {
  1130 		var fieldContainer, syncContainer, widgetForm, idBase, ControlConstructor, ModelConstructor, modelAttributes, widgetControl, widgetModel, widgetId, animatedCheckDelay = 50, renderWhenAnimationDone;
  1126 		var fieldContainer, syncContainer, widgetForm, idBase, ControlConstructor, ModelConstructor, modelAttributes, widgetControl, widgetModel, widgetId, animatedCheckDelay = 50, renderWhenAnimationDone;
  1131 		widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen.
  1127 		widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen.
  1132 		idBase = widgetForm.find( '> .id_base' ).val();
  1128 		idBase = widgetForm.find( '> .id_base' ).val();
  1205 	/**
  1201 	/**
  1206 	 * Setup widget in accessibility mode.
  1202 	 * Setup widget in accessibility mode.
  1207 	 *
  1203 	 *
  1208 	 * @memberOf wp.mediaWidgets
  1204 	 * @memberOf wp.mediaWidgets
  1209 	 *
  1205 	 *
  1210 	 * @returns {void}
  1206 	 * @return {void}
  1211 	 */
  1207 	 */
  1212 	component.setupAccessibleMode = function setupAccessibleMode() {
  1208 	component.setupAccessibleMode = function setupAccessibleMode() {
  1213 		var widgetForm, widgetId, idBase, widgetControl, ControlConstructor, ModelConstructor, modelAttributes, fieldContainer, syncContainer;
  1209 		var widgetForm, widgetId, idBase, widgetControl, ControlConstructor, ModelConstructor, modelAttributes, fieldContainer, syncContainer;
  1214 		widgetForm = $( '.editwidget > form' );
  1210 		widgetForm = $( '.editwidget > form' );
  1215 		if ( 0 === widgetForm.length ) {
  1211 		if ( 0 === widgetForm.length ) {
  1259 	 * @memberOf wp.mediaWidgets
  1255 	 * @memberOf wp.mediaWidgets
  1260 	 *
  1256 	 *
  1261 	 * @param {jQuery.Event} event - Event.
  1257 	 * @param {jQuery.Event} event - Event.
  1262 	 * @param {jQuery}       widgetContainer - Widget container element.
  1258 	 * @param {jQuery}       widgetContainer - Widget container element.
  1263 	 *
  1259 	 *
  1264 	 * @returns {void}
  1260 	 * @return {void}
  1265 	 */
  1261 	 */
  1266 	component.handleWidgetUpdated = function handleWidgetUpdated( event, widgetContainer ) {
  1262 	component.handleWidgetUpdated = function handleWidgetUpdated( event, widgetContainer ) {
  1267 		var widgetForm, widgetContent, widgetId, widgetControl, attributes = {};
  1263 		var widgetForm, widgetContent, widgetId, widgetControl, attributes = {};
  1268 		widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
  1264 		widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
  1269 		widgetId = widgetForm.find( '> .widget-id' ).val();
  1265 		widgetId = widgetForm.find( '> .widget-id' ).val();
  1293 	 * When WordPress enqueues this script, it should have an inline script
  1289 	 * When WordPress enqueues this script, it should have an inline script
  1294 	 * attached which calls wp.mediaWidgets.init().
  1290 	 * attached which calls wp.mediaWidgets.init().
  1295 	 *
  1291 	 *
  1296 	 * @memberOf wp.mediaWidgets
  1292 	 * @memberOf wp.mediaWidgets
  1297 	 *
  1293 	 *
  1298 	 * @returns {void}
  1294 	 * @return {void}
  1299 	 */
  1295 	 */
  1300 	component.init = function init() {
  1296 	component.init = function init() {
  1301 		var $document = $( document );
  1297 		var $document = $( document );
  1302 		$document.on( 'widget-added', component.handleWidgetAdded );
  1298 		$document.on( 'widget-added', component.handleWidgetAdded );
  1303 		$document.on( 'widget-synced widget-updated', component.handleWidgetUpdated );
  1299 		$document.on( 'widget-synced widget-updated', component.handleWidgetUpdated );