1/**
2 * @output wp-admin/js/widgets/media-image-widget.js
3 */
4
5/* eslint consistent-this: [ "error", "control" ] */
6(function( component, $ ) {
7 'use strict';
8
9 var ImageWidgetModel, ImageWidgetControl;
10
11 /**
12 * Image widget model.
13 *
14 * See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
15 *
16 * @class wp.mediaWidgets.modelConstructors.media_image
17 * @augments wp.mediaWidgets.MediaWidgetModel
18 */
19 ImageWidgetModel = component.MediaWidgetModel.extend({});
20
21 /**
22 * Image widget control.
23 *
24 * See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
25 *
26 * @class wp.mediaWidgets.controlConstructors.media_audio
27 * @augments wp.mediaWidgets.MediaWidgetControl
28 */
29 ImageWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_image.prototype */{
30
31 /**
32 * View events.
33 *
34 * @type {object}
35 */
36 events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
37 'click .media-widget-preview.populated': 'editMedia'
38 } ),
39
40 /**
41 * Render preview.
42 *
43 * @return {void}
44 */
45 renderPreview: function renderPreview() {
46 var control = this, previewContainer, previewTemplate, fieldsContainer, fieldsTemplate, linkInput;
47 if ( ! control.model.get( 'attachment_id' ) && ! control.model.get( 'url' ) ) {
48 return;
49 }
50
51 previewContainer = control.$el.find( '.media-widget-preview' );
52 previewTemplate = wp.template( 'wp-media-widget-image-preview' );
53 previewContainer.html( previewTemplate( control.previewTemplateProps.toJSON() ) );
54 previewContainer.addClass( 'populated' );
55
56 linkInput = control.$el.find( '.link' );
57 if ( ! linkInput.is( document.activeElement ) ) {
58 fieldsContainer = control.$el.find( '.media-widget-fields' );
59 fieldsTemplate = wp.template( 'wp-media-widget-image-fields' );
60 fieldsContainer.html( fieldsTemplate( control.previewTemplateProps.toJSON() ) );
61 }
62 },
63
64 /**
65 * Open the media image-edit frame to modify the selected item.
66 *
67 * @return {void}
68 */
69 editMedia: function editMedia() {
70 var control = this, mediaFrame, updateCallback, defaultSync, metadata;
71
72 metadata = control.mapModelToMediaFrameProps( control.model.toJSON() );
73
74 // Needed or else none will not be selected if linkUrl is not also empty.
75 if ( 'none' === metadata.link ) {
76 metadata.linkUrl = '';
77 }
78
79 // Set up the media frame.
80 mediaFrame = wp.media({
81 frame: 'image',
82 state: 'image-details',
83 metadata: metadata
84 });
85 mediaFrame.$el.addClass( 'media-widget' );
86
87 updateCallback = function() {
88 var mediaProps, linkType;
89
90 // Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview.
91 mediaProps = mediaFrame.state().attributes.image.toJSON();
92 linkType = mediaProps.link;
93 mediaProps.link = mediaProps.linkUrl;
94 control.selectedAttachment.set( mediaProps );
95 control.displaySettings.set( 'link', linkType );
96
97 control.model.set( _.extend(
98 control.mapMediaToModelProps( mediaProps ),
99 { error: false }
100 ) );
101 };
102
103 mediaFrame.state( 'image-details' ).on( 'update', updateCallback );
104 mediaFrame.state( 'replace-image' ).on( 'replace', updateCallback );
105
106 // Disable syncing of attachment changes back to server. See <https://core.trac.wordpress.org/ticket/40403>.
107 defaultSync = wp.media.model.Attachment.prototype.sync;
108 wp.media.model.Attachment.prototype.sync = function rejectedSync() {
109 return $.Deferred().rejectWith( this ).promise();
110 };
111 mediaFrame.on( 'close', function onClose() {
112 mediaFrame.detach();
113 wp.media.model.Attachment.prototype.sync = defaultSync;
114 });
115
116 mediaFrame.open();
117 },
118
119 /**
120 * Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment).
121 *
122 * @return {Object} Reset/override props.
123 */
124 getEmbedResetProps: function getEmbedResetProps() {
125 return _.extend(
126 component.MediaWidgetControl.prototype.getEmbedResetProps.call( this ),
127 {
128 size: 'full',
129 width: 0,
130 height: 0
131 }
132 );
133 },
134
135 /**
136 * Get the instance props from the media selection frame.
137 *
138 * Prevent the image_title attribute from being initially set when adding an image from the media library.
139 *
140 * @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame.
141 * @return {Object} Props.
142 */
143 getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) {
144 var control = this;
145 return _.omit(
146 component.MediaWidgetControl.prototype.getModelPropsFromMediaFrame.call( control, mediaFrame ),
147 'image_title'
148 );
149 },
150
151 /**
152 * Map model props to preview template props.
153 *
154 * @return {Object} Preview template props.
155 */
156 mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() {
157 var control = this, previewTemplateProps, url;
158 url = control.model.get( 'url' );
159 previewTemplateProps = component.MediaWidgetControl.prototype.mapModelToPreviewTemplateProps.call( control );
160 previewTemplateProps.currentFilename = url ? url.replace( /\?.*$/, '' ).replace( /^.+\//, '' ) : '';
161 previewTemplateProps.link_url = control.model.get( 'link_url' );
162 return previewTemplateProps;
163 }
164 });
165
166 // Exports.
167 component.controlConstructors.media_image = ImageWidgetControl;
168 component.modelConstructors.media_image = ImageWidgetModel;
169
170})( wp.mediaWidgets, jQuery );
171